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

大致流程

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

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

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

若当前数据包pts为非法值

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

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

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

写入数据包至媒体文件

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

C++音视频开发学习资料点击领取音视频开发(资料文档+视频教程+面试题)(FFmpeg+WebRTC+RTMP+RTSP+HLS+RTP)

在这里插入图片描述

相关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表示失败。

C++音视频开发学习资料点击领取音视频开发(资料文档+视频教程+面试题)(FFmpeg+WebRTC+RTMP+RTSP+HLS+RTP)

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
    
    发表评论
    留言与评论(共有 0 条评论) “”
       
    验证码:

    相关文章

    推荐文章