FFmpeg - selecting appropriate bitrate for VP9 encoding - ffmpeg

I am looking to encode a 4k video shot with iPhone 6s in VP9 in the best quality possible.
For reference, stream data of the video I would like to encode, via ffprobe:
Duration: 00:00:10.48, start: 0.000000, bitrate: 46047 kb/s
Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 3840x2160, 45959 kb/s, 29.98 fps, 29.97 tbr, 600 tbn, 1200 tbc (default)
Metadata:
creation_time : 2017-03-13T21:12:56.000000Z
handler_name : Core Media Data Handler
encoder : H.264
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, mono, fltp, 79 kb/s (default)
Metadata:
creation_time : 2017-03-13T21:12:56.000000Z
handler_name : Core Media Data Handler
I am using the following FFmpeg commands, based on these instructions (see Best Quality (Slowest) Recommended Settings section).
ffmpeg -i INPUT.mov -c:v libvpx-vp9 -pass 1 -b:v 46000K -threads 4 -speed 4 -g 9999 -an -f webm -y /dev/null
ffmpeg -I INPUT.mov -c:v libvpx-vp9 -pass 2 -b:v 46000K -threads 4 -speed 0 -g 9999 -an -f webm OUTPUT.webm
Is there a best practice to select an optimal -b:v value such that the resulting video is visually indistinguishable from the original? I have tried values ranging from 36000K-46000K, but these result in massive files with an overall bitrate exceeding the target bitrate.
Thanks in advance!

Just have to experiment with different, much lower bit rates, and view the results. I try to watch for artifacts. Does hair still look good? Cloth? Lettering, like on road signs and store windows? No blockiness? No bleeding of dark and light at sharp edges? No echoes? I find motion blur in the original hard to judge, have to compare side by side to tell the difference between that and compression artifacts.
Try 1/10th of 36000k. I find vp9 at a nominal 400k bit rate works great on 1280x720 video. (ffmpeg with libvpx-vp9 overshoots, and I typically end up with a 20% higher actual bit rate, 480k) 4K is 3840x2160, 9x the size of 1280x720, so it would seem a 3600k bit rate should produce good results.
Another guide is that vp9 is reportedly about equal in quality to mp4 at half the bit rate. Video that looks good at a 1000k bit rate in mp4 should look good at 500k in vp9.

Related

FFMPEG - concatenating mp4s from different sources - unable to stop "Non-monotonous DTS in output stream" warning

I need to concatenate mp4 files from different sources, this means some of the variables are out of my control such as timebase, aspect ratio and encoding. So to get around this I re-encode and attempt to standardise the files before concatenating them. Unfortunately, despite this I get Non-monotonous DTS in output stream warnings during the concatenation stage, and the output video seems to always have broken audio/video syncing by the last segment.
I know there are a lot of other questions out there about resolving the warning above, but I've been through them all and reviewed the documentation.. but unfortunately I've been still been unable to solve it..
I think the thing which I don't understand is: if I have mp4s from different sources, what exactly do I need to do to ensure that the files will always neatly concatenate together?
What I've tried so far
The script I'm using to standardise the mp4 files before concantenation is the following (amends resolution, frame rate, timebase, bitrate for audio, bitrate for video, audio encoding and video encoding):
ffmpeg -y -i $1 -vf 'scale=1280:720:force_original_aspect_ratio=1,pad=1280:720:(ow-iw)/2:(oh-ih)/2' -r 30 -video_track_timescale 90000 -b:a 128K -b:v 1200K -c:a aac -c:v libx264 $2
Here's the ffprobe output on two of the files, there are some differences but I'm not sure if they are significant?
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'intro.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf58.12.100
Duration: 00:00:08.98, start: 0.000000, bitrate: 1210 kb/s
Stream #0:0(eng): Video: h264 (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 1069 kb/s, 30 fps, 30 tbr, 90k tbn, 60 tbc (default)
Metadata:
handler_name : VideoHandler
Stream #0:1(eng): Audio: aac (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 132 kb/s (default)
Metadata:
handler_name : SoundHandler
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'middle.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf58.12.100
Duration: 00:00:59.72, start: 0.000000, bitrate: 1200 kb/s
Stream #0:0(und): Video: h264 (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 1063 kb/s, 30 fps, 30 tbr, 90k tbn, 60 tbc (default)
Metadata:
handler_name : VideoHandler
Stream #0:1(und): Audio: aac (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default)
Metadata:
handler_name : SoundHandler
They all have normal video and audio at this point.
After that I concatenate them and add a watermark using the following (it sucks that I need to re-encode here):
ffmpeg -y \
-f concat \
-safe 0 \
-i $INFILES \
-c:v libx264 \
-c:a copy \
-preset fast \
-vf drawtext=enable="'between(t, $DRAW_TEXT_DELAY, $DRAW_TEXT_DURATION)': fontfile=$FONT_DIR/$FONT: text='$TEXT': fontcolor=$FONTCOLOR: fontsize=$FONTSIZE: $POSITION" \
$OUTFILE
INFILES is a path to a text file formatted like:
file /usr/src/app/data/test/out/intro.mp4
file /usr/src/app/data/test/out/middle.mp4
file /usr/src/app/data/test/out/outro.mp4
What am I missing here? Is there a way to debug this further?
Your audio streams have distinct sampling rates, and may have distinct channel count as well. Also, compressed MPEG audio streams will introduce slight async upon concat.
Use
ffmpeg -y -i $1 -vf 'scale=1280:720:force_original_aspect_ratio=1,pad=1280:720:(ow-iw)/2:(oh-ih)/2,setsar=1,format=yuv420p' -r 30 -c:v libx264 -b:v 1200K -ac 2 -ar 48000 -c:a pcm_s16le -video_track_timescale 90000 $2
to standardize, but save to MOV.
Then during concat, change -c:a copy to -c:a aac.
There are three methods to concatenate files in FFmpeg.
Demuxer (You are using this)
This method can be used to concat files with the same paramters, like codecs, size, PAR, etc.
$ ffmpeg -concat -i files.txt [...] output.mp4
Protocol
Same as the first one, but on top of that, this method is useful for files that can be copied together bitwise - it doesn't involves re-encoding (some formats support this, like MpegTS or some lossless formats).
$ ffmpeg -i "concat:FILE_0| ... |FILE_N" [...] output.mp4
Filter
If you have videos with different codecs, you have to use this method:
$ ffmpeg -i <FILE_0> ... -i <FILE_N> [...] -filter_complex "[0:0][0:1]...[<N>:0][<N>:1] concat=n=<N>:v=1:a=1[v_out][a_out]" -map [v_out] -map [a_out] output.mp4
The concat filter decodes the video and reencodes it with the same parameters. It also takes care of the audio streams. I'm not entirely sure what does it do if the resolutions are different, but this should be a good start.

