Skip to content

Instantly share code, notes, and snippets.

@mikoim
Last active November 25, 2024 14:00
Show Gist options
  • Save mikoim/27e4e0dc64e384adbcb91ff10a2d3678 to your computer and use it in GitHub Desktop.
Save mikoim/27e4e0dc64e384adbcb91ff10a2d3678 to your computer and use it in GitHub Desktop.
[Updated! Aug 14 2020] YouTube recommended encoding settings on ffmpeg (+ libx264)

Parameters

Container: MP4

Parameter YouTube recommends setting
-movflags faststart moov atom at the front of the file (Fast Start)

Video codec: H.264

Parameter YouTube recommends setting Note
-c:v libx264 H.264
-profile:v high High Profile
-bf 2 2 consecutive B frames
Closed GOP x264 produces closed gop as default
-g 30 GOP of half the frame rate.
CABAC Normally, x264 uses CABAC as an entropy encoder.
-crf 18 Variable bitrate. Currently, YouTube does not have a bitrate limit. Refer official document: https://support.google.com/youtube/answer/1722171?hl=en
-pix_fmt yuv420p Chroma subsampling: 4:2:0 If you like to encode HDR video, this comment might be helpful. https://gist.github.com/mikoim/27e4e0dc64e384adbcb91ff10a2d3678#gistcomment-2859601

Audio codec: AAC-LC

Parameter YouTube recommends setting Note
-c:a libfdk_aac -profile:a aac_low AAC-LC Fraunhofer FDK AAC is a high-quality codec library, but it does not compatible GPL. So your FFmpeg most likely does not contain it. Build FFmpeg manually or use a built-in AAC encoder instead of libfdk_aac.
-b:a 384k Mono 128 kbps, Stereo 384 kbps, 5.1 512 kbps

Sample video

References

