ffmpeg is cutting video length incorrectly - ffmpeg

I use ffmpeg to check the length of the video and to cut video.
I have a video with the lenght of 19.458333 seconds that's why i want to cut it to only have 19 seconds because i don't want the floating point.
I check the video length using below command
ffprobe -i "video.avi" -show_entries format=duration -v quiet -of csv="p=0"
And I use below command to cut video the video
ffmpeg -i "video.avi" -ss 00:00:00 -t 00:00:19.000 -c copy out.mp4
or
ffmpeg -i "video.avi" -ss 00:00:00 -t 19 -c copy output.avi
The problem i have is when i cut the video with the above command and check the length the output file's length is 19.018 seconds. Can someone help me with this problem?

If your video is 30 frames per second, that means each frame is 1/30 or 0.0333 seconds per frame. So .018 is less than one frames duration.

Related

ffmpeg: cutting 20 seconds of video starting from the middle time in a bash cycle

im in a bash script looping a dir full of .mp4 video files each one with a different lenght.
Now: how can i cut 20 seconds starting in the exact middle of any video?
For a single file i can read manually the duration of the video so i know at what second start cutting: e.g.
for a 120 sec. video i use
ffmpeg -i "tmpfile.mp4" -ss 60 -t 20 -c copy "outputfile.mp4" 2>/dev/null
but now the problem is that the "-ss" value should be a variable with the (total lenght of video/2)
some videos are long less than a minute, some are long many minutes, and some are more than one hour.
Thanks
Cant find a middle time value to start cutting
Use ffprobe
len=$(ffprobe -v error -show_entries format=duration -of compact=p=0:nk=1 input.mp4)
mid=$((${len%.*} / 2))
ffmpeg -v error -ss $mid -i input.mp4 -t 20 -c copy output.mp4

Non-consistent results between ffprobe and ffmpeg for keyframes identification

Trying to identify both thumbnails and timestamps of keyframes on a set of videos, I'm getting different results from ffmpeg and ffprobe.
Taking a 1 min. long video as an example:
youtube-dl -f 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/mp4' 'https://www.youtube.com/watch?v=BHlAlN3z4ss' --output "test.mp4"
1/ I extract thumbnails and write on the image the timestamp at which it was extracted:
ffmpeg -i test.mp4 -q:v 2 -vf select="eq(pict_type\,PICT_TYPE_I)","drawtext=fontfile=/path/to/Arial.ttf:fontsize=45:fontcolor=yellow:box=1:boxcolor=black:x=(W-tw)/2:y=H-th-10:text='Time\: %{pts\:hms}'" -vsync 0 thumbs/preview%05d.jpg
2/ I extract and save the timestamps of all keyframes:
ffprobe -v error -skip_frame nokey -show_entries frame=pkt_pts_time -select_streams v -of csv=p=0 test.mp4 | sort -n > keyframes_timestamps.txt
3/ Comparing results, I figure ffprobe found 29 keyframes, while ffmpeg found only 32. Comparing manually, we can see that specific keyframes are not detected by ``ffprobe` while most are very similar.
ffprobe_ts ffmpeg_ts
0.000000 00:00:00.00
5.366667 00:00:05.367
7.200000 00:00:07.200
8.666667 00:00:08.667
10.100000 00:00:10.100
11.500000 00:00:11.500
14.233333 00:00:14.233
15.333333 00:00:15.333
17.366667 00:00:17.367
NO_TS 00:00:18.833
20.800000 00:00:20.800
24.533333 00:00:24.533
25.700000 00:00:25.700
26.033333 00:00:26.033
On larger videos, this happens for around less that 5% of the keyframes.
I can't find an explanation about that, does anyone have a clue ? or an advice on where/what I should inquire further ?
Thanks for your help !
Not all I-frames are keyframes. -skip_frame nokey will skip non-KF I-frames.

ffpmeg vs ffprobe performance

I wanted to try extracting frames at scene changes with ffmpeg, vs. getting the frame numbers with ffprobe and extracting them later.
But I had a surprise: ffprobe seems to be much slower than ffmpeg, while ffmpeg is taking the frames, resizing and saving them as well.
ffmpeg command line:
ffmpeg -hide_banner -y -i d:/test/m/long.mkv -vf "select=gt(scene\,0.4), showinfo, scale=320:-1, tile=12x200" -vsync 0 thumbnails%03d.png
this takes: 488 seconds
ffprobe command line:
ffprobe -show_frames -of compact=p=0 -f lavfi "movie=/test/m/long.mkv,select=gt(scene\,.4)"
this takes: 899 seconds
I am missing something?

ffmpeg convertation image<->video causes artefacts

I want to convert video to images, do some image processing and convert images back to video.
Here is my commands:
./ffmpeg -r 30 -i $VIDEO_NAME "image%d.png"
./ffmpeg -r 30 -y -i "image%d.png" output.mpg
But in output.mpg video I have some artefacts like in jpeg.
Also I don't know how to detrmine fps, I set fps=30 (-r 30).
When I use above first command without -r it produces a lot of images > 1kk, but than I use -r 30 option it produce same number of images as this command calculationg number of frames:
FRAME_COUNT=`./ffprobe -v error -count_frames -select_streams v:0 -show_entries stream=nb_read_frames -of default=nokey=1:noprint_wrappers=1 $VIDEO_NAME`
So my questions are:
How to determine frame rate ?
How to convert images to video and don't reduce initial quality?
UPDATE:
Seems this helped, after I removed -r option
Image sequence to video quality
so resulting command is :
./ffmpeg -y -i "image%d.png" -vcodec mpeg4 -b $BITRATE output_$BITRATE.avi
but I'm still not sure how to select bitrate.
How can I see bitrate of original .mp4 file?
You can use the qscale parameter instead of bitrate e.g.
ffmpeg -y -i "image%d.png" -vcodec mpeg4 -q:v 1 output_1.avi
q:v is short for qscale:v. 1 may produce too large files. 4-6 is a decent range to use.

FFmpeg take screenshots from videos with variable duration

I have bunch of videos which are rather long, so I take screenshots of 10th second (-ss 00:00:10). Sometimes videos are very short, like 5 seconds, and -ss 00:00:10 fails.
I don't have an option to compute video size as don't have an option to download them whole (videos are hosted on S3 and used as streams through CloudFront).
Maybe there are some built-in options that I overlooked?
What I really don't want to do is shorten -ss option gradually on fails so it would be the last resort.
One liner:
ffprobe -show_entries format=filename,duration -of default=noprint_wrappers=1:nokey=1 /path/to/input/file -loglevel 0 | awk 'BEGIN {RS="";FS="\n"}{system("ffmpeg -ss "$2/2" -i "$1" -vframes 1 out.png") }'
meaning:
use ffprobe to get the file duration in seconds then pipe to awk and execute the frame extraction ffmpeg command using a seek time equal to duration/2

Resources