• 网站刚刚上线,难免有不足的地方,敬请谅解!欢迎提出宝贵意见!

  •    3年前 (2015-06-11)  专业技术 多媒体 |   2 条评论  144 
    文章评分 0 次,平均分 0.0

    【多媒体】FFMPEG应用系列第二篇: 分离音视频数据流

    上一篇文章我们搭好了环境并编译出所需的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也可能需要解码):

    【多媒体】FFMPEG应用系列第二篇: 分离音视频数据流

     

    • 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>
    #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;
    }

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

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

    【多媒体】FFMPEG应用系列第二篇: 分离音视频数据流

     

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

      
     

    本文原始地址:http://www.coderonline.net/multimedia-ffmpeg-application-series-second-separate-audio-and-video-streams.html

    本站所有文章,除特别注明外,均为本站原创,转载请注明出处来自http://www.coderonline.net/

    关于

    发表评论

    表情 格式
    1. 老太太要乘出租汽车。“司机,”她说,“我想让你送我去车站。”“好吧,太太。”司机说。“你开得慢点,小心点儿,警察不放下手,请不要走,路面水多,不要急转弯。”司机生气的说:“好吧,太太!可是如果我们真出了车祸,你想进哪个医院呢?”

      http://wulimuqi.com 评论达人 LV.1 2年前 (2016-11-03) [0] [0]
    2. 妻子为房事的问题,前往医院请教医生。妻子:“我丈夫的身体还满强壮的,但是对房事却不行,而且似乎都不太能尽兴,不知道有什么办法可以医治?”医生:“这个问题并不严重,你的先生还很年轻,所以可以利用食物疗法来恢复精力。”妻子:“什么食物疗法呢?”医生:“煮一些可以提高精力的东西给他吃吧!比方说,人参、蟹、蚵、蛋、烤鳗鱼等食物都可以。”妻子回家后,依照医生的话,煮了许多美味的食物,等丈夫回家后,看到这么多好吃的菜肴,不禁食指大动,胃口大开,比平常多吃了许多。当天夜里,丈夫突然摇醒梦中的妻子,妻子兴奋地紧紧抱住丈夫。丈夫却推开她说:“喂!开灯吧! ”妻子:“你现在喜欢亮着灯办事啊?! ”丈夫:“你那边有没有纸?”妻子:“纸?等办完事再拿就可以了嘛! ”丈夫生气地说:“你想到哪里去了!?我肚子不舒服,想上厕所啦! ”

      http://jfdtjx.com 评论达人 LV.1 2年前 (2016-11-03) [0] [0]
    切换注册

    登录

    忘记密码 ?

    切换登录

    注册