【Qt+FFmpeg】FFmpeg解码本地视频流程
目录
一、视频播放器的实现框架
1.解封装(Demuxing)
2.解码(Decode)
3.音视频同步
二、FFmpeg解码视频流程
1.FFmpeg解码视频流程图
2. 代码实现
一、视频播放器的实现框架
1.解封装(Demuxing)
将输入的封装格式的数据,分离成为音频流压缩编码数据和视频流压缩编码数据。封装格式种类很多,例如 MP4,MKV,RMVB,TS,FLV,AVI 等,它的作用就是将已经压缩编码的视频数据和音频数据按照一定的格式放到一起。例如,FLV 格式的数据,经过解封装操作后,输出 H.264 编码的视频码流和 AAC 编码的音频码流;
2.解码(Decode)
将视频/音频压缩编码数据,解码成为非压缩的视频/音频原始数据。音频的压缩编码标准包含 AAC,MP3 等,视频的压缩编码标准则包含 H.264,MPEG2 等。解码是整个系统中最重要也是最复杂的一个环节。通过解码,压缩编码的视频数据输出成为非压缩的颜色数据,例如 YUV、RGB 等等;压缩编码的音频数据输出成为非压缩的音频抽样数据,例如 PCM 数据
3.音视频同步
根据解封装模块处理过程中获取到的参数信息,同步解码出来的音频和视频数据,并将音视频频数据送至系统的显卡和声卡播放出来(Render)。
二、FFmpeg解码视频流程
1.FFmpeg解码视频流程图
音频解码后面会专门出一期介绍,这边就先不说了;
2. 代码实现
头文件中类的数据成员和信号
//视频文件上下文格式AVFormatContext* avformat_context;//编解码器上下文格式AVCodecContext* avcodec_context;//解码器上下文格式AVCodec* avcodec;//数据包AVPacket* av_packet;//保存视频流的索引int av_stream_index;//帧数据AVFrame *pFramein;AVFrame *pFrameRGB;uint8_t * pOutbuffer;int ret;QImage m_image;
signals: //发送解码得到的每一帧像素数据--保存的图片信息void sigGetOneFrame(QImage image);
(1)注册所有组件
av_register_all();
(2)打开视频输入文件
qDebug()<<"2.打开视频输入文件";//给avformat_context开空间avformat_context = avformat_alloc_context();//avformat_open_input参数一:视频文件格式上下文->AVFormatContext->包含了视频信息(视频名、时长、大小等)//参数二:文件路径qDebug()<<"打开"<<filename<<"视频文件进行播放";int avformat_open_result = avformat_open_input(&avformat_context,filename.toStdString().c_str(),NULL,NULL);if (avformat_open_result != 0){//获取异常信息char* error_info = new char[32];av_strerror(avformat_open_result, error_info, 100);qDebug()<<QString("异常信息 %1").arg(error_info);};
(3)查找视频流
qDebug()<<"3.查找视频流信息";//参数一:视频封装格式上下文->AVFormatContext//参数二:配置//返回值:>=0找到,否则失败int avformat_find_stream_info_result = avformat_find_stream_info(avformat_context,NULL);if (avformat_find_stream_info_result < 0){//获取失败char* error_info = new char[32];av_strerror(avformat_find_stream_info_result, error_info, 100);qDebug()<<QString("异常信息 %1").arg(error_info);}av_stream_index = -1;for (int i = 0; i < avformat_context->nb_streams; i++){//循环遍历每一流找到视频流if (avformat_context->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){//找到了av_stream_index = i;break;}}if (av_stream_index == -1){qDebug()<<QString("没有找到视频流");}
4.根据视频流查找对应的解码器
qDebug()<<"4.查找解码器";//第一点:获取当前解码器是属于什么类型解码器->找到了视频流//第二点:根据视频流->查找到视频解码器上下文->视频压缩数据avcodec_context = avformat_context->streams[av_stream_index]->codec;//编解码器上下文//第三点:根据解码器上下文->获取解码器IDavcodec = avcodec_find_decoder(avcodec_context->codec_id);if (avcodec == NULL){qDebug()<<QString("没有找到视频解码器");}
5.打开对应解码器
如果不打开解码器,会出现返回值-22异常错误
qDebug()<<"5.打开解码器";int avcodec_open2_result = avcodec_open2(avcodec_context,avcodec,NULL);if (avcodec_open2_result != 0){char* error_info = new char[32];av_strerror(avformat_find_stream_info_result, error_info, 100);qDebug()<<QString("异常信息 %1").arg(error_info);}
以上就是解码的准备工作,解码和转码的所有参数都可以在这里获取
可以打印视频的详细信息,如名称、时长、分辨率、解码器等等
获取的时长单位是微秒,换算成秒除以1000000
上图最后一行命令可以打印所有详细信息
接下来进行循环解码操作
6. 循环解码
1-5的代码可以放在构造函数中实现
循环解码可以在线程中实现,后续在窗口中播放时可以边解码边播放,更方便一些;
qDebug()<<"6.循环解码";//packet开空间av_packet = (AVPacket*)av_malloc(sizeof(AVPacket));//输入->环境一帧数据->缓冲区->类似于一张图pFramein = av_frame_alloc();//输出->帧数据->数据格式->RGBpFrameRGB = av_frame_alloc();//只有指定了AVFrame的像素格式、画面大小才能真正分配内存//缓冲区分配内存pOutbuffer = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_RGB32, avcodec_context->width, avcodec_context->height));//初始化缓冲区 类似于memsetavpicture_fill((AVPicture *)pFrameRGB, pOutbuffer,AV_PIX_FMT_RGB32, avcodec_context->width, avcodec_context->height);//解码的状态类型(0:表示解码完毕,非0:表示正在解码)// int current_frame_index = 0;//用于转码(缩放)的参数,转之前的宽高,转之后的宽高,格式等//准备一个视频像素数据格式上下文//参数一:输入帧数据宽//参数二:输入帧数据高//参数三:输入帧数据格式//参数四:输出帧数据宽//参数五:输出帧数据高//参数六:输出帧数据格式->AV_PIX_FMT_RGB32//参数七:视频像素数据格式转换算法类型//参数八:字节对齐类型(C/C++里面)->提高读取效率SwsContext* pSwsContext = sws_getContext(avcodec_context->width,avcodec_context->height,avcodec_context->pix_fmt,avcodec_context->width,avcodec_context->height,AV_PIX_FMT_RGB32,SWS_BICUBIC,NULL,NULL,NULL);int ret;//解码的状态类型(0:表示解码完毕,非0:表示正在解码)int current_frame_index = 0;//计算解码的帧数while (m_stop == false){//>=0:说明有数据,继续读取 <0:说明读取完毕,结束//从视频文件上下文中读取包--- 有数据就一直读取if (av_read_frame(avformat_context,av_packet) >= 0){//解码什么类型流(视频流、音频流、字幕流等等...)if (av_packet->stream_index == av_stream_index){//发送一个包数据进行解码avcodec_send_packet(avcodec_context, av_packet);//接收一个包数据,解压成一帧ret = avcodec_receive_frame(avcodec_context,pFramein);if (ret == 0){//图片的转换 输入 输出sws_scale(pSwsContext, (const unsigned char* const*)pFramein->data, pFramein->linesize, 0, avcodec_context->height,pFrameRGB->data, pFrameRGB->linesize);QImage *tmpImg = new QImage((uchar *)pOutbuffer, avcodec_context->width,avcodec_context->height,QImage::Format_RGB32);QImage image=tmpImg->copy();qDebug()<<"接收图片信号"<<image;emit sigGetOneFrame(image);//每保存一帧图片,发送一次信号//遍历每一帧的信息进行打印current_frame_index++;//发送信号//延时操作 1秒显示25帧--1000/25=40QThread::msleep(40);//获取的视频信息qDebug()<<QString("当前遍历第 %1 帧").arg(current_frame_index);}}}av_free_packet(av_packet);}
7.关闭缓冲区
qDebug()<<"7.关闭所有解码组件";av_packet_free(&av_packet);//关闭流和文件avcodec_close(avcodec_context);avformat_free_context(avformat_context);
感谢观看!!!!
以上就是全部内容,如果对您有帮助,欢迎点赞评论,或者发现有哪里写错的,欢迎指正!
【Qt+FFmpeg】FFmpeg解码本地视频流程相关推荐
- 2023-03-05:ffmpeg推送本地视频至lal流媒体服务器(以RTMP为例),请用go语言编写。
2023-03-05:ffmpeg推送本地视频至lal流媒体服务器(以RTMP为例),请用go语言编写. 答案2023-03-05: 使用 github.com/moonfdd/ffmpeg-go 库 ...
- 【Qt+FFmpeg】解码播放本地视频(二)——实现播放、暂停、重播、倍速功能
目录 一.FFmpeg解码流程图 二.播放.暂停.重播.倍速功能实现 1.创建播放.重播和倍速按钮 2.设置布局.样式.没有播放完毕前隐藏重播按钮 3.绑定信号槽 4.实现槽函数 (1)暂停和播放 ( ...
- FFmpeg学习(音视频理论知识)
文章目录 1. 音视频理论知识 1.1 基本概念 1.1.1 音视频必备的基本概念 常用的视频封装格式 常用的视频编码器 常用的音频编程器: 视频流 裸数据YUV 1.1.2 音视频常见处理 采集 处 ...
- linux下ts转mp4,ffmpeg安装及实现视频格式的转换、分片(ts m3u8)
1.简介 FFmpeg是一套可以用来记录.转换数字音频.视频,并能将其转化为流的开源计算机程序.采用LGPL或GPL许可证.它提供了录制.转换以及流化音视频的完整解决方案 2.相关 系统版本:Cent ...
- 【Qt+FFmpeg】鼠标滚轮放大、缩小、移动——解码播放本地视频(三)
上一期我们实现了播放.暂停.重播.倍速功能,这期来谈谈如何实现鼠标滚轮放大缩小和移动:如果还没看过上期,请移步 [Qt+FFmpeg]解码播放本地视频(一)_logani的博客-CSDN博客[Qt+F ...
- 【Qt+FFMPEG】 - 解码播放本地视频
目录 一:结果 二:代码 videodecode.h .cpp videoplaywin.h .cpp indexwin.h .cpp 一:结果 二:代码 videodecode.h .cpp 本文福 ...
- 【Qt学习】 FFmpeg 解码播放本地视频
目录 一:效果展示 二:源码分享 一:效果展示 二:源码分享 videodecode.h .cpp [解码线程的封装] #ifndef VIDEODECODE_H #define VIDEODECOD ...
- android全平台基于ffmpeg解码本地MP4视频推流到RTMP服务器
音视频实践学习 android全平台编译ffmpeg以及x264与fdk-aac实践 ubuntu下使用nginx和nginx-rtmp-module配置直播推流服务器 android全平台编译ffm ...
- 如何使用ffmpeg为Mac进行视频硬解码/硬编码(在Qt环境)
如何使用ffmpeg为Mac进行视频硬解码/硬编码(在Qt环境) 科普 前期准备 安装ffmpeg 将ffmpeg的库文件添加到Qt项目的.pro文件中 在源文件用引入头文件 第一步:先查看本机支持哪 ...
最新文章
- 【golang程序包推荐分享】go-ini、viper、godoc
- 如何更好的创建Java对象
- mysql 约束 域_MySQL-约束
- 抛物线交点式公式_2020“九校联考”中点公式解决平四存在性问题
- fedora 15中使用evolution获取exchange邮件
- Redis学习笔记——SpringDataRedis的使用
- python 字符串unicode编码_python的string与Unicode转换,gbk字符串编码
- mysql 连接查询分组_详解MySQL中的分组查询与连接查询语句
- shapenet各类数据(转载)
- grub2与grub区别
- 三大运营商发5G白皮书:传统短信迎大升级 推出5G消息
- 推荐使用金山WPS 2005 !
- 四叉树 Quadtrees
- javaFX实现登录界面并跳转
- 【BFS 广度优先搜索】详解感染橘子最短时间问题
- R语言时间序列ARIMA新手教程
- 算法:扑克牌顺序问题
- 【BZOJ4864】【BeiJing 2017 Wc】神秘物质(Splay)
- python-opencv截取视频片段
- http协议中get和post的基本区别,tcp/ip协议的三次握手
热门文章
- IAR for 8051 开发环境的安装
- server sql top速度变慢解决方案_SQL Server查询速度慢原因及优化方法
- 游戏行业,室内设计,哪个3d建模师更有前景?工资是不是很高啊
- 官方指定Visual studio 2015卸载工具
- android intent上机,2011山东大学的《人机交互技术》课程上机实验指导书[参考](26页)-原创力文档...
- ModBus-RTU之0x10功能码
- python后端学什么框架_【后端开发】python框架是什么?有哪些?
- 关闭php.ini中register_globals,深入了解 register_globals (附register_globals=off 网站打不开的解决方法)...
- antDesign table按时间排序
- 如何把软件作为服务启动_软件作为服务