利用FFmpeg 开发音视频流(三)——将视频 YUV 格式编码成 H264

本文介绍了如何使用FFmpeg库将YUV格式的视频编码成H264。通过一系列步骤,包括打开YUV文件、设置输出H264路径、获取视频信息、创建流媒体数据、设置编码参数、写入编码头部和尾部,最终完成视频转码。过程中涉及AVFormatContext、AVOutputFormat、AVStream、AVCodecContext等关键结构体的使用。

已经好几个月没有写博客了,突然来感去写,手艺也有些生疏了,确实是这几个月实在太忙了,谁也知道现在直播火了起来,很多公司也在做直播,博主也不例外呀,做起客户端都是从 0 开始,呕心沥血,好了,废话不说太多,说说今天的主题。 首先开始的时候我们插入一张雷神大大的图帮助大家理解一下我们今天的操作究竟属于那一步。

音视频格式封装层次

ps:在这里也要啰嗦一下,大家看见这个图黑白色了么?这是为啥?说起这个太感慨了,
一代雷神大大离我们而去,26岁的博士雷神大大,一个爱分享的人就这么陨落了,太可惜了。

从上图可以看出我们要做的,就是将像素层的 YUV 格式,编码出编码层的 h264数据。

前面讲到我们已经成功编译出 iOS 中可用的 ffmpeg 的库了,那么我们首先熟悉一下今天我们要用到的 ffmpeg 中的函数和结构体

AVFormatContext: 数据文件操作者,主要是用于存储音视频封装格式中包含的信息, 在工程当中占着具足轻重的地位,因为很多函数都要用到它作为参数。同时,它也是我们进行解封装的功能结构体。


AVOutputFormat: 输出的格式,包括音频封装格式、视频装格式、字幕封装格式,所有封装格式都在 AVCodecID 这个枚举类型上面了


AVStream: 一个装载着视频/音频流信息的结构体,包括音视频流的长度,元数据信息,其中 index 属性用于标识视频/音频流。


AVCodecContext: 这个结构体十分庞大,但它的主要是用于编码使用的,结构体中的的 AVCodec *codec 就是编码所采用的编码器器, 当然,这个结构体中要存入视频的基本参数,例如宽高等,存入音频的基本参数,声道,采样率等。


AVCodec:编码器,设置编码类型,像素格式,视频宽高,fps(每秒帧数), 用于编解码音视频编码层使用。


AVIOContext:用于管理输入输出结构体。例如解码的情况下,将一个视频文件中的数据先从硬盘中读入到结构体中的 buffer 中,然后送给解码器用于解码,后面我们会用到。


AVFrame: 结构体一般用于存储原始数据(即非压缩数据,例如对视频来说是YUV,RGB,对音频来说是PCM),此外还包含了一些相关的信息。比如说,解码的时候存储了宏块类型表,QP表,运动矢量表等数据。编码的时候也存储了相关的数据。因此在使用FFMPEG进行码流分析的时候,AVFrame是一个很重要的结构体。

好了,上面就是我们这次解封装用到的结构体的大概解析,那么我们就上代码,好好分析一番。

1、先取个霸气点的函数名,通过输入一个 yuv 文件路径,然后将文件数据进行编码,输出 H264文件。

yuvCodecToVideoH264(const char *input_file_name)

2、打开输入的 yuv 文件, 并设置我们 h264 文件的输出路径

FILE *in_file = fopen(input_file, "rb");  
// 因为我们在 iOS 工程当中,所以输出路径当然要设置本机的路径了
const char* out_file = [[NSTemporaryDirectory() stringByAppendingPathComponent:@"dash.h264"] cStringUsingEncoding:NSUTF8StringEncoding];

3、获取 yuv 视频中的信息

// 注册 ffmpeg 中的所有的封装、解封装 和 协议等,当然,你也可用以下两个函数代替  
// * @see av_register_input_format()
// * @see av_register_output_format()
 av_register_all();
​
//  用作之后写入视频帧并编码成 h264,贯穿整个工程当中
AVFormatContext* pFormatCtx;
pFormatCtx = avformat_alloc_context();
​
// 通过这个函数可以获取输出文件的编码格式, 那么这里我们的 fmt 为 h264 格式(AVOutputFormat *)
fmt = av_guess_format(NULL, out_file, NULL);
pFormatCtx->oformat = fmt;

4、将输出文件中的数据读入到程序的 buffer 当中,方便之后的数据写入,也可以说缓存数据写入

// 打开文件的缓冲区输入输出,flags 标识为  AVIO_FLAG_READ_WRITE ,可读写
if (avio_open(&pFormatCtx->pb,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值