Skip to content

B-frame 하나로 압축률이 달라진다 ​

개요 ​

인코딩 설정 화면에는 "GOP 길이"나 "키프레임 간격"이라는 항목이 있고, 그 옆이나 근처에 "B-frame 개수" 항목이 따로 있는 경우가 많습니다. 두 값 모두 압축 효율에 영향을 준다는 건 알려져 있지만, 실무에서 자주 막히는 지점은 이 두 값이 정확히 무엇을 바꾸는지, 그리고 그 변화가 파일 크기 말고 다른 데도 영향을 주는지가 막연하다는 점입니다.

GOP는 키프레임(I-frame) 하나로 시작해서 다음 키프레임 직전까지 이어지는 프레임 묶음입니다. GOP를 길게 잡으면 키프레임 개수가 줄어들어서 압축 효율이 좋아지지만, 그만큼 임의 지점 탐색(seek)이나 스트림 전환 시 기다려야 하는 구간이 길어집니다.

B-frame(양방향 예측 프레임)은 앞뒤 프레임을 모두 참조해서 압축하는 프레임 타입인데, 압축 효율은 높여주지만 인코더와 디코더 양쪽에 프레임 재정렬 부담을 지웁니다.

이 글에서는 같은 영상 소스를 GOP 길이와 B-frame 개수만 바꿔가며 FFmpeg(libx264)로 실제로 인코딩하고, ffprobe로 I/P/B 프레임이 실제로 어떤 순서로 배열되는지, 키프레임이 정확히 몇 초 간격으로 찍히는지 확인합니다.

이어서 GOP 길이가 HLS 세그먼트 경계와 어떻게 맞물리는지 실제 HLS 출력으로 검증하고, 마지막으로 Tencent Cloud MPS에서 같은 GOP 설정을 걸었을 때 결과물이 로컬 인코딩과 같은 규칙을 따르는지 API로 직접 확인합니다.

실무 시나리오 ​

스트리밍 서비스에서 라이브 방송을 HLS로 서빙하고 있는데, 뷰어들이 "화면 전환할 때 로딩이 길다"거나 "seek 했을 때 반응이 느리다"는 불만을 올렸다고 가정하겠습니다. 인코딩 설정을 보니 GOP가 250프레임(약 10초, 24fps 기준)으로 잡혀 있었습니다.

이 값을 짧게 줄이면 반응성은 좋아지겠지만, 그만큼 대역폭 비용이 늘어날 텐데 정확히 얼마나 늘어나는지 알아야 팀에 제안할 수 있습니다.

동시에 다른 팀에서는 B-frame을 늘려서 대역폭을 아끼자는 제안이 나왔습니다. 그런데 라이브 방송은 지연시간(latency)에 민감하고, B-frame은 디코더가 프레임을 재정렬해야 해서 지연시간을 늘립니다.

B-frame 개수를 2에서 4로 늘렸을 때 압축 효율이 얼마나 좋아지는지, 그 이득이 지연시간 증가를 감수할 만한 수준인지도 실측이 필요합니다.

이 두 질문(GOP를 얼마나 줄여야 반응성과 비용의 균형이 맞는지, B-frame을 늘리는 게 실제로 이득이 되는지)에 답하려면 감이 아니라 실제 인코딩 결과와 프레임 구조를 봐야 합니다. 그리고 이 서비스가 클라우드 트랜스코딩 서비스를 쓰고 있다면, 로컬 FFmpeg에서 확인한 규칙이 클라우드 쪽에서도 똑같이 적용되는지까지 확인해야 안심하고 설정을 바꿀 수 있습니다.

테스트 환경과 소스 ​

  • FFmpeg 8.0 (Homebrew 빌드, libx264 포함), macOS, Apple Silicon
  • 소스: 1920x1080, 24fps, H.264, 오디오 트랙 없음
$ ffprobe -v error -show_entries format=duration,size,bit_rate \
    -show_entries stream=codec_name,width,height,r_frame_rate,pix_fmt \
    -of default=noprint_wrappers=0 d4e71456f0244493.mp4
[STREAM]
codec_name=h264
width=1920
height=1080
pix_fmt=yuv420p
r_frame_rate=24/1
[/STREAM]
[FORMAT]
duration=5.041667
size=14308932
bit_rate=22705080
[/FORMAT]

