ffmpeg系列-解复用流程解析

本文主要来分析demuxer的流程。

1.结构流程图

从上面的结构图中我们可以看到AVFormatContext的iformat指向AVInputFormat。

2.实现流程图
3.avformat_open_input函数作用
首先看函数的声明

int avformat_open_input(AVFormatContext **ps, const char *filename,
                        AVInputFormat *fmt, AVDictionary **options)

这个函数的作用是打开文件的链接,如果是网络连接,还会发起网络请求,并一直等待网络数据的返回,然后读取视频流的数据(协议操作)。

AVFormatContext **ps

 

该函数的主要作用是填充好AVFormatContext **ps这个结构体。AVFormatContext这个结构体里面的参数比较多,这里就不一一列举了,详细可以参考avformat.h这个头文件,具体用到到时再详细说明。

const char *filename

文件的全部路径,比如

http://videocdn.eebbk.net/7abbdb39fd2aa71efa64f9897f4f5616.mp4
AVInputFormat *fmt

 AVInputFormat 的结构体也比较复杂,主要是封装媒体数据封装类型的结构体,比如flv,mpegts,mp4等。在这里可以传入空,如果为空,后面就会从网络数据中读出。当然如果我们知道文件的类型,先用av_find_input_format(“mp4”)初始化出对应的结构体,这里我们用的是mp4,先初始化好这个结构体,比如对于直播来说,会比较节约时间。
 

AVDictionary **options

struct AVDictionary {
  int count;
  AVDictionaryEntry *elems;
};
typedef struct AVDictionaryEntry {
  char *key;
  char *value;
} AVDictionaryEntry;

字典类型的可选参数,可以向ffmpeg中传入指定的参数的值。比如我们这里传入了

//number of frames used to probe fps
 av_dict_set_int(&ffp->format_opts, "fpsprobesize", 0, 0);

表示fpsprobesize对应的参数值为0,当然还可以传入更多值,具体可以参考options_table.h/libavformat这个头文件。

