FFmpeg封装格式处理2-解复用例程

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

作者:叶余

来源:https://www.cnblogs.com/leisure_chn/p/10506642.html


FFmpeg 封装格式处理相关内容分为如下几篇文章:

[1]. FFmpeg 封装格式处理-简介

[2]. FFmpeg 封装格式处理-解复用例程

[3]. FFmpeg 封装格式处理-复用例程

[4]. FFmpeg 封装格式处理-转封装例程

3. 解复用例程

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

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

image.png

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\n", 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\n", 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)\n", 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)\n", pkt.pos, pkt.pts, pkt.dts, ret);
        }
        av_packet_unref(&pkt);
    }
    printf("Demuxing succeeded.\n");
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

image.png

先看一下测试用资源文件的格式:

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 检测发现这两个文件正常。


「视频云技术」你最值得关注的音视频技术公众号,每周推送来自阿里云一线的实践技术文章,在这里与音视频领域一流工程师交流切磋。

阿里云视频云@凡科快图.png

相关文章
|
18天前
|
存储 编解码 算法
探索FFmpeg复用:深入理解媒体数据的组织与封装(三)
探索FFmpeg复用:深入理解媒体数据的组织与封装
48 0
|
18天前
|
存储 编解码 数据处理
【FFmpeg 视频基本格式】深入理解FFmpeg:从YUV到PCM,解码到编码(三)
【FFmpeg 视频基本格式】深入理解FFmpeg:从YUV到PCM,解码到编码
55 0
|
18天前
|
存储 编解码 数据处理
【FFmpeg 视频基本格式】深入理解FFmpeg:从YUV到PCM,解码到编码(二)
【FFmpeg 视频基本格式】深入理解FFmpeg:从YUV到PCM,解码到编码
58 0
|
7月前
|
存储 编解码 Cloud Native
音视频 ffmpeg命令转封装
音视频 ffmpeg命令转封装
|
18天前
FFmpeg开发笔记(十八)FFmpeg兼容各种音频格式的播放
《FFmpeg开发实战》一书中,第10章示例程序playaudio.c原本仅支持mp3和aac音频播放。为支持ogg、amr、wma等非固定帧率音频,需进行三处修改:1)当frame_size为0时,将输出采样数量设为512;2)遍历音频帧时,计算实际采样位数以确定播放数据大小;3)在SDL音频回调函数中,确保每次发送len字节数据。改进后的代码在chapter10/playaudio2.c,可编译运行播放ring.ogg测试,成功则显示日志并播放铃声。
21 1
FFmpeg开发笔记(十八)FFmpeg兼容各种音频格式的播放
|
18天前
|
编解码 API 数据处理
【摄像头数据处理】摄像头数据处理:使用FFmpeg合并、编码和封装视频流
【摄像头数据处理】摄像头数据处理:使用FFmpeg合并、编码和封装视频流
74 0
|
18天前
|
存储 编解码 安全
探索FFmpeg复用:深入理解媒体数据的组织与封装(二)
探索FFmpeg复用:深入理解媒体数据的组织与封装
63 0
|
18天前
|
存储 编解码 算法
探索FFmpeg复用:深入理解媒体数据的组织与封装(一)
探索FFmpeg复用:深入理解媒体数据的组织与封装
62 0
|
18天前
|
存储 缓存 编解码
【FFmpeg 视频基本格式】深入理解FFmpeg:从YUV到PCM,解码到编码(一)
【FFmpeg 视频基本格式】深入理解FFmpeg:从YUV到PCM,解码到编码
62 0
|
18天前
|
存储 算法 前端开发
深入理解FFmpeg音视频编程:处理封装、解码、播放 队列与回放策略
深入理解FFmpeg音视频编程:处理封装、解码、播放 队列与回放策略
48 0