원본 소스는 고움직임 장면이지만 길이가 5.04초(121프레임)뿐이라서, GOP를 250프레임으로 잡으면 클립 전체가 GOP 하나로 끝나버려서 "GOP가 반복되는 패턴"을 확인하기 어렵습니다. 그래서 -stream_loop 5로 소스를 6번 이어붙여 30.25초(726프레임) 분량으로 늘린 뒤, 이 확장된 입력을 인코딩 대상으로 삼았습니다.

그리고 모든 테스트에서 -sc_threshold 0을 걸어서 libx264의 장면전환 감지 키프레임 삽입 기능을 껐습니다. 이 옵션을 꺼두지 않으면 GOP 설정과 무관하게 장면이 바뀔 때마다 인코더가 임의로 키프레임을 추가로 찍어서, 우리가 지정한 GOP 값과 실제 키프레임 간격이 어긋나 보일 수 있기 때문입니다.

1. GOP 길이가 압축 효율과 키프레임 위치에 미치는 영향 ​

같은 CRF와 프리셋으로 GOP만 짧게(24프레임, 1초)와 길게(250프레임, 약 10.4초) 바꿔서 인코딩했습니다.

# GOP 짧게: 24프레임(1초)마다 키프레임, B-frame 없음
$ ffmpeg -y -stream_loop 5 -i src.mp4 -an -c:v libx264 -preset medium -crf 21 \
    -g 24 -keyint_min 24 -sc_threshold 0 -bf 0 -pix_fmt yuv420p gop_short.mp4

# GOP 길게: 250프레임(약 10.4초)마다 키프레임, B-frame 3개
$ ffmpeg -y -stream_loop 5 -i src.mp4 -an -c:v libx264 -preset medium -crf 21 \
    -g 250 -keyint_min 250 -sc_threshold 0 -bf 3 -pix_fmt yuv420p gop_long.mp4

키프레임이 실제로 어디에 찍혔는지 ffprobe로 확인했습니다.

$ ffprobe -v error -select_streams v:0 -show_entries frame=key_frame,pts_time \
    -of csv=p=0 gop_short.mp4 | awk -F, '$1==1{print $2}'
0.000000
1.000000
2.000000
3.000000
4.000000
...

$ ffprobe -v error -select_streams v:0 -show_entries frame=key_frame,pts_time \
    -of csv=p=0 gop_long.mp4 | awk -F, '$1==1{print $2}'
0.000000
10.416667
20.833333

GOP 24는 정확히 1.0초마다, GOP 250은 정확히 10.416667초(250/24초)마다 키프레임이 찍혔습니다. 지정한 프레임 수를 프레임레이트로 나눈 값과 초 단위까지 정확히 일치합니다.

프레임 타입 분포도 확인했습니다.

파일GOPB-frameIPB총 프레임
gop_short.mp4240316950726
gop_long.mp425033365358726

726프레임을 24로 나누면 30.25이므로 키프레임이 31개(마지막 조각 포함) 나온 것과 맞고, 250으로 나누면 2.9이므로 키프레임 3개가 나온 것도 맞습니다.

파일 크기와 비트레이트 ​

설정파일 크기비트레이트
GOP 24, bf=029.68MB8.23Mbps
GOP 250, bf=325.72MB7.14Mbps

GOP 24와 GOP 250 두 설정의 파일 크기를 비교하는 막대 그래프

같은 CRF, 같은 소스인데도 GOP를 24에서 250으로 늘리는 것만으로 파일 크기가 13.33% 줄었습니다. 다만 이 비교에는 B-frame 유무 차이도 섞여 있습니다(GOP 24 쪽은 bf=0, GOP 250 쪽은 bf=3). GOP 길이만 순수하게 분리해서 보려면 B-frame 개수를 고정해야 하는데, 이건 다음 절에서 다룹니다.

2. B-frame 개수가 압축 효율과 프레임 순서에 미치는 영향 ​

GOP를 48프레임(2초)으로 고정하고 B-frame 개수만 0, 2, 4로 바꿔서 인코딩했습니다.

$ ffmpeg -y -stream_loop 5 -i src.mp4 -an -c:v libx264 -preset medium -crf 21 \
    -g 48 -keyint_min 48 -sc_threshold 0 -bf 0 -pix_fmt yuv420p bf0.mp4
$ ffmpeg -y -stream_loop 5 -i src.mp4 -an -c:v libx264 -preset medium -crf 21 \
    -g 48 -keyint_min 48 -sc_threshold 0 -bf 2 -pix_fmt yuv420p bf2.mp4
$ ffmpeg -y -stream_loop 5 -i src.mp4 -an -c:v libx264 -preset medium -crf 21 \
    -g 48 -keyint_min 48 -sc_threshold 0 -bf 4 -pix_fmt yuv420p bf4.mp4

