音视频录制器—打包数据流

------------------------------------全系列文章目录------------------------------------

大致流程
  1. 打开输入的aac和h264文件,并找到对应的数据流;创建并打开一个输出文件,为该文件创建视频/音频数据流;同时拷贝输入数据流的编码器信息;创建并初始化一个AVIOContext以访问url指示的资源;写入媒体文件的数据头数据。

  2. 在各自数据流时间基中比较当前视频帧和音频帧pts的顺序,选取下一帧打包到容器的数据包为音频帧还是视频帧

  3. 从对应的输入文件中读取一帧的数据包

  4. 若当前数据包pts为非法值

    1. 根据帧率计算出该数据包持续时间,并根据输入数据流时间基,换算成输入数据流中的持续时间

    2. 根据帧持续时间和帧数计算出当前数据流时间,再根据输入数据流时间基,换算成输入数据流中的时间戳

  5. 将pts,dts和duration从输入数据流时间基转换为输出数据流时间基

  6. 写入数据包至媒体文件

  7. 释放读取的数据包,更新当前视频帧或音频帧pts,重复上述2—6步操作;直至结束后给媒体文件写入文件尾。
    在这里插入图片描述

相关API函数
  • avformat_alloc_output_context2:申请一个用于输出格式的AVFormatContext。

    int avformat_alloc_output_context2(AVFormatContext **ctx, 
                                       AVOutputFormat *oformat,
                                       const char *format_name, 
                                       const char *filename);
    
    • ctx:返回创建的AVFormatContext,失败返回NULL。

    • oformat:用于申请ctx的格式,如果为NULL,则使用format_name和filename。

    • format_name:用于申请ctx的格式名称,如果为NULL,则使用filename。

    • filename:用于申请ctx的文件名称,可能为NULL。

    • 返回值:>=0表示成功,否则失败。

  • avformat_new_stream:增加一路数据流到媒体文件。

    AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c);
    
    • s:媒体文件句柄。

    • c:unused, does nothing。

    • 返回值:创建的数据流,为NULL表示失败。

  • avcodec_copy_context:将源AVCodecContext的设置复制到目标AVCodecContext。生成的目标编解码器上下文将是未打开的,在使用此AVCodecContext对视频/音频数据进行解码/编码之前,需要调用avcodec_open2。

    int avcodec_copy_context(AVCodecContext *dest, 
                       const AVCodecContext *src);
    
    • dest:目标AVCodecContext

    • src:源AVCodecContext

    • 返回值:0表示成功,否则失败

  • avio_open:创建并初始化一个 AVIOContext 以访问url(在此处fille也属于一种url)指示的资源。

    int avio_open(AVIOContext **s, const char *url, int flags);
    
    • s:返回指向创建的AVIOContext结构体的指针,NULL表示创建失败。

    • url:要访问的url。

    • flags:如何访问url的标志;AVIO_FLAG_READ / AVIO_FLAG_WRITE / AVIO_FLAG_READ_WRITE。

    • 返回值:>=0表示成功,否则失败。

  • avformat_write_header:申请数据流的私有数据,并将数据流header写入到输出文件

    int avformat_write_header(AVFormatContext *s, AVDictionary **options);
    
    • s:必须使用 avformat_alloc_context() 分配的媒体文件句柄。它的 oformat 字段必须设置为所需的输出格式;它的 pb 字段必须设置为已打开的 AVIOContext。

    • options:选项参数。

    • 返回值:AVERROR表示失败。如果编解码器未在avformat_init中初始化,AVSTREAM_INIT_IN_WRITE_HEADER表示成功;已初始化,AVSTREAM_INIT_IN_INIT_OUTPUT表示成功。

  • av_compare_ts:在各自的时间基中比较时间戳

    int av_compare_ts(int64_t ts_a, AVRational tb_a, 
                      int64_t ts_b, AVRational tb_b);
    
    • ts_a / ts_b:时间戳

    • tb_a / tb_b:时间基

    • 返回值:-1表示ts_a在ts_b之前;0表示相等;1表示ts_a在ts_b之后。

  • av_interleaved_write_frame:将数据包写入输出媒体文件,却把正确交错。

    int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt);
    
    • s:媒体文件句柄。

    • pkt:要写入的数据包。

    • 返回值:0表示成功,否则表示失败。

  • av_write_trailer:写入数据流文件尾到输出媒体文件,并释放私有数据;在avformat_write_header成功后才能调用。

    int av_write_trailer(AVFormatContext *s);
    
    • s:媒体文件句柄。

    • 返回值:0表示成功,否则失败。

  • av_rescale_q_rnd:通过指定方式,使用两个时间基,调整一个64位整数;即将以时间基cq表示的数值a转换成以时间基bq来表示;

    /* The operation is mathematically equivalent to a * bq / cq */
    int64_t av_rescale_q_rnd(int64_t a, AVRational bq, AVRational cq,
                             enum AVRounding);
    enum AVRounding {
        AV_ROUND_ZERO     = 0, ///趋近于0
        AV_ROUND_INF      = 1, ///趋远于0
        AV_ROUND_DOWN     = 2, ///< Round toward -infinity.
        AV_ROUND_UP       = 3, ///< Round toward +infinity.
        AV_ROUND_NEAR_INF = 5, ///四舍五入
        AV_ROUND_PASS_MINMAX = 8192, ///< Flag to pass INT64_MIN/MAX through instead of rescaling, this avoids special cases for AV_NOPTS_VALUE
    
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值