zoukankan      html  css  js  c++  java
  • FFmpeg封装格式处理2-解复用例程

    本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10506642.html

    FFmpeg封装格式处理相关内容分为如下几篇文章:
    [1]. FFmpeg封装格式处理-简介
    [2]. FFmpeg封装格式处理-解复用例程
    [3]. FFmpeg封装格式处理-复用例程
    [4]. FFmpeg封装格式处理-转封装例程

    3. 解复用例程

    解复用(demux),表示从一路输入中分离出多路流(视频、音频、字幕等)。

    本例实现,将输入文件中的视频流和音频流分离出来,保存为单独的文件,所保存的文件是不含封装格式的裸流文件。

    demuxing

    3.1 源码

    源码很短,用于演示demux的用法。源码中大部分函数返回值的判断均已省略。

    #include <libavformat/avformat.h>
    
    int main (int argc, char **argv)
    {
        if (argc != 4)
        {
            fprintf(stderr, "usage: %s test.ts test.h264 test.aac
    ", argv[0]);
            exit(1);
        }
    
        const char *input_fname = argv[1];
        const char *output_v_fname = argv[2];
        const char *output_a_fname = argv[3];
        FILE *video_dst_file = fopen(output_v_fname, "wb");
        FILE *audio_dst_file = fopen(output_a_fname, "wb");
    
        AVFormatContext *fmt_ctx = NULL;
        int ret = avformat_open_input(&fmt_ctx, input_fname, NULL, NULL);
        ret = avformat_find_stream_info(fmt_ctx, NULL);
    
        int video_idx = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
        int audio_idx = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
        if (video_idx < 0 || audio_idx < 0)
        {
            printf("find stream failed: %d %d
    ", video_idx, audio_idx);
            return -1;
        }
    
        av_dump_format(fmt_ctx, 0, input_fname, 0);
    
        AVPacket pkt;
        av_init_packet(&pkt);
        pkt.data = NULL;
        pkt.size = 0;
    
        while (av_read_frame(fmt_ctx, &pkt) >= 0)
        {
            if (pkt.stream_index == video_idx)
            {
                ret = fwrite(pkt.data, 1, pkt.size, video_dst_file);
                //printf("vp %x %3"PRId64" %3"PRId64" (size=%5d)
    ", pkt.pos, pkt.pts, pkt.dts, ret);
            }
            else if (pkt.stream_index == audio_idx) {
                ret = fwrite(pkt.data, 1, pkt.size, audio_dst_file);
                //printf("ap %x %3"PRId64" %3"PRId64" (size=%5d)
    ", pkt.pos, pkt.pts, pkt.dts, ret);
            }
            av_packet_unref(&pkt);
        }
    
        printf("Demuxing succeeded.
    ");
    
    end:
        avformat_close_input(&fmt_ctx);
        fclose(video_dst_file);
        fclose(audio_dst_file);
    
        return 0;
    }
    

    3.2 编译

    源文件为demuxing.c,在SHELL中执行如下编译命令:

    gcc -o demuxing demuxing.c -lavformat -lavcodec -g
    

    生成可执行文件demuxing

    3.3 验证

    测试文件下载:tnshih.flv
    祖国昌盛
    先看一下测试用资源文件的格式:

    think@opensuse> ffprobe tnshih.flv 
    ffprobe version 4.1 Copyright (c) 2007-2018 the FFmpeg developers
    Input #0, flv, from 'tnshih.flv':
      Metadata:
        encoder         : Lavf58.20.100
      Duration: 00:00:37.20, start: 0.000000, bitrate: 1182 kb/s
        Stream #0:0: Video: h264 (High), yuv420p(progressive), 800x450, 25 fps, 25 tbr, 1k tbn, 50 tbc
        Stream #0:1: Audio: aac (LC), 44100 Hz, stereo, fltp
    

    可以看到视频文件'tnshih.flv'封装格式为flv,包含一路h264编码的视频流和一路aac编码的音频流。

    运行如下命令进行测试:

    ./demuxing tnshih.flv tnshih_flv.h264 tnshih_flv.aac
    

    使用ffplay播放视频文件thshih_flv.h264及音频文件tnshih_flv.aac,均无法播放。使用ffprobe检测发现这两个文件异常。
    原因参考雷霄骅博士的文章:
    使用FFMPEG类库分离出多媒体文件中的H.264码流
    最简单的基于FFmpeg的封装格式处理:视音频分离器简化版

    本节代码仅关注最简单的解复用功能,FLV、MP4等特定容器中分离出来的h264视频流和aac音频流无法播放。

    那换一种封装格式测一下,利用FFmpeg转码命令将flv封装格式转换为mpegts封装格式:

    测试:

    ffmpeg -i tnshih.flv -map 0 -c copy tnshih.ts
    

    运行如下命令进行测试:

    ./demuxing tnshih.ts tnshih_ts.h264 tnshih_ts.aac
    

    使用ffplay播放视频文件thshih_ts.h264及音频文件tnshih_ts.aac,播放正常。使用ffprobe检测发现这两个文件正常。

  • 相关阅读:
    第十九天:类和对象
    第十五天:模块
    十四天:匿名函数
    十四天作业
    第十三天:迭代器、递归
    十二天:闭包和装饰器
    一个炒鸡简单的购物车
    十一天
    第十天
    第十天作业
  • 原文地址:https://www.cnblogs.com/leisure_chn/p/10506642.html
Copyright © 2011-2022 走看看