qt+ffmpeg 实现音视频播放(三)之视频播放

一、视频播放流程

(PS:视频的播放流程跟音频的及其相似!!)

1、打开视频文件

通过 avformat_open_input() 打开媒体文件并分配和初始化

AVFormatContext 结构体。

函数原型如下:

int avformat_open_input(AVFormatContext **ps, const char *url,

AVInputFormat *fmt, AVDictionary **options);

参数说明:

- `ps`:指向 `AVFormatContext` 结构体指针的指针,用于存储打

开的媒体文件的信息。

- `url`:要打开的媒体文件的 URL 或文件路径。

- `fmt`:指定输入格式,通常可以设置为 `NULL`,由 FFmpeg 根

据文件内容自动检测。

- `options`:附加选项,可以传入一些额外的选项参数。

2、查找输入流信息

调用  avformat_find_stream_info()  函数将会读取媒体文件中的

帧,解析它们的头部,

并填充 AVFormatContext 中的流信息,通过访问

AVFormatContext 的 streams 字段来获取每个流的详细信息。

函数原型如下:
int avformat_find_stream_info(AVFormatContext *ic,

AVDictionary **options);

参数说明:

- `ic`:指向已打开媒体文件的 `AVFormatContext` 结构体的指

针。

- `options`:指向包含附加选项的 `AVDictionary` 指针。

3、查找流索引

使用 av_find_best_stream() 从媒体文件中找到最佳的流索引

函数原型如下:

int av_find_best_stream(AVFormatContext *ic, enum

AVMediaType type, int wanted_stream, int related_stream,

AVCodec **decoder_ret, int flags);

参数说明:

- `ic`:指向已打开媒体文件的 `AVFormatContext` 结构体的指

针。

- `type`:要查找的流类型,可以是 `AVMEDIA_TYPE_VIDEO`、

`AVMEDIA_TYPE_AUDIO` 等。

- `wanted_stream`:期望的流索引,如果为负值,则表示没有特

定的偏好。

- `related_stream`:相关流索引,用于查找与之相关的最佳流。

- `decoder_ret`:用于返回找到的解码器。

- `flags`:附加标志,可以用来指定额外的查找选项。

4、查找解码器

使用 avcodec_find_decoder() 查找符合指定解码器名称的解码

器。

函数原型如下:

AVCodec *avcodec_find_decoder(enum AVCodecID id);

参数说明:

- `id`:要查找的解码器的 ID。

5、初始化解码上下文

调用  avcodec_alloc_context3()  函数会为特定的编解码器分配一

个  AVCodecContext  结构体,并对其进行初始化。

AVCodecContext  结构体包含了编解码器的相关参数和状态信

息,比如编解码器类型、解码参数、帧率等。

函数原型如下:

AVCodecContext *avcodec_alloc_context3(const AVCodec

*codec);

参数说明:

- `codec`:指定要使用的编解码器,可以通过

`avcodec_find_decoder()` 或其他方式获取。

6、获取解码参数

调用 `avcodec_parameters_to_context()` 函数可以方便地将

`AVCodecParameters` 结构体中的参数(如编解码器类型、帧

率、分辨率等)复制到 `AVCodecContext` 结构体中,从而准备

进行编解码操作。

函数原型如下:

int avcodec_parameters_to_context(AVCodecContext *codec,

const AVCodecParameters *par);

参数说明:

- `codec`:要填充参数的 `AVCodecContext` 结构体指针。

- `par`:包含编解码器参数的 `AVCodecParameters` 结构体指

针。

7、打开解码器

调用 `avcodec_open2()` 函数可以打开并初始化指定的编解码器

上下文,使其准备好进行编解码操作。

函数原型如下:

int avcodec_open2(AVCodecContext *avctx, const AVCodec

*codec, AVDictionary **options);

参数说明:

- `avctx`:要打开和初始化的编解码器上下文。

- `codec`:要使用的编解码器,可以通过

`avcodec_find_decoder()` 或其他方式获取。

- `options`:可选的字典参数,用于设置编解码器的选项。

8、获取图像转换上下文

通过调用`sws_getContext`函数获取一个用于执行图像转换的上

下文对象,然后可以使用该上下文对象来进行图像转换操作。

函数原型如下:

struct SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat,
                                  int dstW, int dstH, enum AVPixelFormat dstFormat,
                                  int flags, SwsFilter *srcFilter, SwsFilter *dstFilter, const double *param);

参数说明:

- `srcW`: 源图像的宽度

- `srcH`: 源图像的高度

- `srcFormat`: 源图像的像素格式

- `dstW`: 目标图像的宽度

- `dstH`: 目标图像的高度

- `dstFormat`: 目标图像的像素格式

- `flags`: 可以指定一些转换的选项

- `srcFilter`: 源图像滤镜

- `dstFilter`: 目标图像滤镜

- `param`: 一组额外的参数

9、读取视频源文件

调用 `av_read_frame()` 函数可以从输入文件或流中读取一帧音视

频数据,并将其存储在 AVPacket 结构体中。

函数原型如下:

