第4课 FFmpeg播放本地mp4文件
本课对应源文件下载链接:
https://download.csdn.net/download/XiBuQiuChong/88801326
在上节课,我们使用FFmpeg实现了一个最简单的rtmp播放器,它看起来工作正常。这节课,我们尝试让它来播放本地的mp4文件试试。
一、最终实现的效果
二、使用FFmpeg播放本地mp4文件的原理
要显示视频画面,就要先用FFmpeg读取本地mp4文件,mp4文件中既有视频流也有音频流,FFmpeg对其中的视频流进行解码获取到视频帧,然后将视频帧用openCV转换为Mat数组,把Mat数组绘制到MFC窗口就可以达到上图显示的效果。
与处理rtmp流类似,要播放音频,同样要用FFmpeg对mp4文件中的音频流进行解码获取到音频帧,然后将音频帧数据喂给由Windows系统声音播放API构成的函数就可以了。
三、使用FFmpeg播放本地mp4的主要代码
1.压缩备份上节课工程文件夹为demo3.rar,并修改工程文件夹demo3为demo4,重要的事情再说一遍:及时备份源文件并在原基础上继续迭代开发是一种好习惯。
将原rtmp地址修改为本地mp4地址:
const char *inFileName = "d:\\mp4\\xhn.mp4";
调试运行,会发现视频显示一卡一卡,音频也断断续续的。这是什么原因呢?
2.经过很长时间的研究学习,我才发现:原来是mp4文件的时间基与当前ffmpeg的时间基不一致造成的,为了保证音视频播放正常,就要转换时间基并适当延时。根据以上信息,将延时函数修改如下:
int fmlp::runFFmpeg(){
//返回值
int ret;
//rtmp地址,也可以是本地文件
const char *inFileName = "d:\\mp4\\xhn.mp4";
//输入文件上下文结构体
AVFormatContext *inFormatCtx = NULL;
//视频解码相关
int videoIndex = -1;
AVCodec *vDecodec;
AVCodecContext *vDecodeCtx = NULL;
//图像转换上下文结构体
struct SwsContext* bgrSwsCtx = NULL;
struct SwsContext* yuvSwsCtx = NULL;
//图像数据数组
uint8_t* bgrBuff = NULL;
//读取的数据包
AVPacket normalPkt;
//Mat对象
cv::Mat srcMat;
//音频解码器
int audioIndex = -1;
AVCodec *aDecodec;
AVCodecContext *aDecodeCtx = NULL;
//开始时间和当前时间
int64_t startTime = 0;
int64_t currentTime = 0;
//FFmpeg初始化
av_register_all();
avcodec_register_all();
avformat_network_init();
inFormatCtx = avformat_alloc_context();
AVDictionary* options = NULL;
av_dict_set(&options, "buffer_size", "10240", 0);
av_dict_set(&options, "max_delay", "1000", 0