첫 24프레임의 재생 순서 프레임 타입 시퀀스를 뽑아봤습니다.

$ ffprobe -v error -select_streams v:0 -show_entries frame=pict_type -of csv=p=0 bf0.mp4 | head -24
I P P P P P P P P P P P P P P P P P P P P P P P

$ ffprobe -v error -select_streams v:0 -show_entries frame=pict_type -of csv=p=0 bf2.mp4 | head -24
I B B P B B P P B B P P B B P P P B P P B B P P

$ ffprobe -v error -select_streams v:0 -show_entries frame=pict_type -of csv=p=0 bf4.mp4 | head -24
I B B B P B P P B B B P B B P P P B P P B B P P

여기서 처음 예상과 다른 부분이 나왔습니다. -bf 2를 줬는데 B가 항상 2개씩 붙어 나오지 않고 1개인 구간도 있고("P B P"), -bf 4를 줬는데도 B가 4개 연속으로 나오는 구간이 한 번도 없었습니다. 파일 전체를 스캔해서 연속된 B-frame 런(run)의 길이를 세어봤습니다.

설정관찰된 최대 연속 B런런 길이별 개수
bf=22길이 2: 148회, 길이 1: 24회
bf=43길이 3: 30회, 길이 2: 116회, 길이 1: 26회

-bf는 B-frame 개수를 고정하는 값이 아니라 인코더가 쓸 수 있는 최댓값이라는 걸 실측으로 확인한 셈입니다. libx264는 기본적으로 적응형 B-frame 배치(b_strategy, 기본값 -1인 "fast" 모드)를 쓰는데, 이 알고리즘이 장면 복잡도와 움직임을 보고 프레임마다 B를 몇 개 넣을지 그때그때 판단합니다.

-bf 4를 줬어도 이번 소스에서는 4개를 다 채울 만한 구간이 없었던 것으로 보이고, 그래서 최대 런이 3에서 멈췄습니다.

적응형 배치를 끄고 고정 패턴이 어떻게 나오는지도 확인해봤습니다.

$ ffmpeg -y -stream_loop 5 -i src.mp4 -an -c:v libx264 -preset medium -crf 21 \
    -g 48 -keyint_min 48 -sc_threshold 0 -bf 3 -b_strategy 0 -pix_fmt yuv420p bf3_fixed.mp4

$ ffprobe -v error -select_streams v:0 -show_entries frame=pict_type -of csv=p=0 bf3_fixed.mp4 | head -20
I B B B P B B B P B B B P B B B P B B B

-b_strategy 0을 주자 정확히 "I B B B P" 패턴이 GOP 안에서 그대로 반복됐습니다. 즉 B-frame 개수를 시퀀스 다이어그램에서 보듯 정확히 고정하고 싶다면 -bf만으로는 부족하고 -b_strategy 0까지 같이 줘야 합니다.

이 패턴이 실제 프레임에 어떻게 찍히는지, bf3_fixed.mp4의 첫 GOP를 프레임별로 느리게 재생하면서 ffprobe가 알려준 프레임 타입을 그대로 자막으로 얹어봤습니다.

bf3_fixed.mp4의 첫 48프레임(2초 분량, 실제 재생 시간의 6배로 슬로우 처리), 각 프레임에 ffprobe로 확인한 pict_type을 자막으로 표시

I 다음 B가 세 번 연속되고 P가 오는 패턴이 GOP 안에서 정확히 반복되는 걸 눈으로 확인할 수 있습니다. 이 영상 자체는 인코더가 실제로 어떤 순서로 프레임을 찍는지 보여줄 뿐이고, 화면 속 인물의 움직임과는 관련이 없습니다.

재생 순서와 디코드 순서는 다릅니다 ​

bf3_fixed.mp4를 대상으로 프레임이 실제로 파일에 저장된 순서(디코드/전송 순서)와 화면에 뿌려지는 순서(재생 순서)를 나란히 뽑아봤습니다.

순서첫 24프레임 시퀀스
재생 순서 (pts 기준)I B B B P B B B P B B B P B B B P B B B P B B B
디코드 순서 (dts 기준)I P B B B P B B B P B B B P B B B P B B B P B B

B-frame은 자기보다 뒤에 오는 P-frame(또는 I-frame)을 참조해야 하므로, 인코더는 참조 대상이 될 P-frame을 먼저 압축해서 앞으로 당겨 전송하고, B-frame들은 그다음에 보냅니다.

