Qt+FFmpeg+opengl从零制作视频播放器-3.解封装

解封装:如下图所示,就是将FLV、MKV、MP4等文件解封装为视频H.264或H.265压缩数据,音频MP3或AAC的压缩数据,下图为常用的基本操作。

 ffmpeg使用解封装的基本流程如下:

在使用FFmpeg API之前,需要先注册API,然后才能使用API。当然,新版本ffmpeg库不需要再调用下面的方法。

av_register_all()

初始化网络配置

avformat_network_init

设置一些参数,如下图所示,设置了最大延迟、传输协议等参数。

	//参数设置AVDictionary *opts = NULL;//设置rtsp流已tcp协议打开av_dict_set(&opts, "rtsp_transport", "tcp", 0);av_dict_set(&opts, "max_delay", "500", 0);av_dict_set(&opts, "buffer_size", "1024000", 0);av_dict_set(&opts, "probsize", "4096", 0);av_dict_set(&opts, "fps", "25", 0);

构建AVFormatContext,声明输入的封装结构体,通过输入文件或者流地址作为封装结构的句柄。

    AVFormatContext* inputFmtCtx = nullptr;const char* inputUrl = "test.mp4";///打开输入的流,获取数据 beginint ret = avformat_open_input(&inputFmtCtx, inputUrl, NULL, NULL);

查找音视频流信息,通过下面的接口与AVFormatContext中建立输入文件对应的流信息。

    //查找;if (avformat_find_stream_info(inputFmtCtx, NULL) < 0){printf("Couldn't find stream information.\n");return false;}


