【FFmpeg编程进阶】(15)FLV 编码器Codec初始化 ff_mpv_encode_init() 代码分析 -- 待更新

【FFmpeg编程进阶】(15)FLV 编码器Codec初始化 ff_mpv_encode_init 代码分析

在前面分析《【FFmpeg编程进阶】(11)avcodec_open2() 函数代码分析 - 打开Codec解码器》时,
我们涉及到了Codec 编码器初始化,由于代码比较长,我们再分一章来分析。

主要目的,还是以 FLV 编码器为例 ,来看下编码器初始化主要做了啥

# libavcodec\flvenc.c
AVCodec ff_flv_encoder = {
    .name           = "flv",
    .long_name      = NULL_IF_CONFIG_SMALL("FLV / Sorenson Spark / Sorenson H.263 (Flash Video)"),
    .type           = AVMEDIA_TYPE_VIDEO,
    .id             = AV_CODEC_ID_FLV1,
    .priv_data_size = sizeof(MpegEncContext),
    .init           = ff_mpv_encode_init,
    .encode2        = ff_mpv_encode_picture,
    .close          = ff_mpv_encode_end,
    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
    .pix_fmts       = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P,
                                                     AV_PIX_FMT_NONE},
    .priv_class     = &flv_class,
};

一、ff_mpv_encode_init()

  1. 初始化解码器上下文 MpegEncContext
  2. 结合 avctx->codec_idavctx->pix_fmt 判断编码器是否支持对该pix_fmt格式进行编码
  3. 配置 s->chroma_format 参数 、s->widths->height 等一些其他的参数

PS: 在编解码核心函数里,看了一个多小时代码,发现其逻辑就目前我的理解来说有点看不懂(慢慢花时间看或许多少也会有收获)
考虑效率及目前的需求,对于目前我这样的新手来说,这些更加高深的编解码知识会有点形而上,
与其花大量时间结合封装格式深专研进去学习,还不如先放手学习其他的基础,
比如先掌握ffmpeg 怎么使用、怎么编程,这些或许在当前阶段更加重要,
对于目前来说,我只需要知道调用这个接口,就会对packet 进行编解码,
至于编解码其详细的原理,等随着音视频学习更深时,基础更好时,再返回来学习,这样可能会更好理解,同时与高效些。
因此,本文加上 待更新 字样先留个念想,后面学习深入再补上。

