ffmpeg frame grabbing slow on mp4 files - ffmpeg

The following ffmpeg frame grab command takes a long time to grab an image from the mp4 file.
ffmpeg.exe -itsoffset -200 -i C:\93844428.mp4 -vcodec mjpeg -vframes 1 -y -an -f rawvideo -s 640x360 C:\test\out1.jpg
For a 20MB file (about 2 minutes of video) it takes up to about 6 seconds to find the image depending on what offset (in seconds) you ask to grab it.
For a 100MB it can anything in many minutes if you request a large offset.
This only appears to be an issue with mp4 files.
Is there anything that can be done to improve this?

This logic is inefficient to do a frame grab. Don't use itsoffset. If you want frame at a particular location use the -ss switch to set the time offset you want the frame from.

Related

ffmpeg frame accurate seek with minimum delay

I have a project where I need to extract part of a video near the end of video files and it needs to be frame accurate. I can extract my segment frame accurately now using '-vf' filter command and it works very well. The only problem is for large high-resolution files, the seek time ends up being 10X the time required for the extraction/encoding part. Is there any other or faster way to extract videos frame accurately?
The working command that I am currently using is below:
ffmpeg -i 'test_input.mp4' -vf 'trim=start_frame=134037:end_frame=135024,setpts=PTS-STARTPTS' -an -c:v libx264 -preset slow -f mp4 'test_output.mp4' -y 2>&1

How to make ffmpeg automatically fill frames?

I want to use ffmpeg to convert a sequence of images to a video, the images are got in realtime, the interval of getting image is changeable, maybe i get next image in 1 second or even 1 millisecond.
I want the target video in a special fps(like 100), now my implement is creating a loop, which fade ffmpeg last image then sleep(like 10ms).
Do you guys know some options could let ffmpeg fill frames automatically?
If that option do exist, i wonder is that possible to make video real fps is half of it is claimed.
My ffmpeg command likes follow:
ffmpeg -f image2pipe -r 100 -i pipe:0 -f flv -r 100 pipe:1
You can use
ffmpeg -f image2pipe -use_wallclock_as_timestamps 1 -i pipe:0 -f flv -vsync cfr -r 100 pipe:1
FFmpeg will set each incoming frame's timestamp to the time it is received. SInce the output rate is set and mode is constant frame rate, ffmpeg will duplicate the last frame till next input frame is received, or drop if two frames are less than 10ms apart. Change -r to 1000 to keep frames only a millisecond apart.

Sync files timestamp with ffmpeg

I'm capturing video from 4 cameras connected with HDMI through a capture card. I'm using ffmpeg to save the video feed from the cameras to multiples jpeg files (30 jpeg per second per camera).
I want to be able to save the images with the capture time. Currently I'm using this command for one camera:
ffmpeg -f video4linux2 -pixel_format yuv420p -timestamps abs -I /dev/video0 -c:a jpeg -t 60 -ts_from_file 2 camera0-%5d.jpeg
It saves my file with the names camera0-00001.jpg, camera0-00002.jpg, etc.
Then I rename my file with camera0-HH-mm-ss-(1-30).jpeg based on the modified time of the file.
So in the end I have 4 files with the same time and same frame like this:
camera0-12-00-00-1.jpeg
camera1-12-00-00-1.jpeg
camera2-12-00-00-1.jpeg
camera3-12-00-00-1.jpeg
My issue is that the file may be offset from one to two frame. They may have the same name but sometime one or two camera may show different frame.
Is there a way to be sure that the capture frames has the actual time of the capture and not the time of the creation of the file?
You can use the mkvtimestamp_v2 muxer
ffmpeg -f video4linux2 -pixel_format yuv420p -timestamps abs -copyts -i /dev/video0 \
-vf setpts=PTS-STARTPTS -vsync 0 -vframes 1800 camera0-%5d.jpeg \
-c copy -vsync 0 -vframes 1800 -f mkvtimestamp_v2 timings.txt
timings.txt will have output like this
# timecode format v2
1521177189530
1521177189630
1521177189700
1521177189770
1521177189820
1521177189870
1521177189920
1521177189970
...
where each reading is the Unix epoch time in milliseconds.
I've switched to output frame count limit to stop the process instead of -t 60. You can use -t 60 for the first output since we are resetting timestamps there, but not for the second. If you do that, remember to only use the first N entries from the text file, where N is the number of images produced.

