How to use constrained/capped bit rate mode in FFmpeg - ffmpeg

I used FFmpeg with this command to convert a video:
ffmpeg -i input -c:v libx264 -x264-params opencl=true -preset veryslow -crf 19 -maxrate 7000k -profile:v high -level 4.0 -bf 2 -coder 1 -pix_fmt yuv420p -c:a copy output.mkv
Note that I set -maxrate 7000k to set the maximum bit rate for the video. Still, the end result video has a maximum bit rate of 38.0 Mb/s.
Here are the results before (to the left) and after (to the right), if that helps.
Am I using maxrate properly? Should not the video be capped at 7000 kb/s?

maxrate is enforced via the bufsize option. No bufsize, no enforcement. See https://stackoverflow.com/a/33612662
The smaller the bufsize relative to maxrate, closer the actual peak bitrate to maxrate, but expect transient quality dips (if maxrate is too low for desired quality).
Start with
-maxrate 7000k -bufsize 7000k

Related

Live stream prerecorded video to YouTube using FFMPEG with 4500 kbps bitrate

I tried various ways to make a live streaming script with a bit rate according to YouTube's recommendation of 4500 Kbps bit rate.
The code:
ffmpeg -re -stream_loop -1 -i live1.mp4 -c copy -preset veryfast -b:v 7000k -maxrate 3000k -bufsize 6000k -pix_fmt yuv420p -g 50 -c:a aac -b:a 160k -ac 2 -ar 44100 -f flv -flvflags no_duration_filesize rtmp://a.rtmp.youtube.com/live2/(streamkey)
and in my current code, there is an error when live: Use a keyframe frequency of four seconds or less. Currently, keyframes are sent infrequently which can cause buffering. The current keyframe frequency is 5.0 seconds. Please note that errors in the transfer process can cause the size of the GOP (group of images) to be incorrect.
How to fix my code?
I've tried several ways, but the bit rate is still high, and the error is in YouTube Studio

Ffmpeg nvenc encoder on gpu does not compress files as much as compared to libx264

I wanted to encode a video file which was initially encoded by a libx264 encoder on a non gpu machine with ultrafast preset and crf 23 , i typically re-encode it with preset medium and get a good compression but the process is very slow , so i am considering a gpu based solution
my current command to use ffmpeg on a nvidia turing gpu
ffmpeg -y -vsync passthrough -hwaccel cuda -i a.mp4 -max_muxing_queue_size 9999 -pix_fmt yuv420p -c:v h264_nvenc -preset medium -tune ll -b:v 4M -bufsize 4M -maxrate 10M -qmin 0 b.mp4
usual command i use to do the same
ffmpeg -i a.mp4 -max_muxing_queue_size 9999 -pix_fmt yuv420p -c:v libx264 -preset medium b.mp4
enter code here
How can i make this command do a better job at reducing file size , i am okay to compromise on the quality of the video for a good reduction in size
I would highly recommend reading this H.264 Video Encoding Guide
On the surface, these variants can help you:
Decrease your bitrate
Add -cq option with suitable value 0-51 (-cq for h264_nvenc is pretty the same as -crf for libx264)
Change -tune option value to hq
Try two-pass encoding (if you know desired output file size), but here is very low benefit
If you struggle with available options for h264_nvenc you can see the whole list of them by executing following command:
ffmpeg -hide_banner -h encoder=h264_nvenc
Most of them are self descriptive or similar from libx264

While ffmpeg is recording, I want it to create a smaller and lower quality video

Currently I am using this...
ffmpeg -video_size 1920x1080 -framerate 1 -f x11grab -i :0.0+0,0 -f pulse -ac 2 -i default -t 00:00:10 Output.mkv
While ffmpeg is recording a video, I want it to significantly reduce both the size and quality compared to the ffmpeg command above.
In case you are curious, I am recording brief quality assurance videos to ensure a simple little web scraper I wrote in Python is scraping data properly (specifically, that it is clicking on a particular button, at a particular time, on a particular web page). My Python script triggers the command above to start recording my screen a few seconds before my Python script is supposed to click on that button.
Of course, to verify a button on a web page had been clicked on, low quality video resolution would normally suffice.
For libx264/libx265 the most important option to reduce both the size and quality is -crf. This option controls quality. A value of 51 provides the worst quality. If it's too terrible then use a lower number.
ffmpeg -video_size 1920x1080 -framerate 1 -f x11grab -i :0.0+0,0 -f pulse -channels 2 -i default -t 00:00:10 -c:v libx264 -crf 51 -c:a libopus Output.mkv
See FFmpeg Wiki: H.264.
For significantly reduce both the size and quality of Output.mkv you can use the next ffmpeg configuration:
crop: iw-(cut width in pixels):ih-(cut heigth in pixels)
scale: to set the ratio and resolution (example 1700x800)
crf: to set quality, where 0 is lossless, 23 is default, and 51 is worst possible. A lower value is a higher quality and a subjectively sane range is 18-28. Consider 18 to be visually lossless
bitrate value: -b:v value -minrate value and -maxrate max value (example -b:v 4000K -minrate 2000K -maxrate 6000K)
preset: in theory slow is best quality/size, and you can probe ultrafast
superfast
veryfast
faster
fast
medium – default preset
slow
slower
veryslow
Cut a part of video, changue the resolution, changue crf, and bitrate, first only video, then you can add audio in other work, dont mix, repeat, is very important, encoding/decoding audio and video separate, then you can mix all, but first the video like in this example
ffmpeg -i Output.mkv -map 0:v -vf crop=iw-150:ih-85,scale=ih*16/9:ih,scale=1072:732,setsar=1 -c:v libx264 -crf 17 -b:v 4000K -maxrate 6000K -bufsize 4M -movflags -faststart -preset veryfast -dn video-new.mkv

