ffmpeg player 入门:
我需要一个快速的入门途径, 先从下面代码开始了.
最简单的ffmpeg_player, 代码可参考 https://gitee.com/codeing_q/simplest_ffmpeg_player 雷霄骅分享的代码
1.FFmpeg数据结构简介
下面所说的碼流,可以是音频流,也可以是视频流, 一个AV文件,往往包含一个视频流,一个或多个音频流.
AVFormatContext:AV格式上下文结构体,也是统领全局的结构体,只需要分配一个这样的结构体就可以了.
保存了AV文件的相关信息, 由这个老根,可以找到其它的相关信息.
av_format_open_input(...) 会分配内存并初始化这个结构体
AVInputFormat:每一种输入格式对应一个该结构体(很多种文件格式对应很多种实例)
AVStream:每个码流对应一个该结构体,
AVCodecContext:编码器上下文结构体,保存了编解码相关信息,
AVCodec:每一种编解码器对应一个该结构体
AVPacket:存储一帧压缩编码数据
AVFrame:存储一帧解码后像素(采样)数据
所谓相关信息就是它有很多信息,因而很多函数调用都会用它做参数.老外把它叫context(上下文).
一个AV文件可以同时存在多种碼流(例如多声道碼流)
每一种碼流对应一种编解码方式,ffmpeg有多种编解码器,什么样的碼流它都能解.
另: struct SwsContext 结构体是一个黑盒子,它从来都是以指针形式出现,而且也从不访问它内部的成员.
所以你不用了解它的内部结构定义.它就没有对用户开放. (我跟踪了这个结构定义)
2. SDL 接口简介
首先,SDL 要创建一个window(窗口),一个render(提交),一个texture(纹理).
当解码到视频数据是,更新texture,texture再copy到render,render再提交就形成了画面更新.
40ms更新一次画面,就形成了视频.
猜想,SDL接口是不是不如framebuffer 更有效率? 估计是sdl 接管了framebuffer,多窗口管理方便了.
3. 理解了I贞,p贞,b贞, 并理解了YUV4:2:0
概括来说,碼流就是实时打包了音频流,视频流的压缩的文件. 分包,解压缩,分流,播放就是播放器的任务.
最简单的接口是给你一个文件,然后播放, 这样你什么都不知道.
次简单的就是这个参考代码了, 代码240行, 真正有效代码100来行, 它告诉你了要分解流,解码,解包的概念及播放的概念.
进一步的阅读可阅读ffmpeg 自带的ffplay.c, 这个跨度可能会有点大,因为它有3800行代码, 我目前也没有找到別的好路径
就它了,搞通这个估计音视频播放技术就差不多了.
当然有一个短一点的阶梯更好,我发现了会分享给大家.
------------------------------分割线----------------------------------------
记录一下demo 小程序中使用的 旧接口到新接口的转化:
1. av_register_all(); is deprecated
直接注释掉就可以了.
2. stream 流中的codec; is deprecated
改为codecpar(codec参数), 例如:
FormatCtx->streams[i]->codec->codec_type
FormatCtx->streams[i]->codecpar->codec_type
3. 获取codec_ctx 方式改变, 改用内存分配方式,并从流copy参数.parameter to context ,如下例:
#if 0
pCodecCtx=pFormatCtx->streams[audioStream]->codec;
#else
pCodecCtx = avcodec_alloc_context3(NULL);
if (pCodecCtx == NULL)
{
printf("Could not allocate AVCodecContext\n");
return -1;
}
avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[audioStream]->codecpar);
#endif
4. avcodec_decode_video2; is deprecated
改为 avcodec_send_packet, avcodec_receive_frame
#if 0
avcodec_decode_video2(videoCodec, avFrame, &ret, avPacket);
#else
ret = avcodec_send_packet(videoCodec, avPacket);
if (ret < 0) {
//error_occur;
}
ret = avcodec_receive_frame(videoCodec, avFrame);
if (ret < 0) {
//error_occur;
}
#endif
5. av_free_packet(packet); is deprecated
改为av_packet_unref(packet)
ffmpeg 的帮助系统非常好.
$ffmpeg -h
$ffmpeg -filters
$ffmpeg -h filter=<...>
有空研究一下这个帮助系统是怎样构建的.
顺便记录一下,编译ffmpeg, 我使用如下配置命令:
./configure --enable-gpl --enable-nonfree --prefix=/opt/ffmpeg_build --enable-shared
前面两项保证生成ffplay, --prefix 指定安装目录, --enable-shared 指定生成共享库so