{"id":645,"date":"2024-09-26T10:40:23","date_gmt":"2024-09-26T14:40:23","guid":{"rendered":"https:\/\/waterloobae.com\/?p=645"},"modified":"2025-08-20T14:26:05","modified_gmt":"2025-08-20T18:26:05","slug":"ffmpeg-how-to-speed-up-some-segments-in-your-video","status":"publish","type":"post","link":"https:\/\/waterloobae.com\/blog\/2024\/09\/26\/ffmpeg-how-to-speed-up-some-segments-in-your-video\/","title":{"rendered":"[FFmpeg] How to speed up some segments in your video"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">I am making scenic trail ride videos. Those videos have some repetitive segments in them. It can be very boring to viewers. So, I wanted to speed up those segments with FFmpeg. I&#8217;ve given requirements to ChatGPT to create one Bash script for it. Since ChatGPT does not know the environments of my machine, it took much longer to try and debug those scripts generated by ChatGPT. After around two days of try and error. I could make this video with that Bash script Chat GPT created for me.<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"[4K] [050] New Format | Thrilling Ride Home (September 24, 2024) #bike #scenery #trail #commute\" width=\"800\" height=\"450\" src=\"https:\/\/www.youtube.com\/embed\/NDvhMjZjbv0?start=73&#038;feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The usage of the scripts goes as below.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash\">speedup.sh video.mp4 ranges.txt<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">speedup.sh is the name of the script you saved. ranges.txt will look like as below. Those ranges in the file will be in normal speed. All segments between those ranges will be speed up 10 times.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">00:00:00 00:00:40\n00:03:45 00:04:40\n00:05:30 00:10:20\n00:12:40 00:13:55\n00:15:16 00:16:10<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You can edit the script below to change magnitude of speed up or so. If you feel lazy, you can throw this to ChatGPT and ask to modify as you needed. I hope this helps.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash\">#!\/bin\/bash\n\n# Input parameters\nINPUT_FILE=\"$1\"\nRANGES_FILE=\"$2\"\nFRAMERATE=30\n\nif [ -z \"$INPUT_FILE\" ] || [ -z \"$RANGES_FILE\" ]; then\n    echo \"Usage: $0 &lt;input_file> &lt;ranges_file>\"\n    exit 1\nfi\n\nTEMP_DIR=$(mktemp -d)\nif [ ! -d \"$TEMP_DIR\" ]; then\n    echo \"Failed to create temporary directory\"\n    exit 1\nfi\n\nOUTPUT_FILE=\"output.mp4\"\nFINAL_CONCAT_LIST=\"$TEMP_DIR\/final_concat_list.txt\"\n\n# Empty the concat list file\n> \"$FINAL_CONCAT_LIST\"\n\n# Function to process a normal speed segment\nprocess_normal_segment() {\n    local start_time=\"$1\"\n    local end_time=\"$2\"\n    local segment_file=\"$TEMP_DIR\/normal_${start_time\/\/:\/-}_${end_time\/\/:\/-}.mp4\"\n    \n    # Generate normal speed segment with re-encoding\n    ffmpeg -fflags +genpts -hwaccel auto -r \"$FRAMERATE\" -ss \"$start_time\" -to \"$end_time\" -i \"$INPUT_FILE\" -r \"$FRAMERATE\" -avoid_negative_ts make_zero -fps_mode cfr -c:v libx264 -preset slow -crf 18 -c:a aac -b:a 192k \"$segment_file\" -y\n    if [ $? -ne 0 ]; then\n        echo \"Error processing normal segment: $start_time to $end_time\"\n        exit 1\n    fi\n    \n    # Add segment to the list\n    echo \"file '$segment_file'\" >> \"$FINAL_CONCAT_LIST\"\n}\n\n# Function to process sped-up segment\nprocess_sped_up_segment() {\n    local start_time=\"$1\"\n    local end_time=\"$2\"\n    local segment_file=\"$TEMP_DIR\/sped_${start_time\/\/:\/-}_${end_time\/\/:\/-}.mp4\"\n    \n    # Generate sped-up segment with 20x speed increase and re-encoding\n    ffmpeg -fflags +genpts -hwaccel auto -r \"$FRAMERATE\" -ss \"$start_time\" -to \"$end_time\" -i \"$INPUT_FILE\" -r \"$FRAMERATE\" -avoid_negative_ts make_zero -fps_mode cfr -filter:v \"setpts=0.05*PTS\" -c:v libx264 -preset slow -crf 18 -an \"$segment_file\" -y\n    if [ $? -ne 0 ]; then\n        echo \"Error processing sped-up segment: $start_time to $end_time\"\n        exit 1\n    fi\n    \n    # Add sped-up segment to the list\n    echo \"file '$segment_file'\" >> \"$FINAL_CONCAT_LIST\"\n}\n\n# Get the duration of the input file\ninput_duration=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 \"$INPUT_FILE\")\ninput_duration=$(echo \"$input_duration\" | awk '{printf \"%02d:%02d:%02d\\n\", $1\/3600, ($1%3600)\/60, $1%60}')\n\n# Read the ranges file and store in an array\nranges=()\nwhile IFS= read -r line; do\n    ranges+=(\"$line\")\ndone &lt; \"$RANGES_FILE\"\n\n# Debug: Echo the ranges\necho \"Ranges:\"\nfor range in \"${ranges[@]}\"; do\n    echo \"$range\"\ndone\n\n# Process each range\nprevious_end_time=\"00:00:00\"\nfor range in \"${ranges[@]}\"; do\n    IFS=' ' read -r start_time end_time &lt;&lt;&lt; \"$range\"\n    \n    # Process the segment before the current range\n    if [ \"$previous_end_time\" != \"$start_time\" ]; then\n        process_sped_up_segment \"$previous_end_time\" \"$start_time\"\n    fi\n    \n    # Process the current range as normal speed\n    process_normal_segment \"$start_time\" \"$end_time\"\n    \n    # Update the previous end time\n    previous_end_time=\"$end_time\"\ndone\n\n# Process the segment after the last range\nif [ \"$previous_end_time\" != \"$input_duration\" ]; then\n    process_sped_up_segment \"$previous_end_time\" \"$input_duration\"\nfi\n\n# Concatenate all segments into the final output file\nffmpeg -f concat -safe 0 -i \"$FINAL_CONCAT_LIST\" -c copy \"$OUTPUT_FILE\" -y\nif [ $? -ne 0 ]; then\n    echo \"Error concatenating segments\"\n    exit 1\nfi\n\n# Clean up temporary files\nrm -rf \"$TEMP_DIR\"\n\necho \"Processing complete. Output file: $OUTPUT_FILE\"<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>I am making scenic trail ride videos. Those videos have some repetitive segments in them. It can be very boring to viewers. So, I wanted to speed up those segments with FFmpeg. I&#8217;ve given requirements to ChatGPT to create one Bash script for it. Since ChatGPT does not know the environments of my machine, it [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,22],"tags":[],"class_list":["post-645","post","type-post","status-publish","format-standard","hentry","category-it-tips","category-video"],"_links":{"self":[{"href":"https:\/\/waterloobae.com\/blog\/wp-json\/wp\/v2\/posts\/645","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/waterloobae.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/waterloobae.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/waterloobae.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/waterloobae.com\/blog\/wp-json\/wp\/v2\/comments?post=645"}],"version-history":[{"count":1,"href":"https:\/\/waterloobae.com\/blog\/wp-json\/wp\/v2\/posts\/645\/revisions"}],"predecessor-version":[{"id":646,"href":"https:\/\/waterloobae.com\/blog\/wp-json\/wp\/v2\/posts\/645\/revisions\/646"}],"wp:attachment":[{"href":"https:\/\/waterloobae.com\/blog\/wp-json\/wp\/v2\/media?parent=645"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/waterloobae.com\/blog\/wp-json\/wp\/v2\/categories?post=645"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/waterloobae.com\/blog\/wp-json\/wp\/v2\/tags?post=645"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}