ffmpeg version N-98725-gcfc6552032 Copyright (c) 2000-2020 the FFmpeg developers
built with gcc 10 (GCC)
configuration: --prefix=xxx --enable-nonfree --enable-gpl --enable-libfdk-aac --enable-libx264 --enable-libx265
libavutil 56. 58.100 / 56. 58.100
libavcodec 58.100.100 / 58.100.100
libavformat 58. 50.100 / 58. 50.100
libavdevice 58. 11.101 / 58. 11.101
libavfilter 7. 87.100 / 7. 87.100
libswscale 5. 8.100 / 5. 8.100
libswresample 3. 8.100 / 3. 8.100
libpostproc 55. 8.100 / 55. 8.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'source.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf58.20.100
Duration: 00:00:23.60, start: 0.000000, bitrate: 13088 kb/s
Stream #0:0(eng): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 3840x2160, 12970 kb/s, 23.98 fps, 23.98 tbr, 24k tbn, 47.95 tbc (default)
Metadata:
handler_name : ?Mainconcept Video Media Handler
Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 129 kb/s (default)
Metadata:
handler_name : #Mainconcept MP4 Sound Media Handler
Stream mapping:
Stream #0:0 -> #0:0 (h264 (native) -> h264 (libx264))
Stream #0:1 -> #0:1 (aac (native) -> aac (libfdk_aac))
Press [q] to stop, [?] for help
[libx264 @ 0x2337f40] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2 AVX512
[libx264 @ 0x2337f40] profile High, level 5.1, 4:2:0, 8-bit
[libx264 @ 0x2337f40] 264 - core 159 r2999 296494a - H.264/MPEG-4 AVC codec - Copyleft 2003-2020 - http://www.videolan.org/x264.html - options: cabac=1 ref=5 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=8 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=2 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=27 lookahead_threads=4 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=2 b_pyramid=2 b_adapt=1 b_bias=0 direct=3 weightb=1 open_gop=0 weightp=2 keyint=12 keyint_min=1 scenecut=40 intra_refresh=0 rc_lookahead=12 rc=crf mbtree=1 crf=18.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
Output #0, mp4, to 'output.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf58.50.100
Stream #0:0(eng): Video: h264 (libx264) (avc1 / 0x31637661), yuv420p, 3840x2160, q=-1--1, 23.98 fps, 24k tbn, 23.98 tbc (default)
Metadata:
handler_name : ?Mainconcept Video Media Handler
encoder : Lavc58.100.100 libx264
Side data:
cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A
Stream #0:1(eng): Audio: aac (libfdk_aac) (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, s16, 384 kb/s (default)
Metadata:
handler_name : #Mainconcept MP4 Sound Media Handler
encoder : Lavc58.100.100 libfdk_aac
[mp4 @ 0x2346280] Starting second pass: moving the moov atom to the beginning of the file0.881x
frame= 565 fps= 20 q=-1.0 Lsize= 50496kB time=00:00:23.57 bitrate=17548.0kbits/s speed=0.828x
video:49380kB audio:1107kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.017619%
[libx264 @ 0x2337f40] frame I:54 Avg QP:12.52 size:145222
[libx264 @ 0x2337f40] frame P:508 Avg QP:15.73 size: 83671
[libx264 @ 0x2337f40] frame B:3 Avg QP:15.72 size: 72715
[libx264 @ 0x2337f40] consecutive B-frames: 98.9% 1.1% 0.0%
[libx264 @ 0x2337f40] mb I I16..4: 32.3% 61.1% 6.6%
[libx264 @ 0x2337f40] mb P I16..4: 18.7% 32.0% 0.7% P16..4: 21.4% 3.8% 1.2% 0.0% 0.0% skip:22.1%
[libx264 @ 0x2337f40] mb B I16..4: 4.4% 10.4% 0.4% B16..8: 48.1% 7.4% 0.4% direct: 3.5% skip:25.4% L0:65.6% L1:33.4% BI: 1.0%
[libx264 @ 0x2337f40] 8x8 transform intra:62.0% inter:85.3%
[libx264 @ 0x2337f40] direct mvs spatial:33.3% temporal:66.7%
[libx264 @ 0x2337f40] coded y,uvDC,uvAC intra: 25.4% 34.5% 3.6% inter: 5.2% 15.3% 0.0%
[libx264 @ 0x2337f40] i16 v,h,dc,p: 11% 21% 8% 60%
[libx264 @ 0x2337f40] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 30% 18% 23% 4% 5% 5% 6% 5% 5%
[libx264 @ 0x2337f40] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 32% 16% 18% 5% 8% 7% 6% 4% 4%
[libx264 @ 0x2337f40] i8c dc,h,v,p: 56% 22% 17% 5%
[libx264 @ 0x2337f40] Weighted P-Frames: Y:0.0% UV:0.0%
[libx264 @ 0x2337f40] ref P L0: 72.7% 1.1% 15.9% 6.0% 2.6% 1.7%
[libx264 @ 0x2337f40] ref B L0: 89.1% 7.4% 3.5%
[libx264 @ 0x2337f40] kb/s:17165.92
#!/bin/bash
AAC_ENCODER=libfdk_aac
# AAC_ENCODER=aac
AUDIO_PARAMS="-c:a $AAC_ENCODER -profile:a aac_low -b:a 384k"
VIDEO_PARAMS="-pix_fmt yuv420p -c:v libx264 -profile:v high -preset slow -crf 18 -g 30 -bf 2"
CONTAINER_PARAMS="-movflags faststart"
# You need to adjust the GOP length to fit your source video.
# 60 fps -> -g 30
# 23.976 (24000/1001) -> -g 24000/1001/2 (???) <- plz comment
ffmpeg -i "$1" $AUDIO_PARAMS $VIDEO_PARAMS $CONTAINER_PARAMS "$2"
General
Complete name : output.mp4
Format : MPEG-4
Format profile : Base Media
Codec ID : isom (isom/iso2/avc1/mp41)
File size : 49.3 MiB
Duration : 23 s 616 ms
Overall bit rate : 17.5 Mb/s
Writing application : Lavf58.50.100
Video
ID : 1
Format : AVC
Format/Info : Advanced Video Codec
Format profile : [email protected]
Format settings : CABAC / 5 Ref Frames
Format settings, CABAC : Yes
Format settings, Reference frames : 5 frames
Format settings, GOP : M=1, N=11
Codec ID : avc1
Codec ID/Info : Advanced Video Coding
Duration : 23 s 566 ms
Bit rate : 17.2 Mb/s
Width : 3 840 pixels
Height : 2 160 pixels
Display aspect ratio : 16:9
Frame rate mode : Constant
Frame rate : 23.976 (24000/1001) FPS
Color space : YUV
Chroma subsampling : 4:2:0
Bit depth : 8 bits
Scan type : Progressive
Bits/(Pixel*Frame) : 0.086
Stream size : 48.2 MiB (98%)
Writing library : x264 core 159 r2999 296494a
Encoding settings : cabac=1 / ref=5 / deblock=1:0:0 / analyse=0x3:0x113 / me=hex / subme=8 / psy=1 / psy_rd=1.00:0.00 / mixed_ref=1 / me_range=16 / chroma_me=1 / trellis=2 / 8x8dct=1 / cqm=0 / deadzone=21,11 / fast_pskip=1 / chroma_qp_offset=-2 / threads=27 / lookahead_threads=4 / sliced_threads=0 / nr=0 / decimate=1 / interlaced=0 / bluray_compat=0 / constrained_intra=0 / bframes=2 / b_pyramid=2 / b_adapt=1 / b_bias=0 / direct=3 / weightb=1 / open_gop=0 / weightp=2 / keyint=12 / keyint_min=1 / scenecut=40 / intra_refresh=0 / rc_lookahead=12 / rc=crf / mbtree=1 / crf=18.0 / qcomp=0.60 / qpmin=0 / qpmax=69 / qpstep=4 / ip_ratio=1.40 / aq=1:1.00
Language : English
Codec configuration box : avcC
Audio
ID : 2
Format : AAC LC
Format/Info : Advanced Audio Codec Low Complexity
Codec ID : mp4a-40-2
Duration : 23 s 616 ms
Bit rate mode : Constant
Bit rate : 384 kb/s
Channel(s) : 2 channels
Channel layout : L R
Sampling rate : 48.0 kHz
Frame rate : 46.875 FPS (1024 SPF)
Compression mode : Lossy
Stream size : 1.08 MiB (2%)
Language : English
Default : Yes
Alternate group : 1
@varenc
Copy link

