解密多媒体封装解封装框架

 上一篇文章我们搭好了环境并编译出所需的ffmpeg库,本篇我们讨论如何利用ffmpeg提供的API函数进行多媒体文件的解封装(demux)过程。在讲解之前,我们需要了解一些基本的多媒体文件知识,大虾请飘过。

  • 容器格式:不管是音频文件还是视频格式的文件,都是一个多媒体的容器,即container,比如常见的视频容器格式有avi、mp4、mkv、flv、rm/rmvb、mov、ts、vob、dat,音频容器格式有MP3、WAV、AAC、APE,FLAC等等,它容纳了视频、音频、字幕(subtitle)等一个或多个基本流数据,有的甚至一个容器中存放有多个视频、音频以及字幕。

  • 压缩格式:对视频、音频数据的基本流进行的压缩方式就是音视频的压缩格式。常见的视频压缩格式如mpeg2、mpeg4、H264、VC1、Rm/Rmvb,常见音频压缩格式如MPA、AAC、AC3、DTS。注意这里的部分名字和上面的一样,但意义不同,上面是封装格式,这里是压缩格式。为什么要压缩呢?因为不压缩的话,要存储图像或声音就需要非常多的空间,比如mpeg2压缩比能达到25:1左右,而H264甚至能达到102:1的惊人程度!

  • ES:也就是ElementaryStream,也称为基本流、组件流等称呼,就是单独的一路视频、一条音频、一个subtitle字幕或者单个的附加数据。显然常见的多媒体文件一个都有一个视频ES、音频ES,有的也含有多个视频ES和音频ES以及subtitleES。比如蓝光原版的TS一般都含有多个音轨ES和字幕ES,但不是所有有字幕都有字幕ES,可能字幕已经内嵌进视频,这样的字幕其实成了视频的一部分。

  • Demux:在播放时,需要把这些视音频以及字幕等基本流分离出来,这个过程就叫Demux,或者解封装,也称为解复用。分离出来的各个基本流(ES)分别送给视频解码器、音频解码器等解码后才能得到图像声音。Demux过程如下图(subtitle也可能需要解码):

  • Remux:当然Demux反过来把基本的音频、视频、字幕等组合成一个完整的多媒体就是Remux或者封装,也称为复用。比如很多电影网站的音视频压制的人就需要先做Demux,分离成ES,在加入必要的中文字幕和音轨后、重新封装。所有的转码工具也都必须有Remux和重新Demux的过程。复用与解复用的概念对于熟悉DVB行业的读者来说应该比较清楚。

  • PTS:也就是显示时间戳,指图像或者声音在解码后应该显示或者发声的时间点。音视频不是一解码出来就播出来,否则就乱了,性能好的解码器播放的快,差的播放的慢,并且视频和音频也对不上号。所有这些都是靠PTS来同步的。至于DTS解码时间戳在现在相对以前较大解码内存缓冲下,显得不那么重要了。

有了这些基本的多媒体知识,我们就可以继续讲解如何利用ffmpeg来进行Demux这个过程。首先介绍一下主要的几个API函数:

intavformat_open_input(AVFormatContext **ps, const char *filename,

AVInputFormat *fmt, AVDictionary **options)

这个函数用于打开多媒体文件,并读取相关文件头信息。

voidavformat_close_input(AVFormatContext **ps)

这个函数用于关闭上面打开的多媒体文件,释放相关资源。

intavformat_find_stream_info(AVFormatContext *ic, AVDictionary**options);

这个函数通过注册的文件格式解析器读取文件的取各种信息,比如播放持续时间、音视频压缩格式、音轨信息、字幕信息、帧率、采样率等等。

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

这个函数对于Demux过程是最重要的一个函数,它从文件中读取一帧视频、一帧或多帧音频、字幕等ES数据包,除了数据本身之外,还包括PTS、持续时间、参考帧等重要信息。

void av_free_packet(AVPacket *pkt)

这个函数用于释放ES数据包,与上面的函数成对使用。

