用AVCodecParameters代替AVCodecContext

在高版本的ffmpeg库中使用AVStream::codec成员时,编译和运行时都出现一堆警告:

main.cpp:151: warning: ‘AVStream::codec’ is deprecated (declared at ……\Other_libs\ffmpeg3.2\include/libavformat/avformat.h:893)

Using AVStream.codec … deprecated, use AVStream.codecpar instead

从提示来看,需要使用AVStream.codecpar代替AVStream.codec,前者的类型是AVCodecParameters,后者的类型是AVCodecContext。事实上,AVCodecContext结构体仍然是编解码时不可或缺的结构体。换言之,AVCodecContext结构体的重要成员仍然需要设置,才能使用(特别是编码),比如bit_rate。

之所以使用AVStream.codec,是因为解码时很容易获得源视频的一些基本信息。

const char *filename = "a.mp4";
AVFormatContext fmt_ctx = nullptr;
avformat_open_input(&fmt_ctx, filename, nullptr, nullptr);//打开一个视频
avformat_find_stream_info(fmt_ctx, nullptr);//读取视频,然后得到流和码率等信息
for(size_t i = 0; i < fmt_ctx->nb_streams; ++i)
{
    AVStream *stream = m_fmt_ctx->streams[i];
    AVCodecContext *codec_ctx = stream->codec;
    //此时就可以通过stream和codec_ctx的结构体成员获取流的绝大部分信息,相当方便
}

上面的代码十分简洁,又能获取大部分流相关的信息。编码时直接从源视频的AVCodecContext中复制成员值,并作简单的修改即可。也正因为如此,多数人不肯离开这温床。

事实上,无论是编解码,使用AVCodecParameters的代码都相当简洁。

解码

const char *filename = "a.mp4";
AVFormatContext fmt_ctx = nullptr;
avformat_open_input(&fmt_ctx, filename, nullptr, nullptr);//打开一个视频
avformat_find_stream_info(fmt_ctx, nullptr);//读取视频,然后得到流和码率等信息
for(size_t i = 0; i < fmt_ctx->nb_streams; ++i)
{
    AVStream *stream = fmt_ctx->streams[i];
    AVCodec *codec =  avcodec_find_decoder(stream->codecpar->codec_id);
    AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);//需要使用avcodec_free_context释放

    //事实上codecpar包含了大部分解码器相关的信息,这里是直接从AVCodecParameters复制到AVCodecContext
    avcodec_parameters_to_context(codec_ctx, stream->codecpar);

    av_codec_set_pkt_timebase(codec_ctx, stream->time_base);
    avcodec_open2(codec_ctx, codec, nullptr);
}

视频的帧率,应该从AVStream结构的avg_frame_rate成员获取,而非AVCodecContext结构体。如果avg_frame_rate为{0, 1},那么再尝试从r_frame_rate成员获取。

编码

编码时,需要分配一个AVCodecContext,然后为成员变量设置适当的值,最后将设置值复制到AVCodecParameters。

const char *filename = "b.mp4";
AVFormatContext *fmt_ctx = nullptr;
avformat_alloc_output_context2(&fmt_ctx, nullptr, nullptr, filename); //需要调用avformat_free_context释放

//new一个流并挂到fmt_ctx名下,调用avformat_free_context时会释放该流
AVStream *stream = avformat_new_stream(fmt_ctx, nullptr);
AVCodec *codec = avcodec_find_encoder(fmt_ctx->oformat->video_codec);//音频为audio_codec
AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);

codec_ctx->video_type = AVMEDIA_TYPE_VIDEO;
codec_ctx->codec_id = m_fmt_ctx->oformat->video_codec;

codec_ctx->width = 1280;//你想要的宽度
codec_ctx->height = 720;//你想要的高度
codec_ctx->format = AV_PIX_FMT_YUV420P;//受codec->pix_fmts数组限制

codec_ctx->gop_size = 12;

codec_ctx->time_base = AVRational{1, 25};//应该根据帧率设置
codec_ctx->bit_rate = 1400 * 1000;

avcodec_open2(codec_ctx, codec, nullptr);
//将AVCodecContext的成员复制到AVCodecParameters结构体。前后两行不能调换顺序
avcodec_parameters_from_context(stream->codecpar, codec_ctx);

av_stream_set_r_frame_rate(stream, {1, 25});
  • 9
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值