diff --git a/libavcodec/mfenc.c b/libavcodec/mfenc.c index 942c75cb9d..3569562b58 100644 --- a/libavcodec/mfenc.c +++ b/libavcodec/mfenc.c @@ -29,6 +29,7 @@ #include "libavutil/opt.h" #include "libavutil/time.h" #include "codec_internal.h" +#include "profiles.h" #include "internal.h" #include "compat/w32dlfcn.h" #if CONFIG_D3D11VA @@ -711,6 +712,26 @@ static int64_t mf_enca_output_score(AVCodecContext *avctx, IMFMediaType *type) score |= 4LL << 32; } + if (avctx->codec_id == AV_CODEC_ID_AAC) { + hr = IMFAttributes_GetUINT32(type, &MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, &t); + switch (avctx->profile) { + case AV_PROFILE_AAC_LOW: + if (!FAILED(hr) && !(t >= 0x28 && t < 0x2c) && t != 0x50 && t != 0x51) + return -1; + break; + + case AV_PROFILE_AAC_HE: + if (!FAILED(hr) && !(t >= 0x2c && t < 0x30) && t != 0x52 && t != 0x53) + return -1; + break; + + case AV_PROFILE_AAC_HE_V2: + if (!FAILED(hr) && !(t >= 0x30 && t < 0x34)) + return -1; + break; + } + } + // Select the bitrate (lowest priority). hr = IMFAttributes_GetUINT32(type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &t); if (!FAILED(hr)) { @@ -986,12 +1007,32 @@ static int mf_choose_output_type(AVCodecContext *avctx) } if (ret >= 0) { + unsigned int profile_set; + unsigned int profile_negotiated; av_log(avctx, AV_LOG_VERBOSE, "setting output type:\n"); ff_media_type_dump(avctx, out_type); + IMFAttributes_GetUINT32(out_type, &MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, &profile_set); + hr = IMFTransform_SetOutputType(c->mft, c->out_stream_id, out_type, 0); if (!FAILED(hr)) { - ret = 1; + unsigned int bitrate; + IMFAttributes_GetUINT32(out_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &bitrate); + + if (avctx->codec_id == AV_CODEC_ID_AAC) { + IMFAttributes_GetUINT32(out_type, &MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, &profile_negotiated); + + if (profile_set != profile_negotiated) { // Setting PROFILE_LEVEL_INDICATION in AAC Encoder is only supported starting from Win11 24H2, fail if reported a mismatch in profile level indication. + av_log(avctx, AV_LOG_ERROR, "profile level indication mismatch: (out_type profile_level) %d != (out_type_negotiated profile_level) %d\n", profile_set, profile_negotiated); + ret = AVERROR_EXTERNAL; + } else { + av_log(avctx, AV_LOG_INFO, "using bitrate %dkbps, profile level: 0x%02x\n", bitrate / 125, profile_set); + ret = 1; + } + } else { + av_log(avctx, AV_LOG_INFO, "using bitrate %dkbps\n", bitrate / 125); + ret = 1; + } } else if (hr == MF_E_TRANSFORM_TYPE_NOT_SET) { av_log(avctx, AV_LOG_VERBOSE, "rejected - need to set input type\n"); ret = 0; @@ -1427,7 +1468,13 @@ static av_cold int mf_init(AVCodecContext *avctx) .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID | \ AV_CODEC_CAP_DR1 | AV_CODEC_CAP_VARIABLE_FRAME_SIZE, -MF_ENCODER(AUDIO, aac, AAC, NULL, AFMTS, ACAPS, NULL); +#define AE AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption aac_opts[] = { + FF_AAC_PROFILE_OPTS + {NULL} +}; + +MF_ENCODER(AUDIO, aac, AAC, aac_opts, AFMTS, ACAPS, NULL); MF_ENCODER(AUDIO, ac3, AC3, NULL, AFMTS, ACAPS, NULL); MF_ENCODER(AUDIO, mp3, MP3, NULL, AFMTS, ACAPS, NULL);