有了这些函数和上面的基本知识,下面我们来实现一个简单的Demux框架实例。这个实例的功能是把多媒体文件中的音视频ES数据抽出来分别写入不同文件。我们为了简单,这里不处理返回错误,在实际项目中自己添加错误处理机制。本文力求用最简单最原始的方式把ffmpeg解封装的基本框架讲解清楚。

 1 #include "libavformat/avformat.h"
 2 
 3 static const char *media_file = "test_media.mp4";
 4 int main(void)
 5 {
 6 int i, vid_idx, aud_idx;
 7 FILE *fp_vides = NULL, *fp_audes = NULL;
 8 AVFormatContext *pFormatCtx = NULL;
 9 AVPacket pkt;
10 
11 av_register_all();
12 avformat_open_input(&pFormatCtx, media_file, NULL, NULL);
13 avformat_find_stream_info(pFormatCtx, NULL);
14 
15 fp_vides = fopen("vid_es.dat", "wb");
16 fp_audes = fopen("aud_es.dat", "wb");
17 // 1, handle stream info
18 for (i=0; i<pFormatCtx->nb_streams; i++)
19 {
20 if (pFormatCtx->streams[i]->codec->codec_type ==AVMEDIA_TYPE_VIDEO)
21 vid_idx = i;
22 else if (pFormatCtx->streams[i]->codec->codec_type ==AVMEDIA_TYPE_AUDIO)
23 aud_idx = i;
24 else
25 ;//such as subtitile
26 }
27 while (av_read_frame(pFormatCtx, &pkt) >= 0)
28 {
29 // 2, handle pkt data
30 if (pkt.stream_index == vid_idx)
31 fwrite(pkt.data, pkt.size, 1, fp_vides);
32 else if (pkt.stream_index == aud_idx)
33 fwrite(pkt.data, pkt.size, 1, fp_audes);
34 else
35 ;// such as subtitile
36 av_free_packet(&pkt);
37 }
38 fclose(fp_vides);
39 fclose(fp_audes);
40 avformat_close_input(&pFormatCtx);
41 return 0;
42 }

 

在注释1的地方,需要处理基本流索引与音视频对应的关系和重要信息记录,这个关系会在注释2的地方用到,并且也是后续的多音轨、字幕切换的凭据,本例只处理了最简单的只有一路音视频的情况,且没有对其他信息进行记录,比如帧率、视频宽高、编码类型、时间标度、第一个PTS等等。原则上这些跟Demux的框架没有关系,且每个人有有自己的处理方式,就不在这里贴出来。

要想获得更详细信息或者Demo代码,请关注微信号:程序员互动联盟,扫一扫下方二维码或者搜索微信号coder_online即可关注,我们可以在线交流。

如需转载请注明出处:谢谢合作!

 

转载于:https://www.cnblogs.com/2010wuhao/p/4389274.html

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

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

相关文章

python入门及日常应用_python的日常应用-入门篇02

大部分人在编写自己第一个程序的时候会做什么&#xff1f;当然是让你的程序对我们的世界大喊一声“Hello world!”了。今天我们来学习的便是Python中的输出语句。如何让你的程序“说话”&#xff1f;我们想要让程序帮我们做事之前首先要教会程序怎么“说话”&#xff0c;这样我…

bzoj 3611

和BZOJ消耗站一样&#xff0c;先将那个询问的简图构建出来&#xff0c;然后就是简单的树形DP。 &#xff08;倍增数组开小了&#xff0c;然后就狂WA&#xff0c;自己生成的极限数据深度又没有那么高&#xff0c;链又奇迹般正确&#xff09; 1 #include <cstdio>2 #includ…

vscode添加源文件_VSCode自制的IDE编译多个源文件

文/EdwardVSCode的预定义变量我们上一篇文章中讲述了如何将MinGW工具嵌入到VSCode文本编辑器中&#xff0c;在这个配置的过程中&#xff0c;我们只需要通过修改VSCode生成的“luanch.json”和“task.json”两个JSON文件中的特定字段&#xff0c;就可以实现开发环境的搭建。那么…

c# 第四课 interfaces

An interface is a contract(协定) that guarantees to a client how a class or struct will behave.When a class implements an interface(实现一个接口), it tells any potential(可能的) client “I guarantee I’ll support all the methods, properties, events, and in…

mysql+自动还原备份_Mysql 自动备份与恢复

自动备份MySql 5.0有三个方案&#xff1a;备份方案一&#xff1a; 通过 mysqldump命令,直接生成一个完整的 .sql 文件Step 1: 创建一个批处理(说明&#xff1a;root 是mysql默认用户名, aaaaaa 是mysql密码, bugtracker 是数据库名)------------mySql_backup.bat--------------…

SqlServer按时间自动生成生成单据编号