How to process a video to mp4 with ffmpeg for quality and compatibility?

I am beginning to be more serious about video. I am processing my videos with ffmpeg in a fully updated Linux into mp4 to use it in HTML5 directly.
Now, I have old AVI videos that I want to convert to mp4 with ffmpeg for use with HTML5. In particular, I have this one:
http://luis.impa.br/photo/1101_aves_ce/caneleiro-de-chapeu-preto_femea_Quixada-CE-110126-E_05662+7a.avi
(I know, terrible quality... sorry). According to ffprobe:
Duration: 00:01:35.30, start: 0.000000, bitrate: 1284 kb/s
Stream #0:0: Video: mpeg4 (Simple Profile) (DX50 / 0x30355844), yuv420p, 640x480 [SAR 1:1 DAR 4:3], 1144 kb/s, 30 fps, 30 tbr, 30 tbn, 30 tbc
Stream #0:1: Audio: mp3 (U[0][0][0] / 0x0055), 44100 Hz, stereo, s16p, 128 kb/s
That seems perfect: mpeg4 video and mp3 audio. So I tried:
ffmpeg -i input.avi -acodec copy -vcodec copy output.mp4
It generates a file that plays nicely in mplayer, but not in firefox getting an error:
Video format or MIME type not supported.
Chrome plays the audio, but no video is shown... Now, if I do:
ffmpeg -i input.avi output.mp4
firefox works, but the video is reencoded in another one with half the size (half the bitrate). This is what ffprobe says about the reencoded video:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf57.71.100
Duration: 00:01:35.30, start: 0.000000, bitrate: 685 kb/s
Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 640x480 [SAR 1:1 DAR 4:3], 548 kb/s, 30 fps, 30 tbr, 15360 tbn, 60 tbc (default)
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default)
I suppose that I am loosing lots of quality (and time processing the video). So, my questions:
Why are browsers not playing my video with the copy codecs ?
Can I work with ffmpeg in this particular file without reencoding? If yes, how?
If I need to reencode, which are "reasonable" parameters to keep close to the original quality? Would something like
ffmpeg -i input.avi -b:v 1024k -bufsize 1024k output.mp4
suffice for this video? This generates a new video with size closer to the original one.
Thanks!
According to ffprobe and if I see it correctly, you have a DivX (5) video file. Do not use it for web!! ;)
mpeg4 (Simple Profile) (DX50 / 0x30355844)
So I don't see any chance to use this video without reencoding. Not if you wish to support firefox.
Use WebM or h264: https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats
UPDATE
Good settings for reencode depends on your input (bitrate, resolution, fps, kind of material ...), so there is no standard answer.
But you have to specify a codec or ffmpeg choose one depending on your output file extension (so it can be the wrong one).
You can try this:
ffmpeg -i input.avi -c:v libx264 -preset slow -crf 22 -c:a copy output.mkv
Presets and tunes can help to find the best choice: https://trac.ffmpeg.org/wiki/Encode/H.264