int av_read_frame(AVFormatContext *s, AVPacket *pkt);

参数说明:

- `s`:输入文件或流的 AVFormatContext 上下文。

- `pkt`:存储读取到的音视频帧数据的 AVPacket 结构体。

12、发送音频数据到解码器

调用 `avcodec_send_packet()` 函数可以将 AVPacket 数据包发送

给解码器进行解码。在发送完所有数据包后,需要调用

`avcodec_send_packet()` 传递一个空的 AVPacket 指针,以便告

知解码器已经发送完所有数据。

函数原型如下:
int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt);
参数说明:
- `avctx`:指向 AVCodecContext 结构体的指针,表示解码器上下文。
- `avpkt`:指向要发送给解码器的 AVPacket 数据包的指针。

13、从解码器接收解码后的视频数据

调用 `avcodec_receive_frame()` 函数可以从解码器中接收解码后

的音视频帧数据,并将其存储在 AVFrame 结构体中。


函数原型如下:

int avcodec_receive_frame(AVCodecContext *avctx, AVFrame

*frame);

参数说明:

- `avctx`:指向 AVCodecContext 结构体的指针,表示解码器上

下文。

- `frame`:用于存储接收到的解码后的 AVFrame 帧数据的结构体。

14、分配图像数据缓冲区

通过调用`av_image_alloc`函数为图像数据分配内存,并

将分配的内存绑定到指定的指针数组和行大小数组中,以便后续

在这些内存区域中存储图像数据。
 

函数原型如下所示:
int av_image_alloc(uint8_t *pointers[4], int linesizes[4], int w, int h, enum AVPixelFormat pix_fmt, int align);

参数解释:
- `pointers`: 用于存储图像数据的指针数组
- `linesizes`: 每个图像数据平面的行大小
- `w`: 图像宽度
- `h`: 图像高度
- `pix_fmt`: 像素格式
- `align`: 内存对齐参数


15、执行图像转换和缩放操作

通过调用`sws_scale`函数,可以使用提供的SwcContext对象和输入图像数据,对图像进行转换和缩放操作,然后将结果存储到输出图像数据中。

函数原型如下所示:
int sws_scale(struct SwsContext *c, const uint8_t *const srcSlice[], const int srcStride[], int srcSliceY, int srcSliceH, uint8_t *const dst[], const int dstStride[]);

参数解释:

- `c`: SwsContext对象,用于存储图像转换相关信息

- `srcSlice`: 指向输入图像数据的指针数组

- `srcStride`: 输入图像每个平面的跨度(stride)

- `srcSliceY`: 输入图像的起始行

- `srcSliceH`: 输入图像的高度

- `dst`: 指向输出图像数据的指针数组

- `dstStride`: 输出图像每个平面的跨度(stride)

16、显示图像

直接显示执行 sws_scale 后的图像便可。

二、代码例程

音頻播放:点击跳转

視頻播放:点击跳转


觉得有帮助的话,打赏一下呗。。

           

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

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

相关文章

Java项目:71 ssm基于ssm+vue的外卖点餐系统+vue

作者主页:舒克日记 简介:Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 系统功能 系统分为前台订餐和后台管理: 1.前台订餐 用户注册、用户登录、我的购物车、我的订单、商品列表 2.后台管理 商品管理&#xf…

QT tableWidget横向纵向设置

横向控件 要设置QTabWidget选项卡的字体方向,可以使用QTabWidget的setTabPosition()方法。通过传递Qt枚举值QTabWidget.east或QTabWidget.west作为参数,可以设置选项卡的字体方向为从左到右或从右到左。 myTabWidget QTabWidget() myTabWidget.setTabP…

Grass手机注册使用教程,利用闲置手机WiFi带宽赚钱

文章目录 Grass是什么? 项目介绍Grasss手机使用步骤第一步:下载狐猴浏览器第二步:注册账户(已注册直接跳过)第三步:安装Grass Chrome插件1、推荐离线安装2、在线安装 第四步:登录第五步&#xf…

MySQL 更新执行的过程

优质博文:IT-BLOG-CN Select语句的执行过程会经过连接器、分析器、优化器、执行器、存储引擎,同样的 Update语句也会同样走一遍 Select语句的执行过程。 但是和 Select最大不同的是,Update语句会涉及到两个日志的操作redo log(重做…

欧科云链OKLink:坎昆升级后,Layer2项目是否更具竞争力?

在坎昆升级激活之际,OKLink 上线以太坊坎昆升级 Dencun 专题页 👉 从专业链上数据分析角度,带来一场充实且即时的 Layer2 数据盛宴。 在近日由 137Labs 发起,Cointime 主持的 Layer2 生态专场讨论中,OKLink 产品…

InnoDB 缓存

本文主要聊InnoDB内存结构, 先来看下官网Mysql 8.0 InnoDB架构图 MySQL :: MySQL 8.0 Reference Manual :: 17.4 InnoDB Architecture 如上图所示,InnoDB内存主要包含Buffer Pool, Change Buffer, Log Buffer, Adaptive Hash Index Buffer Pool 其实 buffer pool 就是内存中的…

练习实践-进程回收01-找到并清理僵尸进程

参考来源: https://blog.csdn.net/qq_36528114/article/details/71076110 https://blog.51cto.com/u_12083623/2363384 极客时间-性能优化实战-CPU性能篇 进程回收中的孤儿和僵尸进程的特点 演示环境: 操作系统:Ubuntu18.04 查询工具&#x…

Golang案例开发之gopacket抓包三次握手四次分手(3)

文章目录 前言一、理论知识三次握手四次分手二、代码实践1.模拟客户端和服务器端2.三次握手代码3.四次分手代码验证代码完整代码总结前言 TCP通讯的三次握手和四次分手,有很多文章都在介绍了,当我们了解了gopacket这个工具的时候,我们当然是用代码实践一下,我们的理论。本…

Java 基础学习(二十)Maven、XML与WebServer

1 Maven 1.1 什么是Maven 1.1.1 Maven概述 Maven是一种流行的构建工具,用于管理Java项目的构建,依赖管理和项目信息管理。它使用XML文件来定义项目结构和构建步骤,并使用插件来执行各种构建任务。Maven可以自动下载项目依赖项并管理它们的…

PMSM 永磁同步电机滑膜控制 SVPWM矢量控制 matlab simulink 仿真

仿真搭建平台: (1)该模型采用matlab/simulink 2016b版本搭建,使用matlab 2016b及以上版本打开最佳; (2)该模型已经提前转换了各个常用版本(最低为matlab2012b),防止出现提示版本过高的情况。 模型截图: 算…

1、goreplay流量回放

目的 在实际项目中,会有大量的回归测试工作,通常会使用自动化代码的手段来实现回归,但是对于一个庞大的系统来说,通过自动化脚本的方式来实现回归测试,又显得很费时费力。并且如果有定期将线上数据同步到测试环境的需求…

【mysql 127错误】mysql启动报错mysqld.service: Failed with result ‘exit-code‘.

无网环境,mysql 安装 出现如下错误 [rootmysql tools]# systemctl status mysqld.service ● mysqld.service - MySQL ServerLoaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)Active: failed (Result: exit-code) since…

XSKY 智能存储,助力“数据要素 X”先进制造

3 月 21-22 日,主题为“突破 智行”的 IMC2024 第七届中国智造数字科技峰会在重庆召开。作为在先进制造领域拥有领先存储解决方案以及众多应用实践的企业,星辰天合受邀参加了此次峰会并荣获大会颁发的“最佳存储解决方案奖”。同时,星辰天合先…

防火墙的原理和配置

“防火墙”一词起源于建筑领域,用来隔离火灾,阻止火势从一个区域蔓延到另一个区域。引入到通信领域,防火墙这一具体设备通常用于两个网络之间有针对性的、逻辑意义上的隔离。这种隔离是选择性的,隔离“火”的蔓延,而又…

Set A Light 3D Studio中文--- 打造专业级3D照明效果

Set A Light 3D Studio是一款专业的灯光模拟软件,专为摄影师和电影制片人打造。它允许用户在计算机上模拟并预览各种布光效果,助力拍摄出真实、精准且具有艺术感的作品。软件提供了丰富的灯光和场景模型,用户可以灵活调整光源参数&#xff0c…

(附源码)基于Spring Boot与Vue的宠物用品销售系统设计与实现

前言 💗博主介绍:✌专注于Java、小程序技术领域和毕业项目实战✌💗 👇🏻 精彩专栏 推荐订阅👇🏻 2024年Java精品实战案例《100套》 🍅文末获取源码联系🍅 &#x1f31…

2024年3月22蚂蚁新村今日答案:以下哪一项是陕西省的非遗美食?

2024年3月22日蚂蚁新村今日问题的正确答案如下: 问题:以下哪一项是陕西省的非遗美食? 选项:驴肉火烧 水盆羊肉 答案:水盆羊肉 解析:水盆羊肉是陕西省的非遗美食。水盆羊肉是陕西省的一道传统著名饭食&a…

蓝桥杯第二天刷真题

public class Main {public static void main(String [] args) { //存大数方法String s"202320232023"; // 定义一个字符串&#xff0c;它将被转换为结束循环的数值long end Long.parseLong(s);long sum 0;long primarynumber 1;for(int i 1; i<end; i) {long …

需求:JSON数据显示null值或者不显示null值

使用hutool的工具类 import cn.hutool.json.JSON; import cn.hutool.json.JSONConfig; import cn.hutool.json.JSONUtil;public class Main {public static void main(String[] args) {String sss "{\"1\":\"a\",\"2\":null}";// 不…

手撕LRU 最近最少使用缓存淘汰策略 + LinkedHashMap

LRU 最近最少使用缓存淘汰策略 1 LRU 算法就是一种缓存淘汰策略2 手撕LRU3 LinkedHashMap 常见面试题 1 LRU 算法就是一种缓存淘汰策略 计算机的缓存容量有限&#xff0c;如果缓存满了就要删除一些内容&#xff0c;给新内容腾位置。但问题是&#xff0c;删除哪些内容呢&#x…