文章最后扫码进qun,可免费领取音视频学习资料,资料包括(C/C++,Linux,FFmpeg webRTC rtmp hls rtsp ffplay srs 等等

 

函数使用sample:

    AVFormatContext *ic = NULL;//初始化ic变量
	//申请AVFormatContext内存
    ic = avformat_alloc_context();
    if (!ic) {//内存申请失败
        av_log(NULL, AV_LOG_FATAL, "Could not allocate context.\n");
        ret = AVERROR(ENOMEM);
        goto fail;
    }
    ic->interrupt_callback.callback = decode_interrupt_cb;//IO层错误回调
    ic->interrupt_callback.opaque = is;
    if (!av_dict_get(format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) {
        av_dict_set(&format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE);
        scan_all_pmts_set = 1;
    }
    err = avformat_open_input(&ic, is->filename, is->iformat, &format_opts);
    if (err < 0) {
        print_error(is->filename, err);
        ret = -1;
        goto fail;
    }

4.流程实现分析

讲解解复用流程,我们还是需要从avformat_open_input/utils.c/libavformat函数开始分析整个解析流程。

int avformat_open_input(AVFormatContext **ps, const char *filename,
                        AVInputFormat *fmt, AVDictionary **options)
{
    AVFormatContext *s = *ps;
    int i, ret = 0;
    AVDictionary *tmp = NULL;
    ID3v2ExtraMeta *id3v2_extra_meta = NULL;
	//如果s为空,且没有申请内存的话,申请AVFormatContext内存
    if (!s && !(s = avformat_alloc_context()))
        return AVERROR(ENOMEM);
    if (!s->av_class) {
        av_log(NULL, AV_LOG_ERROR, "Input context has not been properly allocated by avformat_alloc_context() and is not NULL either\n");
        return AVERROR(EINVAL);
    }
    if (fmt)
        s->iformat = fmt;//AVInputFormat赋值给AVFormatContext的AVInputFormat

    if (options)//获取option,拷贝给tmp
        av_dict_copy(&tmp, *options, 0);

    if (s->pb) // must be before any goto fail
        s->flags |= AVFMT_FLAG_CUSTOM_IO;
    //把获取的option设置给AVFormatContext
    if ((ret = av_opt_set_dict(s, &tmp)) < 0)
        goto fail;
	//filename赋值给s->filename
    av_strlcpy(s->filename, filename ? filename : "", sizeof(s->filename));
	//初始化协议与初始化解封装(文件探测等)
    if ((ret = init_input(s, filename, &tmp)) < 0)
        goto fail;
    s->probe_score = ret;//获取文件探测回来的分数
	//协议白名单
    if (!s->protocol_whitelist && s->pb && s->pb->protocol_whitelist) {
        s->protocol_whitelist = av_strdup(s->pb->protocol_whitelist);
        if (!s->protocol_whitelist) {
            ret = AVERROR(ENOMEM);
            goto fail;
        }
    }
	//协议黑名单
    if (!s->protocol_blacklist && s->pb && s->pb->protocol_blacklist) {
        s->protocol_blacklist = av_strdup(s->pb->protocol_blacklist);
        if (!s->protocol_blacklist) {
            ret = AVERROR(ENOMEM);
            goto fail;
        }
    }

    if (s->format_whitelist && av_match_list(s->iformat->name, s->format_whitelist, ',') <= 0) {
        av_log(s, AV_LOG_ERROR, "Format not on whitelist \'%s\'\n", s->format_whitelist);
        ret = AVERROR(EINVAL);
        goto fail;
    }
	//打开流的时候跳过最初的字节
    avio_skip(s->pb, s->skip_initial_bytes);

    /* Check filename in case an image number is expected. */
    if (s->iformat->flags & AVFMT_NEEDNUMBER) {
        if (!av_filename_number_test(filename)) {
            ret = AVERROR(EINVAL);
            goto fail;
        }
    }
	//把AVFormatContext的duration和start_time置为NOPTS
    s->duration = s->start_time = AV_NOPTS_VALUE;

    /* Allocate private data. */
    if (s->iformat->priv_data_size > 0) {
        if (!(s->priv_data = av_mallocz(s->iformat->priv_data_size))) {
            ret = AVERROR(ENOMEM);
            goto fail;
        }
        if (s->iformat->priv_class) {
            *(const AVClass **) s->priv_data = s->iforma
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用ffmpeg复用TS流,可以使用以下命令: ``` ffmpeg -i input.ts -map 0 -c copy output.mp4 ``` 其中,`input.ts`是输入的TS流文件,`output.mp4`是输出的目标文件。这个命令会将输入的TS流复用并复制到目标文件中。 释一下命令的参数: - `-i input.ts`指定输入文件为`input.ts`,即要复用的TS流文件。 - `-map 0`表示将输入文件中的所有流都映射到输出文件中。 - `-c copy`表示使用原始的编码格式进行复制,不进行任何重新编码操作。这样可以保持原始的编码质量和格式。 - `output.mp4`是输出的目标文件名,可以根据需要自行指定。 这个命令会将TS流中的所有流(包括视频流、音频流等)复用,并将它们复制到输出文件中,不对流进行任何重新编码操作。这样可以快速地提取TS流中的音视频数据。 注意:这只是一个简单的示例命令,具体的使用方法和参数根据实际情况可能会有所不同。在实际使用中,可以根据需要调整命令参数来满足自己的需求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [修改ffmpeg源码,并用它对多路节目TS流复用及播放](https://blog.csdn.net/cf125313/article/details/80764829)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [基于FFmpeg的视频播放器之二:复用](https://blog.csdn.net/caoshangpa/article/details/124486435)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [FLV复用代码实现!!!!](https://download.csdn.net/download/qq_39466755/87020098)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值