转码就是把链接长:解出来、改一改、再编回去。 「处理」那一环是本课后面所有特效的入口。
4.3 与 4.4 讲了两头,这一节把两头接起来。 下一篇 4.5.2 对比「不解码」的另一条路。
一、链接长了两环
转封装走两头,转码走全部五环。 环 转封装 转码
解封装 有 有 解码 跳过 有 处理 跳过 有 编码 跳过 有 封装 有 有
「跳过」不等于「不存在」。 转封装时那三环的位置空着,数据直接从包流到封装器, 一次都没经过解码器。 这个空位是本课价值最高的一处:想加任何画面处理,都在这个位置插进去。
二、「处理」这一环能放什么
位置在解码之后、编码之前,此处数据是原始帧。 想做的事 归谁
改尺寸、改像素格式 libswscale 改采样率、改声道 libswresample 加水印、加字幕 libavfilter 调色、磨皮、美颜 libavfilter 或 OpenCV
为什么不能放在解码之前:包是压缩的,要改得懂码流语法。 放在解码之后,拿到的是像素矩阵,改一个数就是改一个像素。 代价是必须完整解一遍,所以「只改容器」与「要改画面」的耗时差一个量级。 这个代价在 4.5.2 会用实测摆出来。
三、转码链的三个易错点
这三个都不报错,只是结果不对。 易错点 症状
忘了冲空包 结尾少一小段 没重排时间戳 播出来忽快忽慢 音频视频各转各的 音画不同步,越放越偏
第三个最隐蔽。 视频与音频的时间基不同,各自重排之后如果不统一换算, 两条轨道的相对位置会漂移。短片子看不出来,长片子会差出几秒。 处理办法是定一条基准时间轴,两条轨道都换算到它上面。这一步在教材后面的综合案例里会具体做。
四、转码不是无损的
每一次有损重编都会掉一点画质,掉了就回不来。 代码里做一次转码,画质损失通常看不出来;做成流水线,A 转 B 再转 C 再转 D,五代之后明显发糊。 这是「二手视频为什么糊」的答案:不是哪一步做错了,是每一步都掉了一点,累积起来就明显了。 能转封装就别转码。 这句话在这一节是理论,下一节会用时间与体积的实测把它变成结论。
五、动手 Demo:转码流程——一条链上插进两个新环
数清每个环各过了多少个东西。
import av
with av.open("_media32/tiny.mp4") as ic:
with av.open("_media32/trans_out.mp4", "w") as oc:
vs = oc.add_stream("libx264", rate=25)
vs.width, vs.height, vs.pix_fmt = 80, 60, "yuv420p"
vs.options = {"crf": "30", "preset": "ultrafast"}
n = 0
for frame in ic.decode(ic.streams.video[0]):
n += 1
nf = frame.reformat(width=80, height=60, format="yuv420p")
for pkt in vs.encode(nf):
oc.mux(pkt)
for pkt in vs.encode():
oc.mux(pkt)
print(n)
实跑输出:
--------------------------------------------------------------------
转码流程——一条链上插进两个新环
--------------------------------------------------------------------
**① 转码就是把链接长:解出来,改一改,再编回去**
环 转封装 转码
------------------------------
解封装 有 有
解码 没有 有
处理 没有 有
编码 没有 有
封装 有 有
**转封装是「拆信封换信封」,转码是「拆开重写一遍」。** 前者快得多,后者能做任何改动。
**② 真跑一次转码,数清每个环过了多少东西**
环 过了多少 说明
----------------------------------------
解封装 138 包 两路包合计
解码 50 帧 只数了视频
处理 50 帧 每帧缩小一半
编码 50 帧 送进编码器
封装 50 包 视频方向
耗时 **129.8 毫秒**,产物 **6940 字节**(原 46137 字节)。
**③ 中间那个「处理」环是本课后面所有特效的入口**
这里只做了一件事:缩小一半。
换成加水印、磨皮、调色、加滤镜,位置就在这一环——**解码之后、编码之前**。
**这个位置选得对,因为此处的数据是原始帧**,改起来最直接。
要是想改压缩后的包,就得懂码流语法,代价大得多。
**④ 转码贵在哪**
转封装只搬字节,转码要完整解一遍再完整编一遍。
**下面 4.5.2 会用同一个文件把两条路都跑一次,把时间与体积摆在一起。**
reformat 就是「处理」那一环,这里只做缩小一半。
真实项目里这一行会换成滤镜图或者 OpenCV 调用。
30 秒实验
- 把
80, 60改成320, 240,看耗时与体积怎么变。 - 把
crf改成 18,看体积翻几倍。 - 在
reformat之后打印frame.format.name,确认格式真的变了。
常见误区
- 以为转码能提画质。 有损重编只会掉,不会涨。
- 把处理放在解码之前。 包是压缩的,改不了像素。
- 两条轨道各自重排时间戳不统一。 长片子上会音画漂移。
自测三问(点开对答案)
1. 转码比转封装多了哪几环? —— 解码、处理、编码三环。数据从压缩包变成帧再变回压缩包。 2. 为什么「处理」必须放在解码之后? —— 解码之后拿到的是像素矩阵,改一个数就是改一个像素;压缩包里改不了。 3. 为什么二手视频看着糊? —— 每次有损重编都掉一点画质,掉的部分回不来,多转几代就明显了。- ☐ (本节完,下一节 4.5.2 FFmpeg 的两种转码方式)