demuxing_decoding.c 解读

----------------------------------------
authhor:hjjdebug
data: 2022-02-07
----------------------------------------

demuxing_decoding.c 解读
****************************************
特点: 能够同时操作音频和视频, 比较接近于实际的碼流. 是常用的操作流程.
程序分析:
1. avformat 登场.
    if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0)
    if (avformat_find_stream_info(fmt_ctx, NULL) < 0)
    采用了avio 的方式来读取来打开和读取输入文件, 见avio.c分析

2. 利用fmt_ctx来打开video_dec_ctx 及 audio_dec_ctx, 不用再制定codec
    if (open_codec_context(&video_stream_idx, &video_dec_ctx, fmt_ctx, AVMEDIA_TYPE_VIDEO) >= 0)
    if (open_codec_context(&audio_stream_idx, &audio_dec_ctx, fmt_ctx, AVMEDIA_TYPE_AUDIO) >= 0)
    从ctx中来获取参数:
        video_stream = fmt_ctx->streams[video_stream_idx];
        audio_stream = fmt_ctx->streams[audio_stream_idx];
        width = video_dec_ctx->width;
        height = video_dec_ctx->height;
        pix_fmt = video_dec_ctx->pix_fmt;
3. 导出fmt_ctx 信息. 很好用的函数!
    av_dump_format(fmt_ctx, 0, src_filename, 0);


4. 读取pkt, 不再用av_parser, 而是利用fmt_ctx, av_read_frame 函数进行.
    然后video_dec_ctx,解包video包,audio_dec_ctx,解包audio包. context包含必要信息,可读可写.
    while (av_read_frame(fmt_ctx, pkt) >= 0) {
        if (pkt->stream_index == video_stream_idx)
            ret = decode_packet(video_dec_ctx, pkt);
        else if (pkt->stream_index == audio_stream_idx)
            ret = decode_packet(audio_dec_ctx, pkt);
        av_packet_unref(pkt);
        }

5. 利用context, 解码包decode_packet(AVCodecContext *dec,const AVPacket *pkt)
  流程还是send_parcket, receive_frame, 根据dec->codec->type 来分别保存音频frame或视频frame

------------------------------------------------------------
补充: 怎样从fmt_ctx来打开video 或audio context
------------------------------------------------------------
1. 首先根据类型type(AVMEDIA_TYPE_VIDEO, AVMEDIA_TYPE_AUDIO) 来找到流的索引号及流
    ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0);
    返回值为流索引,找到了索引即拿到了流
    stream_index = ret;
    st = fmt_ctx->streams[stream_index];
2. 根据流的codec_id 找到decoder
    dec = avcodec_find_decoder(st->codecpar->codec_id);
3. 由decoder 分配codec_context
        *dec_ctx = avcodec_alloc_context3(dec);
4. 初始化dec_ctx
      ret = avcodec_parameters_to_context(*dec_ctx, st->codecpar))
5. 打开decoder      
      ret = avcodec_open2(*dec_ctx, dec, &opts))
************************************************************************************
    保存视频,可以用av_image_copy, 再写入到文件. 它是把 frame-data 三行数据YUV合并到一行
************************************************************************************
    /* copy decoded frame to destination buffer:
     * this is required since rawvideo expects non aligned data */
    av_image_copy(video_dst_data, video_dst_linesize,
                  (const uint8_t **)(frame->data), frame->linesize,
                  pix_fmt, width, height);

    /* write to rawvideo file */
    fwrite(video_dst_data[0], 1, video_dst_bufsize, video_dst_file);

************************************************************************************
    保存音频,把数据写到文件
************************************************************************************
    size_t unpadded_linesize = frame->nb_samples * av_get_bytes_per_sample(frame->format);
    fwrite(frame->extended_data[0], 1, unpadded_linesize, audio_dst_file);

------------------------------------------------------------
补充2: AVFormatContext 概念
------------------------------------------------------------
一个合格的音视频文件,能够被avformat_open_input打开,创建一个AVFormatContext 对象fmt_ctx
再通过find_stream_info 进一步填充信息。
fmt_ctx 有节目的概念 AVPogram, 一个fmt_ctx 可以包含多套节目(fmt_ctx->nb_programs,fmt_ctx->programs[0-nb_programs-1])数组。
每一个节目有节目id, program->id, 及若干个节目流构成(program->nb_stream_indexes, program->stream_index[0-nb_stream_indexes]),
例如节目中音频流对应一个音频stream_index, 视频流对应一个视频stream_index, 找到了流的index, 就可以找到流 fmp_ctx->stream[index]
找到了流,就可以找到流的一切属性。
当然,常见的,简单的fmt_ctx,只包含一套节目,而且一套节目只包含2个流,音频流,视频流。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值