Concat mp4 files with a command line tool

I am blocked trying to do something, and I'm ready to make a donation if somebody can help me:
I try to concat http://s.serero.free.fr/rolex.mp4 video and http://s.serero.free.fr/video.mp4 video in one output mp4 file and I tried during a big time without results.
I want to concat http://s.serero.free.fr/rolex.mp4 + http://s.serero.free.fr/video.mp4
or http://s.serero.free.fr/video.mp4 + http://s.serero.free.fr/rolex.mp4.
I tried with ffmpeg command line software and with mp4box command line software, I think that I don't have the good method.
I tried to transform http://s.serero.free.fr/video.mp4 in the same format of http://s.serero.free.fr/rolex.mp4 (and vice versa):
I transformed http://s.serero.free.fr/rolex.mp4 with the same frame rate of http://s.serero.free.fr/video.mp4
I transformed http://s.serero.free.fr/rolex.mp4 with the same video bitrate of http://s.serero.free.fr/video.mp4
I transformed http://s.serero.free.fr/rolex.mp4 with the same video audio bitrate of http://s.serero.free.fr/video.mp4
Can somebody help me?
Explain to me what is wrong in my strategy?
Your input parameters vary, so you have to make them similar before concatenation.
rolex.mp4
Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, bt709), 1280x720 [SAR 1:1 DAR 16:9], 835 kb/s, 25 fps, 25 tbr, 90k tbn, 50 tbc (default)
Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 125 kb/s (default)
video.mp4
Video: h264 (High) (avc1 / 0x31637661), yuvj420p(pc), 1152x720, 1749 kb/s, 30 fps, 30 tbr, 15360 tbn, 60 tbc (default)
Audio: mp3 (mp4a / 0x6134706D), 44100 Hz, stereo, s16p, 127 kb/s (default)
This example will make video.mp4 more like rolex.mp4 then concat them:
ffmpeg -i rolex.mp4 -i video.mp4 -filter_complex \
"[1:v]pad=1280:720:(ow-iw)/2:0,fps=25,format=yuv420p[v1]; \
[0:v][0:a][v1][1:a]concat=n=2:v=1:a=1[v][a]" \
-map "[v]" -map "[a]" output.mp4
You don't actually need to declare fps or format because, as the concat filter documentation states:
All corresponding streams must have the same parameters in all
segments; the filtering system will automatically select a common
pixel format for video streams, and a common sample format, sample
rate and channel layout for audio streams, but other settings, such as
resolution, must be converted explicitly by the user.
...but doing so will allow you to manually choose the "common" settings instead of relying on the filter automatically doing so and potentially selecting a setting you don't want.
Thanks for LordNeckbeard for his excellent answer, he just let a little mistake on the command, i just want to a little explanation :
If I want to concat video.mp4(1152X720) with rolex.mp4(1280X720), we must understand that "video.mp4" is the main video so the video(s) to concatene must have exactly the same frame size.
So before to do this operation you need to resize rolex.mp4 video with the same size like video.mp4 with ffmpeg :
ffmpeg -i rolex.mp4 -s 1152x720 -c:a copy newrolexsized.mp4
No video.mp4 and newrolexsized.mp4 has the same frame size, and you can use the command (spcifying pad=1152:720 => size of the main video):
ffmpeg -i video.mp4 -i newrolexsized.mp4 -filter_complex "[1:v]pad=1152:720:(ow-iw)/2:0,fps=25,format=yuv420p[v1];[0:v][0:a][v1][1:a]concat=n=2:v=1:a=1[v][a]" -map "[v]" -map "[a]" out.mp4

How to use the information from ffprobe to use with ffmpeg. Is there a shortcut to the syntax?

