一、概述
编码从数据结构上看,是将 AVFrame
转换为 AVPacket
的过程。如何构建 AVFrame,以及获取到 AVPacket 后续要进行什么操作,严格来说并不是编码的步骤。
x264
是作为一个插件编译入 FFmpeg
的。 FFmpeg 对 VideoToolBox
也做了适配。单独使用 x264
或 VideoToolBox
也可以进行编码,本文主要关注通过 FFmpeg 相关 API 进行 H.264
编码。
二、视频文件准备工作
x264 支持多种像素格式:
1 2 3 4 5
| $ ffmpeg -hide_banner -h encoder=libx264 Encoder libx264 [libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10]: General capabilities: delay threads Threading capabilities: auto Supported pixel formats: yuv420p yuvj420p yuv422p yuvj422p yuv444p yuvj444p nv12 nv16 nv21
|
h264_videotoolbox 支持的像素格式要少些:
1 2 3 4 5
| $ ffmpeg -hide_banner -h encoder=h264_videotoolbox Encoder h264_videotoolbox [VideoToolbox H.264 Encoder]: General capabilities: delay Threading capabilities: none Supported pixel formats: videotoolbox_vld nv12 yuv420p
|
准备一个很常用也很容易获得的 yuv420p
格式的视频文件。
FFmpeg 内置解码器解码出来的 AVFrame 里面的数据就是 yuv420p,不过 YUV 数组是分放在 3 个数组中的,可以拷贝至一个新建的 Buffer 中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| AVFrame *frame = av_frame_alloc();
int buffer_size = frame->height * frame->width * 1.5; uint8_t *buffer = malloc(buffer_size); int offset = 0, i; for (i = 0; i < height; i++) { memcpy(buffer + offset, frame->data[0] + i * frame->linesize[0], width); offset += width; } for (i = 0; i < height / 2; i++) { memcpy(buffer + offset, frame->data[1] + i * frame->linesize[1], width / 2); offset += width / 2; } for (i = 0; i < height / 2; i++) { memcpy(buffer + offset, frame->data[2] + i * frame->linesize[2], width / 2); offset += width / 2; }
|
备注:
- 如果解码出来是 nv12 之类的,将数据写入 Buffer 的算法是不同的,这里不详述。
- 官方示例 decode_video 保存的是 pgm 格式的文件。
三、编码过程描述
编码过程对应的 FFmpeg API,可以用伪代码表示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| fopen() avcodec_find_encoder_by_name("libx264") avcodec_alloc_context3()
av_frame_alloc()
av_frame_get_buffer() av_frame_make_writable() avcodec_open2() while(true) { fread() fread() avcodec_send_frame() while(true) { avcodec_receive_packet() } }
avcodec_send_frame() while(true) { avcodec_receive_packet() }
|
使用 VideoToolBox
编码非常简单,将 avcodec_find_encoder_by_name("libx264")
中的参数改为 h264_videotoolbox
即可。
备注:
- 在官方的示例
encode_video.c
中使用 VideoToolBox 时,请将分辨率改为 1280 * 720 等改为 VideoToolBox 支持的分辨率。
- 不设置
AVCodecContext
的 hw_device_ctx
似乎也不影响编码。
参考资料