SET _tmpDateTime GETDATE() EXEC dbo.Dtw_Common_GenerateProofCode ProofType SO,WhsCodeWhsCode, ProofDate _tmpDateTime, RtnCode _tmpProofCode OUTPUT --生成的最终的CODE USE [SZVB]GO/****** Object: StoredProcedure [dbo].[Dtw_Common_GenerateProofCode]…

hive创建分区表 指定分隔符_HIVE 对于分区表的操作

CREATE EXTERNALTABLE IF NOT EXISTS data_zh(ROWKEY STRING,STATION INT,YEAR INT,MONTH INT,DAY INT,HOUR INT,MINUTE INT,)PARTITIONED BY (AGE INT)指定分区(此列并没真正存储列&#xff0c;也就是不存于你的数据中。但是如果你的数据从Oracle按年份导出&#xff0c;按照年…

Web Service 学习

1. Web services 平台的元素&#xff1a; SOAP (简易对象访问协议) UDDI (通用描述、发现及整合) WSDL (Web services 描述语言)1.1 什么是 SOAP&#xff1f; 基本的 Web services 平台是 XML HTTP。 SOAP 指简易对象访问协议 SOAP 是一种通信协议 SOAP 用于应用程序之间的通信…

java高级mysql面试题_Java高级面试题

一.基础知识&#xff1a;1)集合类&#xff1a;List和Set比较&#xff0c;各自的子类比较(ArrayList&#xff0c;Vector&#xff0c;LinkedList&#xff1b;HashSet&#xff0c;TreeSet)&#xff1b;2)HashMap的底层实现&#xff0c;之后会问ConcurrentHashMap的底层实现&#x…

转:Oracle 中union的用法

UNION 指令的目的是将两个 SQL 语句的结果合并起来,可以查看你要的查询结果. 例如: SELECT Date FROM Store_Information UNION SELECT Date FROM Internet_Sales 注意:union用法中,两个select语句的字段类型匹配,而且字段个数要相同,如上面的例子,在实际的软件开发过程,会遇到…

mysql skip_counter_mysql的三个故障解决小结

mysql使用过程中经常会遇到的三个故障&#xff0c;在此小结一下。1、MySQl服务无法启动我们在使用mysql的过程中&#xff0c;常会遇到MySQl服务无法启动&#xff0c;具体报错信息&#xff1a;Starting MySQL ERROR.The server quit without updating PID file (/[FAILED]l/mysq…

Httpd 使用ip可以访问,localhost和127.0.0.1不能访问

解决方法&#xff1a;打开/etc/httpd/conf目录下的httpd.conf文件&#xff0c; 加入 Listen 127.0.0.1:81 加入后&#xff1a; Listen xxx.xxx.xxx.xxx:81 Listen 127.0.0.1:81 其中xxx.xxx.xxx.xxx是我的ip 这样通过ip、localhost、127.0.0.1都可以访问了 转载于:https://www.…

如何将每一条记录放入到对应的范围中

编程序的时候遇到一个问题&#xff1a; 画热图 &#xff1a;计算热力值--->画网格&#xff0c;将在一定范围内定位出的mac累积计数--->编写出了定位程序&#xff0c;但是如何将每个具体的坐标值放入对应的范围&#xff08;网格&#xff09;--->因为具体坐标和网格选取…

mysql主从进行扩展_Mysql主从知识扩展部分1

一、使用mysql-proxy 快速实现mysql 集群 读写分离1、有两种方法&#xff1a;a)程序代码内部实现&#xff0c;对select操作分发到从库&#xff0c;其他到主库&#xff0c;再生产环境中应用比较广泛&#xff0c;比较知名的有DISCUZX2&#xff0c;优点性能好&#xff0c;成本低&a…

Python之异常追踪模块:traceback

正常时输出追踪信息&#xff1a; import traceback def stack():print The python stack:traceback.print_stack() from twisted.internet import reactor reactor.callWhenRunning(stack) reactor.run()#摘录来自: likebeta. “Twisted与异步编程入门”。 iBooks. 异常时输出…

mysql事务所_mysql事务

1.事务的ACID属性事务(Database Transaction) &#xff0c;是指作为单个逻辑工作单元执行的一系列操作。事务处理可以确保除非事务性单元内的所有操作都成功完成&#xff0c;否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元&…

[草稿]挂载新硬盘

查看新硬盘&创建分区 xxxxxx:/dev$ sudo fdisk -l [sudo] password for xxx: Disk /dev/sda: 85.9 GB, 85899345920 bytes 255 heads, 63 sectors/track, 10443 cylinders, total 167772160 sectors Units sectors of 1 * 512 512 bytes Sector size (logical/physical):…

php mysql 迁移_将phpstudy中的mysql迁移至Linux教程

项目目的将原来windows环境中使用phpstudy搭建的mysql 5.5.53 中的数据迁移至新主机Linux环境中环境情况新主机系统平台&#xff1a;CentOS release 7.4 (Final) 内核 3.10.0-693.el7.x86_64mysql环境&#xff1a;mysql> statusServer version: 5.6.39-log…

Swift 操作符

这里只记录一些swift特殊的运算符 1.swift里面 仅仅进行赋值操作&#xff0c;不再向右边返回左值 2.模运算的操作数可以是小数了 3.Nil Coalescing Operator nil coalescing operator用来判断一个可选值是否有值&#xff0c;如果没有的话就赋予其一个缺省值 注意这里面“&…

python json.dumps慢_python json.dumps中文乱码问题解决

json.dumps(var,ensure_asciiFalse)并不能解决中文乱码的问题json.dumps在不同版本的Python下会有不同的表现&#xff0c; 注意下面提到的中文乱码问题在Python3版本中不存在。注:下面的代码再python 2.7版本下测试通过# -*- coding: utf-8 -*-odata {a : 你好}print odata结果…