/* hbffmpeg.c Copyright (c) 2003-2025 HandBrake Team This file is part of the HandBrake source code Homepage: . It may be used under the terms of the GNU General Public License v2. For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html */ #include "handbrake/handbrake.h" #include "handbrake/hbffmpeg.h" #include "libavutil/cpu.h" static int get_frame_type(int type) { switch (type) { case AV_PICTURE_TYPE_B: return HB_FRAME_B; case AV_PICTURE_TYPE_S: case AV_PICTURE_TYPE_P: case AV_PICTURE_TYPE_SP: return HB_FRAME_P; case AV_PICTURE_TYPE_BI: case AV_PICTURE_TYPE_SI: case AV_PICTURE_TYPE_I: default: return HB_FRAME_I; } } static void free_side_data(AVFrameSideData **ptr_sd) { AVFrameSideData *sd = *ptr_sd; av_buffer_unref(&sd->buf); av_dict_free(&sd->metadata); av_freep(ptr_sd); } static void wipe_avframe_side_data(AVFrame *frame) { for (int i = 0; i < frame->nb_side_data; i++) { free_side_data(&frame->side_data[i]); } frame->nb_side_data = 0; av_freep(&frame->side_data); } static void hb_buffer_close_callback(void *opaque, uint8_t *data) { hb_buffer_t *buf = opaque; hb_buffer_close(&buf); } void hb_video_buffer_to_avframe(AVFrame *frame, hb_buffer_t **buf_in) { hb_buffer_t *buf = *buf_in; if (buf->storage_type == AVFRAME) { av_frame_ref(frame, buf->storage); } else { // Create a refcounted AVBufferRef to avoid additional copies AVBufferRef *buf_ref = av_buffer_create(buf->data, buf->size, hb_buffer_close_callback, buf, 0); frame->buf[0] = buf_ref; for (int pp = 0; pp <= buf->f.max_plane; pp++) { frame->data[pp] = buf->plane[pp].data; frame->linesize[pp] = buf->plane[pp].stride; } for (int i = 0; i < buf->nb_side_data; i++) { const AVFrameSideData *sd_src = buf->side_data[i]; AVBufferRef *ref = av_buffer_ref(sd_src->buf); AVFrameSideData *sd_dst = av_frame_new_side_data_from_buf(frame, sd_src->type, ref); if (!sd_dst) { av_buffer_unref(&ref); wipe_avframe_side_data(frame); } } frame->extended_data = frame->data; } frame->pts = buf->s.start; frame->duration = buf->s.duration; frame->width = buf->f.width; frame->height = buf->f.height; frame->format = buf->f.fmt; if (buf->s.combed) { frame->flags |= AV_FRAME_FLAG_INTERLACED; } else { frame->flags &= ~AV_FRAME_FLAG_INTERLACED; } if (buf->s.flags & PIC_FLAG_TOP_FIELD_FIRST) { frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST; } else { frame->flags &= ~AV_FRAME_FLAG_TOP_FIELD_FIRST; } frame->format = buf->f.fmt; frame->color_primaries = hb_colr_pri_hb_to_ff(buf->f.color_prim); frame->color_trc = hb_colr_tra_hb_to_ff(buf->f.color_transfer); frame->colorspace = hb_colr_mat_hb_to_ff(buf->f.color_matrix); frame->color_range = buf->f.color_range; frame->chroma_location = buf->f.chroma_location; if (buf->storage_type == AVFRAME) { hb_buffer_close(&buf); } *buf_in = NULL; } void hb_avframe_set_video_buffer_flags(hb_buffer_t * buf, AVFrame *frame, AVRational time_base) { if (buf == NULL || frame == NULL) { return; } buf->s.start = av_rescale_q(frame->pts, time_base, (AVRational){1, 90000}); buf->s.duration = frame->duration; if (frame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST) { buf->s.flags |= PIC_FLAG_TOP_FIELD_FIRST; } if (!(frame->flags & AV_FRAME_FLAG_INTERLACED)) { buf->s.flags |= PIC_FLAG_PROGRESSIVE_FRAME; } else { buf->s.combed = HB_COMB_HEAVY; } if (frame->repeat_pict == 1) { buf->s.flags |= PIC_FLAG_REPEAT_FIRST_FIELD; } if (frame->repeat_pict == 2) { buf->s.flags |= PIC_FLAG_REPEAT_FRAME; } buf->s.frametype = get_frame_type(frame->pict_type); buf->f.fmt = frame->format; buf->f.color_prim = hb_colr_pri_ff_to_hb(frame->color_primaries); buf->f.color_transfer = hb_colr_tra_ff_to_hb(frame->color_trc); buf->f.color_matrix = hb_colr_mat_ff_to_hb(frame->colorspace); buf->f.color_range = frame->color_range; buf->f.chroma_location = frame->chroma_location; } #define HB_BUFFER_WRAP_AVFRAME 1 hb_buffer_t * hb_avframe_to_video_buffer(AVFrame *frame, AVRational time_base) { hb_buffer_t *buf; #ifdef HB_BUFFER_WRAP_AVFRAME // Zero-copy path buf = hb_buffer_wrapper_init(); if (buf == NULL) { return NULL; } AVFrame *frame_copy = av_frame_alloc(); if (frame_copy == NULL) { hb_buffer_close(&buf); return NULL; } int ret; ret = av_frame_ref(frame_copy, frame); if (ret < 0) { hb_buffer_close(&buf); av_frame_free(&frame_copy); return NULL; } buf->storage_type = AVFRAME; buf->storage = frame_copy; buf->s.type = FRAME_BUF; buf->f.width = frame_copy->width; buf->f.height = frame_copy->height; hb_avframe_set_video_buffer_flags(buf, frame_copy, time_base); buf->side_data = (void **)frame_copy->side_data; buf->nb_side_data = frame_copy->nb_side_data; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame_copy->format); for (int ii = 0; ii < desc->nb_components; ii++) { int pp = desc->comp[ii].plane; if (pp > buf->f.max_plane) { buf->f.max_plane = pp; } } for (int pp = 0; pp <= buf->f.max_plane; pp++) { buf->plane[pp].data = frame_copy->data[pp]; buf->plane[pp].width = hb_image_width(buf->f.fmt, buf->f.width, pp); buf->plane[pp].height = hb_image_height(buf->f.fmt, buf->f.height, pp); buf->plane[pp].stride = frame_copy->linesize[pp]; buf->plane[pp].size = buf->plane[pp].stride * buf->plane[pp].height; buf->size += buf->plane[pp].size; } #else // Memcpy to a standard hb_buffer_t buf = hb_frame_buffer_init(frame->format, frame->width, frame->height); if (buf == NULL) { return NULL; } hb_avframe_set_video_buffer_flags(buf, frame, time_base); int pp; for (pp = 0; pp <= buf->f.max_plane; pp++) { hb_image_copy_plane(buf->plane[pp].data, frame->data[pp], buf->plane[pp].stride, frame->linesize[pp], buf->plane[pp].height); } for (int i = 0; i < frame->nb_side_data; i++) { const AVFrameSideData *sd_src = frame->side_data[i]; AVBufferRef *ref = av_buffer_ref(sd_src->buf); AVFrameSideData *sd_dst = hb_buffer_new_side_data_from_buf(buf, sd_src->type, ref); if (!sd_dst) { av_buffer_unref(&ref); hb_buffer_wipe_side_data(buf); } } #endif return buf; } struct SwsContext* hb_sws_get_context(int srcW, int srcH, enum AVPixelFormat srcFormat, int srcRange, int dstW, int dstH, enum AVPixelFormat dstFormat, int dstRange, int flags, int colorspace) { struct SwsContext * ctx; ctx = sws_alloc_context(); if ( ctx ) { flags |= SWS_FULL_CHR_H_INT | SWS_FULL_CHR_H_INP; av_opt_set_int(ctx, "srcw", srcW, 0); av_opt_set_int(ctx, "srch", srcH, 0); av_opt_set_int(ctx, "src_range", srcRange, 0); av_opt_set_int(ctx, "src_format", srcFormat, 0); av_opt_set_int(ctx, "dstw", dstW, 0); av_opt_set_int(ctx, "dsth", dstH, 0); av_opt_set_int(ctx, "dst_range", dstRange, 0); av_opt_set_int(ctx, "dst_format", dstFormat, 0); av_opt_set_int(ctx, "sws_flags", flags, 0); sws_setColorspaceDetails( ctx, sws_getCoefficients( colorspace ), // src colorspace srcRange, // src range 0 = MPG, 1 = JPG sws_getCoefficients( colorspace ), // dst colorspace dstRange, // dst range 0 = MPG, 1 = JPG 0, // brightness 1 << 16, // contrast 1 << 16 ); // saturation if (sws_init_context(ctx, NULL, NULL) < 0) { hb_error("Cannot initialize resampling context"); sws_freeContext(ctx); ctx = NULL; } } return ctx; } int hb_sws_get_colorspace(int color_matrix) { int color_space = SWS_CS_DEFAULT; switch (color_matrix) { case HB_COLR_MAT_SMPTE170M: color_space = SWS_CS_ITU601; break; case HB_COLR_MAT_SMPTE240M: color_space = SWS_CS_SMPTE240M; break; case HB_COLR_MAT_BT709: color_space = SWS_CS_ITU709; break; case HB_COLR_MAT_BT2020_CL: case HB_COLR_MAT_BT2020_NCL: color_space = SWS_CS_BT2020; break; default: break; } return color_space; } int hb_colr_pri_hb_to_ff(int colr_prim) { switch (colr_prim) { case HB_COLR_PRI_BT709: return AVCOL_PRI_BT709; case HB_COLR_PRI_EBUTECH: return AVCOL_PRI_BT470BG; case HB_COLR_PRI_BT470M: return AVCOL_PRI_BT470M; case HB_COLR_PRI_SMPTEC: return AVCOL_PRI_SMPTE170M; case HB_COLR_PRI_SMPTE240M: return AVCOL_PRI_SMPTE240M; case HB_COLR_PRI_BT2020: return AVCOL_PRI_BT2020; case HB_COLR_PRI_SMPTE428: return AVCOL_PRI_SMPTE428; case HB_COLR_PRI_SMPTE431: return AVCOL_PRI_SMPTE431; case HB_COLR_PRI_SMPTE432: return AVCOL_PRI_SMPTE432; case HB_COLR_PRI_JEDEC_P22: return AVCOL_PRI_JEDEC_P22; default: case HB_COLR_PRI_UNDEF: return AVCOL_PRI_UNSPECIFIED; } } int hb_colr_tra_hb_to_ff(int colr_tra) { switch (colr_tra) { case HB_COLR_TRA_BT709: return AVCOL_TRC_BT709; case HB_COLR_TRA_GAMMA22: return AVCOL_TRC_GAMMA22; case HB_COLR_TRA_GAMMA28: return AVCOL_TRC_GAMMA28; case HB_COLR_TRA_SMPTE170M: return AVCOL_TRC_SMPTE170M; case HB_COLR_TRA_SMPTE240M: return AVCOL_TRC_SMPTE240M; case HB_COLR_TRA_LINEAR: return AVCOL_TRC_LINEAR; case HB_COLR_TRA_LOG: return AVCOL_TRC_LOG; case HB_COLR_TRA_LOG_SQRT: return AVCOL_TRC_LOG_SQRT; case HB_COLR_TRA_IEC61966_2_4: return AVCOL_TRC_IEC61966_2_4; case HB_COLR_TRA_BT1361_ECG: return AVCOL_TRC_BT1361_ECG; case HB_COLR_TRA_IEC61966_2_1: return AVCOL_TRC_IEC61966_2_1; case HB_COLR_TRA_BT2020_10: return AVCOL_TRC_BT2020_10; case HB_COLR_TRA_BT2020_12: return AVCOL_TRC_BT2020_12; case HB_COLR_TRA_SMPTEST2084: return AVCOL_TRC_SMPTE2084; case HB_COLR_TRA_SMPTE428: return AVCOL_TRC_SMPTE428; case HB_COLR_TRA_ARIB_STD_B67: return AVCOL_TRC_ARIB_STD_B67; default: case HB_COLR_TRA_UNDEF: return AVCOL_TRC_UNSPECIFIED; } } int hb_colr_mat_hb_to_ff(int colr_mat) { switch (colr_mat) { case HB_COLR_MAT_RGB: return AVCOL_SPC_RGB; case HB_COLR_MAT_BT709: return AVCOL_SPC_BT709; case HB_COLR_MAT_FCC: return AVCOL_SPC_FCC; case HB_COLR_MAT_BT470BG: return AVCOL_SPC_BT470BG; case HB_COLR_MAT_SMPTE170M: return AVCOL_SPC_SMPTE170M; case HB_COLR_MAT_SMPTE240M: return AVCOL_SPC_SMPTE240M; case HB_COLR_MAT_YCGCO: return AVCOL_SPC_YCGCO; case HB_COLR_MAT_BT2020_NCL: return AVCOL_SPC_BT2020_NCL; case HB_COLR_MAT_BT2020_CL: return AVCOL_SPC_BT2020_CL; case HB_COLR_MAT_SMPTE2085: return AVCOL_SPC_SMPTE2085; case HB_COLR_MAT_CD_NCL: return AVCOL_SPC_CHROMA_DERIVED_NCL; case HB_COLR_MAT_CD_CL: return AVCOL_SPC_CHROMA_DERIVED_CL; case HB_COLR_MAT_ICTCP: return AVCOL_SPC_ICTCP; default: case HB_COLR_MAT_UNDEF: return AVCOL_SPC_UNSPECIFIED; } } int hb_colr_pri_ff_to_hb(int colr_prim) { switch (colr_prim) { case AVCOL_PRI_BT709: return HB_COLR_PRI_BT709; case AVCOL_PRI_BT470M: return HB_COLR_PRI_BT470M; case AVCOL_PRI_BT470BG: return HB_COLR_PRI_EBUTECH; case AVCOL_PRI_SMPTE170M: return HB_COLR_PRI_SMPTEC; case AVCOL_PRI_SMPTE240M: return HB_COLR_PRI_SMPTE240M; case AVCOL_PRI_FILM: return HB_COLR_PRI_FILM; case AVCOL_PRI_BT2020: return HB_COLR_PRI_BT2020; case AVCOL_PRI_SMPTE428: return HB_COLR_PRI_SMPTE428; case AVCOL_PRI_SMPTE431: return HB_COLR_PRI_SMPTE431; case AVCOL_PRI_SMPTE432: return HB_COLR_PRI_SMPTE432; case AVCOL_PRI_JEDEC_P22: return HB_COLR_PRI_JEDEC_P22; default: case AVCOL_PRI_RESERVED: case AVCOL_PRI_RESERVED0: case AVCOL_PRI_UNSPECIFIED: return HB_COLR_PRI_UNDEF; } } int hb_colr_tra_ff_to_hb(int colr_tra) { switch (colr_tra) { case AVCOL_TRC_BT709: return HB_COLR_TRA_BT709; case AVCOL_TRC_GAMMA22: return HB_COLR_TRA_GAMMA22; case AVCOL_TRC_GAMMA28: return HB_COLR_TRA_GAMMA28; case AVCOL_TRC_SMPTE170M: return HB_COLR_TRA_SMPTE170M; case AVCOL_TRC_SMPTE240M: return HB_COLR_TRA_SMPTE240M; case AVCOL_TRC_LINEAR: return HB_COLR_TRA_LINEAR; case AVCOL_TRC_LOG: return HB_COLR_TRA_LOG; case AVCOL_TRC_LOG_SQRT: return HB_COLR_TRA_LOG_SQRT; case AVCOL_TRC_IEC61966_2_4: return HB_COLR_TRA_IEC61966_2_4; case AVCOL_TRC_BT1361_ECG: return HB_COLR_TRA_BT1361_ECG; case AVCOL_TRC_IEC61966_2_1: return HB_COLR_TRA_IEC61966_2_1; case AVCOL_TRC_BT2020_10: return HB_COLR_TRA_BT2020_10; case AVCOL_TRC_BT2020_12: return HB_COLR_TRA_BT2020_12; case AVCOL_TRC_SMPTE2084: return HB_COLR_TRA_SMPTEST2084; case AVCOL_TRC_SMPTE428: return HB_COLR_TRA_SMPTE428; case AVCOL_TRC_ARIB_STD_B67: return HB_COLR_TRA_ARIB_STD_B67; default: case AVCOL_TRC_UNSPECIFIED: case AVCOL_TRC_RESERVED: case AVCOL_TRC_RESERVED0: return HB_COLR_TRA_UNDEF; } } int hb_colr_mat_ff_to_hb(int colr_mat) { switch (colr_mat) { case AVCOL_SPC_RGB: return HB_COLR_MAT_RGB; case AVCOL_SPC_BT709: return HB_COLR_MAT_BT709; case AVCOL_SPC_FCC: return HB_COLR_MAT_FCC; case AVCOL_SPC_BT470BG: return HB_COLR_MAT_BT470BG; case AVCOL_SPC_SMPTE170M: return HB_COLR_MAT_SMPTE170M; case AVCOL_SPC_SMPTE240M: return HB_COLR_MAT_SMPTE240M; case AVCOL_SPC_YCGCO: return HB_COLR_MAT_YCGCO; case AVCOL_SPC_BT2020_NCL: return HB_COLR_MAT_BT2020_NCL; case AVCOL_SPC_BT2020_CL: return HB_COLR_MAT_BT2020_CL; case AVCOL_SPC_SMPTE2085: return HB_COLR_MAT_SMPTE2085; case AVCOL_SPC_CHROMA_DERIVED_NCL: return HB_COLR_MAT_CD_NCL; case AVCOL_SPC_CHROMA_DERIVED_CL: return HB_COLR_MAT_CD_CL; case AVCOL_SPC_ICTCP: return HB_COLR_MAT_ICTCP; default: case AVCOL_SPC_UNSPECIFIED: case AVCOL_SPC_RESERVED: return HB_COLR_MAT_UNDEF; } } static hb_rational_t hb_rational_ff_to_hb(AVRational rational) { hb_rational_t hb_rational = {rational.num, rational.den}; return hb_rational; } static AVRational hb_rational_hb_to_ff(hb_rational_t rational) { AVRational ff_rational = {rational.num, rational.den}; return ff_rational; } hb_mastering_display_metadata_t hb_mastering_ff_to_hb(AVMasteringDisplayMetadata mastering) { hb_mastering_display_metadata_t hb_mastering; for (int i = 0; i < 3; i++) { hb_mastering.display_primaries[i][0] = hb_rational_ff_to_hb(mastering.display_primaries[i][0]); hb_mastering.display_primaries[i][1] = hb_rational_ff_to_hb(mastering.display_primaries[i][1]); } hb_mastering.white_point[0] = hb_rational_ff_to_hb(mastering.white_point[0]); hb_mastering.white_point[1] = hb_rational_ff_to_hb(mastering.white_point[1]); hb_mastering.min_luminance = hb_rational_ff_to_hb(mastering.min_luminance); hb_mastering.max_luminance = hb_rational_ff_to_hb(mastering.max_luminance); hb_mastering.has_primaries = mastering.has_primaries; hb_mastering.has_luminance = mastering.has_luminance; return hb_mastering; } AVMasteringDisplayMetadata hb_mastering_hb_to_ff(hb_mastering_display_metadata_t mastering) { AVMasteringDisplayMetadata ff_mastering; for (int i = 0; i < 3; i++) { ff_mastering.display_primaries[i][0] = hb_rational_hb_to_ff(mastering.display_primaries[i][0]); ff_mastering.display_primaries[i][1] = hb_rational_hb_to_ff(mastering.display_primaries[i][1]); } ff_mastering.white_point[0] = hb_rational_hb_to_ff(mastering.white_point[0]); ff_mastering.white_point[1] = hb_rational_hb_to_ff(mastering.white_point[1]); ff_mastering.min_luminance = hb_rational_hb_to_ff(mastering.min_luminance); ff_mastering.max_luminance = hb_rational_hb_to_ff(mastering.max_luminance); ff_mastering.has_primaries = mastering.has_primaries; ff_mastering.has_luminance = mastering.has_luminance; return ff_mastering; } hb_ambient_viewing_environment_metadata_t hb_ambient_ff_to_hb(AVAmbientViewingEnvironment ambient) { hb_ambient_viewing_environment_metadata_t hb_ambient; hb_ambient.ambient_illuminance = hb_rational_ff_to_hb(ambient.ambient_illuminance); hb_ambient.ambient_light_x = hb_rational_ff_to_hb(ambient.ambient_light_x); hb_ambient.ambient_light_y = hb_rational_ff_to_hb(ambient.ambient_light_y); return hb_ambient; } AVAmbientViewingEnvironment hb_ambient_hb_to_ff(hb_ambient_viewing_environment_metadata_t ambient) { AVAmbientViewingEnvironment ff_ambient; ff_ambient.ambient_illuminance = hb_rational_hb_to_ff(ambient.ambient_illuminance); ff_ambient.ambient_light_x = hb_rational_hb_to_ff(ambient.ambient_light_x); ff_ambient.ambient_light_y = hb_rational_hb_to_ff(ambient.ambient_light_y); return ff_ambient; } AVDOVIDecoderConfigurationRecord hb_dovi_hb_to_ff(hb_dovi_conf_t dovi) { AVDOVIDecoderConfigurationRecord ff_dovi; ff_dovi.dv_version_major = dovi.dv_version_major; ff_dovi.dv_version_minor = dovi.dv_version_minor; ff_dovi.dv_profile = dovi.dv_profile; ff_dovi.dv_level = dovi.dv_level; ff_dovi.rpu_present_flag = dovi.rpu_present_flag; ff_dovi.el_present_flag = dovi.el_present_flag; ff_dovi.bl_present_flag = dovi.bl_present_flag; ff_dovi.dv_bl_signal_compatibility_id = dovi.dv_bl_signal_compatibility_id; return ff_dovi; } hb_dovi_conf_t hb_dovi_ff_to_hb(AVDOVIDecoderConfigurationRecord dovi) { hb_dovi_conf_t hb_dovi; hb_dovi.dv_version_major = dovi.dv_version_major; hb_dovi.dv_version_minor = dovi.dv_version_minor; hb_dovi.dv_profile = dovi.dv_profile; hb_dovi.dv_level = dovi.dv_level; hb_dovi.rpu_present_flag = dovi.rpu_present_flag; hb_dovi.el_present_flag = dovi.el_present_flag; hb_dovi.bl_present_flag = dovi.bl_present_flag; hb_dovi.dv_bl_signal_compatibility_id = dovi.dv_bl_signal_compatibility_id; return hb_dovi; } int hb_ff_mixdown_ch_xlat(AVChannelLayout *channel_layout, int hb_mixdown, int *downmix_mode) { uint64_t layout = hb_ff_mixdown_xlat(hb_mixdown, downmix_mode); return av_channel_layout_from_mask(channel_layout, layout); } uint64_t hb_ff_mixdown_xlat(int hb_mixdown, int *downmix_mode) { uint64_t ff_layout = 0; int mode = AV_MATRIX_ENCODING_NONE; switch (hb_mixdown) { // Passthru case HB_AMIXDOWN_NONE: break; case HB_AMIXDOWN_MONO: case HB_AMIXDOWN_LEFT: case HB_AMIXDOWN_RIGHT: ff_layout = AV_CH_LAYOUT_MONO; break; case HB_AMIXDOWN_DOLBY: ff_layout = AV_CH_LAYOUT_STEREO; mode = AV_MATRIX_ENCODING_DOLBY; break; case HB_AMIXDOWN_DOLBYPLII: ff_layout = AV_CH_LAYOUT_STEREO; mode = AV_MATRIX_ENCODING_DPLII; break; case HB_AMIXDOWN_STEREO: ff_layout = AV_CH_LAYOUT_STEREO; break; case HB_AMIXDOWN_5POINT1: ff_layout = AV_CH_LAYOUT_5POINT1; break; case HB_AMIXDOWN_6POINT1: ff_layout = AV_CH_LAYOUT_6POINT1; break; case HB_AMIXDOWN_7POINT1: ff_layout = AV_CH_LAYOUT_7POINT1; break; case HB_AMIXDOWN_5_2_LFE: ff_layout = (AV_CH_LAYOUT_5POINT1_BACK| AV_CH_FRONT_LEFT_OF_CENTER| AV_CH_FRONT_RIGHT_OF_CENTER); break; default: ff_layout = AV_CH_LAYOUT_STEREO; hb_log("hb_ff_mixdown_xlat: unsupported mixdown %d", hb_mixdown); break; } if (downmix_mode != NULL) *downmix_mode = mode; return ff_layout; } /* * Set sample format to the request format if supported by the codec. * The planar/packed variant of the requested format is the next best thing. */ void hb_ff_set_sample_fmt(AVCodecContext *context, const AVCodec *codec, enum AVSampleFormat request_sample_fmt) { if (context != NULL && codec != NULL && codec->type == AVMEDIA_TYPE_AUDIO) { const enum AVSampleFormat *sample_fmts = NULL; if (avcodec_get_supported_config(context, NULL, AV_CODEC_CONFIG_SAMPLE_FORMAT, 0, (const void **)&sample_fmts, NULL) == 0 && sample_fmts != NULL) { const enum AVSampleFormat *fmt; enum AVSampleFormat next_best_fmt; next_best_fmt = (av_sample_fmt_is_planar(request_sample_fmt) ? av_get_packed_sample_fmt(request_sample_fmt) : av_get_planar_sample_fmt(request_sample_fmt)); context->request_sample_fmt = AV_SAMPLE_FMT_NONE; for (fmt = sample_fmts; *fmt != AV_SAMPLE_FMT_NONE; fmt++) { if (*fmt == request_sample_fmt) { context->request_sample_fmt = request_sample_fmt; break; } else if (*fmt == next_best_fmt) { context->request_sample_fmt = next_best_fmt; } } /* * When encoding and AVCodec.sample_fmts exists, avcodec_open2() * will error out if AVCodecContext.sample_fmt isn't set. */ if (context->request_sample_fmt == AV_SAMPLE_FMT_NONE) { context->request_sample_fmt = sample_fmts[0]; } context->sample_fmt = context->request_sample_fmt; } } } int hb_av_can_use_zscale(enum AVPixelFormat pix_fmt, int in_width, int in_height, int out_width, int out_height) { #if defined (__aarch64__) && defined(_WIN32) { return 0; } #endif #if ARCH_X86_64 || ARCH_X86_32 if ((av_get_cpu_flags() & AV_CPU_FLAG_AVX2) == 0) { return 0; } #endif if ((in_width % 2) != 0 || (in_height % 2) != 0 || (out_width % 2) != 0 || (out_height % 2) != 0) { return 0; } static const enum AVPixelFormat pixel_fmts[] = { AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA444P12, AV_PIX_FMT_YUVA422P12, AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16, AV_PIX_FMT_NONE }; for (int i = 0; pixel_fmts[i] != AV_PIX_FMT_NONE; i++) { if (pix_fmt == pixel_fmts[i]) { return 1; } } return 0; }