Our security system records and archives our IP cameras streams with ffmpeg -use_wallclock_as_timestamps 1 -i rtsp://192.168.x.x:554/mpeg4 -c copy -t 60 my_input_video.avi
I run it with crontab every minute so it creates videos of 60 seconds (~15Mb) for each camera every minute. When an intrusion occurs, the camera sends a picture through FTP and a script called by incrontab:
1- forwards immediately the picture by email
2- selects the video covering the minute the intrusion occured, compress it with h264 (to ~2,6Mb) and sends it by email
It is working really well but if a thief crosses the path of various cameras, the connection to the SMTP server is not fast enough so video emails are delayed. I'd like to compress the videos even more to avoid that. I could lower the resolution (640x480 to 320x240 for example) but sometimes 640x480 is handy to zoom on something which looks to be moving...
So my idea is to drop frames in the video in order to lower the filesize. I don't care if the thief is walking like a "stop motion Lego" on the video, the most important is I know there is someone so I can act.
mediainfo my_input_video.avi says Frame rate = 600.000 fps but it is of course wrong. FPS sent by IP cameras are always false because it varies with the network quality; this is why i use "-use_wallclock_as_timestamps 1" in my command to record the streams.
with ffmpeg -i my_input_video.avi -vcodec h264 -preset ultrafast -crf 28 -acodec mp3 -q:a 5 -r 8 output.avi the video is OK but filesize is higher (3Mb)
with ffmpeg -i my_input_video.avi -vcodec h264 -preset ultrafast -crf 28 -acodec mp3 -q:a 5 -r 2 output.avi the filesize is lower (2,2Mb) but the video doesn't work (it is blocked at the first frame).
Creating a mjpeg video (mjpeg = not interlaced frames) in the middle of the process (first exporting to mjpeg with less frames and then exporting to h264) creates same results.
Do you know how I can get my thief to walk like a "stop motion Lego" to lower the filesize to a minimum?
Thanks for any help
What are your constraints file size wise? 2.6MB for 60 seconds of video seems pretty reasonable to me, thats about 350kbps, which is pretty low for video quality.
You need to specify the video bitrate -b:v 125000 (125kbps, should drop you to about 900kb) to control the bitrate/s you want the video encoded at. Your not giving FFMpeg enough hints as to how you want the video handled, so its picking arbitrary values you don't like. As you drop the frame rate, its just using up the buffers allocating more bits to each frame. (one big thing you need to keep in mind with this is, as you stretch the video out over a longer time period the more likely the scene will change significantly require an I frame (full encoded frame vs frame based on previous frame) so reducing the frame rate will help some, but may not help as much as you'd think).
Your "(it is blocked at the first frame)." is most likely an issue with you trying to start decoding a stream when it is not at an I frame and not an issue with your settings.
Related
When extracting segments from a media file with video and audio streams without re-encoding (-c copy), it is likely that the requested seek & end time specified will not land precisely on a keyframe in the source.
In this case, ffmpeg will grab the nearest keyframe of each track and position them with differing starting PTS values so that they remain in sync.
Video keyframes tend to be a lot more spaced apart, so you can often end up with something like this:
Viewing the clip in VLC, the audio will start at 5 seconds in.
However, in other video players or video editors I've noticed this can lead to some playback issues or a/v desync.
A solution would be to re-encode both streams when extracting the clip, allowing ffmpeg to precisely seek to the specified seek time and generating equal length & synced audio and video tracks.
However, in my case I do not want to re-encode the video, it is costly and produces lower quality video and/or greater file sizes. I would prefer to only re-encode the audio, filling the initial gap with generated silence.
This should be simple, but everything I've tried has failed to generate silence before the audio stream begins.
I've tried apad, aresample=sync=1, and using amerge to combine the audio with anullsrc. None of it works.
All I can think to possibly get around this is to use ffprobe on the misaligned source to retrieve the first audio PTS, and in a second ffmpeg process apply this value as a negative -itoffset, then concatting the audio track with generated silence lasting the duration of silence... But surely there's a better way, with just one instance of ffmpeg?
Any ideas?
I just stumbled across the solution by trying some more things.
I take the misaligned source media and process it with another ffmpeg instance with some audio filters:
ffmpeg -fflags +genpts -i input.mkv -c copy -c:a aac -af apad,aresample=async=1:first_pts=0 -ac 2 -shortest -y output.mkv
And it does exactly what I want, pads the beginning (and end) of the audio stream with silence making the audio stream equal length to the video.
The only drawback is that I can't combine this with my original ffmpeg command that extracts the clip, the only way this works is as a 2-step process.
I have 30 mkv files which have multiple audio streams and multiple subtitles.
For each file I am trying to: extract the dutch audio and subtitles from that file (25fps)
And merge it with another mkv file (23.976216fps)
With this command it seems like I extract the dutch audio and subtitles into a mkv:
ffmpeg -y -r 23.976216 -i "S01E01 - Example.mkv" -c copy -map 0:m:language:dut S01E01.mkv
But it does not adjust the fps from 25 to 23.976216.
I think I am going to use mkvmerge to merge the two mkv's, but they need to be the same framerate
Anyone knows how I could make this work? Thanks! :)
The frame rate of the video has nothing to do with the frame rate of audio. They are totally independent. In fact there is really no such thing as audio frame rate (well, there is, but that’s a byproduct of the codecs). If you are changing the video frame rate by dropping frames, you are not changing the videos duration, hence you should not change the audios duration. If you are slowing down the video, you must decode the audio, slow it down (likely with pitch correction) and re-encode it.
Something like this would change the audio pitch from standard PAL to NTSC framerate (example valid if your audio track is the 2nd in list, -check with ffmpeg -i video.mkv and see-)
ffmpeg -i video.mkv -vn -map 0:1 -filter:a atempo=0.95904 -y slowed-down-audio-to-23.976-fps.ac3
(23976/25000 = 0.95904 so this is the converted frame rate needed for NTSC films)
Conversely, you can figure out how to speed up NTSC standard frame rate audio to the PAL system (1.0427094).
This trick works, for example, should you want to add a better quality audio track obtained from a different source.
First, I have looked at the older questions asking the same, but the responses do not work.
Adding -r 30 or 60 to the input file does not impact the output, nor does setting it for the output, which remains unchanged.
I am handling a very large number of files from 1 to 22 gigs recorded (with audio) in 30fps that need to be re-posted as 60pfs, with the corresponding speed increase.
I toyed with ffmpeg a bit and came up with this..
-filter_complex "[0:v]setpts=0.50*PTS[v];[0:a]atempo=2.0[a]" -map "[v]" -map "[a]" -vcodec:v libx264
It works fine, but to have to wait out a complete re-encoding of the video and audio to produce the same video with the fps changed seems like an insane waste of time.
Am I missing something simple? Is there not a way to -c copy with a new fps playback rate on the resulting file?
(if it still has to recode the audio to maintain sync that's fine, audio is quick enough it doesn't much matter)
I have slideshow video (i.e. 10GB) 1080p quality (30 FPS), and each image lasts about 15 seconds ...
Is there any option with FFMPEG, to convert those 15 seconds periods from 30 FPS(because they are just duplicate frames) into i.e. 1 fps, thus, making the video small size...
the only periods that should keep original FPS is the fadeout period from image to image (that lasts 3 seconds... they are not duplicate frames, each frame is different because of fade-out effect).
You just need to re-encode with ffmpeg using a mid CRF value, like between 24-27. I-frames will be smaller but mainly P-frames which are static will only take few dozen bytes to store. Actually decimating the static frames and keeping the fade sequences at full FPS can be done but will be cumbersome and subject to trial and error. Just doing a simple re-encode will get you most of the size savings you would have gotten
Basic command is
ffmpeg -i in.mp4 -crf 25 -c:a copy out.mp4
I'm creating a fragmented MP4 for the use of playing in Media Source Extensions.
The command line is: ffmpeg.exe -probesize 10000000 -r 10 -i - -vcodec copy -an -f mp4 -reset_timestamps 0 -blocksize 30000 -movflags empty_moov+default_base_moof+frag_keyframe -loglevel debug -
The source of the video is an IP camera streaming H.264.
The configured and expected frame rate is 10FPS but there is no guarantee for 10FPS, for example a frame may get dropped occasionally, or the camera may just not play nice with what it declares.
I have simulate a 10% p-frames drops to emphasize the following issue:
With the above command, the output video plays faster than real-time and this is a problem because the whole pipe is a live stream.
With the 10% frame drop simulation, the effective playback rate it 1.1x.
I don't want to obligate to a fixed frame rate because there is no guarantee for a fixed-rate.
If I remove the -r 10 flag entirely, the MP4 seems to the playing at 2x-3x speed.
Is there a way building the MP4 timestamps in a more dynamic way? for example, giving it the RTP timestamp or somehow telling ffmpeg to build the MP4 with the timestamp of the "feed" time?