Want to batch convert a bunch of different video files from cli instead of Rolands old-and-slow-drag-and-drop-one-file-at-a-time-software. I have used ffprobe in OS X Terminal here. This shows us what the software did to the file and I want to do the same. MJPEG AVI I get but the rest, how would my ffmpeg syntax look to achieve this result efter converting?
Example: My ffprobe give me this
Input #0, avi, from 'P10_0001.AVI':
Metadata:
comment :
encoder : Roland Corporation
Duration: 00:03:17.64, start: 0.000000, bitrate: 16694 kb/s
Stream #0:0: Video: mjpeg (MJPG / 0x47504A4D), yuvj422p(pc, bt470bg/unknown/unknown), 640x480, 15285 kb/s, 25 fps, 25 tbr, 25 tbn, 25 tbc
Stream #0:1: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 44100 Hz, 2 channels, s16, 1411 kb/s
What would the ffmpeg syntax look like to do this with a new file.
I've been trying some simple ones but those are not accepted by the machine (Edirol p-10) and I hope someone can point me in the right direction. :)
Edit:
OK. The syntax I want to do is involving 3 files.
File that has the correct codec and everything to work with the machine. P10_0001.AVI
A file that does not have the correct format (codec etc.) softvision.mpg
A new file just as file 2 but with the codec of file number 1. P10_0002.AVI
ffmpeg -i gradomat.mpg -framerate 25 -vf scale=640:480 -vcodec mjpeg -pix_fmt yuvj422p -b:v 15285k -b:a 1411k -acodec pcm_s16le -ar 44100 -ac 2 -metadata encoder="Roland Corporation" P10_000X.AVI
Think this solved it temporarily but the problem is that I have to write that my self, it would have been better if ffprobe gave me that syntax instead.
This is also a solution, but in python.
https://github.com/cskonopka/rolandp10fp

how to convert videos to flv using ffmpeg in php?

i am trying to convert some different video formats to flv using ffmpeg. But it seems that only some videos go through.
ffmpeg -i /var/www/tmp/91640.avi -ar 22050 -ab 32 -f flv /var/www/videos/91640.flv
here is some debug info:
Seems stream 0 codec frame rate differs from container frame rate: 23.98 (65535/2733) -> 23.98 (5000000/208541)
Input #0, avi, from '/var/www/tmp/91640.avi':
Duration: 00:01:12.82, start: 0.000000, bitrate: 5022 kb/s
Stream #0.0: Video: mpeg4, yuv420p, 1280x528 [PAR 1:1 DAR 80:33], 23.98 tbr, 23.98 tbn, 23.98 tbc
Stream #0.1: Audio: ac3, 48000 Hz, 5.1, s16, 448 kb/s
WARNING: The bitrate parameter is set too low. It takes bits/s as argument, not kbits/s
Output #0, flv, to '/var/www/videos/91640.flv':
Stream #0.0: Video: flv, yuv420p, 1280x528 [PAR 1:1 DAR 80:33], q=2-31, 200 kb/s, 90k tbn, 23.98 tbc
Stream #0.1: Audio: adpcm_swf, 22050 Hz, 5.1, s16, 0 kb/s
Stream mapping:
Stream #0.0 -> #0.0
Stream #0.1 -> #0.1
Error while opening codec for output stream #0.1 - maybe incorrect parameters such as bit_rate, rate, width or height
also, if i try to grab one frame ad convert it to jpeg i get an error as well
ffmpeg -i /var/www/tmp/91640.avi -an -ss 00:00:03 -t 00:00:01 -r 1 -y /var/www/videos/91640.jpg
debug info
...
[mpeg4 # 0x1d7d810]Invalid and inefficient vfw-avi packed B frames detected
av_interleaved_write_frame(): I/O error occurred
Usually that means that input file is truncated and/or corrupted.
im thinking that the image fails because the video conversion failed in the first place, not sure though
any ideas what goes wrong?
Bits, not kbits
From your console output:
WARNING: The bitrate parameter is set too low. It takes bits/s as argument, not kbits/s
Use 32k, not just 32.
Only stereo or mono is supported
The encoder adpcm_swf ony supports mono or stereo, so add -ac 2 as an output option. The console output would have suggested this if you were using a recent ffmpeg build.
Use -vframes 1 for single image outputs
Instead of -t 00:00:01 -r 1 use -vframes 1.
A better encoder
Instead of using the encoders flv and adpcm_swf, I recommend libx264 and libmp3lame:
ffmpeg -i input -vcodec libx264 -preset medium -crf 23 -acodec libmp3lame -ar 44100 -q:a 5 output.flv
-preset – Controls the encoding speed to compression ratio. Use the slowest preset you have patience for: ultrafast,superfast, veryfast, faster, fast, medium, slow, slower, veryslow.
-crf – Constant Rate Factor. A lower value is a higher quality. Range is 0-51 for this encoder. 0 is lossless, 18 is roughly "visually lossless", 23 is default, and 51 is worst quality. Use the highest value that still gives an acceptable quality.
-q:a – Audio quality for libmp3lame. Range is 0-9 for this encoder. A lower value is a higher quality.
Also see
FFmpeg and x264 Encoding Guide
Encoding VBR (Variable Bit Rate) mp3 audio

Resources