热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

本文为作者原创,转载请注明出处:https:www.cnblogs.comleisure_chnp10506642.htmlFFmpeg封装格式处理相关内容分为如下几篇文章:[1].

本文为作者原创,转载请注明出处: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 

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
祖国昌盛
先看一下测试用资源文件的格式:

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


推荐阅读
  • 【shell】网络处理:判断IP是否在网段、两个ip是否同网段、IP地址范围、网段包含关系
    本文介绍了使用shell脚本判断IP是否在同一网段、判断IP地址是否在某个范围内、计算IP地址范围、判断网段之间的包含关系的方法和原理。通过对IP和掩码进行与计算,可以判断两个IP是否在同一网段。同时,还提供了一段用于验证IP地址的正则表达式和判断特殊IP地址的方法。 ... [详细]
  • 本文介绍了Android中的assets目录和raw目录的共同点和区别,包括获取资源的方法、目录结构的限制以及列出资源的能力。同时,还解释了raw目录中资源文件生成的ID,并说明了这些目录的使用方法。 ... [详细]
  • 本文讨论了如何使用GStreamer来删除H264格式视频文件中的中间部分,而不需要进行重编码。作者提出了使用gst_element_seek(...)函数来实现这个目标的思路,并提到遇到了一个解决不了的BUG。文章还列举了8个解决方案,希望能够得到更好的思路。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • 本文介绍了关于Java异常的八大常见问题,包括异常管理的最佳做法、在try块中定义的变量不能用于catch或finally的原因以及为什么Double.parseDouble(null)和Integer.parseInt(null)会抛出不同的异常。同时指出这些问题是由于不同的开发人员开发所导致的,不值得过多思考。 ... [详细]
  • 流数据流和IO流的使用及应用
    本文介绍了流数据流和IO流的基本概念和用法,包括输入流、输出流、字节流、字符流、缓冲区等。同时还介绍了异常处理和常用的流类,如FileReader、FileWriter、FileInputStream、FileOutputStream、OutputStreamWriter、InputStreamReader、BufferedReader、BufferedWriter等。此外,还介绍了系统流和标准流的使用。 ... [详细]
  • Tomcat安装与配置教程及常见问题解决方法
    本文介绍了Tomcat的安装与配置教程,包括jdk版本的选择、域名解析、war文件的部署和访问、常见问题的解决方法等。其中涉及到的问题包括403问题、数据库连接问题、1130错误、2003错误、Java Runtime版本不兼容问题以及502错误等。最后还提到了项目的前后端连接代码的配置。通过本文的指导,读者可以顺利完成Tomcat的安装与配置,并解决常见的问题。 ... [详细]
  • 抽空写了一个ICON图标的转换程序
    抽空写了一个ICON图标的转换程序,支持png\jpe\bmp格式到ico的转换。具体的程序就在下面,如果看的人多,过两天再把思路写一下。 ... [详细]
  • java的流分两大类,字节流和字符流。一般在cc++中,一个字节是8位,java也是一样。但是,在cc++中一个字符,即char一般也是8位(可能机器不同会有所不同),但java为 ... [详细]
  • 第四讲ApacheLAMP服务器基本配置Apache的编译安装从Apache的官方网站下载源码包:http:httpd.apache.orgdownload.cgi今 ... [详细]
author-avatar
45度向上倾斜的世界取_872
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有