I need to trim a video without encoding into sections that later i can put back together with the concat demuxer of ffmpeg, in a way that when i join the video i have the same lenght of the original file. I understand that to cut precisely without encoding it is necessary to cut at keyframes, i'm using this command to get the keyframes:
ffprobe -loglevel error -select_streams v:0 -show_entries packet=pts_time,flags -of csv=print_section=0 -input | awk -F',' '/K/ {print $1}'
and they also correspond to the times that Avidemux reports for the keyframes. I'm using this command to trim the source:
ffmpeg -ss 00:0:2.4607 -noaccurate_seek -avoid_negative_ts 1 -i input.mp4 -to 00:0:3.545 -c copy /content/out.mp4
But it always ends up with different durations. I would expect that if i cut between keyframe at time 2.460792 and keyframe at time 3.545208 i would get a video of lenght that is the difference between those two times, but it is never the case.
Any help? thanks
Try StreamFab Downloader and download from Netflix, Amazon, Youtube! Or Try DVDFab and copy Blu-rays!
+ Reply to Thread
Results 1 to 10 of 10
Thread
-
-
I've found that the keyframe readings using Avidemux are 0.066 seconds larger than those when using VirtualDub2, at least on MP4 video files. The VirtualDub2 keyframe readings match exactly the ffprobe keyframe readings. If you use the keyframes from VirtualDub2 in your ffmpeg cutter command, you should get the correct length. However one weird note: You have to subtract exactly 0.1 second from all the keyframe readings to get the exact cut points even when starting at 0.0 which becomes -0.1 seconds. It's easy to find your keyframe cut point using 2 running copies of VirtualDub2 working on the same video. I've been cutting and reassembling my original multiple episode Doctor Who videos into single videos so I don't have to listen to all the theme music between the episodes. This means matching scenes between episodes which seems to work well. Oh, by the way I do have a life! I just like working on little projects like this. One last note: Using ffmpeg to cut your videos, keeps the embedded subtitles where using Avidemux or VirtualDub2 won't.
Clarification: The above 0.066 seconds difference was measured on a video with a frame rate of 29.97. It's really a 2 frame difference ( 2 / 29.97 ) = 0.06673 seconds. For a 59.94 frame rate video, it's a difference of 0.03337 seconds. For a 23.976 frame rate video, it's a difference of 0.08345 seconds.Last edited by pjcrown; 15th Oct 2020 at 19:03.
-
When there are no subtitles Avidemux is excelent, always keep in mind that your cut needs to start on an I Frame and must end on an I or P frame, wo when in avidemux up and down keys go to I frames left and right keys to every frame, while navigating to an endpoint of your cut make sure that's it on a P frame.
-
If you cut from key frame through the 'P' frame before the next Key frame, FFmpeg will cut correctly, If you include the next Key frame or more as the end point, FFMpeg will include, alter PTS, or exclude frames. Case in point Cut IBBBPBBBPBBBPIBB and you will get IBBBPBBBPBBBPIBP but the timings for the last couple of frames will not be the correct length of the frame duration.
Also, If the audio and video length do not match, the total size of the video will be altered to match the longest one.
If you use FFMpeg correctly it is a great tool:
1. Cut from I frame THROUGH the last frame before the next key frame (Usually a 'P' frame for Closed GOP)
2. Make sure the last frames PTS's are separated by equal amounts (25fps = .04, .04, .04)
3. these can be checked using a batch file that list each frame:
4. Using -vframes tends to be more accurate.
Code:ffmpeg -ss 2.240000 -i "C:\Mixed GOP Black Yellow Test Video.mp4" -vframes 56 -c:v copy -c:a copy -y "C:\0_0_Mixed GOP Blak Yellow Test Video.mp4"
[Attachment 55860 - Click to enlarge]
Example cutting 56 frames (28 +28):
[Attachment 55857 - Click to enlarge]
Original Frame times:
[Attachment 55858 - Click to enlarge]
End result:
[Attachment 55859 - Click to enlarge]
Notice the last frame does not include the 3rd segments start time of 4.48 (4.48-2.24=224) End segment is 2.20 for .04 but does not include 2.24 frame time
Time always:
General
Complete name : C:\0_0_Mixed GOP Black Yellow Test Video.mp4
Format : MPEG-4
Format profile : Base Media
Codec ID : isom (isom/iso2/avc1/mp41)
File size : 28.7 KiB
Duration : 2 s 240 ms
Overall bit rate mode : Variable
Overall bit rate : 105 kb/s
Writing application : Lavf58.47.100 -
@Budman1
3. these can be checked using a batch file that list each frame
Any suggestions?? -
You need to have ffprobe in the same folder as the CMD file or use the pathed ffprobe on your computer.
It creates a csv file and a simplified text file (like the 'original frame times image in my post). It takes a while to scan
a large video but that can be shortened with multiple ffprobe statements to read the beginning few frames and the end frames.
Try it on a short filed to ssee its performance
This is the drag and drop CMD file I use. Create is as a CMD file and then drag/drop your video onto it.:
Code:setlocal enabledelayedexpansion @echo off ::for %%a in (*.mp4,*.mpg,*.flv) Do ( for %%a in ("%~nx1") Do ( set /a count=0 cd %%~dpa echo frame,media_type,stream_index,key_frame,pkt_pts,pkt_pts_time,pkt_dts,pkt_dts_time,best_effort_timestamp,^ best_effort_timestamp_time,pkt_duration,pkt_duration_time,pkt_pos,pkt_size,^ Width,Height,pix_fmt,sample_aspect_ratio,pict_type,coded_picture_number,display_picture_number,^ interlaced_frame,top_field_first,repeat_pict,color_range,color_space,color_primaries,color_transfer,^ chroma_location > "%%~na_ffprobe.csv" echo No. pts_time type > "%%~na_AllFrames.txt" ver > nul set /a Number=0 ffprobe.exe -v quiet -select_streams v:0 -print_format csv -show_entries frame "%%~nxa" >> "%%~na_ffprobe.csv" for /F "tokens=4,6,18,19 delims=," %%b in ('findstr "video" "%%~na_ffprobe.csv"') do ( set "x=%%b" set "y=%%c" set "z=%%d" set "w=%%e" set "v=%%f" set "u=%%g" set sort=!y:~0,-7! ::if !sort! GEQ 0 if !sort! LEQ 10 echo !count! !y:~0,13! !x! !w:~0,1! >> "%%~na_AllFrames.txt" echo !count! !y:~0,13! !x! !w:~0,1! >> "%%~na_AllFrames.txt" set /a count+=1 set /a ekko=count%%100 if !ekko! EQU 0 echo Frame !count! processed ) ) rem pause
-
Shortened version asks for how many frames at the beginning to list (Minimum 5 due to FFprobe characteristics) and
How long the file is in seconds. The way FFprobe seeks the end of a file is to seek to the last 'I' frame and since this
may be 250 frames to the end for maximum GOP size, the count is hard coded to 250. Its not perfect like you can get
in a windows GUI version but its a lot faster than scanning a long video.
Code:setlocal enabledelayedexpansion @echo off ::for %%a in (*.mp4,*.mpg,*.flv) Do ( set /P searchno=set number of frames to search set /P duration=set length in seconds ::set /a searchno=10 for %%a in ("%~nx1") Do ( set /a count=0 cd %%~dpa echo frame,media_type,stream_index,key_frame,pkt_pts,pkt_pts_time,pkt_dts,pkt_dts_time,best_effort_timestamp,^ best_effort_timestamp_time,pkt_duration,pkt_duration_time,pkt_pos,pkt_size,^ Width,Height,pix_fmt,sample_aspect_ratio,pict_type,coded_picture_number,display_picture_number,^ interlaced_frame,top_field_first,repeat_pict,color_range,color_space,color_primaries,color_transfer,^ chroma_location > "%%~na_ffprobe.csv" echo No. pts_time type > "%%~na_AllFrames.txt" ver > nul set /a Number=0 ffprobe.exe -v quiet -select_streams v:0 -print_format csv -show_entries frame -read_intervals %%+#!searchno! "%%~nxa" >> "%%~na_ffprobe.csv" ffprobe.exe -v quiet -select_streams v:0 -print_format csv -show_entries frame -read_intervals !duration!%%+#250 "%%~nxa" >> "%%~na_ffprobe.csv" for /F "tokens=4,6,18,19 delims=," %%b in ('findstr "video" "%%~na_ffprobe.csv"') do ( set "x=%%b" set "y=%%c" set "z=%%d" set "w=%%e" set "v=%%f" set "u=%%g" set sort=!y:~0,-7! ::if !sort! GEQ 0 if !sort! LEQ 10 echo !count! !y:~0,13! !x! !w:~0,1! >> "%%~na_AllFrames.txt" echo !count! !y:~0,13! !x! !w:~0,1! >> "%%~na_AllFrames.txt" set /a count+=1 set /a ekko=count%%100 if !ekko! EQU 0 echo Frame !count! processed ) )
-
@Budman1 thanks a lot for that script, here's a revised .cmd version which avoids extra spaces:
Code:setlocal enabledelayedexpansion @echo off ::for %%a in (*.mp4,*.mpg,*.flv) Do ( for %%a in ("%~nx1") Do ( set /a count=0 cd %%~dpa echo frame,media_type,stream_index,key_frame,pkt_pts,pkt_pts_time,pkt_dts,pkt_dts_time,best_effort_timestamp,^ best_effort_timestamp_time,pkt_duration,pkt_duration_time,pkt_pos,pkt_size,^ Width,Height,pix_fmt,sample_aspect_ratio,pict_type,coded_picture_number,display_picture_number,^ interlaced_frame,top_field_first,repeat_pict,color_range,color_space,color_primaries,color_transfer,^ chroma_location> "%%~na_ffprobe.csv" echo No. pts_time type> "%%~na_AllFrames.txt" ver > nul set /a Number=0 ffprobe.exe -v quiet -select_streams v:0 -print_format csv -show_entries frame "%%~nxa" >> "%%~na_ffprobe.csv" for /F "tokens=4,6,18,19 delims=," %%b in ('findstr "video" "%%~na_ffprobe.csv"') do ( set "x=%%b" set "y=%%c" set "z=%%d" set "w=%%e" set "v=%%f" set "u=%%g" set sort=!y:~0,-7! ::if !sort! GEQ 0 if !sort! LEQ 10 echo !count! !y:~0,13! !x! !w:~0,1!>> "%%~na_AllFrames.txt" echo !count! !y:~0,13! !x! !w:~0,1!>> "%%~na_AllFrames.txt" set /a count+=1 set /a ekko=count%%100 if !ekko! EQU 0 echo Frame !count! processed ) ) rem pause
Code:#!/bin/sh if [ $# -eq 0 ]; then printf "Usage: %s file [file...]\n" "$0" exit 1 fi for a in "$@"; do # Check if the file exists if [ ! -f "$a" ]; then printf "File not found: %s\n" "$a" continue fi cd "$(dirname "$a")" || { printf "Failed to change directory to %s\n" "$(dirname "$a")"; continue; } base_name="$(basename "${a%.*}")" { printf "frame,media_type,stream_index,key_frame,pkt_pts,pkt_pts_time,pkt_dts,pkt_dts_time,best_effort_timestamp," printf "best_effort_timestamp_time,pkt_duration,pkt_duration_time,pkt_pos,pkt_size," printf "Width,Height,pix_fmt,sample_aspect_ratio,pict_type,coded_picture_number,display_picture_number," printf "interlaced_frame,top_field_first,repeat_pict,color_range,color_space,color_primaries,color_transfer," printf "chroma_location\r\n" } > "${base_name}_ffprobe.csv" ffprobe -v quiet -select_streams v:0 -print_format csv -show_entries frame "$a" | sed 's/$/\r/' >> "${base_name}_ffprobe.csv" count=0 printf "No. pts_time type\r\n" > "${base_name}_AllFrames.txt" grep "video" "${base_name}_ffprobe.csv" | cut -d, -f4,6,18,19 | while IFS=, read -r b d f h j l; do printf "%s %s %s %s\r\n" "$count" "${d:0:13}" "$b" "${h:0:1}" >> "${base_name}_AllFrames.txt" count=$((count + 1)) if [ $((count % 100)) -eq 0 ]; then printf "Frame %d processed\n" "$count" fi done done
Similar Threads
-
Downloading video full of m4v chunks
By umbada in forum Video Streaming DownloadingReplies: 5Last Post: 17th Oct 2019, 03:28 -
Salvage FLV video, several downloads, missing chunks (source disappeared)
By abolibibelot in forum RestorationReplies: 6Last Post: 17th Aug 2019, 18:05 -
Searching *.mp4 video editor which allows deletion of chunks without re-enc
By pxstein in forum EditingReplies: 5Last Post: 15th May 2017, 09:40 -
Reencoding video to a lower bitrate: downsample first?
By pachura in forum Video ConversionReplies: 3Last Post: 31st Mar 2017, 12:14 -
Cutting mkv without reencoding
By Clnthl in forum EditingReplies: 1Last Post: 16th Oct 2015, 09:59