디코더 입장에서는 P-frame이 도착해야 비로소 그 앞의 B-frame들을 복원할 수 있고, 복원한 뒤에는 다시 원래 재생 순서로 정렬해서 화면에 뿌려야 합니다. 이 재정렬 버퍼가 B-frame 개수만큼 늘어나는 게 바로 지연시간 증가의 원인입니다.

GOP 구조에서 재생 순서와 디코드 순서가 어떻게 달라지는지, P-frame이 B-frame보다 먼저 전송되는 이유를 보여주는 다이어그램

파일 크기와 비트레이트 ​

설정파일 크기비트레이트bf=0 대비 절감률
bf=028.45MB7.89Mbps-
bf=227.00MB7.49Mbps5.11%
bf=426.87MB7.45Mbps5.56%

B-frame 개수 0, 2, 4에 따른 파일 크기를 비교하는 막대 그래프

B-frame을 0에서 2로 늘렸을 때는 5.11%가 줄었는데, 2에서 4로 늘렸을 때는 추가로 0.48%밖에 줄지 않았습니다. 이번 소스와 설정 기준으로는 B-frame 2개 근처에서 효율 개선이 대부분 끝나고, 그 이상 늘려도 이득이 빠르게 줄어드는 모습입니다.

앞서 실무 시나리오에서 나온 "B-frame을 2에서 4로 늘리면 이득이 있는가"라는 질문에는, 적어도 이 소스에서는 "지연시간 증가를 감수할 만큼 크지 않다"는 게 실측 답변입니다.

3. HLS 세그먼트 경계와 GOP의 관계 ​

GOP 48프레임(2초, 24fps 기준)으로 인코딩하면서 동시에 HLS로 2초 세그먼트를 요청했습니다.

$ ffmpeg -y -stream_loop 5 -i src.mp4 -an -c:v libx264 -preset medium -crf 21 \
    -g 48 -keyint_min 48 -sc_threshold 0 -bf 3 -pix_fmt yuv420p \
    -hls_time 2 -hls_list_size 0 -hls_segment_type mpegts -f hls out.m3u8

생성된 플레이리스트입니다.

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:2
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:2.000000,
out0.ts
#EXTINF:2.000000,
out1.ts
...
#EXTINF:2.000000,
out14.ts
#EXTINF:0.250000,
out15.ts
#EXT-X-ENDLIST

726프레임을 48프레임 GOP로 나누면 15.125이므로, 2초짜리 세그먼트가 15개 나오고 마지막에 0.25초(6프레임)짜리 자투리 세그먼트 하나가 더 붙었습니다. 각 세그먼트의 첫 프레임이 실제로 키프레임인지도 확인했습니다.

$ for i in 0 1 2 3; do
    ffprobe -v error -select_streams v:0 -show_entries frame=key_frame,pict_type,pts_time \
        -of csv=p=0 "out$i.ts" | head -1
  done
1,1.483333,I,
1,3.483333,I
1,5.483333,I
1,7.483333,I

(첫 프레임의 pts 값이 0, 2, 4, 6이 아니라 1.48, 3.48, 5.48초로 찍힌 건 ffmpeg의 mpegts 먼서가 출력 시작 시각에 임의의 오프셋을 넣는 관례적인 동작이고, 세그먼트 사이 간격 자체는 정확히 2초씩입니다.)

네 세그먼트 모두 첫 프레임이 key_frame=1인 I-frame으로 시작했습니다. -hls_time은 "목표 세그먼트 길이"일 뿐, 실제 자르는 지점은 항상 가장 가까운 키프레임으로 스냅됩니다.

이번처럼 GOP(2초)와 -hls_time(2초)을 정확히 맞춰뒀기 때문에 세그먼트 길이가 요청한 값과 정확히 일치했지만, 만약 GOP를 2.5초로 잡고 -hls_time 2를 요청했다면 세그먼트는 2초가 아니라 2.5초 단위로 잘렸을 것입니다.

HLS나 DASH처럼 세그먼트 기반으로 스트리밍하는 파이프라인에서는 GOP 길이가 세그먼트 길이의 약수이거나 최소한 GOP와 세그먼트 목표 길이를 맞춰둬야, 세그먼트마다 독립적으로 디코딩을 시작할 수 있는 조건(세그먼트 시작 = 키프레임)이 매끄럽게 지켜집니다.

4. Tencent Cloud MPS에서 GOP 설정 검증하기 ​

