static av_cold int vtenc_init(AVCodecContext *avctx)

{

    CFMutableDictionaryRef enc_info;

    CFMutableDictionaryRef pixel_buffer_info;

    CMVideoCodecType       codec_type;

    VTEncContext           *vtctx = avctx->priv_data;

    CFStringRef            profile_level;

    CFBooleanRef           has_b_frames_cfbool;

    CFNumberRef            gamma_level = NULL;

    int                    status;



    codec_type = get_cm_codec_type(avctx->codec_id);

    if (!codec_type) {

        av_log(avctx, AV_LOG_ERROR, "Error: no mapping for AVCodecID %d\n", avctx->codec_id);

        return AVERROR(EINVAL);

    }



    vtctx->has_b_frames = avctx->max_b_frames > 0;

    if(vtctx->has_b_frames && vtctx->profile == H264_PROF_BASELINE){

        av_log(avctx, AV_LOG_WARNING, "Cannot use B-frames with baseline profile. Output will not contain B-frames.\n");

        vtctx->has_b_frames = false;

    }



    if (vtctx->entropy == VT_CABAC && vtctx->profile == H264_PROF_BASELINE) {

        av_log(avctx, AV_LOG_WARNING, "CABAC entropy requires 'main' or 'high' profile, but baseline was requested. Encode will not use CABAC entropy.\n");

        vtctx->entropy = VT_ENTROPY_NOT_SET;

    }



    if (!get_vt_profile_level(avctx, &profile_level)) return AVERROR(EINVAL);



    vtctx->session = NULL;



    enc_info = CFDictionaryCreateMutable(

        kCFAllocatorDefault,

        20,

        &kCFCopyStringDictionaryKeyCallBacks,

        &kCFTypeDictionaryValueCallBacks

    );



    if (!enc_info) return AVERROR(ENOMEM);



#if !TARGET_OS_IPHONE

    if (!vtctx->allow_sw) {

        CFDictionarySetValue(enc_info, kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder, kCFBooleanTrue);

    } else {

        CFDictionarySetValue(enc_info, kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder,  kCFBooleanTrue);

    }

#endif



    if (avctx->pix_fmt != AV_PIX_FMT_VIDEOTOOLBOX) {

        status = create_cv_pixel_buffer_info(avctx, &pixel_buffer_info);

        if (status)

            goto init_cleanup;

    } else {

        pixel_buffer_info = NULL;

    }



    pthread_mutex_init(&vtctx->lock, NULL);

    pthread_cond_init(&vtctx->cv_sample_sent, NULL);

    vtctx->dts_delta = vtctx->has_b_frames ? -1 : 0;



    get_cv_transfer_function(avctx, &vtctx->transfer_function, &gamma_level);

    get_cv_ycbcr_matrix(avctx, &vtctx->ycbcr_matrix);

    get_cv_color_primaries(avctx, &vtctx->color_primaries);





    if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {

        status = vtenc_populate_extradata(avctx,

                                          codec_type,

                                          profile_level,

                                          gamma_level,

                                          enc_info,

                                          pixel_buffer_info);

        if (status)

            goto init_cleanup;

    }



    status = vtenc_create_encoder(avctx,

                                  codec_type,

                                  profile_level,

                                  gamma_level,

                                  enc_info,

                                  pixel_buffer_info,

                                  &vtctx->session);



    if (status < 0)

        goto init_cleanup;



    status = VTSessionCopyProperty(vtctx->session,

                                   kVTCompressionPropertyKey_AllowFrameReordering,

                                   kCFAllocatorDefault,

                                   &has_b_frames_cfbool);



    if (!status) {

        //Some devices don't output B-frames for main profile, even if requested.

        vtctx->has_b_frames = CFBooleanGetValue(has_b_frames_cfbool);

        CFRelease(has_b_frames_cfbool);

    }

    avctx->has_b_frames = vtctx->has_b_frames;



init_cleanup:

    if (gamma_level)

        CFRelease(gamma_level);



    if (pixel_buffer_info)

        CFRelease(pixel_buffer_info);



    CFRelease(enc_info);



    return status;

}