读取音视频流,采用av_read_frame来读取数据包,读出来的数据存储在AVPacket中,确定其为音频、视频、字幕数据,最后解码,或者存储。

    AVPacket* pkt = NULL;pkt = av_packet_alloc();while (av_read_frame(inputFmtCtx, pkt) >= 0){//获取数据包//.....解码或者存储//重置av_packet_unref(pkt);}

上述代码所示,通过循环调用av_read_frame()读取到pkt包,然后可以进行解码或者存储数据,如果读取的数据结束,则退出循环,开始指向结束操作。

每次使用完AVPacket包后,需要重置,否则会内存泄漏。

    //重置av_packet_unref(pkt);

执行结束后关闭输入文件,释放资源。

    //关闭avformat_close_input(&inputFmtCtx);//释放avformat_free_context(inputFmtCtx);//释放资源av_packet_free(&pkt);

 新建空白解决方案,如下图所示。

解决方案,右键-添加-新建项目。 

新建Qt控制台程序,3_demuxDemo 

然后,配置ffmpeg的编译环境:看目录4。

ffmpeg环境配置 

解封装源码示例:

#include <QtCore/QCoreApplication>extern "C" {
#include "libavutil/avstring.h"
#include "libavutil/channel_layout.h"
#include "libavutil/eval.h"
#include "libavutil/mathematics.h"
#include "libavutil/pixdesc.h"
#include "libavutil/imgutils.h"
#include "libavutil/dict.h"
#include "libavutil/fifo.h"
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/time.h"
#include "libavutil/bprint.h"
#include "libavutil/opt.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libavfilter/avfilter.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libavutil/opt.h"
#include "libavutil/imgutils.h"  
#include "libavcodec/avfft.h"
#include "libswresample/swresample.h"
}#include <iostream>
using namespace std;static double r2d(AVRational r)
{return r.den == 0 ? 0 : (double)r.num / (double)r.den;
}int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);//av_register_all();avformat_network_init();AVDictionary* options = NULL;av_dict_set(&options, "buffer_size", "1024000", 0);av_dict_set(&options, "max_delay", "500000", 0);av_dict_set(&options, "stimeout", "2000000", 0);av_dict_set(&options, "rtsp_transport", "tcp", 0);AVFormatContext* inputFmtCtx = nullptr;const char* inputUrl = "F:/1920x1080.mp4";///打开输入的流,获取数据 beginint ret = avformat_open_input(&inputFmtCtx, inputUrl, NULL, NULL);if (ret != 0){printf("Couldn't open input stream.\n");return -1;}int vIndex = -1;int aIndex = -1;//查找;if (avformat_find_stream_info(inputFmtCtx, NULL) < 0){printf("Couldn't find stream information.\n");return false;}for (int i = 0; i < inputFmtCtx->nb_streams/*视音频流的个数*/; i++){//查找视频if (inputFmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){vIndex = i;}else if (inputFmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO){aIndex = i;}}//===================video=================//视频宽int width = inputFmtCtx->streams[vIndex]->codecpar->width;//视频高int height = inputFmtCtx->streams[vIndex]->codecpar->height;//视频总时长sint64_t m_totalTime = static_cast<double>(inputFmtCtx->duration) / AV_TIME_BASE;//获取帧率;int fps = r2d(inputFmtCtx->streams[vIndex]->avg_frame_rate);if (fps == 0){fps = 25;}int iHour, iMinute, iSecond, iTotalSeconds;//HH:MM:SS//打印结构体信息puts("AVFormatContext信息:");puts("---------------------------------------------");iTotalSeconds = (int)inputFmtCtx->duration/*微秒*/ / 1000000;iHour = iTotalSeconds / 3600;//小时iMinute = iTotalSeconds % 3600 / 60;//分钟iSecond = iTotalSeconds % 60;//秒printf("持续时间:%02d:%02d:%02d\n", iHour, iMinute, iSecond);printf("平均混合码率:%d kb/s\n", inputFmtCtx->bit_rate / 1000);printf("视音频个数:%d\n", inputFmtCtx->nb_streams);puts("---------------------------------------------");puts("AVInputFormat信息:");puts("---------------------------------------------");printf("封装格式名称:%s\n", inputFmtCtx->iformat->name);printf("封装格式长名称:%s\n", inputFmtCtx->iformat->long_name);printf("封装格式扩展名:%s\n", inputFmtCtx->iformat->extensions);printf("封装格式ID:%d\n", inputFmtCtx->iformat->raw_codec_id);puts("---------------------------------------------");puts("AVStream信息:");puts("---------------------------------------------");printf("视频流标识符:%d\n", inputFmtCtx->streams[vIndex]->index);printf("音频流标识符:%d\n", inputFmtCtx->streams[aIndex]->index);printf("视频流长度:%d微秒\n", inputFmtCtx->streams[vIndex]->duration);printf("音频流长度:%d微秒\n", inputFmtCtx->streams[aIndex]->duration);puts("---------------------------------------------");printf("视频时长:%d微秒\n", inputFmtCtx->streams[vIndex]->duration);printf("音频时长:%d微秒\n", inputFmtCtx->streams[aIndex]->duration);printf("视频宽:%d\n", inputFmtCtx->streams[vIndex]->codecpar->width);printf("视频高:%d\n", inputFmtCtx->streams[vIndex]->codecpar->height);printf("音频采样率:%d\n", inputFmtCtx->streams[aIndex]->codecpar->sample_rate);printf("音频信道数目:%d\n", inputFmtCtx->streams[aIndex]->codecpar->channels);puts("AVFormatContext元数据:");puts("---------------------------------------------");AVDictionaryEntry *dict = NULL;while (dict = av_dict_get(inputFmtCtx->metadata, "", dict, AV_DICT_IGNORE_SUFFIX)){printf("[%s] = %s\n", dict->key, dict->value);}puts("---------------------------------------------");puts("AVStream视频元数据:");puts("---------------------------------------------");dict = NULL;while (dict = av_dict_get(inputFmtCtx->streams[vIndex]->metadata, "", dict, AV_DICT_IGNORE_SUFFIX)){printf("[%s] = %s\n", dict->key, dict->value);}puts("---------------------------------------------");puts("AVStream音频元数据:");puts("---------------------------------------------");dict = NULL;while (dict = av_dict_get(inputFmtCtx->streams[aIndex]->metadata, "", dict, AV_DICT_IGNORE_SUFFIX)){printf("[%s] = %s\n", dict->key, dict->value);}puts("---------------------------------------------");av_dump_format(inputFmtCtx, -1, inputUrl, 0);printf("\n\n编译信息:\n%s\n\n", avcodec_configuration());AVPacket* pkt = NULL;pkt = av_packet_alloc();while (av_read_frame(inputFmtCtx, pkt) >= 0){//获取数据包//.....解码或者存储//重置av_packet_unref(pkt);}//关闭avformat_close_input(&inputFmtCtx);//释放avformat_free_context(inputFmtCtx);//释放资源av_packet_free(&pkt);return a.exec();
}

