如何利用ffmpeg提供的API函数进行多媒体文件的解封装
多媒体已经无处不在,程序员必须知道的一些多媒体封装知识 如何利用ffmpeg提供的API函数进行多媒体文件的解封装。
上一篇文章我们搭好了环境并编译出所需的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也可能需要解码)汉游天下(http://vdisk.weibo.com/s/FuhRYFUVmMhCZ)
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解封装的基本框架讲解清楚。
#include <stdio.h>
![](/assets/blank.gif)
#include "libavformat/avformat.h"static const char *media_file = "test_media.mp4"; int main(void) { int i, vid_idx, aud_idx; FILE *fp_vides = NULL, *fp_audes = NULL; AVFormatContext *pFormatCtx = NULL; AVPacket pkt;av_register_all(); avformat_open_input(&pFormatCtx, media_file, NULL, NULL); avformat_find_stream_info(pFormatCtx, NULL);fp_vides = fopen("vid_es.dat", "wb"); fp_audes = fopen("aud_es.dat", "wb"); // 1, handle stream info for (i=0; i<pFormatCtx->nb_streams; i++) { if (pFormatCtx->streams[i]->codec->codec_type ==AVMEDIA_TYPE_VIDEO) vid_idx = i; else if (pFormatCtx->streams[i]->codec->codec_type ==AVMEDIA_TYPE_AUDIO) aud_idx = i; else ;//such as subtitile } while (av_read_frame(pFormatCtx, &pkt) >= 0) { // 2, handle pkt data if (pkt.stream_index == vid_idx) fwrite(pkt.data, pkt.size, 1, fp_vides); else if (pkt.stream_index == aud_idx) fwrite(pkt.data, pkt.size, 1, fp_audes); else ;// such as subtitile av_free_packet(&pkt); } fclose(fp_vides); fclose(fp_audes); avformat_close_input(&pFormatCtx); return 0; }
![](/assets/blank.gif)
在注释1的地方,需要处理基本流索引与音视频对应的关系和重要信息记录,这个关系会在注释2的地方用到,并且也是后续的多音轨、字幕切换的凭据,本例只处理了最简单的只有一路音视频的情况,且没有对其他信息进行记录,比如帧率、视频宽高、编码类型、时间标度、第一个PTS等等。原则上这些跟Demux的框架没有关系,且每个人有有自己的处理方式,就不在这里贴出来。
第一时间获得博客更新,获得更详细信息和Demo代码,请关注微信号:程序员互动联盟,扫一扫下方二维码或者搜索微信号coder_online即可关注,我们可以在线交流。
如何利用ffmpeg提供的API函数进行多媒体文件的解封装相关推荐
- 利用ffmpeg提供的库(API)进行音频与视频的编码并生成文件
Output example.c 目录 [隐藏] 1 概述 2 音频输出 2.1 add_audio_stream 2.2 open_audio 2.3 get_audio_frame 2.4 wri ...
- 利用操作系统提供的API编写防火墙
利用操作系统提供的API编写防火墙 /* 利用操作系统提供的API编写防火墙. 该程序涉及到的API说明请访问微软的MSDN Library 代码在C++ Builder 5编译通过 如果您想和我交流 ...
- 通过ntdll.dll提供的API函数实现当前进程的枚举
这种枚举的方法是通过ntdll.dll提供的API函数ZwQuery?SystemInformation()来实现,此方法比前面所提供的方法复杂一些, 下面提供实际的代码如下: #include &l ...
- FFmpeg入门详解之43:FFmpeg解封装的原理与实战
FFMpeg 解封装 本例子实现的是将音视频分离,例如将封装格式为 FLV.MKV.MP4.AVI 等封装格式的文件,将音频.视频分离开来. 大致的解封装流程: 1.首先要对解复用器进行初始化. 2. ...
- FFmpeg解封装、解码音频和视频(分别使用OpenGL和OpenAL播放)
1 ffmpeg解码大致流程 下图是ffmpeg解码播放音视频的基本流程: 首先是网络媒体解协议,解协议之后得到对应的媒体文件比如mp4,ts等,这些格式是媒体文件的封装格式,也就是将音频,视频, ...
- VBS调用Windows API函数
Demon's Blog 忘记了,喜欢一个人的感觉 Demon's Blog » 程序设计 » VBS调用Windows API函数 « 用VBS修改Windows用户密码 在VB中创建和使用 ...
- C++文件操作API函数介绍
转自 http://www.studentblog.net/m/tonycat/archives/2006/26364.html 文件的基本概念 所谓"文件"是指一组相关数据的有序 ...
- GPIO子系统下的API函数
GPIO子系统下的API函数 1.GPIO子系统下的API函数 1.1.gpio_request 函数 1.2. gpio_free 函数 1.3. gpio_direction_input 函数 1 ...
- 利用FFMPEG进行视频分割
转载地址:http://blog.csdn.net/bikeytang/article/details/51491139 利用FFMPEG命令进行文件分割 ffmpeg -ss 00:00:00 -i ...
最新文章
- fiddler4 使用教程
- delphi公共函数 UMyPubFuncFroc--版权所有 (C) 2008 勇者工作室
- How should I set up tag files for a multi-level directory hierarchy? kiss snow
- Python库引用import多种用法及比较
- 23. which命令
- 实现接口java_Java – 实现接口
- cocos2d-x初探学习笔记(4)--触屏事件
- oracle中packages使用,oracle中packages的使用
- 预见2021:《2021年中国呼叫中心产业全景图谱》 未来十年八大预测
- Springboot知识库系统答辩PPT模板
- Forms Authentication With Absolute Return URLs
- 【Matlab】Plot的用法详解
- Atitit gc 垃圾回收原理与概论and 自动资源管理的艺术 v2 1. 为什么需要gc	1 1.1. 如果长期不被释放,可能导致OOM。	1 1.2. ,目的在于防止由程序猿引入的人为的内存
- Binding.scala使用教程8--binding.scala结合semanticUI
- 工欲善其事必先利其器之学编程的电脑需要什么配置
- 矢量字体合并《注意事项》
- 通信中的MGF(矩生成函数)
- 制作二十四进制的时钟特效(JavaScript)
- Spring Cloud入门系列(1)- Spring生态体系发展史+全系框架介绍
- 电脑使用图片转换器打开heic图片方法
热门文章
- python逻辑流程图_python-程序流程图
- html5 canvas 不兼容safari浏览器_HTML5简介
- vue菜单点击html,基于vue.js实现侧边菜单栏
- InvalidCharacterError: Failed to execute 'setAttribute' on 'Element': ')' is not a valid
- ffmpeg 分辨率 压缩_用GPU加速FFmpeg中的超分辨率功能
- centos7根目录root扩容操作记录
- VX的这一重大变化,你支持嘛?
- 2021中国低代码市场研究报告
- 2020快手移动游戏行业玩家数据价值报告
- 鲲鹏服务器的作用,眼见为实,华为鲲鹏架构服务器生态大揭秘