FFmpeg static keyframe rate - ffmpeg

I have a question about ffmpeg usage. Every time when I trying to convert video files into
some different format, output file getting static keyframe sequence.
What I mean is that keyframes appear at the distance of 12 frames. I know that its controllerd by parameter -g that you can change to any other number.
ffmpeg -i 1.avi -vcodec mpeg4 -b 2000000 out.avi
I believe there should be some way to make keyframes appear on uneven intervals. These interval should be calculated by codec, and it should be based on image changes in the video file. So keyframes should be inserted only when they needed, but not consistently after N frames.
Can somebody please explain to me how this "smart" encoding can be done with ffmpeg ?
Thank you
SOLUTION: ok what I'ev been looking for has very simple solution. If you set -g to zero, ffmpeg will choose keyframes based on the video shots and bitrate

If you set -g to zero, ffmpeg will choose keyframes based on the video shots and bitrate

Related

Increase bit rate while converting FFMPEG

I am trying to convert an .mp4 to .mpeg using:
ffmpeg -i "01_b.wmv" -an -c:v mpeg1video -b:v 20M "intro.mpeg"
My source video is 20MB/s but the converted .mpeg file doesn't ever go that high (usually ends up being around 12MB/s).
Is there something I am missing? I am relatively inexperienced with FFMPEG, so any help is appreciated.
The bit rate is calculated to an average at output versus being a simple duration/file size calculation. 100MB file, 10s = 10Mb/s, even though 40Mb/s could be the two seconds, and the rest is a lower bit rate.

Prepending generated audio silence when merging audio w/ non-zero starting PTS and video with zero-based PTS for equal duration, aligned streams

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.

ffmpeg output file smaller than input file

I am using ffmpeg to rotate videos 90 or 180 degrees in a Python script. It works great. But, I am curious as to why the output file would be a smaller amount of bytes than the input file.
Here are the commands I use:
180 degrees:
ffmpeg -i ./input.mp4 -preset veryslow -vf "transpose=2,transpose=2,format=yuv420p" -metadata:s:v rotate=0 -codec:v libx264 -codec:a copy ./output.mp4
90 degrees:
ffmpeg -i ./input.mp4 -vf "transpose=2" ./output.mp4
For example, a GoPro Hero 3 MP4 file was originally 2.0 GB. The resulting output file was 480.9 MB. Another GoPro file was 2.0 and its resulting file was 671.5 MB. Is this maybe because the GoPro files were 2.0 but contains empty space, sort of like how some NTFS filesystems make a minimal 4k file, even when there is less bytes in it?
If this isn't the GoPro Hero 3, how do I rotate the files 90 or 180 degrees but ensure the output file size is the same? Or, is data loss expected? Does the data loss have to do with the format?
Note that the quality of the video doesn't appear to be damaged, which is good. So, I am interested in learning more about why this is happening, then I can read the section of ffmpeg documentation that is relevant to this.
Thank you!
Bitrate is ignored from the start
ffmpeg fully decodes the input into uncompressed raw video and audio (except when stream copying – more about that below). The input format or bitrate does not matter: it does this for all formats. The encoder then works from these raw, decoded frames. See diagram.
H.264 vs H.264
Your input and output are both H.264. A format, such as H.264, is created by an encoder. Anyone can make an encoder. However, not all encoders are equal. Given the same input, the output from one H.264 encoder may have the same quality as an output from another H.264 encoder, but the bitrate may be several times smaller.
The GoPro H.264 encoder was made to work on a platform with limited hardware. That means bitrate (file size) is sacrificed for speed and quality. x264 is the ultimate H.264 encoder: nothing can beat its quality-to-bitrate ratio.
Rotate without re-encoding
You can stream copy (re-mux) and rotate at the same time. The rotation is handled by the metadata/sidedata:
ffmpeg -i input.mp4 -metadata:s:v rotate=90 -c copy output.mp4
Downside is your player/device may ignore the rotation, so you may have to physically rotate with filters which requires re-encoding, and therefore stream copy can't be used.
I had the same rotation issue once...
I fixed it by "resetting" the rotation instead...
ffmpeg ...... -metadata:s:v rotate="0" ......

FFMPEG change fps of audio and subtitles and merge 2 files

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.

ffmpeg transcode video from different sizes to 4:3

We have some videos that have different scale and aspect ratio and we'd like to convert them to a fix 640x480 size (4/3 ar letterbox padding if necessary).
Two sizes are occurs very often: 853 × 480, 1280 × 720.
I made some research and tries before write this question but didn't get the expected result.
For example:
ffmpeg -i video.mp4 -vf "scale=640:480,pad=640:480:(ow-iw)/2:(oh-ih)/2,setdar=4/3" -c:a copy output.mp4
setdar=4/3 seems to required because if I omitted the result remain the original aspect ratio.
Are there any solution for different size conversion?
The generic filterchain for fitting a video in a WxH canvas is
"scale=iw*sar:ih,scale=640:480:force_original_aspect_ratio=decrease,pad=640:480:-1:-1"
The first scale filter makes sure the video is not kept anamorphic. If you know the video is square-pixels, you can skip it. The 2nd filter fits the video in a canvas of 640x480 using the force_original_aspect_ratio option.

Resources