运行截图:

完整工程:

https://download.csdn.net/download/wzz953200463/88959152icon-default.png?t=N7T8https://download.csdn.net/download/wzz953200463/88959152

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/745915.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

福派斯猫粮的适口性有何特点?

亲爱的朋友们&#xff0c;今天我想和大家分享一下福派斯猫粮的适口性特点。作为一位养猫多年的铲屎官&#xff0c;我深知猫粮的适口性对于猫咪的健康和幸福是多么重要。那么&#xff0c;福派斯猫粮在这方面究竟有何独到之处呢&#xff1f; 1️⃣ 首先&#xff0c;福派斯猫粮的口…

第2周 Python列表、元组刷题

第2周 Python列表、元组刷题 单击题目&#xff0c;直接跳转到页面刷题&#xff0c;一周后公布答案。 1.B2124&#xff1a;判断字符串是否为回文 2. P1427&#xff1a;小鱼的数字游戏 3. B2057&#xff1a;最高的分数 4. B2055&#xff1a;均值 5. B2056&#xff1a;求整数的和…

【Java多线程】关于多线程的一些案例 —— 单例模式中的饿汉模式和懒汉模式以及阻塞队列

目录 1、单例模式 1.1、饿汉模式 2.1、懒汉模式 2、阻塞队列 2.1、BlockingQueue 阻塞队列数据结构 1、单例模式 对框架和设计模式的简单理解就是&#xff0c;这两者都是“大佬”设计出来的&#xff0c;让即使是一个代码写的不太好的“菜鸡程序员”也能写出还可以的代码…

全球化服务能力,助力企业拓展海外市场,仓储物流行业解决方案

随着全球化的加速推进&#xff0c;越来越多的企业开始将目光投向海外市场&#xff0c;寻求更广阔的发展空间。然而&#xff0c;海外市场的拓展并非易事&#xff0c;需要企业具备强大的全球化服务能力。作为通信行业的领军企业&#xff0c;中国联通凭借其强大的网络资源和技术实…

基于SCIP的约束处理器Conshdlr添加惰性约束——以TSP问题为例

文章目录 1. TSP案例引入2. 考虑惰性约束的求解效率对比2.1 求解基础TSP模型2.2 基于SCIP的Conshdlr添加惰性约束1. TSP案例引入 在运筹学建模和求解过程中,“lazy constraints”(惰性约束)是一种动态添加约束的策略,松弛部分约束后求解得到的“可行解”,不断地进行可行性…

求职分享123

阿里学长 简历&#xff1a;github上找&#xff0c;填信息 项目&#xff1a; 1. 教研室项目 2. github上下载项目下来做 3. 对于项目&#xff0c;要把个人工作详细地准备下来。 4. 给面试官挖坑。 5. 企业实习是巨大的加分项。 知识储备 刷题 不卷&#xff0c;leetcod…

同步和异步程序的关联和区别是?Guide to Synchronous and Asynchronous Code

2024/3/12 发布 正在寻觅一份前端开发工作&#xff0c;如果您觉得这篇文章对你有所帮助&#xff0c;这是我的简历1 在这篇文章中你能学习和理解&#xff1a;NodeJS是如何工作、如何处理所有发送给服务器的函数&#xff08;无论同步或者异步&#xff09;和请求、Event Loops in …

rk36566 uboot - dm 模型数据结构与常见接口

文章目录 一、数据结构1、udevice2、driver3、uclass4、uclass\_driver5、 总结6、device\_probe 二、常用接口1、udevice 创建接口1) device_bind_with_driver_data2) device_bind3) device_bind_by_name 2、uclass 操作函数1) uclass_get2) uclass_get_name3) uclass_find_de…

LeetCode 面试经典150题 27.移除元素

