h264编码器实现
FFmpeg是一个开源的多媒体库,使用非常广泛。FFmpeg在Linux平台下开发,但它同样也可以在其它操作系统环境中编译运行。
本文使用FFmpeg + MinGW(MSYS) + Yasm + VS2017 的技术路线来完成FFmpeg在Windows 10(64bit)下的编译,并参考相关学习文档,使用c++语言编写一个简单的编码程序,通过调用FFmpeg库中开源.h及.dll文件,实现yuv格式视频文件的h.264编码。
原理
相关工具
FFmpeg
FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。
FFmpeg库主要由以下几个部分组成:
- libavformat:用于各种音视频封装格式的生成和解析,包括获取解码所需信息以生成解码上下文结构和读取音视频帧等功能;
- __libavcodec__:用于各种类型声音/图像编解码;
- libavutil:包含一些公共的工具函数;
- libswscale:用于视频场景比例缩放、色彩映射转换;
- libpostproc:用于后期效果处理;
- _ffmpeg_:该项目提供的一个工具,可用于格式转换、解码或电视卡即时编码等;
- _ffsever_:一个 HTTP 多媒体即时广播串流服务器;
- _ffplay_:是一个简单的播放器,使用ffmpeg 库解析和解码,通过SDL显示;
本文主要使用了libavcodec库中相关源码实现h.264视频编码。
MinGW
MinGW,是Minimalist GNUfor Windows的缩写。它是一个可自由使用和自由发布的Windows特定头文件和使用GNU工具集导入库的集合,允许用户在GNU/Linux和Windows平台生成本地的Windows程序而不需要第三方C运行时(C Runtime)库。
MSYS,即Minimal GNU(POSIX)system on Windows,是一个小型的GNU环境,包括基本的bash,make等等。是Windows下最优秀的GNU环境。
本文主要利用了MingW中的MSYS模块来完成FFmpeg的编译。
Yasm
Yasm是一款汇编语言编译程序,是一个完全重写的NASM汇编,具有编译器程序跨平台和模块化的特性。目前,它支持x86和AMD64指令集。
本文使用Yasm以达到在x86/x64平台下汇编代码加速的作用,来给予FFmpeg支持。
VS2017
Microsoft Visual Studio(简称VS)是美国微软公司的开发工具包系列产品。VS是一个基本完整的开发工具集,它包括了整个软件生命周期中所需要的大部分工具,目前最新版本为 Visual Studio 2017。
本文使用VS的开发环境,主要利用它的 lib.exe 生成 *.lib 文件。
H.264
H.264,是由ITU-T视频编码专家组(VCEG)和ISO/IEC动态图像专家组(MPEG)联合组成的联合视频组(JVT,Joint Video Team)提出的高度压缩数字视频编解码器标准。
H.264主要有以下几点优势:
- 低码率(Low Bit Rate):和MPEG2和MPEG4 ASP等压缩技术相比,在同等图像质量下,采用H.264技术压缩后的数据量只有MPEG2的1/8,MPEG4的1/3。
- 高质量的图像:H.264能提供连续、流畅的高质量图像(DVD质量)。
- 容错能力强:H.264提供了解决在不稳定网络环境下容易发生的丢包等错误的必要工具。
- 网络适应性强:H.264提供了网络抽象层(Network Abstraction Layer),使得H.264的文件能容易地在不同网络上传输(例如互联网,CDMA,GPRS,WCDMA,CDMA2000等)。
本文主要实现了视频的h.264编码,并对编码后的h.264文件进行码流解析。
编码流程
使用FFmpeg编码视频的流程大致如下图所示:
1 | st=>start: begin |
其中各个函数的作用如下:
- av_register_all():注册FFmpeg所有编解码器。
- avformat_alloc_output_context2():初始化输出码流的AVFormatContext。
- avio_open():打开输出文件。
- av_new_stream():创建输出码流的AVStream。
- avcodec_find_encoder():查找编码器。
- avcodec_open2():打开编码器。
- avformat_write_header():写文件头。
- __avcodec_encode_video2()__:编码一帧视频。即将AVFrame(存储YUV像素数据)编码为AVPacket(存储H.264等格式的码流数据)。
- av_write_frame():将编码后的视频码流写入文件。
- flush_encoder():用于输出编码器中剩余的AVPacket。
- av_write_trailer():写文件尾。
实现
程序安装及环境配置
前期工作大致为以下几步:
- 下载yasm,地址:http://yasm.tortall.net/Download.html 。改名为yasm.exe放到___C:\MinGW\msys\1.0\bin___文件夹下。
- 下载MinGW,并选择安装相应的项,即MSYS Basic System 。
- 安装Visual Studio 2017,使用默认路径。
- 打开___C:\MinGW\msys\1.0\msys.bat___文件,在文件头部加上:
call “C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat”
即设置开发环境,从而使用它的 lib.exe 生成 *.lib 文件。 - 运行__msys.bat__, 程序根据我当前的用户名,在目录___C:\MinGW\msys\1.0\home___下建一个工作目录即___C:\MinGW\msys\1.0\home\gaoteng17___。
- 访问FFmpeg的Github页面,将代码打包下载并解压至我的MinGW工作目录下。
- 运行__msys.bat__,输入
cd FFmpeg
,进入FFmpeg目录;输入./configure ./configure --disable-debug --enable-static --enable-swscale --disable-avformat --disable-avfilter --enable-pthreads --enable-runtime-cpudetect --disable-w32threads --disable-ffprobe --enable-version3 --disable-everything --enable-decoder=h264 --enable-decoder=mpeg4 --disable-ffmpeg --enable-parser=h264 --enable-parser=mpeg4video --enable-parser=mpegvideo make make install
成功后,编译生成的文件保存在 C:\MinGW\msys\1.0\local\bin,头文件保存在 ___C:\MinGW\msys\1.0\local\include___。
至此,FFmpeg已编译完毕,前期工作完成。
编码函数
编码部分的代码在这里给出,并在关键部分添加了简单注释:
1 | /* |
上述代码在MinGW命令行下的编译命令为:
1 | g++ h264_encoder.cpp -g -o h264_encoder.exe \ |
码流解析
H.264原始码流由一个一个的NALU组成,该程序通过从码流中搜索0x000001和0x00000001,分离出NALU,然后再分析NALU的各个字段,从而达到H.264码流解析作用。
H.264码流解析代码在这里给出,并在关键部分添加简单注释:
1 | /* |
结果
编码
原始YUV文件ds_480x272.yuv
位于目录首页,480x272分辨率,总共100帧。H264编码程序运行时截图如下:
将编码后的h264使用FFmpeg中的ffplay命令播放测试,运行截图如下:
码流解析
本程序的输入为一个H.264原始码流(裸流)的文件路径,输出为该码流的NALU统计数据,如下图所示。
至此,完成了视频的H.264编码及其码流的解析。
结语
FFMPEG的视音频编解码功能极其强大,几乎囊括了现存所有的视音频编码标准。如今做视音频开发的相关企业,几乎离不开它。
但从另一个角度来看,FFmpeg的学习难度也比较大。写作本篇课程设计所学习到的知识只是FFmpeg框架中极少的一部分,但对于认识FFmpeg有极大帮助。
本文使用Markdown语法编写,文中所有代码,借助的库函数及测试文件均上传至了我的Github项目页面。
如需查阅,请访问:https://github.com/gaoteng17/h264_encoder_parser 。
参考资料
- FFmpeg Documentation. https://ffmpeg.org/ffmpeg.html
- FFmpeg - Wikipedia. https://en.wikipedia.org/wiki/FFmpeg
- MinGW - Wikipedia. https://en.wikipedia.org/wiki/MinGW
- H.264 - Wikipedia. https://en.wikipedia.org/wiki/H.264/MPEG-4_AVC
- FFmpeg - Github. https://github.com/FFmpeg/FFmpeg
- leixiaohua - Github. https://github.com/leixiaohua1020