로컬에서 확인한 규칙이 클라우드 트랜스코딩 서비스에서도 그대로 적용되는지 확인하기 위해, 같은 소스를 COS에 올리고 MPS의 ProcessMedia API로 GOP 24와 GOP 250 두 가지 설정을 각각 실행했습니다.

미리 등록된 템플릿을 쓰지 않고 GOP 값을 직접 지정하고 싶었기 때문에, Definition을 0으로 두고 즉석 파라미터를 넘기는 방식을 썼습니다. 처음에는 이 즉석 파라미터를 OverrideParameter 필드에 담아 보냈는데, 태스크가 InvalidParameterValue.Container is null 에러로 실패했습니다.

실패한 태스크 상세를 들여다보니 API 내부적으로 이 값을 RawParameter라는 별도 필드로 받고 있었고, 제가 보낸 OverrideParameter는 그냥 무시된 상태였습니다. OverrideParameter는 Definition이 실제 존재하는 템플릿 ID를 가리킬 때 그 템플릿의 일부 값만 덮어쓰는 용도이고, Definition=0으로 즉석 파라미터 전체를 지정하는 경우에는 RawParameter를 써야 한다는 걸 이 과정에서 확인했습니다.

필드명을 고치자 이번에는 InvalidParameterValue.AudioCodec is null로 다시 실패했습니다. 소스에 오디오 트랙이 아예 없는데도 즉석 파라미터 방식은 오디오 처리 방침을 명시적으로 요구했고, RawParameter.RemoveAudio를 1로 넣어서 해결했습니다.

python
task = {
    "OutputStorage": output_storage,
    "OutputObjectPath": out_prefix + "{Definition}.{format}",
    "Definition": 0,
    "RawParameter": {
        "Container": "mp4",
        "RemoveAudio": 1,
        "VideoTemplate": {
            "Codec": "libx264",
            "Fps": 24,
            "Bitrate": 8000,
            "ResolutionAdaptive": "close",
            "Width": 1920,
            "Height": 1080,
            "Gop": 24,   # 또는 250
        },
    },
}

두 태스크 모두 DescribeTaskDetail로 SUCCESS를 확인한 뒤 결과물을 내려받아 ffprobe로 검증했습니다.

$ ffprobe -v error -select_streams v:0 -show_entries frame=key_frame,pts_time \
    -of csv=p=0 mps_gop24.mp4 | awk -F, '$1==1{print $2}'
0.000000
1.000000
2.000000
3.000000
4.000000
5.000333

Gop: 24로 요청한 결과물은 정확히 1초 간격으로 키프레임이 찍혔습니다. 로컬 FFmpeg에서 -g 24로 얻은 것과 같은 규칙입니다.

Gop: 250으로 요청한 결과물은 소스 자체가 5.04초(121프레임)라서 250프레임에 한 번도 도달하지 못했고, 그 결과 키프레임이 클립 시작 지점(0초) 단 하나만 찍혔습니다. GOP 값은 "이 프레임 수를 넘기기 전에는 새 키프레임을 만들지 않는다"는 상한이므로, 소스가 그보다 짧으면 영상 전체가 GOP 하나로 끝난다는 걸 클라우드 트랜스코딩 결과로도 그대로 확인한 셈입니다.

구분Gop 설정파일 크기비트레이트(메타데이터)
MPS 트랜스코딩242.90MB4.84Mbps
MPS 트랜스코딩2502.59MB4.31Mbps

GOP를 24에서 250으로 늘리자 파일 크기가 10.94% 줄었는데, 이 방향은 로컬 FFmpeg 실험과 같지만 절댓값은 다릅니다. Bitrate: 8000(8Mbps)으로 요청했는데 실제 결과물의 비트레이트는 4.3~4.8Mbps 선에서 나왔습니다.

이건 MPS 트랜스코딩 결과가 나쁘다는 뜻이 아니라, Bitrate 파라미터가 고정 비트레이트를 강제하는 값이 아니라 인코더 내부 레이트 컨트롤이 참고하는 상한에 가깝게 동작한다는 뜻으로 읽는 게 맞습니다. 이 소스처럼 짧고 반복 움직임이 많은 클립에서는 상한까지 채우지 않고도 화질 목표를 만족할 수 있었던 것으로 보입니다.

GOP를 실험하는 김에 B-frame 개수도 MPS의 VideoTemplate에서 직접 지정할 수 있는지 확인했습니다. 실패한 요청들이 되돌려준 RawParameter.VideoTemplate 스키마를 보면 Codec, Fps, Bitrate, Width, Height, Gop, GopUnit, NoScenecut, VideoProfile, VideoLevel 같은 필드는 있지만 B-frame 개수를 직접 지정하는 필드는 없습니다.