ffmpeg dump specific length of video after seeking PICT_TYPE_I keyframe

I have a flv video and want to dump let's say 3s length of the video after first keyframe PICT_TYPE_I meet after 00:39. I ready the document of ffmpeg seeking and quote here
ffmpeg -ss 00:23:00 -i Mononoke.Hime.mkv -frames:v 1 out1.jpg
This example will produce one image frame (out1.jpg) at the
twenty-third minute from the beginning of the movie. The input will be
parsed using keyframes, which is very fast. As of FFmpeg 2.1, when
transcoding with ffmpeg (i.e. not just stream copying), -ss is now
also "frame-accurate" even when used as an input option. Previous
behavior (seeking only to the nearest preceding keyframe, even if not
precisely accurate) can be restored with the -noaccurate_seek option.
So I think if I use this command (put -ss before -i)
ffmpeg -noaccurate_seek -ss 00:39 -i input.flv -r 10 -s 720x400 -t 3.12 dump.flv
And this should dump a video that last 3.12s and begin with the first keyframe after 00:39 right? after all, this is what I need.
But the result is dump.flv not start with a keyframe, ie a PICT_TYPE_I frame.
I know I could find all keyframe start time with ffprobe and re-calculate the -ss seeking time to achieve this. But is there a better way?
If audio is of no concern, you can use
ffmpeg -ss 39.00 -i in.flv -vf select='if(eq(pict_type,I),st(1,t),gt(t,ld(1)))',setpts=N/FRAME_RATE/TB -an -t 3.12 out.flv
Here, the select filter discards all frames before the first keyframe which is after the seek point. The t value controls the total duration selected.
Do note that video duration is quantized i.e. a 25 fps video can have duration in steps of 0.04s.

FFmpeg Slideshow issues

trying to get my head around ffmpeg to create a slideshow where each image is displayed for ~5 seconds with some audio. created a bat file to run the following so far:
ffmpeg -f image2 -i image-%%03d.jpg -i music.mp3 output.mpg
It gets the images and displayes them all very fast in the first second of the video, it then plays out the rest of the audio while showing the last image.
I want to make the images stay up longer (about 5 seconds), and stop the video after the last frame (not playing the rest of the song), are either of these things possible? i could hack the frame rate thing i guess by having hundreds of the same image in order to keep it up longer, but this is far from ideal!
Thanks
The default encoder for mpg output, mpeg1video, is strict about the allowed frame rates, so an input and an output -r are required:
ffmpeg -r 1/5 -i image-%03d.jpg -i music.mp3 -r 25 -qscale:v 2 -shortest -codec:a copy output.mpg
The input images will have a frame rate of 1 frame every 5 seconds and the output will duplicate frames to reach 25 frames per second.
-f image2 is generally not required.
-qscale:v can control output quality. A sane range is 2-5.
-shortest will make the output duration the same as the shortest input duration.
-codec:a copy copy your MP3 audio instead of re-encoding.
MPEG-1 video has more modern alternatives. See the FFmpeg and x264 Encoding Guide for more info.
Also see:
* FFmpeg FAQ: How do I encode single pictures into movies?
* FFmpeg Wiki: Create a video slideshow from images
You could use the filter fps instead of output framerate
ffmpeg -r 1/5 -i img%03d.png -i musicfile -c:v libx264 -vf fps=25 -pix_fmt yuv420p out.mp4
This however skips the last image for me strangely.

Resources