阅读 247

FFmpeg学习之四(音视频的编解码)

libavcodec:主要实现一系列编码器的实现

一编码/解码常见结构体

(1) AVCodec:编码器信息
(2) AVCodecContext:编码器上下文

(3)AVFrame:音视频的原始帧数据,对应的AVPacket里面的帧是压缩后的帧.

2 内存分配和释放

av_frame_alloc()\av_frame_free() 生成和释放:AVFrame

  // 分配编解码器的上下文
avcodec_alloc_context3()/avcodec_free_context 

二 解码

avcodec_find_decoder:查找解码器

   AVCodec *codec;
  // 获取解码器实例, st 是AVStream
   codec = avcodec_find_decoder(st->codecpar->codec_id)(旧版本)
 codec = avcodec_find_decoder(AV_CODEC_ID_MPEG1VIDEO)(新版本)

avcodec_open2:打开解码器
avcodec_decode_video2:视频解码(已废弃).

注意在新版本中如ffmpeg4.3.1中视频解码使用avcodec_send_packetavcodec_receive_frame 实现了后台解码,源码如下:

static void decode(AVCodecContext *dec_ctx, AVFrame *frame, AVPacket *pkt,
                   const char *filename)
{
    char buf[1024];
    int ret;
   // 发送数据到ffmpeg,放到解码队列中
    ret = avcodec_send_packet(dec_ctx, pkt);
    if (ret < 0) {
        fprintf(stderr, "Error sending a packet for decoding\n");
        exit(1);
    }

    while (ret >= 0) {
// 在解码队列中,取出frame
        ret = avcodec_receive_frame(dec_ctx, frame);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
            return;
        else if (ret < 0) {
            fprintf(stderr, "Error during decoding\n");
            exit(1);
        }

        printf("saving frame %3d\n", dec_ctx->frame_number);
        fflush(stdout);

        /* the picture is allocated by the decoder. no need to
           free it */
        snprintf(buf, sizeof(buf), "%s-%d", filename, dec_ctx->frame_number);
        pgm_save(frame->data[0], frame->linesize[0],
                 frame->width, frame->height, buf);
    }
}
// 新版本源码路径是:/FFmpeg/FFmpeg-iOS-build-script-master/thin/arm64/share/ffmpeg/examples/decode_video.c (需要编译)

对已经h264编码的适配用上述方法解码,结果 ret = avcodec_receive_frame(dec_ctx, frame); ret = -541478725 (错误信息:End of file)

三 编码

avcodec_find_encoder_by_name:查找编码器,和解码不同的是,通过名字查找.
avcodec_open2:编码的时候需要设置一些参数,分辨率,帧率等
avcodec_encode_video2:编码 编解码ffmpeg用的是第三方库比如lib264,ffmpeg只是二次封装

H264编码一些参数设置

  AVCodecContext * codec = NULL;
c = avcodec_alloc_context3(codec);
  //libx264
   // 查询编解码器
   codec = avcodec_find_encoder_by_name(codec_name);
   // 码率
   c->bit_rate = 400000;
  // 分辨率
  c->width = 352;
  c->height = 288;
 // 时间基 随帧率变化 1/25
   c->time_base = (AVRational){1, 25};
  //  帧率越大 码率越大 流畅度越好
   c->framerate = (AVRational){25, 1};
   // gop_size:多少帧产生一个关键帧,比如 120帧  c->gop_size = 10 120分成10组,10帧有个关键帧,后面都是参考帧  gop_size设置很小的话:码率增加  关键帧就多了 设置太大 码率减少,关键帧少了
   c->gop_size = 10;
   // 1 b帧:前后参考帧  max_b_frames 压缩率非常高
   // 2 p帧:向前参考帧 参考帧越多 ,压缩率越高 同样编码时长越大,实时性有影响
   // 3 i帧:关键帧
   c->max_b_frames = 1;
   // YUV 420
   c->pix_fmt = AV_PIX_FMT_YUV420P;

AAC 编码的一些设置参数设置

   AVCodecContext * codec = NULL;
c = avcodec_alloc_context3(codec);

 // 比特率64k
   c->bit_rate = 64000;
// 采样格式 16位的
    c->sample_fmt = AV_SAMPLE_FMT_S16;
// 采样率
    c->sample_rate    = select_sample_rate(codec);
 c->channel_layout = select_channel_layout(codec);
// 通道
c->channels       = av_get_channel_layout_nb_channels(c->channel_layout);

结语:在学习ffmpeg其他内容之前,调研一下SDL.主要为SDL安装,编译程序,窗口创建,SDL事件处理,纹理渲染等.

作者:Hunter琼

原文链接:https://www.jianshu.com/p/57b84121c0a0

文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