最简单的基于FFmpeg的解码器-纯净版(不包含libavformat)
来源:互联网 发布:软件测试兼职网站 编辑:程序博客网 时间:2024/05/11 01:15
=====================================================
最简单的基于FFmpeg的视频播放器系列文章列表:
100行代码实现最简单的基于FFMPEG+SDL的视频播放器(SDL1.x)
最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)
最简单的基于FFmpeg的解码器-纯净版(不包含libavformat)
=====================================================
本文记录一个更加“纯净”的基于FFmpeg的视频解码器。此前记录过基于FFmpeg的视频播放器实际上就是一个解码器:
《最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)》这个播放器调用了FFmpeg中的libavformat和libavcodec两个库完成了视频解码工作。但是这不是一个“纯净”的解码器。该解码器中libavformat完成封装格式的解析,而libavcodec完成解码工作。一个“纯净”的解码器,理论上说只需要使用libavcodec就足够了,并不需要使用libavformat。本文记录的解码器就是这样的一个“纯净”的解码器,它仅仅通过调用libavcodec将H.264/HEVC等格式的压缩视频码流解码成为YUV数据。
流程图
本文记录的纯净版本的基于FFmpeg的解码器的函数调用流程图如下图所示。需要注意的是,此解码器的输入必须是只包含视频编码数据“裸流”(例如H.264、HEVC码流文件),而不能是包含封装格式的媒体数据(例如AVI、MKV、MP4)。
avcodec_register_all():注册所有的编解码器。有两个平时“不太常见”的函数:
avcodec_find_decoder():查找解码器。
avcodec_alloc_context3():为AVCodecContext分配内存。
avcodec_open2():打开解码器。
avcodec_decode_video2():解码一帧数据。
av_parser_init():初始化AVCodecParserContext。
av_parser_parse2():解析获得一个Packet。
两个存储数据的结构体如下所列:
AVFrame:存储一帧解码后的像素数据
AVPacket:存储一帧(一般情况下)压缩编码数据
AVCodecParser
AVCodecParser用于解析输入的数据流并把它分成一帧一帧的压缩编码数据。比较形象的说法就是把长长的一段连续的数据“切割”成一段段的数据。他的核心函数是av_parser_parse2()。它的定义如下所示。
其中poutbuf指向解析后输出的压缩编码数据帧,buf指向输入的压缩编码数据。如果函数执行完后输出数据为空(poutbuf_size为0),则代表解析还没有完成,还需要再次调用av_parser_parse2()解析一部分数据才可以得到解析后的数据帧。当函数执行完后输出数据不为空的时候,代表解析完成,可以将poutbuf中的这帧数据取出来做后续处理。
对比
简单记录一下这个只使用libavcodec的“纯净版”视频解码器和使用libavcodec+libavformat的视频解码器的不同。
PS:使用libavcodec+libavformat的解码器参考文章《》(1)下列与libavformat相关的函数在“纯净版”视频解码器中都不存在。
av_register_all():注册所有的编解码器,复用/解复用器等等组件。其中调用了avcodec_register_all()注册所有编解码器相关的组件。(2)新增了如下几个函数。
avformat_alloc_context():创建AVFormatContext结构体。
avformat_open_input():打开一个输入流(文件或者网络地址)。其中会调用avformat_new_stream()创建AVStream结构体。avformat_new_stream()中会调用avcodec_alloc_context3()创建AVCodecContext结构体。
avformat_find_stream_info():获取媒体的信息。
av_read_frame():获取媒体的一帧压缩编码数据。其中调用了av_parser_parse2()。
avcodec_register_all():只注册编解码器有关的组件。比如说编码器、解码器、比特流滤镜等,但是不注册复用/解复用器这些和编解码器无关的组件。(3)程序的流程发生了变化。
avcodec_alloc_context3():创建AVCodecContext结构体。
av_parser_init():初始化AVCodecParserContext结构体。
av_parser_parse2():使用AVCodecParser从输入的数据流中分离出一帧一帧的压缩编码数据。
在“libavcodec+libavformat”的视频解码器中,使用avformat_open_input()和avformat_find_stream_info()就可以解析出输入视频的信息(例如视频的宽、高)并且赋值给相关的结构体。因此我们在初始化的时候就可以通过读取相应的字段获取到这些信息。
在“纯净”的解码器则不能这样,由于没有上述的函数,所以不能在初始化的时候获得视频的参数。“纯净”的解码器中,可以通过avcodec_decode_video2()获得这些信息。因此我们只有在成功解码第一帧之后,才能通过读取相应的字段获取到这些信息。
源代码
运行结果
通过设定定义在程序开始的宏,确定需要使用的解码器。当TEST_H264设置为1的时候,解码H.264文件“bigbuckbunny_480x272.h264”。
当TEST_HEVC设置为1的时候,解码HEVC文件“bigbuckbunny_480x272.hevc”。
解码后的数据保存成YUV420P格式的文件“bigbuckbunny_480x272.yuv”。
此外,程序在运行的过程中,会打印出AVCodecParserContext中的一些信息,比如说帧类型等等,如下图所示。
输入H.264码流如下所示。
输出YUV420P像素数据如下图所示。
下载
Simplest ffmpeg decoder pure工程被作为子工程添加到了simplest ffmpeg player 2工程中。新版的simplest ffmpeg player 2工程的信息如下。
Simplest ffmpeg player 2
项目主页
SourceForge:https://sourceforge.net/projects/simplestffmpegplayer/
Github:https://github.com/leixiaohua1020/simplest_ffmpeg_player
开源中国:http://git.oschina.net/leixiaohua1020/simplest_ffmpeg_player
是最简单的FFmpeg视频解码方面的教程。
通过学习本例子可以了解FFmpeg的解码流程。
项目包含3个工程:
simplest_ffmpeg_player:标准版,FFmpeg学习的开始。
simplest_ffmpeg_player_su:SU(SDL Update)版,加入了简单的SDL的Event。
simplest_ffmpeg_decoder_pure:一个纯净的解码器。
version 2.3========================================
更新-2.4(2015.2.13)===============================
VC++:打开sln文件即可编译,无需配置。
cl.exe:打开compile_cl.bat即可命令行下使用cl.exe进行编译,注意可能需要按照VC的安装路径调整脚本里面的参数。编译命令如下。
MinGW:MinGW命令行下运行compile_mingw.sh即可使用MinGW的g++进行编译。编译命令如下。
GCC:Linux或者MacOS命令行下运行compile_gcc.sh即可使用GCC进行编译。编译命令如下。
PS:相关的编译命令已经保存到了工程文件夹中
CSDN项目下载地址:http://download.csdn.net/detail/leixiaohua1020/8443943
SourceForge上已经更新。
- 最简单的基于FFmpeg的解码器-纯净版(不包含libavformat)
- 最简单的基于FFmpeg的解码器-纯净版(不包含libavformat)
- 最简单的基于FFmpeg的解码器-纯净版(不包含libavformat)
- 最简单的基于FFmpeg的编码器-纯净版(不包含libavformat)
- 最简单的基于FFmpeg的编码器-纯净版(不包含libavformat)
- 最简单的基于FFmpeg的编码器-纯净版(不包含libavformat)
- 最简单的基于FFmpeg的AVfilter的例子-纯净版
- 最简单的基于FFmpeg的移动端例子:Android 视频解码器-单个库版
- 最简单的基于FFmpeg的移动端例子:Android 视频解码器-单个库版
- 最简单的基于FFmpeg的移动端例子:Android 视频解码器-单个库版
- 纯净版基于FFMPEG解码器(H264到YUV)
- 最简单的基于FFMPEG+SDL的视频播放器:拆分-解码器和播放器
- 最简单的基于FFMPEG+SDL的音频播放器:拆分-解码器和播放器
- 最简单的基于FFmpeg的移动端例子:Android 视频解码器
- 最简单的基于FFmpeg的移动端例子:IOS 视频解码器
- 最简单的基于FFmpeg的移动端例子:Android 视频解码器
- 最简单的基于FFmpeg的移动端例子:IOS 视频解码器
- 最简单的基于FFMPEG+SDL的视频播放器:拆分-解码器和播放器
- pat(A)1073(同PAT(B)1024)
- 两两交换链表的结点
- A -KIDx's Pagination(练功底)
- Android | Vuforia 更换模型
- LCS 最长公共字串
- 最简单的基于FFmpeg的解码器-纯净版(不包含libavformat)
- Android Service两种启动启动方式 及 adndroid service生命周期
- 我对Struts2的配置结果的理解
- (五十六)iOS多线程之NSOperation
- 在matlab中显示中文
- 图片处理
- 关于Controller中的重定向做法
- 20条Linux命令面试问答
- SpringMVC路径映射的四种做法