# libavcodec\mpegvideo_enc.c
/* init video encoder */
av_cold int ff_mpv_encode_init(AVCodecContext *avctx)
{
    MpegEncContext *s = avctx->priv_data;
    AVCPBProperties *cpb_props;
    
	// 1. 初始化解码器上下文 MpegEncContext
    mpv_encode_defaults(s);

	// 2. 结合 avctx->codec_id 和 avctx->pix_fmt 判断编码器是否支持对该pix_fmt格式进行编码,
    switch (avctx->codec_id) {
    case AV_CODEC_ID_MPEG2VIDEO:
        if (avctx->pix_fmt != AV_PIX_FMT_YUV420P && avctx->pix_fmt != AV_PIX_FMT_YUV422P) {
            av_log(avctx, AV_LOG_ERROR,  "only YUV420 and YUV422 are supported\n");
            return AVERROR(EINVAL);
        }
        break;
    case AV_CODEC_ID_MJPEG:
    case AV_CODEC_ID_AMV:
        format_supported = 0;
        /* JPEG color space */
        if (avctx->pix_fmt == AV_PIX_FMT_YUVJ420P ||
            avctx->pix_fmt == AV_PIX_FMT_YUVJ422P ||
            avctx->pix_fmt == AV_PIX_FMT_YUVJ444P ||
            (avctx->color_range == AVCOL_RANGE_JPEG &&
             (avctx->pix_fmt == AV_PIX_FMT_YUV420P ||
              avctx->pix_fmt == AV_PIX_FMT_YUV422P ||
              avctx->pix_fmt == AV_PIX_FMT_YUV444P)))
            format_supported = 1;
        /* MPEG color space */
        else if (avctx->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL &&
                 (avctx->pix_fmt == AV_PIX_FMT_YUV420P ||
                  avctx->pix_fmt == AV_PIX_FMT_YUV422P ||
                  avctx->pix_fmt == AV_PIX_FMT_YUV444P))
            format_supported = 1;

        if (!format_supported) {
            av_log(avctx, AV_LOG_ERROR, "colorspace not supported in jpeg\n");
            return AVERROR(EINVAL);
        }
        break;
    default:
        if (avctx->pix_fmt != AV_PIX_FMT_YUV420P) {
            av_log(avctx, AV_LOG_ERROR, "only YUV420 is supported\n");
            return AVERROR(EINVAL);
        }
    }
	// 3. 配置s->chroma_format 参数
    switch (avctx->pix_fmt) {
    case AV_PIX_FMT_YUVJ444P:
    case AV_PIX_FMT_YUV444P:
        s->chroma_format = CHROMA_444;
        break;
    case AV_PIX_FMT_YUVJ422P:
    case AV_PIX_FMT_YUV422P:
        s->chroma_format = CHROMA_422;
        break;
    case AV_PIX_FMT_YUVJ420P:
    case AV_PIX_FMT_YUV420P:
    default:
        s->chroma_format = CHROMA_420;
        break;
    
    avctx->bits_per_raw_sample = av_clip(avctx->bits_per_raw_sample, 0, 8);

    s->bit_rate = avctx->bit_rate;
    s->width    = avctx->width;
    s->height   = avctx->height;
    if (avctx->gop_size > 600 &&  avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
        av_log(avctx, AV_LOG_WARNING, "keyframe interval too large!, reducing it from %d to %d\n", avctx->gop_size, 600);
        avctx->gop_size = 600;
    }
    s->gop_size     = avctx->gop_size;
    s->avctx        = avctx;
    if (avctx->max_b_frames > MAX_B_FRAMES) {
        av_log(avctx, AV_LOG_ERROR, "Too many B-frames requested, maximum ""is %d.\n", MAX_B_FRAMES);
        avctx->max_b_frames = MAX_B_FRAMES;
    }
    s->max_b_frames = avctx->max_b_frames;
    s->codec_id     = avctx->codec->id;
    s->strict_std_compliance = avctx->strict_std_compliance;
    s->quarter_sample     = (avctx->flags & AV_CODEC_FLAG_QPEL) != 0;
    s->rtp_mode           = !!s->rtp_payload_size;
    s->intra_dc_precision = avctx->intra_dc_precision;

    // workaround some differences between how applications specify dc precision
    if (s->intra_dc_precision < 0) {
        s->intra_dc_precision += 8;
    } else if (s->intra_dc_precision >= 8)
        s->intra_dc_precision -= 8;

    if (avctx->codec_id == AV_CODEC_ID_AMV || (avctx->active_thread_type & FF_THREAD_SLICE))
        s->huffman = 0;

    s->user_specified_pts = AV_NOPTS_VALUE;

    if (s->gop_size <= 1) {
        s->intra_only = 1;
        s->gop_size   = 12;
    } else {
        s->intra_only = 0;
    }

    /* Fixed QSCALE */
    s->fixed_qscale = !!(avctx->flags & AV_CODEC_FLAG_QSCALE);

    s->adaptive_quant = (avctx->lumi_masking ||
                         avctx->dark_masking ||
                         avctx->temporal_cplx_masking ||
                         avctx->spatial_cplx_masking  ||
                         avctx->p_masking      ||
                         s->border_masking ||
                         (s->mpv_flags & FF_MPV_FLAG_QP_RD)) &&
                        !s->fixed_qscale;

    s->loop_filter = !!(avctx->flags & AV_CODEC_FLAG_LOOP_FILTER);

    if (avctx->rc_max_rate && !avctx->rc_buffer_size) {
        switch(avctx->codec_id) {
        case AV_CODEC_ID_MPEG1VIDEO:
        case AV_CODEC_ID_MPEG2VIDEO:
            avctx->rc_buffer_size = FFMAX(avctx->rc_max_rate, 15000000) * 112LL / 15000000 * 16384;
            break;
        case AV_CODEC_ID_MPEG4:
        case AV_CODEC_ID_MSMPEG4V1:
        case AV_CODEC_ID_MSMPEG4V2:
        case AV_CODEC_ID_MSMPEG4V3:
            if       (avctx->rc_max_rate >= 15000000) {
                avctx->rc_buffer_size = 320 + (avctx->rc_max_rate - 15000000LL) * (760-320) / (38400000 - 15000000);
            } else if(avctx->rc_max_rate >=  2000000) {
                avctx->rc_buffer_size =  80 + (avctx->rc_max_rate -  2000000LL) * (320- 80) / (15000000 -  2000000);
            } else if(avctx->rc_max_rate >=   384000) {
                avctx->rc_buffer_size =  40 + (avctx->rc_max_rate -   384000LL) * ( 80- 40) / ( 2000000 -   384000);
            } else
                avctx->rc_buffer_size = 40;
            avctx->rc_buffer_size *= 16384;
            break;
        }
        if (avctx->rc_buffer_size) {
            av_log(avctx, AV_LOG_INFO, "Automatically choosing VBV buffer size of %d kbyte\n", avctx->rc_buffer_size/8192);
        }
    }

    if ((s->codec_id == AV_CODEC_ID_MPEG4 ||
         s->codec_id == AV_CODEC_ID_H263  ||
         s->codec_id == AV_CODEC_ID_H263P) &&
        (avctx->sample_aspect_ratio.num > 255 ||
         avctx->sample_aspect_ratio.den > 255)) {
        av_log(avctx, AV_LOG_WARNING, "Invalid pixel aspect ratio %i/%i, limit is 255/255 reducing\n",
               avctx->sample_aspect_ratio.num, avctx->sample_aspect_ratio.den);
        av_reduce(&avctx->sample_aspect_ratio.num, &avctx->sample_aspect_ratio.den,
                   avctx->sample_aspect_ratio.num,  avctx->sample_aspect_ratio.den, 255);
    }


    if (s->mpeg_quant || s->codec_id == AV_CODEC_ID_MPEG1VIDEO || s->codec_id == AV_CODEC_ID_MPEG2VIDEO || s->codec_id == AV_CODEC_ID_MJPEG || s->codec_id==AV_CODEC_ID_AMV) {
        // (a + x * 3 / 8) / x
        s->intra_quant_bias = 3 << (QUANT_BIAS_SHIFT - 3);
        s->inter_quant_bias = 0;
    } else {
        s->intra_quant_bias = 0;
        // (a - x / 4) / x
        s->inter_quant_bias = -(1 << (QUANT_BIAS_SHIFT - 2));
    }

    av_log(avctx, AV_LOG_DEBUG, "intra_quant_bias = %d inter_quant_bias = %d\n",s->intra_quant_bias,s->inter_quant_bias);

    s->time_increment_bits = av_log2(avctx->time_base.den - 1) + 1;

    switch (avctx->codec->id) {
    case AV_CODEC_ID_MPEG1VIDEO:
        s->out_format = FMT_MPEG1;
        s->low_delay  = !!(avctx->flags & AV_CODEC_FLAG_LOW_DELAY);
        avctx->delay  = s->low_delay ? 0 : (s->max_b_frames + 1);
        break;
    case AV_CODEC_ID_MPEG2VIDEO:
        s->out_format = FMT_MPEG1;
        s->low_delay  = !!(avctx->flags & AV_CODEC_FLAG_LOW_DELAY);
        avctx->delay  = s->low_delay ? 0 : (s->max_b_frames + 1);
        s->rtp_mode   = 1;
        break;
    case AV_CODEC_ID_MJPEG:
    case AV_CODEC_ID_AMV:
        s->out_format = FMT_MJPEG;
        s->intra_only = 1; /* force intra only for jpeg */
   		ret = ff_mjpeg_encode_init(s);
        avctx->delay = 0;
        s->low_delay = 1;
        break;
    case AV_CODEC_ID_H261:
        if (ff_h261_get_picture_format(s->width, s->height) < 0) {
            av_log(avctx, AV_LOG_ERROR, "The specified picture size of %dx%d is not valid for the "
                   "H.261 codec.\nValid sizes are 176x144, 352x288\n",
                    s->width, s->height);
            return AVERROR(EINVAL);
        }
        s->out_format = FMT_H261;
        avctx->delay  = 0;
        s->low_delay  = 1;
        s->rtp_mode   = 0; /* Sliced encoding not supported */
        break;
    case AV_CODEC_ID_H263:
        if (!CONFIG_H263_ENCODER)
            return AVERROR_ENCODER_NOT_FOUND;
        if (ff_match_2uint16(ff_h263_format, FF_ARRAY_ELEMS(ff_h263_format),
                             s->width, s->height) == 8) {
            av_log(avctx, AV_LOG_ERROR,
                   "The specified picture size of %dx%d is not valid for "
                   "the H.263 codec.\nValid sizes are 128x96, 176x144, "
                   "352x288, 704x576, and 1408x1152. "
                   "Try H.263+.\n", s->width, s->height);
            return AVERROR(EINVAL);
        }
        s->out_format = FMT_H263;
        avctx->delay  = 0;
        s->low_delay  = 1;
        break;
    case AV_CODEC_ID_H263P:
        s->out_format = FMT_H263;
        s->h263_plus  = 1;
        /* Fx */
        s->h263_aic        = (avctx->flags & AV_CODEC_FLAG_AC_PRED) ? 1 : 0;
        s->modified_quant  = s->h263_aic;
        s->loop_filter     = (avctx->flags & AV_CODEC_FLAG_LOOP_FILTER) ? 1 : 0;
        s->unrestricted_mv = s->obmc || s->loop_filter || s->umvplus;

        /* /Fx */
        /* These are just to be sure */
        avctx->delay = 0;
        s->low_delay = 1;
        break;
    case AV_CODEC_ID_FLV1:
        s->out_format      = FMT_H263;
        s->h263_flv        = 2; /* format = 1; 11-bit codes */
        s->unrestricted_mv = 1;
        s->rtp_mode  = 0; /* don't allow GOB */
        avctx->delay = 0;
        s->low_delay = 1;
        break;
    case AV_CODEC_ID_RV10:
        s->out_format = FMT_H263;
        avctx->delay  = 0;
        s->low_delay  = 1;
        break;
    case AV_CODEC_ID_RV20:
        s->out_format      = FMT_H263;
        avctx->delay       = 0;
        s->low_delay       = 1;
        s->modified_quant  = 1;
        s->h263_aic        = 1;
        s->h263_plus       = 1;
        s->loop_filter     = 1;
        s->unrestricted_mv = 0;
        break;
    case AV_CODEC_ID_MPEG4:
        s->out_format      = FMT_H263;
        s->h263_pred       = 1;
        s->unrestricted_mv = 1;
        s->low_delay       = s->max_b_frames ? 0 : 1;
        avctx->delay       = s->low_delay ? 0 : (s->max_b_frames + 1);
        break;
    case AV_CODEC_ID_MSMPEG4V2:
        s->out_format      = FMT_H263;
        s->h263_pred       = 1;
        s->unrestricted_mv = 1;
        s->msmpeg4_version = 2;
        avctx->delay       = 0;
        s->low_delay       = 1;
        break;
    case AV_CODEC_ID_MSMPEG4V3:
        s->out_format        = FMT_H263;
        s->h263_pred         = 1;
        s->unrestricted_mv   = 1;
        s->msmpeg4_version   = 3;
        s->flipflop_rounding = 1;
        avctx->delay         = 0;
        s->low_delay         = 1;
        break;
    case AV_CODEC_ID_WMV1:
        s->out_format        = FMT_H263;
        s->h263_pred         = 1;
        s->unrestricted_mv   = 1;
        s->msmpeg4_version   = 4;
        s->flipflop_rounding = 1;
        avctx->delay         = 0;
        s->low_delay         = 1;
        break;
    case AV_CODEC_ID
    avctx->has_b_frames = !s->low_delay;

    s->encoding = 1;

    s->progressive_frame    =
    s->progressive_sequence = !(avctx->flags & (AV_CODEC_FLAG_INTERLACED_DCT |
                                                AV_CODEC_FLAG_INTERLACED_ME) ||
                                s->alternate_scan);

    /* init */
    ff_mpv_idct_init(s);
    if ((ret = ff_mpv_common_init(s)) < 0)
        return ret;

    ff_fdctdsp_init(&s->fdsp, avctx);
    ff_me_cmp_init(&s->mecc, avctx);
    ff_mpegvideoencdsp_init(&s->mpvencdsp, avctx);
    ff_pixblockdsp_init(&s->pdsp, avctx);
    ff_qpeldsp_init(&s->qdsp);

    if (s->msmpeg4_version) {
        int ac_stats_size = 2 * 2 * (MAX_LEVEL + 1) *  (MAX_RUN + 1) * 2 * sizeof(int);
        if (!(s->ac_stats = av_mallocz(ac_stats_size)))
            return AVERROR(ENOMEM);
    }

    if (!(avctx->stats_out = av_mallocz(256))               ||
        !FF_ALLOCZ_TYPED_ARRAY(s->q_intra_matrix,          32) ||
        !FF_ALLOCZ_TYPED_ARRAY(s->q_chroma_intra_matrix,   32) ||
        !FF_ALLOCZ_TYPED_ARRAY(s->q_inter_matrix,          32) ||
        !FF_ALLOCZ_TYPED_ARRAY(s->q_intra_matrix16,        32) ||
        !FF_ALLOCZ_TYPED_ARRAY(s->q_chroma_intra_matrix16, 32) ||
        !FF_ALLOCZ_TYPED_ARRAY(s->q_inter_matrix16,        32) ||
        !FF_ALLOCZ_TYPED_ARRAY(s->input_picture,           MAX_PICTURE_COUNT) ||
        !FF_ALLOCZ_TYPED_ARRAY(s->reordered_input_picture, MAX_PICTURE_COUNT))
        return AVERROR(ENOMEM);

    if (s->noise_reduction) {
        if (!FF_ALLOCZ_TYPED_ARRAY(s->dct_offset, 2))
            return AVERROR(ENOMEM);
    }

    ff_dct_encode_init(s);

    if ((CONFIG_H263P_ENCODER || CONFIG_RV20_ENCODER) && s->modified_quant)
        s->chroma_qscale_table = ff_h263_chroma_qscale_table;

    if (s->slice_context_count > 1) {
        s->rtp_mode = 1;

        if (avctx->codec_id == AV_CODEC_ID_H263P)
            s->h263_slice_structured = 1;
    }

    s->quant_precision = 5;

#if FF_API_PRIVATE_OPT
FF_DISABLE_DEPRECATION_WARNINGS
    if (avctx->frame_skip_threshold)
        s->frame_skip_threshold = avctx->frame_skip_threshold;
    if (avctx->frame_skip_factor)
        s->frame_skip_factor = avctx->frame_skip_factor;
    if (avctx->frame_skip_exp)
        s->frame_skip_exp = avctx->frame_skip_exp;
    if (avctx->frame_skip_cmp != FF_CMP_DCTMAX)
        s->frame_skip_cmp = avctx->frame_skip_cmp;
FF_ENABLE_DEPRECATION_WARNINGS
#endif

    ff_set_cmp(&s->mecc, s->mecc.ildct_cmp,      avctx->ildct_cmp);
    ff_set_cmp(&s->mecc, s->mecc.frame_skip_cmp, s->frame_skip_cmp);

    if (CONFIG_H261_ENCODER && s->out_format == FMT_H261)
        ff_h261_encode_init(s);
    if (CONFIG_H263_ENCODER && s->out_format == FMT_H263)
        ff_h263_encode_init(s);
    if (CONFIG_MSMPEG4_ENCODER && s->msmpeg4_version)
        if ((ret = ff_msmpeg4_encode_init(s)) < 0)
            return ret;
    if ((CONFIG_MPEG1VIDEO_ENCODER || CONFIG_MPEG2VIDEO_ENCODER)
        && s->out_format == FMT_MPEG1)
        ff_mpeg1_encode_init(s);

    /* init q matrix */
    for (i = 0; i < 64; i++) {
        int j = s->idsp.idct_permutation[i];
        if (CONFIG_MPEG4_ENCODER && s->codec_id == AV_CODEC_ID_MPEG4 &&
            s->mpeg_quant) {
            s->intra_matrix[j] = ff_mpeg4_default_intra_matrix[i];
            s->inter_matrix[j] = ff_mpeg4_default_non_intra_matrix[i];
        } else if (s->out_format == FMT_H263 || s->out_format == FMT_H261) {
            s->intra_matrix[j] =
            s->inter_matrix[j] = ff_mpeg1_default_non_intra_matrix[i];
        } else {
            /* MPEG-1/2 */
            s->chroma_intra_matrix[j] =
            s->intra_matrix[j] = ff_mpeg1_default_intra_matrix[i];
            s->inter_matrix[j] = ff_mpeg1_default_non_intra_matrix[i];
        }
        if (avctx->intra_matrix)
            s->intra_matrix[j] = avctx->intra_matrix[i];
        if (avctx->inter_matrix)
            s->inter_matrix[j] = avctx->inter_matrix[i];
    }

    /* precompute matrix */
    /* for mjpeg, we do include qscale in the matrix */
    if (s->out_format != FMT_MJPEG) {
        ff_convert_matrix(s, s->q_intra_matrix, s->q_intra_matrix16,
                          s->intra_matrix, s->intra_quant_bias, avctx->qmin,
                          31, 1);
        ff_convert_matrix(s, s->q_inter_matrix, s->q_inter_matrix16,
                          s->inter_matrix, s->inter_quant_bias, avctx->qmin,
                          31, 0);
    }

    if ((ret = ff_rate_control_init(s)) < 0)
        return ret;

#if FF_API_PRIVATE_OPT
    FF_DISABLE_DEPRECATION_WARNINGS
    if (avctx->brd_scale)
        s->brd_scale = avctx->brd_scale;

    if (avctx->prediction_method)
        s->pred = avctx->prediction_method + 1;
    FF_ENABLE_DEPRECATION_WARNINGS
#endif

    if (s->b_frame_strategy == 2) {
        for (i = 0; i < s->max_b_frames + 2; i++) {
            s->tmp_frames[i] = av_frame_alloc();
            if (!s->tmp_frames[i])
                return AVERROR(ENOMEM);

            s->tmp_frames[i]->format = AV_PIX_FMT_YUV420P;
            s->tmp_frames[i]->width  = s->width  >> s->brd_scale;
            s->tmp_frames[i]->height = s->height >> s->brd_scale;

            ret = av_frame_get_buffer(s->tmp_frames[i], 0);
            if (ret < 0)
                return ret;
        }
    }

    cpb_props = ff_add_cpb_side_data(avctx);
    if (!cpb_props)
        return AVERROR(ENOMEM);
    cpb_props->max_bitrate = avctx->rc_max_rate;
    cpb_props->min_bitrate = avctx->rc_min_rate;
    cpb_props->avg_bitrate = avctx->bit_rate;
    cpb_props->buffer_size = avctx->rc_buffer_size;

    return 0;
}

©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页