FFmpeg: Get better encoding out of my function

I needed some assistance on my task.
I am using FFmpeg to burn time and the channel name onto the video.
My goal is to record a stream that is html5 compatible with the following settings:
Video wrapper MP4
Video codec H.264
Bitrate 1Mbps
Audio codec AAC
Audio bitrate 128Kbps
And GPU encoding.
This is what I am using:
ffmpeg -hwaccel cuvid -y -i {udp} -vf "drawtext=fontfile=calibrib.tff:fontsize=25:text='{ChannelName} %{localtime}': x=10: y=10: fontcolor=white: box=1: boxcolor=0x000000" -pix_fmt yuv420p -vsync 1 -c:v h264_nvenc -r 25 -threads 0 -b:v 1M -profile:v main -minrate 1M -maxrate 1M -bufsize 10M -sc_threshold 0 -c:a aac -b:a 128k -ac 2 -ar 44100 -af "aresample=async=1:min_hard_comp=0.100000:first_pts=0" -bsf:v h264_mp4toannexb -t 00:30:00 {output}\{ChannelName}\{ChannelName}_{year}_{monthno}_{day}__{Hours}_{Minutes}_{Seconds}.mp4
{ChannelName}_{year}_{monthno}_{day}__{Hours}_{Minutes}_{Seconds} are all variable holding information.
{udp} holds the UDP stream link.
I have done it this way as I have multiple UDP stream recording.
Although this works, is there a better way for me to do this keeping in the -vf as I need the time and channel name.
Currently, this uses between 0.8% to 1.9% GPU on my Quadro P4000. I don't want to use more than this as I have more than 30 streams.
Here are some of the suggestion
-profile:v use Constrained Baseline Profile or Baseline Profile - as most of the Browser or HTML will support.
Check How many parallel instances of the Encoder you can run on GPU - Quadro P4000, remaining you can run on cpu.
Based on the resolution & fps you can decide the video bitrate of encoding range min & max bitrate. (-b:v 1M -minrate 1M -maxrate 1M) - refer : https://trac.ffmpeg.org/wiki/Limiting%20the%20output%20bitrate
-sc_threshold (FFmpeg)
Adjusts the sensitivity of x264's scenecut detection. Rarely needs to be adjusted. Recommended default: 40

Does a scencut feature of H.264 increases a file size?

When I use this command:
ffmpeg -i original.mp4 -codec:v:0 libx264 -b:v 650k -crf 21 -minrate:v 0k -maxrate:v 750k -bufsize:v 5000k -r 30 -preset slow -x264opts "no-scenecut" -vcodec libx264 -force_key_frames "expr:bitor(eq(t,0),gte(t,prev_forced_t+5))" -f mp4 test.mp4
I always get smaller file size than from this command (same command but without: -x264opts "no-scenecut"):
ffmpeg -i original.mp4 -codec:v:0 libx264 -b:v 650k -crf 21 -minrate:v 0k -maxrate:v 750k -bufsize:v 5000k -r 30 -preset slow -vcodec libx264 -force_key_frames "expr:bitor(eq(t,0),gte(t,prev_forced_t+5))" -f mp4 test.mp4
I thought that the scencut puts I frames only if it is more efficient to use I frame insted of P or B frame.
In what cases we need to use the scencut feature?
When a scenecut triggers it puts either an IDR if the distance is greater than min-keyint OR an I-frame otherwise.
Here's some pseudo-code posted on the doom9.org forum (adding it here for future reference):
encode current frame as (a really fast approximation of) a P-frame and an I-frame.
if ((distance from previous keyframe) > keyint) then
set IDR-frame
else if (1 - (bit size of P-frame) / (bit size of I-frame) < (scenecut / 100) * (distance from previous keyframe) / keyint) then
if ((distance from previous keyframe) >= minkeyint) then
set IDR-frame
else
set I-frame
else
set P-frame
encode frame for real.
You should use scenecut when you don't need a fixed GOP / forced keyframes. If you're trying to encode for ABR delivery then you can alternatively use two-pass encoding and generate a stat file for the highest resolution on pass-1 and then reuse it on pass-2 for each rendition.

Resources