이건 현재 기본 기능으로는 지원하지 않는 옵션입니다. B-frame 개수를 프레임 단위로 정밀하게 통제해야 하는 요구사항이 있다면, 담당 계정팀이나 기술지원팀에 문의해서 커스텀 인코딩 프로파일 지원 여부를 논의하는 걸 권합니다.

참고로 GopUnit, NoScenecut 필드는 이번 테스트 범위에서 다루지 않았지만, 이름으로 미루어 GOP를 프레임 대신 초 단위로 지정하거나 장면전환 키프레임 삽입을 끄는 용도로 짐작됩니다.

작업에 쓴 COS 오브젝트(gop-bframe-test/ 아래 소스 파일과 두 트랜스코딩 결과물)는 검증이 끝난 뒤 전부 삭제했습니다.

정리 ​

  1. GOP 길이는 키프레임 간격을 정확히 결정합니다. -g 24는 정확히 1초(24fps 기준)마다, -g 250은 정확히 10.416667초마다 키프레임을 찍었고, 이 규칙은 로컬 FFmpeg와 Tencent Cloud MPS 양쪽에서 동일하게 확인됐습니다.
  2. GOP를 24에서 250으로 늘리면(동시에 B-frame도 0에서 3으로 늘어난 조건에서) 파일 크기가 13.33% 줄었습니다. GOP를 늘릴수록 압축 효율은 좋아지지만, 그만큼 seek 응답성과 스트림 전환 속도는 느려집니다.
  3. -bf 값은 B-frame 개수를 고정하는 값이 아니라 상한입니다. -bf 2에서도 B가 1개만 들어간 구간이 있었고, -bf 4에서도 실측 최대 연속 B런은 3에 그쳤습니다. B-frame 개수를 정확히 고정하고 싶다면 -b_strategy 0을 같이 줘야 합니다.
  4. GOP를 48로 고정하고 B-frame만 0, 2, 4로 늘렸을 때 파일 크기는 각각 5.11%, 5.56% 줄었습니다. 0에서 2로 늘릴 때의 이득이 대부분이고, 2에서 4로 늘려도 추가 절감은 0.48%뿐이었습니다.
  5. B-frame이 있는 스트림은 재생 순서와 디코드(전송) 순서가 다릅니다. P-frame은 뒤따르는 B-frame들의 참조 대상이 되기 때문에 인코더가 먼저 압축해서 앞으로 당겨 보내고, 디코더는 이걸 받아 복원한 뒤 재생 순서로 재정렬합니다. 이 재정렬 버퍼가 지연시간 증가의 직접적인 원인입니다.
  6. HLS 세그먼트는 -hls_time이 요청한 목표 길이가 아니라 가장 가까운 키프레임 위치에서 잘립니다. GOP 길이를 세그먼트 목표 길이와 맞춰두지 않으면 세그먼트 길이가 어긋날 수 있습니다.
  7. Tencent Cloud MPS에서 즉석 파라미터(Definition=0)로 GOP를 지정하려면 RawParameter 필드를 써야 하고(OverrideParameter는 기존 템플릿의 일부를 덮어쓰는 용도), 오디오 트랙이 없는 소스라도 RemoveAudio를 명시해야 합니다. Bitrate는 고정값이 아니라 레이트 컨트롤 상한에 가깝게 동작했고, B-frame 개수를 직접 지정하는 파라미터는 현재 노출돼 있지 않습니다.

GOP와 B-frame은 둘 다 "압축 효율을 높이는 손잡이"로 뭉뚱그려 이야기되기 쉽지만, 실제로는 서로 다른 트레이드오프를 갖고 있습니다. GOP는 압축 효율과 탐색/전환 반응성 사이의 트레이드오프이고, B-frame은 압축 효율과 인코딩/디코딩 지연시간 사이의 트레이드오프입니다.

이번 실측에서 본 것처럼 두 값 모두 "설정한 숫자가 그대로 결과에 반영되는지"조차 인코더 내부 알고리즘(적응형 B-frame 배치, 장면전환 감지, 레이트 컨트롤)에 따라 달라질 수 있으므로, 최종 설정값은 감으로 정하지 말고 ffprobe로 실제 프레임 구조를 찍어보고 확정하는 절차가 필요합니다.

基于 VitePress 构建 · 部署于腾讯云 EdgeOne Pages