题目&#xff1a; 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑数…

efcore coderfirst 生成数据库

使用 Entity Framework Core 的 Code First 方法开发时&#xff0c;你可以根据定义的实体模型和 DbContext 类自动生成数据库和表结构。下面的步骤将指导你如何使用 EF Core Code First 来生成数据库。 1. 安装必要的 NuGet 包 首先&#xff0c;确保已经安装了 Entity Framew…

Cesium 地图鼠标悬浮某个位置显示弹窗

问题&#xff1a;地图上显示了图标&#xff0c;在鼠标悬浮在地图上时&#xff0c;不出现弹窗&#xff0c;当悬浮在地图的图标上时&#xff0c;显示该图标的信息解决过程&#xff1a; 1.建立处理用户输入事件的画布&#xff0c;写出要在输入事件上执行的功能。 2.Cesium.ScreenS…

python调用jar中java方法 静态类为例

java package test;public class test {// run方法返回当前脚本路径public static String runV1(String s) {return "log: " System.getProperty(s);}}python import jpype from jpype import * import osif __name__ "__main__":print(os.environ[JAV…

java中的日期类

1.1 第一代日期类 第一代日期时间API主要有java.util.Date和日期时间格式化有关的java.text.DateFormat及其子类。 1.1.1 Date类 JDK1.0就在java.util包下面提供了Date类用于表示特定的瞬间&#xff0c;可以精确到毫秒。   通过API或源码&#xff0c;可以看出Date类的大部…

如何计算视频流需要的服务器带宽

一、如何计算视频流需要的服务器带宽 计算视频流需要的服务器带宽涉及多个因素,包括视频的编码质量、分辨率、帧率、同时观看的用户数量等。下面是一个基本的计算方法: 确定视频的平均比特率:视频的比特率(通常以比特/秒为单位)是衡量视频数据流量的关键指标。这取决于视…

vscode 导入前端项目

vscode 导入前端项目 导入安装依赖 运行 参考vscode 下载 导入 安装依赖 运行 在前端项目的终端中输入npm run serve

NCC环境配置

一、后端配置 安装eclipse汉化插件安装svn插件调试配置中配置启动参数 -Dnc.exclude.modules${FIELD_EX_MODULES} -Dnc.runModedevelop -Dnc.server.location${FIELD_NC_HOME} -DEJBConfigDir${FIELD_NC_HOME}/ejbXMLs -DExtServiceConfigDir${FIELD_NC_HOME}/ejbXMLs -…

C#,数值计算,数据测试用的对称正定矩阵(Symmetric Positive Definite Matrix)的随机生成算法与源代码

C.Hermite 1、对称矩阵 对称矩阵(Symmetric Matrices)是指以主对角线为对称轴,各元素对应相等的矩阵。在线性代数中,对称矩阵是一个方形矩阵,其转置矩阵和自身相等。1855年,埃米特(C.Hermite,1822-1901年)证明了别的数学家发现的一些矩阵类的特征根的特殊性质,如称为埃…

ASPICE-SYSSWE

文章主要内容&#xff1a; Automotive SPICE 过程参考模型 SYS.1 需求挖掘 过程ID SYS.1 过程名称 需求挖掘 过程目的 需求挖掘过程的目的是:在产品和/或服务的整个生命周期内收集、处理和跟踪不断变化的利益相关方的需要和需求&#xff0c;从而建立一个需求基线&#x…

交换机/路由器的存储介质-思科

交换机/路由器的存储介质-思科 本文主要介绍网络设备的存储介质组成。 RAM(random-accessmemory&#xff0c;随机访问存储器) RAM中内容断电丢失&#xff0c;主要用于运行操作系统、运行配置文件、IP 路由表:、ARP 缓存、数据包缓存区。 ROM(read-only memory&#xff0c;只…

uniapp遇到的问题

【uniapp】小程序中input输入框的placeholder-class不生效解决办法 解决&#xff1a;写在scope外面 uniapp设置底部导航 引用&#xff1a;https://www.jianshu.com/p/738dd51a0162 【微信小程序】moveable-view / moveable-area的使用 https://blog.csdn.net/qq_36901092/…