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

系列文章目录

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


前言

前面一章中我们介绍了如何使用 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 中找到。

参考

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【资源说明】 C++开发基于Qt ffmpeg实现的视频播放器源码+详细注释.zipC++开发基于Qt ffmpeg实现的视频播放器源码+详细注释.zipC++开发基于Qt ffmpeg实现的视频播放器源码+详细注释.zipC++开发基于Qt ffmpeg实现的视频播放器源码+详细注释.zipC++开发基于Qt ffmpeg实现的视频播放器源码+详细注释.zipC++开发基于Qt ffmpeg实现的视频播放器源码+详细注释.zipC++开发基于Qt ffmpeg实现的视频播放器源码+详细注释.zipC++开发基于Qt ffmpeg实现的视频播放器源码+详细注释.zipC++开发基于Qt ffmpeg实现的视频播放器源码+详细注释.zipC++开发基于Qt ffmpeg实现的视频播放器源码+详细注释.zipC++开发基于Qt ffmpeg实现的视频播放器源码+详细注释.zipC++开发基于Qt ffmpeg实现的视频播放器源码+详细注释.zipC++开发基于Qt ffmpeg实现的视频播放器源码+详细注释.zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载使用,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!
基于ffmpeg的开源视频播放器是一种可以在各种操作系统上使用的免费软件,它利用ffmpeg库来码和播放视频文件。ffmpeg是一个强大的多媒体处理工具,可以处理各种视频和音频格式。基于ffmpeg视频播放器可以支持多种视频格式,包括常见的MP4、AVI、MKV等,同时也能够提供高质量的音频和视频播放体验。 这种开源视频播放器的主要优势是其灵活性和可扩展性。开发者可以根据自己的需要对播放器进行定制和扩展,添加新的功能或者改进现有功能。这使得基于ffmpeg视频播放器成为一个非常受欢迎和受欢迎的选择,因为它可以满足用户的不同需求。 除了支持多种视频格式外,基于ffmpeg视频播放器还具有许多其他功能,例如调整音量、播放列表、循环播放、字幕支持、画面调整等。用户可以根据自己的喜好和需求进行设置和调整。 基于ffmpeg视频播放器也具有良好的兼容性和稳定性。由于ffmpeg库经过了广泛的测试和验证,因此可以保证播放器在不同操作系统和设备上的良好运行。 总之,基于ffmpeg的开源视频播放器是一种功能强大,灵活性高,兼容性好的视频播放软件。它为用户提供高质量的视听体验,并且可以根据用户的需求进行定制和扩展。无论是作为普通用户还是开发者,基于ffmpeg视频播放器都是一个出色的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值