varenc commented Sep 4, 2020

For anyone else on macOS looking to use ffmpeg with the libfdk_aac encoder, check out this 3rd party homebrew formula. Tap it and then brew install/compile ffmpeg with the --with-fdk-aac option.

That said, ffmpeg's own aac encoder has gotten way better than it used to be and works fine for me.

@alou-S
Copy link

alou-S commented Oct 19, 2020

I would highly suggest using -preset veryfast because it both produces a smaller file size and is twice as fast as -preset slow. (Can be even faster when using lesser threads)

If you want file sizes smaller than -preset veryfast you will have use -preset veryslow instead which is painstakingly slow and not worth the time.

I have tested this on my own and it's even shown in detail here.

Note: I think that the lower file size is due to a small loss in video quality but again a rate control is already being used so the loss is minimal.

@bassel999
Copy link

I would highly suggest using -preset veryfast because it both produces a smaller file size and is twice as fast as -preset slow. (Can be even faster when using lesser threads)

If you want file sizes smaller than -preset veryfast you will have use -preset veryslow instead which is painstakingly slow and not worth the time.

I have tested this on my own and it's even shown in detail here.

Note: I think that the lower file size is due to a small loss in video quality but again a rate control is already being used so the loss is minimal.

@alou-S
Man you did great job, I was impreased by your test.

@varenc
Copy link

varenc commented Dec 19, 2020

I would highly suggest using -preset veryfast because it both produces a smaller file size and is twice as fast as -preset slow. (Can be even faster when using lesser threads)

What about the encoded video's quality? A smaller file doesn't mean it's better compressed. For something I only have to upload once, I still say go with the slow preset. Even with the same crf, a slower preset likely produce a higher quality encoding. Though I agree it's weird and confusing how -preset veryfast seems to be the odd one out when compared with the other presets.

I found this great answer on Stack Overflow that does a nice job explaining this paradoxical veryfast preset behavior: https://superuser.com/a/1557090/692789

@alou-S
Copy link

alou-S commented Dec 19, 2020 via email

@rodrigopolo
Copy link

rodrigopolo commented Apr 23, 2021

A simple shell script, call it encode.sh, do the typical chmod +x encode.sh and then execute it with ./encode.sh input.mp4, enjoy.

#!/usr/bin/env bash

PRESET=faster
CRF=21

IFS=$'\t\n'

real_path () {
	TARGET_FILE=$1
	cd `dirname $TARGET_FILE`
	TARGET_FILE=`basename $TARGET_FILE`

	while [ -L "$TARGET_FILE" ]
	do
		TARGET_FILE=`readlink $TARGET_FILE`
		cd `dirname $TARGET_FILE`
		TARGET_FILE=`basename $TARGET_FILE`
	done
	
	PHYS_DIR=`pwd -P`
	RESULT=$PHYS_DIR/$TARGET_FILE
	echo $RESULT
}

rp_fullpath_noext () {
	echo "${1%.*}"
}

SOURCE="`real_path \"$1\"`"
OUTPUT="`rp_fullpath_noext \"$SOURCE\"`"
OUTPUT=$OUTPUT.$CRF.$PRESET.mp4

ffmpeg \
-y \
-hide_banner \
-i "$1" \
-pix_fmt yuv420p \
-c:v libx264 \
-preset $PRESET \
-crf $CRF \
-c:a aac \
-b:a 128k \
-ar 44100 \
-ac 2 \
-movflags +faststart \
$OUTPUT

@varenc
Copy link

varenc commented Dec 11, 2021

@eladkarako

prevent pyramidal B-frames with -bf_ref 0.

Do things like this matter if the intention is to upload these video to YouTube? YouTube will re-encode all videos uploaded to it so if that's the use case I don't think there's much point in tweaking encoding params to improve player compatibility. (I've even used YouTube as a free video transcoding service by uploading a buggy video, then downloading YouTube's fixed version of it). If the intention is to upload to YouTube, and you don't mind uploading a lot, I'd just encoded with -preset superfast -crf 15, or even lossless -crf 0, and trust YouTube will re-encode my video 20 different ways for player compatibility.

That said if I'm serving my encoded .mp4 directly to users, this is valuable info! Had no idea about pyramidal b-frames

@wanghaisheng
Copy link

@varenc for long duration video, when upload it to studio, it got so much time to finish upload,processing and finally copyright check process.
I just want to know

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment