基于 FFMPEG 的跨平台视频播放器简明教程(二):基础知识和解封装(demux)

news2024/11/25 0:39:10

系列文章目录

  1. 基于 FFMPEG 的跨平台视频播放器简明教程(一):FFMPEG + Conan 环境集成

文章目录

  • 系列文章目录
  • 前言
  • 基础知识
    • 视频,你所看到的!
    • 音频 - 你所听到的声音
    • 编解码器 - 压缩数据
    • 容器 - 存放音频和视频的地方
  • 解封装
  • 使用 ffmpeg api 进行解封装
  • 总结
  • 参考


前言

前面一章中我们介绍了如何使用 conan 和 cmake 搭建 ffmpeg 运行环境,你做的还顺利吗?如果遇到任何问题,请在进行评论,我看到都会回复的。

从本章开始,将正式开始我们的 ffmpeg 播放器学习之旅。接下去的任务是:使用 ffmpeg 解码视频,并将解码后的视频帧保存在本地(就像对视频截图一样)。其中涉及到两个重要的知识点:解封装和视频解码。今天我们先聊解封装。此外,还会扩展 ffmpeg api 以及编解码相关的知识。

本文参考文章来自 An ffmpeg and SDL Tutorial - Tutorial 01: Making Screencaps。这个系列对新手较为友好,但 2015 后就不再更新了,以至于文章中的 ffmpeg api 已经被弃用了。幸运的是,有人对该教程的代码进行重写,使用了较新的 api,你可以在 rambodrahmani/ffmpeg-video-player 找到这些代码。

本文解封装的代码在 ffmpeg_video_player_tutorial-tutorial01。


基础知识

本章节翻译自 ffmpeg-libav-tutorial Intro 部分。

视频,你所看到的!

视频频是由一系列图像组成的,这些图像以一定的频率改变(比如说每秒24帧),从而产生运动的错觉。简而言之,这就是视频的基本原理:以一定的速率运行的一系列图片/帧。
在这里插入图片描述

音频 - 你所听到的声音

尽管无声视频可以表达各种感情,但添加声音会给体验带来更多的乐趣。声音是作为压力波传播的振动,通过空气或任何其他传输介质(如气体、液体或固体)。在数字音频系统中,麦克风将声音转换为模拟电信号,然后模拟-数字转换器(ADC)(通常使用脉冲编码调制(PCM))将模拟信号转换为数字信号。
在这里插入图片描述

编解码器 - 压缩数据

编解码器(CODEC)是一种电子电路或软件,用于压缩或解压缩数字音频/视频。它将原始(未压缩)的数字音频/视频转换为压缩格式,反之亦然。https://en.wikipedia.org/wiki/Video_codec

但是,如果我们选择将数百万个图像打包到一个文件中,并称之为电影,可能会得到一个巨大的文件。让我们做个计算:

假设我们正在创建一个分辨率为1080 x 1920(高 x 宽)的视频,每个像素的颜色编码需要3个字节(屏幕上的最小点)(或者称为24位颜色,提供了16,777,216种不同的颜色),这个视频以每秒24帧的速度运行,并持续30分钟。

toppf = 1080 * 1920 //每帧的像素总数
cpp = 3 //每个像素的成本
tis = 30 * 60 //时间长度(以秒为单位)
fps = 24 //每秒帧数

required_storage = tis * fps * toppf * cpp

这个视频将需要约250.28GB的存储空间或1.19 Gbps的带宽!这就是为什么我们需要使用编解码器。

容器 - 存放音频和视频的地方

容器或封装格式是一种元文件格式,其规范描述了不同数据和元数据在计算机文件中如何共存。https://en.wikipedia.org/wiki/Digital_container_format

容器是一个包含所有流(通常是音频和视频)的单个文件,并提供同步和通用元数据,如标题、分辨率等。
通常,我们可以通过查看文件的扩展名来推断其格式:例如,video.webm可能是使用 webm 容器的。
在这里插入图片描述
当我们谈到视频格式时,常提到的是封装格式,比如 MP4。一个 MP4 文件可以包含一个视频流和一个音频流,其中视频流通常使用 H.264 进行视频压缩,音频流则通常使用 AAC 进行压缩。因此,当我们提及 H.264 和 AAC 时,它们既可以视为视频和音频的编码格式,也可以视为用于视频和音频压缩的算法。然而,通常我们很少单独将一个视频描述为 H.264 格式,因为视频通常以封装格式的形式出现,封装格式包含了视频流和音频流。

在下文中,我们会提及视频文件、封装格式、容器这三个术语,通常它们是指同一个意思。


解封装

回到今天的任务:使用 ffmpeg 将视频解封装。

在大多数情况下,你下载到的视频文件是一个容器,一个视频文件包含多个流(stream),通常包括视频流和音频流。流(stream)是指一系列随时间可用的数据元素。每个流使用不同的编解码器进行编码,编解码器定义了实际数据的编码和解码方式,因此被称为编解码器(CODEC),例如MP3、H.264等。从流中可以读取数据包(packet),数据包包含经过编码器压缩后的数据。将数据包传递给解码器后,我们可以获取到所需的视频帧数据。在FFmpeg中,存放视频帧数据的数据结构被称为帧(frame)。

为了从这个容器中找到视频并将其解码,第一步需要做的是解封装(demux)。前面提到了容器,它就好像一个盒子,你可以往里头装不同的物品,例如视频、音频、字幕等等。解封装就相当于打开这盒子,按需的取出里头的各类物品,以便能够在播放器或者设备上进行播放、编辑或者其他处理。

现在假设我们要从视频文件中获取到视频数据,进行解封装流程为:

  1. 打开 video.mp4 文件
  2. 从 streams 中找到视频流
  3. 从视频流中读取 packet

使用 ffmpeg api 进行解封装

在这里插入图片描述
如果站在 ffmpeg api 使用者的角度来看解封装的流程:

  1. 你首先需要将视频文件加载到一个叫 AVFormatContext 的组件中。实际上,它并不完全加载整个文件,通常只读取文件的头部信息。
  2. 加载了视频文件的最小头部信息后,我们就可以访问文件的流 ,在 ffmpeg 中使用 AVStream 来保存这些流的信息。
  3. 假设我们有两个流:一个使用 AAC 编码器进行编码的音频流,另一个是使用 h264 编码器进行编码的视频流。从每个流中,我们可以读取名为 packet 的数据片段,这些数据片段在 ffmepg 使用 AVPacket 来保存。

话不多说,让我们上代码。解封装的代码你可以在 ffmpeg_video_player_tutorial-tutorial01 找到。解下来是代码的详细解释,我们会跳过一些细节,但没有关系,你可以在源码中找到你想要的。

首先我们声明一个 AVFormatContext 组件,它里头存放着关于容器的关键信息,主要用于封装(muxing)和解封装(demuxing)媒体文件。

AVFormatContext * pFormatCtx = NULL;

接下来,我们将打开文件并读取其头部信息,并填充AVFormatContext结构体,提供有关格式的最小信息(注意,通常不会打开编解码器)。用于执行此操作的函数是avformat_open_input。它需要一个AVFormatContext、一个文件名和两个可选参数:AVInputFormat(如果传递NULL,FFmpeg将猜测格式)和AVDictionary(这些是解封装器的选项)。

int ret = avformat_open_input(&pFormatCtx, argv[1], NULL, NULL);

如果梳理的话,你可以打印文件格式和视频时长:

printf("Format %s, duration %lld us", pFormatCtx->iformat->long_name, pFormatCtx->duration);

avformat_open_input 只是读取了最小头部信息,接下去我们需要找到文件中流的信息,avformat_find_stream_info 用于执行次操作:

ret = avformat_find_stream_info(pFormatCtx, NULL);

现在,pFormatCtx->nb_streams将保存流的数量,而pFormatCtx->streams[i]将给出第i个流(一个AVStream)。你可以通过循环查看所有流:

for (int i = 0; i < pFormatContext->nb_streams; i++)
{
  //
}

由于我们目前只对视频感兴趣,因此在遍历 streams 时我们可以纪录视频流的下标,它在后面是有用的:

for (i = 0; i < pFormatCtx->nb_streams; i++)
{
	if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
	{
		videoStream = i;
		break;
	}
}

每个 AVStream 里头有一个类型为 AVCodecParameters 成员变量叫 codecpar,它描述了这个流中编解码相关的信息,例如 codec_id 是啥。关于编解码的信息非常重要,在后面的「视频解码」章节中将使用到这些信息。这里先暂时跳过。

接下来,根据 ffmpeg_video_player_tutorial-tutorial01 中代码,你会看到一系列和编解码相关的操作,例如通过 codec_id 找到编解码。但是先等等,让我们直接跳到读取 packet 的部分中,编解码内容的讲解将放到下一篇博客中。

接下来,我们将从流中读取 packet,首先要做的是先申请一个 AVPacket:

AVPacket * pPacket = av_packet_alloc();

接着使用 av_read_frame 从文件中读取一个 packet:

while (av_read_frame(pFormatContext, pPacket) >= 0) {
  //...
}

读取的到的这个 packet,它可能来自视频流,也可能来自其他流。由于我们只对视频数据感兴趣,如果当前的 packet 来自其他流,那么直接忽略处理即可:

if (pPacket->stream_index == videoStream)
{
	// do something on video data
}

看!这里对 packet 来源的进行不同的处理,就是所谓的解封装,就这么简单!


总结

本文介绍了视频、音频、编解码器和容器的基本概念,介绍了什么是解封装以及使用 ffmpeg api 进行解封装的基本流程。所有代码可以在 ffmpeg_video_player_tutorial-tutorial01 中找到。

参考

  • An ffmpeg and SDL Tutorial - Tutorial 01: Making Screencaps
  • rambodrahmani/ffmpeg-video-player
  • ffmpeg-libav-tutorial
  • ffmpeg_video_player_tutorial-tutorial01

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

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

相关文章

vue3.0与vue2.0的区别简记(基于官方文档)

vue3.0与vue2.0的区别简记&#xff08;基于官方文档&#xff09; 基于vue3.0和vue2.0官方文档简单记录vue3.0版本和2.0版本的区别。 一直没有看文档的习惯&#xff08;就是不爱学习&#xff0c;现在吃了没文化的亏&#xff09;&#xff0c;遇到问题才去补充点食粮&#xff0c…

祝2023高考考生高考顺利!金榜题名

前言&#xff1a;光阴似箭&#xff0c;岁月如梭。明天就是全国每年一次的高考了&#xff0c;我也即将结束我的大一生活成为一名大二的小学长啦嘿嘿。而我今天呢主要是想祝马上要高考的学弟学妹们高考顺利&#xff0c;金榜题名&#xff0c;并且借此机会顺便讲讲我的高考前后的故…

解决python通过pip离线安装flask,numpy报错解决(centos)

1. 离线安装Python https://www.python.org/ftp/python/3.7.1/Python-3.7.1.tgz 解压&#xff0c;编译&#xff0c;安装 tar xzvf Python-3.7.1.tgz ./configuremakemake install 离线环境下如果系统不是完整版安装编译会报错&#xff0c;需要解决依赖问题&#xff0c;如下&am…

5 种常见的 Linux 打包类型:tar、gzip、bzip2、zip 、 7z

在 Linux 系统中&#xff0c;打包和压缩文件是常见的操作。不同的打包类型适用于不同的用途和需求。本文将详细介绍 5 种常见的 Linux 打包类型&#xff0c;包括tar、gzip、bzip2、zip 和 7z&#xff0c;以及它们的特点、使用方法和适用场景。 1. tar tar&#xff08;tape arc…

音悦台项目测试报告

文章目录 项目背景项目功能测试计划与设计功能测试自动化测试 测试结果功能测试结果UI自动化测试结果 项目背景 现如今人们的生活压力大&#xff0c;容易使人疲惫&#xff0c;为了使得人们在闲暇之余可以听音乐放松&#xff0c;为此设计出一款轻量的听音乐网站&#xff0c;快速…

centos安装部署Kubernetes(k8s)步骤使用kubeadm方式

文章目录 1、修改系统配置2、安装docker应用3. 拉取docker镜像4、cri-dockerd安装5、安装kubeadm和kubelet6、配置flannel网络插件7、Node节点加入集群操作 机器地址&#xff1a; 192.168.0.35 k8s-master 192.168.0.39 k8s-node1 192.168.0.116 k8s-node2 1、修改系统配置 修…

Web应用技术(第十六周/持续更新)

本次联系基于how2j的教程完成对SpringBoot的初步学习。 初识Springboot 学习导入&#xff1a;1.第一个基于SpringBoot的项目&#xff1a;&#xff08;1&#xff09;application.java&#xff1a;该文件中的核心代码&#xff1a; &#xff08;2&#xff09;HelloController.jav…

一. ATR技术指标的定义与运用

一. ATR的定义 1. 什么是ATR ATR英文全名是Average true range&#xff0c;翻译过来就是平均真实波幅&#xff0c;这个指标主要用来衡量最近N天TR(真实波幅)的平均值。 2. ATR相关计算公式 T R [ ( 最高价 − 最低价 ) &#xff0c; ( 前一次收盘价 − 最高价 ) &#xff0…

macOS Sonoma 14.0 Beta 1 (23A5257q) Boot ISO 原版可引导镜像

macOS Sonoma 14.0 Beta 1 (23A5257q) Boot ISO 原版可引导镜像 本站下载的 macOS 软件包&#xff0c;既可以拖拽到 Applications&#xff08;应用程序&#xff09;下直接安装&#xff0c;也可以制作启动 U 盘安装&#xff0c;或者在虚拟机中启动安装。另外也支持在 Windows 和…

OAuth2.0 授权 OpenID Connect 身份认证

文章目录 OAuth2.0历史由来名词解释授权码模式&#xff08;authorization code 最常用&#xff09;先换取code&#xff0c;再根据 code 换取 access_token原因 简化模式&#xff08;implicit&#xff09;密码模式&#xff08;resource owner password credentials&#xff09;客…

【P49】JMeter 查看结果树(View Results Tree)

文章目录 一、查看结果树&#xff08;View Results Tree&#xff09;参数说明二、准备工作三、测试计划设计 一、查看结果树&#xff08;View Results Tree&#xff09;参数说明 可以查看取样器的请求参数、返回结果 使用场景&#xff1a;一般在调试测试计划期间用来查看取样…

Bigdata1234.cn课堂测试

Java源文件中有一个公共类名称为Test&#xff0c;则该源文件名必须是&#xff1a;Test.java . Java中的基本数据类型共有8个&#xff1a;byte、short、int、long、float、double、char、boolean。 . Eclipse中内容补全的快捷键是alt/ Eclipse 中自动导包的快捷键是 Ctrl Sh…

MySQL数据库从入门到精通学习第8天(表数据的查询)

表数据的查询 基本查询语句单表查询聚合函数查询多表连接查询子查询合并查询结果定义表和字段的别名使用正则表达式查询 基本查询语句 SELECT 语句非常的强大&#xff0c;是最常用的查询语句。他具有一个固定的格式&#xff0c;如下&#xff1a; SELECT 查询的内容 FROM 数据…

【Mysql数据库从0到1】-入门基础篇--mysql 多表查询

【Mysql数据库从0到1】-入门基础篇--mysql 多表查询 &#x1f53b;一、mysql 多表查询1.1 &#x1f343; 7种sql joins 的实现1.2 &#x1f343; 错误写法---笛卡尔积错误1.3 &#x1f343; 正确的多表select写法 &#x1f53b;二、内连接( inner) join&#x1f53b;三、 外连接…

100天精通Golang(基础入门篇)——第2天:学习Go语言的前世今生:一门强大的编程语言的崛起

&#x1f337; 博主 libin9iOak带您 Go to Golang Language.✨ &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &#x1f30a; 《I…

如何构建一个可实盘的跨期套利策略?

一、策略摘要 跨期套利&#xff0c;在同一个品种但不同月份的期货合约上建立仓位相同、方向相反的交易头寸&#xff0c;最后以对冲或交割方式结束交易、获得收益。因其合约价差具有较好的稳定性&#xff0c;被众多交易者所青睐。本篇内容我们将通过掘金量化平台构建一个可交易…

私募证券基金动态-23年5月报

成交量&#xff1a;5月日均11,342.95亿元 2023年5月A股两市日均成交9,284.12亿元&#xff0c;环比下降18.15%、同比上升10.56%。5月整体20个交易日&#xff0c;仅有月初5个交易日单日成交金额过万亿。 管理人&#xff1a;新提交备案6家&#xff0c;备案通过0家 2023年5月新提…

Shape-Erased Feature Learning for Visible-Infrared Person Re-Identification

Shape-Erased Feature Learning for Visible-Infrared Person Re-Identification&#xff08;形状擦除特征学习在可见红外人物再识别中的应用&#xff09; 期刊合集&#xff1a;最近五年&#xff0c;包含顶刊&#xff0c;顶会&#xff0c;学报>>网址 文章来源&#xff1…

Lecture 10 Distributional Semantics

目录 Problems of Lexical Database 词汇数据库的问题分布假设根据上下文猜测单词含义Word vectors 词向量词嵌入Count-based Word Vectors 基于计数的方法Document as Context: The Vector Space Model 向量空间模型TF-IDFDimensionality Reduction 降维 Words as Context 单词…

跨数据中心高可用架构设计

前言 随着常年的码代码&#xff0c;做设计&#xff0c;笔者做过基础编码&#xff0c;云计算平台&#xff0c;架构师&#xff0c;见过不少应用设计&#xff0c;系统设计&#xff0c;中间件&#xff0c;了解现有的技术体系发展模式&#xff0c;集中式->分布式&#xff1b;cap…