diff -urN cmake/modules/FindFFMPEG.cmake.orig cmake/modules/FindFFMPEG.cmake --- cmake/modules/FindFFMPEG.cmake.orig 2023-03-11 22:16:38.000000000 +0000 +++ cmake/modules/FindFFMPEG.cmake 2023-04-19 10:01:30.831589000 +0000 @@ -151,14 +151,14 @@ set(REQUIRED_FFMPEG_VERSION undef) else() # required ffmpeg library versions - set(REQUIRED_FFMPEG_VERSION 4.4.1) - set(_avcodec_ver ">=58.134.100") - set(_avfilter_ver ">=7.110.100") - set(_avformat_ver ">=58.76.100") - set(_avutil_ver ">=56.70.100") - set(_postproc_ver ">=55.9.100") - set(_swresample_ver ">=3.9.100") - set(_swscale_ver ">=5.9.100") + set(REQUIRED_FFMPEG_VERSION 6.0.0) + set(_avcodec_ver ">=60.2.100") + set(_avfilter_ver ">=9.3.100") + set(_avformat_ver ">=60.3.100") + set(_avutil_ver ">=58.2.100") + set(_postproc_ver ">=57.1.100") + set(_swresample_ver ">=4.10.100") + set(_swscale_ver ">=7.1.100") endif() # Allows building with external ffmpeg not found in system paths, diff -urN tools/buildsteps/windows/patches/0001-ffmpeg-windows-configure-detect-openssl.patch.orig tools/buildsteps/windows/patches/0001-ffmpeg-windows-configure-detect-openssl.patch --- tools/buildsteps/windows/patches/0001-ffmpeg-windows-configure-detect-openssl.patch.orig 2023-03-11 22:16:38.000000000 +0000 +++ tools/buildsteps/windows/patches/0001-ffmpeg-windows-configure-detect-openssl.patch 2023-04-19 10:01:22.854832000 +0000 @@ -11,7 +11,7 @@ index d7a3f507e8..4b85e881b1 100755 --- a/configure +++ b/configure -@@ -6530,6 +6530,8 @@ enabled openssl && { check_pkg_config openssl openssl openssl/ssl.h OP +@@ -6728,6 +6728,8 @@ enabled openssl && { check_pkg_config openssl openssl openssl/ssl.h OP check_lib openssl openssl/ssl.h SSL_library_init -lssl -lcrypto || check_lib openssl openssl/ssl.h SSL_library_init -lssl32 -leay32 || check_lib openssl openssl/ssl.h SSL_library_init -lssl -lcrypto -lws2_32 -lgdi32 || diff -urN tools/buildsteps/windows/patches/0002-ffmpeg-windows-configure-fix-zlib-conflict.patch.orig tools/buildsteps/windows/patches/0002-ffmpeg-windows-configure-fix-zlib-conflict.patch --- tools/buildsteps/windows/patches/0002-ffmpeg-windows-configure-fix-zlib-conflict.patch.orig 2023-03-11 22:16:38.000000000 +0000 +++ tools/buildsteps/windows/patches/0002-ffmpeg-windows-configure-fix-zlib-conflict.patch 2023-04-19 10:01:22.854952000 +0000 @@ -11,16 +11,16 @@ index 4b85e881b1..da457705d1 100755 --- a/configure +++ b/configure -@@ -7627,6 +7627,9 @@ print_config CONFIG_ "$config_files" $CONFIG_LIST \ +@@ -7825,6 +7825,9 @@ print_config CONFIG_ "$config_files" $CONFIG_LIST \ + print_config CONFIG_ "$config_files" $CONFIG_LIST \ $CONFIG_EXTRA \ - $ALL_COMPONENTS \ +echo "#if defined(HAVE_UNISTD_H) && HAVE_UNISTD_H == 0" >> $TMPH +echo "#undef HAVE_UNISTD_H" >> $TMPH +echo "#endif" >> $TMPH echo "#endif /* FFMPEG_CONFIG_H */" >> $TMPH - echo "endif # FFMPEG_CONFIG_MAK" >> ffbuild/config.mak + # Do not overwrite an unchanged config.h to avoid superfluous rebuilds. -- 2.29.2 diff -urN tools/buildsteps/windows/patches/0003-ffmpeg-windows-configure-allow-building-static.patch.orig tools/buildsteps/windows/patches/0003-ffmpeg-windows-configure-allow-building-static.patch --- tools/buildsteps/windows/patches/0003-ffmpeg-windows-configure-allow-building-static.patch.orig 2023-03-11 22:16:38.000000000 +0000 +++ tools/buildsteps/windows/patches/0003-ffmpeg-windows-configure-allow-building-static.patch 2023-04-19 10:01:22.855081000 +0000 @@ -11,7 +11,7 @@ index da457705d1..e3a8f45ff4 100755 --- a/configure +++ b/configure -@@ -5440,6 +5440,8 @@ case $target_os in +@@ -5566,6 +5566,8 @@ case $target_os in enabled shared && ! enabled small && test_cmd $windres --version && enable gnu_windres enabled x86_32 && check_ldflags -Wl,--large-address-aware shlibdir_default="$bindir_default" @@ -20,7 +20,7 @@ SLIBPREF="" SLIBSUF=".dll" SLIBNAME_WITH_VERSION='$(SLIBPREF)$(FULLNAME)-$(LIBVERSION)$(SLIBSUF)' -@@ -5489,6 +5491,8 @@ case $target_os in +@@ -5615,6 +5617,8 @@ case $target_os in fi enabled x86_32 && check_ldflags -LARGEADDRESSAWARE shlibdir_default="$bindir_default" diff -urN tools/buildsteps/windows/patches/0004-ffmpeg-windows-configure-detect-libdav1d.patch.orig tools/buildsteps/windows/patches/0004-ffmpeg-windows-configure-detect-libdav1d.patch --- tools/buildsteps/windows/patches/0004-ffmpeg-windows-configure-detect-libdav1d.patch.orig 2023-03-11 22:16:38.000000000 +0000 +++ tools/buildsteps/windows/patches/0004-ffmpeg-windows-configure-detect-libdav1d.patch 2023-04-19 10:01:22.855205000 +0000 @@ -11,7 +11,7 @@ index e3a8f45ff4..983d7e1078 100755 --- a/configure +++ b/configure -@@ -6358,7 +6358,7 @@ enabled libcelt && require libcelt celt/celt.h celt_decode -lcelt0 && +@@ -6541,7 +6541,7 @@ enabled libcelt && require libcelt celt/celt.h celt_decode -lcelt0 && die "ERROR: libcelt must be installed and version must be >= 0.11.0."; } enabled libcaca && require_pkg_config libcaca caca caca.h caca_create_canvas enabled libcodec2 && require libcodec2 codec2/codec2.h codec2_create -lcodec2 diff -urN tools/depends/target/ffmpeg/CMakeLists.txt.orig tools/depends/target/ffmpeg/CMakeLists.txt --- tools/depends/target/ffmpeg/CMakeLists.txt.orig 2023-03-11 22:16:38.000000000 +0000 +++ tools/depends/target/ffmpeg/CMakeLists.txt 2023-04-19 10:01:22.854687000 +0000 @@ -92,6 +92,7 @@ elseif(CORE_SYSTEM_NAME STREQUAL darwin_embedded) list(APPEND ffmpeg_conf --disable-crystalhd --enable-videotoolbox + --disable-filter=yadif_videotoolbox --target-os=darwin ) elseif(CORE_SYSTEM_NAME STREQUAL osx) diff -urN tools/depends/target/ffmpeg/FFMPEG-VERSION.orig tools/depends/target/ffmpeg/FFMPEG-VERSION --- tools/depends/target/ffmpeg/FFMPEG-VERSION.orig 2023-03-11 22:16:38.000000000 +0000 +++ tools/depends/target/ffmpeg/FFMPEG-VERSION 2023-04-19 10:02:41.108169000 +0000 @@ -1,5 +1,5 @@ LIBNAME=ffmpeg -BASE_URL=https://github.com/xbmc/FFmpeg -VERSION=4.4.1-Nexus-Alpha1 +VERSION=6.0 ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz -SHA512=8beb04d577b5251e74b0d52f4d130997a8ba94bbd488c7c8309e6b45095c27807e150212888ce3a384b23dff52f8df1a7bde5407bae924ddc363f8125c0616c5 +SHA512=b3214328f2792364353f38c6b46a71d4970c071d8656b20780abf0e02950167d0933eae825c09102cf8fb19fc679ac444bf1f41a448b624eaa5ea6b0f0bdf4f5 + diff -urN xbmc/cdrip/EncoderFFmpeg.cpp.orig xbmc/cdrip/EncoderFFmpeg.cpp --- xbmc/cdrip/EncoderFFmpeg.cpp.orig 2023-03-11 22:16:38.000000000 +0000 +++ xbmc/cdrip/EncoderFFmpeg.cpp 2023-04-19 10:01:22.848595000 +0000 @@ -11,6 +11,7 @@ #include "ServiceBroker.h" #include "addons/Addon.h" #include "addons/AddonManager.h" +#include "cores/FFmpeg.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" #include "utils/StringUtils.h" @@ -19,24 +20,9 @@ #include "utils/log.h" using namespace KODI::CDRIP; +using FFMPEG_HELP_TOOLS::FFMpegErrorToString; +using FFMPEG_HELP_TOOLS::FFMpegException; -namespace -{ - -struct EncoderException : public std::exception -{ - std::string s; - template - EncoderException(const std::string& fmt, Args&&... args) - : s(StringUtils::Format(fmt, std::forward(args)...)) - { - } - ~EncoderException() throw() {} // Updated - const char* what() const throw() { return s.c_str(); } -}; - -} /* namespace */ - bool CEncoderFFmpeg::Init() { try @@ -54,7 +40,7 @@ } else { - throw EncoderException("Could not get add-on: {}", addonId); + throw FFMpegException("Could not get add-on: {}", addonId); } // Hack fix about PTS on generated files. @@ -66,50 +52,50 @@ else if (addonId == "audioencoder.kodi.builtin.wma") m_samplesCountMultiply = 1000; else - throw EncoderException("Internal add-on id \"{}\" not known as usable", addonId); + throw FFMpegException("Internal add-on id \"{}\" not known as usable", addonId); const std::string filename = URIUtils::GetFileName(m_strFile); m_formatCtx = avformat_alloc_context(); if (!m_formatCtx) - throw EncoderException("Could not allocate output format context"); + throw FFMpegException("Could not allocate output format context"); m_bcBuffer = static_cast(av_malloc(BUFFER_SIZE + AV_INPUT_BUFFER_PADDING_SIZE)); if (!m_bcBuffer) - throw EncoderException("Could not allocate buffer"); + throw FFMpegException("Could not allocate buffer"); m_formatCtx->pb = avio_alloc_context(m_bcBuffer, BUFFER_SIZE, AVIO_FLAG_WRITE, this, nullptr, avio_write_callback, avio_seek_callback); if (!m_formatCtx->pb) - throw EncoderException("Failed to allocate ByteIOContext"); + throw FFMpegException("Failed to allocate ByteIOContext"); /* Guess the desired container format based on the file extension. */ m_formatCtx->oformat = av_guess_format(nullptr, filename.c_str(), nullptr); if (!m_formatCtx->oformat) - throw EncoderException("Could not find output file format"); + throw FFMpegException("Could not find output file format"); m_formatCtx->url = av_strdup(filename.c_str()); if (!m_formatCtx->url) - throw EncoderException("Could not allocate url"); + throw FFMpegException("Could not allocate url"); /* Find the encoder to be used by its name. */ - AVCodec* codec = avcodec_find_encoder(m_formatCtx->oformat->audio_codec); + const AVCodec* codec = avcodec_find_encoder(m_formatCtx->oformat->audio_codec); if (!codec) - throw EncoderException("Unable to find a suitable FFmpeg encoder"); + throw FFMpegException("Unable to find a suitable FFmpeg encoder"); /* Create a new audio stream in the output file container. */ m_stream = avformat_new_stream(m_formatCtx, nullptr); if (!m_stream) - throw EncoderException("Failed to allocate AVStream context"); + throw FFMpegException("Failed to allocate AVStream context"); m_codecCtx = avcodec_alloc_context3(codec); if (!m_codecCtx) - throw EncoderException("Failed to allocate the encoder context"); + throw FFMpegException("Failed to allocate the encoder context"); /* Set the basic encoder parameters. * The input file's sample rate is used to avoid a sample rate conversion. */ - m_codecCtx->channels = m_iInChannels; - m_codecCtx->channel_layout = av_get_default_channel_layout(m_iInChannels); + av_channel_layout_uninit(&m_codecCtx->ch_layout); + av_channel_layout_default(&m_codecCtx->ch_layout, m_iInChannels); m_codecCtx->sample_rate = m_iInSampleRate; m_codecCtx->sample_fmt = codec->sample_fmts[0]; m_codecCtx->bit_rate = bitrate; @@ -128,14 +114,14 @@ int err = avcodec_open2(m_codecCtx, codec, nullptr); if (err < 0) - throw EncoderException("Failed to open the codec {} (error '{}')", - codec->long_name ? codec->long_name : codec->name, - FFmpegErrorToString(err)); + throw FFMpegException("Failed to open the codec {} (error '{}')", + codec->long_name ? codec->long_name : codec->name, + FFMpegErrorToString(err)); err = avcodec_parameters_from_context(m_stream->codecpar, m_codecCtx); if (err < 0) - throw EncoderException("Failed to copy encoder parameters to output stream (error '{}')", - FFmpegErrorToString(err)); + throw FFMpegException("Failed to copy encoder parameters to output stream (error '{}')", + FFMpegErrorToString(err)); m_inFormat = GetInputFormat(m_iInBitsPerSample); m_outFormat = m_codecCtx->sample_fmt; @@ -150,44 +136,48 @@ m_bufferFrame = av_frame_alloc(); if (!m_bufferFrame || !m_buffer) - throw EncoderException("Failed to allocate necessary buffers"); + throw FFMpegException("Failed to allocate necessary buffers"); m_bufferFrame->nb_samples = m_codecCtx->frame_size; m_bufferFrame->format = m_inFormat; - m_bufferFrame->channel_layout = m_codecCtx->channel_layout; + + av_channel_layout_uninit(&m_bufferFrame->ch_layout); + av_channel_layout_copy(&m_bufferFrame->ch_layout, &m_codecCtx->ch_layout); + m_bufferFrame->sample_rate = m_codecCtx->sample_rate; err = av_frame_get_buffer(m_bufferFrame, 0); if (err < 0) - throw EncoderException("Could not allocate output frame samples (error '{}')", - FFmpegErrorToString(err)); + throw FFMpegException("Could not allocate output frame samples (error '{}')", + FFMpegErrorToString(err)); avcodec_fill_audio_frame(m_bufferFrame, m_iInChannels, m_inFormat, m_buffer, m_neededBytes, 0); if (m_needConversion) { - m_swrCtx = swr_alloc_set_opts(nullptr, m_codecCtx->channel_layout, m_outFormat, - m_codecCtx->sample_rate, m_codecCtx->channel_layout, m_inFormat, + int ret = swr_alloc_set_opts2(&m_swrCtx, &m_codecCtx->ch_layout, m_outFormat, + m_codecCtx->sample_rate, &m_codecCtx->ch_layout, m_inFormat, m_codecCtx->sample_rate, 0, nullptr); - if (!m_swrCtx || swr_init(m_swrCtx) < 0) - throw EncoderException("Failed to initialize the resampler"); + if (ret || swr_init(m_swrCtx) < 0) + throw FFMpegException("Failed to initialize the resampler"); m_resampledBufferSize = av_samples_get_buffer_size(nullptr, m_iInChannels, m_neededFrames, m_outFormat, 0); m_resampledBuffer = static_cast(av_malloc(m_resampledBufferSize)); m_resampledFrame = av_frame_alloc(); if (!m_resampledBuffer || !m_resampledFrame) - throw EncoderException("Failed to allocate a frame for resampling"); + throw FFMpegException("Failed to allocate a frame for resampling"); m_resampledFrame->nb_samples = m_neededFrames; m_resampledFrame->format = m_outFormat; - m_resampledFrame->channel_layout = m_codecCtx->channel_layout; + av_channel_layout_uninit(&m_resampledFrame->ch_layout); + av_channel_layout_copy(&m_resampledFrame->ch_layout, &m_codecCtx->ch_layout); m_resampledFrame->sample_rate = m_codecCtx->sample_rate; err = av_frame_get_buffer(m_resampledFrame, 0); if (err < 0) - throw EncoderException("Could not allocate output resample frame samples (error '{}')", - FFmpegErrorToString(err)); + throw FFMpegException("Could not allocate output resample frame samples (error '{}')", + FFMpegErrorToString(err)); avcodec_fill_audio_frame(m_resampledFrame, m_iInChannels, m_outFormat, m_resampledBuffer, m_resampledBufferSize, 0); @@ -204,7 +194,7 @@ /* write the header */ err = avformat_write_header(m_formatCtx, nullptr); if (err != 0) - throw EncoderException("Failed to write the header (error '{}')", FFmpegErrorToString(err)); + throw FFMpegException("Failed to write the header (error '{}')", FFMpegErrorToString(err)); CLog::Log(LOGDEBUG, "CEncoderFFmpeg::{} - Successfully initialized with muxer {} and codec {}", __func__, @@ -212,16 +202,19 @@ : m_formatCtx->oformat->name, codec->long_name ? codec->long_name : codec->name); } - catch (EncoderException& caught) + catch (const FFMpegException& caught) { CLog::Log(LOGERROR, "CEncoderFFmpeg::{} - {}", __func__, caught.what()); av_freep(&m_buffer); + av_channel_layout_uninit(&m_bufferFrame->ch_layout); av_frame_free(&m_bufferFrame); swr_free(&m_swrCtx); + av_channel_layout_uninit(&m_resampledFrame->ch_layout); av_frame_free(&m_resampledFrame); av_freep(&m_resampledBuffer); av_free(m_bcBuffer); + av_channel_layout_uninit(&m_codecCtx->ch_layout); avcodec_free_context(&m_codecCtx); if (m_formatCtx) { @@ -299,7 +292,7 @@ if (swr_convert(m_swrCtx, m_resampledFrame->data, m_neededFrames, const_cast(m_bufferFrame->extended_data), m_neededFrames) < 0) - throw EncoderException("Error resampling audio"); + throw FFMpegException("Error resampling audio"); frame = m_resampledFrame; } @@ -316,8 +309,8 @@ m_bufferSize = 0; err = avcodec_send_frame(m_codecCtx, frame); if (err < 0) - throw EncoderException("Error sending a frame for encoding (error '{}')", __func__, - FFmpegErrorToString(err)); + throw FFMpegException("Error sending a frame for encoding (error '{}')", + FFMpegErrorToString(err)); while (err >= 0) { @@ -329,19 +322,18 @@ } else if (err < 0) { - throw EncoderException("Error during encoding (error '{}')", __func__, - FFmpegErrorToString(err)); + throw FFMpegException("Error during encoding (error '{}')", FFMpegErrorToString(err)); } err = av_write_frame(m_formatCtx, pkt); if (err < 0) - throw EncoderException("Failed to write the frame data (error '{}')", __func__, - FFmpegErrorToString(err)); + throw FFMpegException("Failed to write the frame data (error '{}')", + FFMpegErrorToString(err)); av_packet_unref(pkt); } } - catch (EncoderException& caught) + catch (const FFMpegException& caught) { CLog::Log(LOGERROR, "CEncoderFFmpeg::{} - {}", __func__, caught.what()); } @@ -366,8 +358,10 @@ /* Flush if needed */ av_freep(&m_buffer); + av_channel_layout_uninit(&m_bufferFrame->ch_layout); av_frame_free(&m_bufferFrame); swr_free(&m_swrCtx); + av_channel_layout_uninit(&m_resampledFrame->ch_layout); av_frame_free(&m_resampledFrame); av_freep(&m_resampledBuffer); m_needConversion = false; @@ -379,6 +373,7 @@ /* cleanup */ av_free(m_bcBuffer); + av_channel_layout_uninit(&m_codecCtx->ch_layout); avcodec_free_context(&m_codecCtx); av_freep(&m_formatCtx->pb); avformat_free_context(m_formatCtx); @@ -400,14 +395,6 @@ case 32: return AV_SAMPLE_FMT_S32; default: - throw EncoderException("Invalid input bits per sample"); + throw FFMpegException("Invalid input bits per sample"); } -} - -std::string CEncoderFFmpeg::FFmpegErrorToString(int err) -{ - std::string text; - text.reserve(AV_ERROR_MAX_STRING_SIZE); - av_strerror(err, text.data(), AV_ERROR_MAX_STRING_SIZE); - return text; } diff -urN xbmc/cdrip/EncoderFFmpeg.h.orig xbmc/cdrip/EncoderFFmpeg.h --- xbmc/cdrip/EncoderFFmpeg.h.orig 2023-03-11 22:16:38.000000000 +0000 +++ xbmc/cdrip/EncoderFFmpeg.h 2023-04-19 10:01:22.835616000 +0000 @@ -39,7 +39,6 @@ void SetTag(const std::string& tag, const std::string& value); bool WriteFrame(); AVSampleFormat GetInputFormat(int inBitsPerSample); - std::string FFmpegErrorToString(int err); AVFormatContext* m_formatCtx{nullptr}; AVCodecContext* m_codecCtx{nullptr}; diff -urN xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp.orig xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp --- xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp.orig 2023-03-11 22:16:38.000000000 +0000 +++ xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp 2023-04-19 10:01:22.848879000 +0000 @@ -10,14 +10,25 @@ #define DTS_ENCODE_BITRATE 1411200 #include "cores/AudioEngine/Encoders/AEEncoderFFmpeg.h" -#include "cores/AudioEngine/Utils/AEUtil.h" + #include "ServiceBroker.h" -#include "utils/log.h" +#include "cores/AudioEngine/Utils/AEUtil.h" +#include "cores/FFmpeg.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" -#include +#include "utils/log.h" + +extern "C" +{ +#include +} + #include +#include +using FFMPEG_HELP_TOOLS::FFMpegErrorToString; +using FFMPEG_HELP_TOOLS::FFMpegException; + CAEEncoderFFmpeg::CAEEncoderFFmpeg() : m_CodecCtx(NULL), m_SwrCtx(NULL) { } @@ -26,6 +37,7 @@ { Reset(); swr_free(&m_SwrCtx); + av_channel_layout_uninit(&m_CodecCtx->ch_layout); avcodec_free_context(&m_CodecCtx); } @@ -81,7 +93,7 @@ bool ac3 = CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_AUDIOOUTPUT_AC3PASSTHROUGH); - AVCodec *codec = NULL; + const AVCodec* codec = nullptr; /* fallback to ac3 if we support it, we might not have DTS support */ if (ac3) @@ -102,7 +114,8 @@ m_CodecCtx->bit_rate = m_BitRate; m_CodecCtx->sample_rate = format.m_sampleRate; - m_CodecCtx->channel_layout = AV_CH_LAYOUT_5POINT1_BACK; + av_channel_layout_uninit(&m_CodecCtx->ch_layout); + av_channel_layout_from_mask(&m_CodecCtx->ch_layout, AV_CH_LAYOUT_5POINT1_BACK); /* select a suitable data format */ if (codec->sample_fmts) @@ -179,22 +192,28 @@ LOGERROR, "CAEEncoderFFmpeg::Initialize - Unable to find a suitable data format for the codec ({})", m_CodecName); + av_channel_layout_uninit(&m_CodecCtx->ch_layout); avcodec_free_context(&m_CodecCtx); return false; } } - m_CodecCtx->channels = BuildChannelLayout(m_CodecCtx->channel_layout, m_Layout); + uint64_t mask = m_CodecCtx->ch_layout.u.mask; + av_channel_layout_uninit(&m_CodecCtx->ch_layout); + av_channel_layout_from_mask(&m_CodecCtx->ch_layout, mask); + m_CodecCtx->ch_layout.nb_channels = BuildChannelLayout(mask, m_Layout); /* open the codec */ if (avcodec_open2(m_CodecCtx, codec, NULL)) { + av_channel_layout_uninit(&m_CodecCtx->ch_layout); avcodec_free_context(&m_CodecCtx); return false; } format.m_frames = m_CodecCtx->frame_size; - format.m_frameSize = m_CodecCtx->channels * (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3); + int channels = m_CodecCtx->ch_layout.nb_channels; + format.m_frameSize = channels * (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3); format.m_channelLayout = m_Layout; m_CurrentFormat = format; @@ -204,14 +223,14 @@ if (m_NeedConversion) { - m_SwrCtx = swr_alloc_set_opts(NULL, - m_CodecCtx->channel_layout, m_CodecCtx->sample_fmt, m_CodecCtx->sample_rate, - m_CodecCtx->channel_layout, AV_SAMPLE_FMT_FLT, m_CodecCtx->sample_rate, - 0, NULL); - if (!m_SwrCtx || swr_init(m_SwrCtx) < 0) + int ret = swr_alloc_set_opts2(&m_SwrCtx, &m_CodecCtx->ch_layout, m_CodecCtx->sample_fmt, + m_CodecCtx->sample_rate, &m_CodecCtx->ch_layout, + AV_SAMPLE_FMT_FLT, m_CodecCtx->sample_rate, 0, NULL); + if (ret || swr_init(m_SwrCtx) < 0) { CLog::Log(LOGERROR, "CAEEncoderFFmpeg::Initialize - Failed to initialise resampler."); swr_free(&m_SwrCtx); + av_channel_layout_uninit(&m_CodecCtx->ch_layout); avcodec_free_context(&m_CodecCtx); return false; } @@ -242,62 +261,83 @@ int CAEEncoderFFmpeg::Encode(uint8_t *in, int in_size, uint8_t *out, int out_size) { - int got_output; - AVFrame *frame; + int size = 0; + int err = AVERROR_UNKNOWN; + AVFrame* frame = nullptr; + AVPacket* pkt = nullptr; if (!m_CodecCtx) - return 0; + return size; - /* allocate the input frame - * sadly, we have to alloc/dealloc it everytime since we have no guarantee the - * data argument will be constant over iterated calls and the frame needs to - * setup pointers inside data */ - frame = av_frame_alloc(); - if (!frame) - return 0; + try + { + /* allocate the input frame and output packet + * sadly, we have to alloc/dealloc it everytime since we have no guarantee the + * data argument will be constant over iterated calls and the frame needs to + * setup pointers inside data */ + frame = av_frame_alloc(); + pkt = av_packet_alloc(); + if (!frame || !pkt) + throw FFMpegException( + "Failed to allocate \"AVFrame\" or \"AVPacket\" for encoding (error '{}')", + strerror(errno)); - frame->nb_samples = m_CodecCtx->frame_size; - frame->format = m_CodecCtx->sample_fmt; - frame->channel_layout = m_CodecCtx->channel_layout; - frame->channels = m_CodecCtx->channels; + frame->nb_samples = m_CodecCtx->frame_size; + frame->format = m_CodecCtx->sample_fmt; + av_channel_layout_uninit(&frame->ch_layout); + av_channel_layout_copy(&frame->ch_layout, &m_CodecCtx->ch_layout); + int channelNum = m_CodecCtx->ch_layout.nb_channels; - avcodec_fill_audio_frame(frame, m_CodecCtx->channels, m_CodecCtx->sample_fmt, - in, in_size, 0); + avcodec_fill_audio_frame(frame, channelNum, m_CodecCtx->sample_fmt, in, in_size, 0); - /* initialize the output packet */ - AVPacket* pkt = av_packet_alloc(); - if (!pkt) + /* encode it */ + err = avcodec_send_frame(m_CodecCtx, frame); + if (err < 0) + throw FFMpegException("Error sending a frame for encoding (error '{}')", + FFMpegErrorToString(err)); + + err = avcodec_receive_packet(m_CodecCtx, pkt); + //! @TODO: This is a workaround for our current design. The caller should be made + // aware of the potential error values to use the ffmpeg API in a proper way, which means + // copying with EAGAIN and multiple packet output. + // For the current situation there is a relationship implicitely assumed of: + // 1 frame in - 1 packet out. This holds true in practice but the API does not guarantee it. + if (err >= 0) + { + if (pkt->size <= out_size) + { + memset(out, 0, out_size); + memcpy(out, pkt->data, pkt->size); + size = pkt->size; + } + else + { + CLog::LogF(LOGERROR, "Encoded pkt size ({}) is bigger than buffer ({})", pkt->size, + out_size); + } + av_packet_unref(pkt); + } + else + { + CLog::LogF(LOGERROR, "Error receiving encoded paket ({})", err); + } + } + catch (const FFMpegException& caught) { - CLog::Log(LOGERROR, "CAEEncoderFFmpeg::{} - av_packet_alloc failed: {}", __FUNCTION__, - strerror(errno)); - av_frame_free(&frame); - return 0; + CLog::Log(LOGERROR, "CAEEncoderFFmpeg::{} - {}", __func__, caught.what()); } - pkt->size = out_size; - pkt->data = out; + av_channel_layout_uninit(&frame->ch_layout); - /* encode it */ - int ret = avcodec_encode_audio2(m_CodecCtx, pkt, frame, &got_output); - - int size = pkt->size; - /* free temporary data */ av_frame_free(&frame); /* free the packet */ av_packet_free(&pkt); - if (ret < 0 || !got_output) - { - CLog::Log(LOGERROR, "CAEEncoderFFmpeg::Encode - Encoding failed"); - return 0; - } - /* return the number of frames used */ return size; } - int CAEEncoderFFmpeg::GetData(uint8_t **data) { diff -urN xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp.orig xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp --- xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp.orig 2023-03-11 22:16:38.000000000 +0000 +++ xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp 2023-04-19 10:01:22.849708000 +0000 @@ -16,17 +16,16 @@ #include "ActiveAESound.h" #include "ActiveAEStream.h" #include "ServiceBroker.h" +#include "cores/AudioEngine/AEResampleFactory.h" +#include "cores/AudioEngine/Encoders/AEEncoderFFmpeg.h" #include "cores/AudioEngine/Interfaces/IAudioCallback.h" -#include "cores/AudioEngine/Utils/AEUtil.h" #include "cores/AudioEngine/Utils/AEStreamData.h" #include "cores/AudioEngine/Utils/AEStreamInfo.h" -#include "cores/AudioEngine/AEResampleFactory.h" -#include "cores/AudioEngine/Encoders/AEEncoderFFmpeg.h" - +#include "cores/AudioEngine/Utils/AEUtil.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" -#include "windowing/WinSystem.h" #include "utils/log.h" +#include "windowing/WinSystem.h" using namespace std::chrono_literals; @@ -3043,8 +3042,8 @@ AVFormatContext *fmt_ctx = nullptr; AVCodecContext *dec_ctx = nullptr; AVIOContext *io_ctx; - AVInputFormat *io_fmt = nullptr; - AVCodec *dec = nullptr; + const AVInputFormat* io_fmt = nullptr; + const AVCodec* dec = nullptr; SampleConfig config; // No custom deleter until sound is registered @@ -3096,8 +3095,8 @@ AVCodecID codecId = fmt_ctx->streams[0]->codecpar->codec_id; dec = avcodec_find_decoder(codecId); config.sample_rate = fmt_ctx->streams[0]->codecpar->sample_rate; - config.channels = fmt_ctx->streams[0]->codecpar->channels; - config.channel_layout = fmt_ctx->streams[0]->codecpar->channel_layout; + config.channels = fmt_ctx->streams[0]->codecpar->ch_layout.nb_channels; + config.channel_layout = fmt_ctx->streams[0]->codecpar->ch_layout.u.mask; } } if (dec == nullptr) @@ -3113,10 +3112,14 @@ dec_ctx = avcodec_alloc_context3(dec); dec_ctx->sample_rate = config.sample_rate; - dec_ctx->channels = config.channels; + AVChannelLayout layout = {}; if (!config.channel_layout) - config.channel_layout = av_get_default_channel_layout(config.channels); - dec_ctx->channel_layout = config.channel_layout; + av_channel_layout_default(&layout, config.channels); + else + av_channel_layout_from_mask(&layout, config.channel_layout); + config.channel_layout = layout.u.mask; + av_channel_layout_copy(&dec_ctx->ch_layout, &layout); + av_channel_layout_uninit(&layout); AVPacket* avpkt = av_packet_alloc(); if (!avpkt) @@ -3183,6 +3186,7 @@ av_packet_free(&avpkt); av_frame_free(&decoded_frame); + av_channel_layout_uninit(&dec_ctx->ch_layout); avcodec_free_context(&dec_ctx); avformat_close_input(&fmt_ctx); if (io_ctx) diff -urN xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEFilter.cpp.orig xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEFilter.cpp --- xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEFilter.cpp.orig 2023-03-11 22:16:38.000000000 +0000 +++ xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEFilter.cpp 2023-04-19 10:01:22.849964000 +0000 @@ -12,8 +12,8 @@ #include extern "C" { -#include #include +#include #include #include #include @@ -171,7 +171,10 @@ } if (m_pOutFrame) + { + av_channel_layout_uninit(&m_pOutFrame->ch_layout); av_frame_free(&m_pOutFrame); + } if (m_pConvertFrame) av_frame_free(&m_pConvertFrame); @@ -205,10 +208,9 @@ if (!frame) return -1; - int channels = av_get_channel_layout_nb_channels(m_channelLayout); - - frame->channel_layout = m_channelLayout; - frame->channels = channels; + av_channel_layout_uninit(&frame->ch_layout); + av_channel_layout_from_mask(&frame->ch_layout, m_channelLayout); + int channels = frame->ch_layout.nb_channels; frame->sample_rate = m_sampleRate; frame->nb_samples = src_samples; frame->format = m_sampleFormat; @@ -224,6 +226,7 @@ src_buffer[0], src_bufsize, 16); if (result < 0) { + av_channel_layout_uninit(&frame->ch_layout); av_frame_free(&frame); CLog::Log(LOGERROR, "CActiveAEFilter::ProcessFilter - avcodec_fill_audio_frame failed"); m_filterEof = true; @@ -231,6 +234,7 @@ } result = av_buffersrc_write_frame(m_pFilterCtxIn, frame); + av_channel_layout_uninit(&frame->ch_layout); av_frame_free(&frame); if (result < 0) { @@ -284,7 +288,8 @@ { av_frame_unref(m_pOutFrame); m_pOutFrame->format = m_sampleFormat; - m_pOutFrame->channel_layout = m_channelLayout; + av_channel_layout_uninit(&m_pOutFrame->ch_layout); + av_channel_layout_from_mask(&m_pOutFrame->ch_layout, m_channelLayout); m_pOutFrame->sample_rate = m_sampleRate; result = swr_convert_frame(m_pConvertCtx, m_pOutFrame, m_pConvertFrame); av_frame_unref(m_pConvertFrame); @@ -302,7 +307,10 @@ if (m_hasData) { - int channels = av_get_channel_layout_nb_channels(m_channelLayout); + AVChannelLayout layout = {}; + av_channel_layout_from_mask(&layout, m_channelLayout); + int channels = layout.nb_channels; + av_channel_layout_uninit(&layout); int planes = av_sample_fmt_is_planar(m_sampleFormat) ? channels : 1; int samples = std::min(dst_samples, m_pOutFrame->nb_samples - m_sampleOffset); int bytes = samples * av_get_bytes_per_sample(m_sampleFormat) * channels / planes; diff -urN xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp.orig xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp --- xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp.orig 2023-03-11 22:16:38.000000000 +0000 +++ xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp 2023-04-19 10:01:22.850224000 +0000 @@ -49,15 +49,30 @@ m_doesResample = true; if (m_dst_chan_layout == 0) - m_dst_chan_layout = av_get_default_channel_layout(m_dst_channels); + { + AVChannelLayout layout = {}; + av_channel_layout_default(&layout, m_dst_channels); + m_dst_chan_layout = layout.u.mask; + av_channel_layout_uninit(&layout); + } if (m_src_chan_layout == 0) - m_src_chan_layout = av_get_default_channel_layout(m_src_channels); + { + AVChannelLayout layout = {}; + av_channel_layout_default(&layout, m_src_channels); + m_src_chan_layout = layout.u.mask; + av_channel_layout_uninit(&layout); + } - m_pContext = swr_alloc_set_opts(NULL, m_dst_chan_layout, m_dst_fmt, m_dst_rate, - m_src_chan_layout, m_src_fmt, m_src_rate, - 0, NULL); + AVChannelLayout dstChLayout = {}; + AVChannelLayout srcChLayout = {}; - if (!m_pContext) + av_channel_layout_from_mask(&dstChLayout, m_dst_chan_layout); + av_channel_layout_from_mask(&srcChLayout, m_src_chan_layout); + + int ret = swr_alloc_set_opts2(&m_pContext, &dstChLayout, m_dst_fmt, m_dst_rate, &srcChLayout, + m_src_fmt, m_src_rate, 0, NULL); + + if (ret) { CLog::Log(LOGERROR, "CActiveAEResampleFFMPEG::Init - create context failed"); return false; @@ -126,10 +141,12 @@ else if (upmix && m_src_channels == 2 && m_dst_channels > 2) { memset(m_rematrix, 0, sizeof(m_rematrix)); + av_channel_layout_uninit(&dstChLayout); + av_channel_layout_from_mask(&dstChLayout, m_dst_chan_layout); for (int out=0; out #endif -extern "C" { -#include -} - void AEDelayStatus::SetDelay(double d) { delay = d; @@ -550,34 +546,64 @@ } } -uint64_t CAEUtil::GetAVChannel(enum AEChannel aechannel) +uint64_t CAEUtil::GetAVChannelMask(enum AEChannel aechannel) { + enum AVChannel ch = GetAVChannel(aechannel); + if (ch == AV_CHAN_NONE) + return 0; + return (1ULL << ch); +} + +enum AVChannel CAEUtil::GetAVChannel(enum AEChannel aechannel) +{ switch (aechannel) { - case AE_CH_FL: return AV_CH_FRONT_LEFT; - case AE_CH_FR: return AV_CH_FRONT_RIGHT; - case AE_CH_FC: return AV_CH_FRONT_CENTER; - case AE_CH_LFE: return AV_CH_LOW_FREQUENCY; - case AE_CH_BL: return AV_CH_BACK_LEFT; - case AE_CH_BR: return AV_CH_BACK_RIGHT; - case AE_CH_FLOC: return AV_CH_FRONT_LEFT_OF_CENTER; - case AE_CH_FROC: return AV_CH_FRONT_RIGHT_OF_CENTER; - case AE_CH_BC: return AV_CH_BACK_CENTER; - case AE_CH_SL: return AV_CH_SIDE_LEFT; - case AE_CH_SR: return AV_CH_SIDE_RIGHT; - case AE_CH_TC: return AV_CH_TOP_CENTER; - case AE_CH_TFL: return AV_CH_TOP_FRONT_LEFT; - case AE_CH_TFC: return AV_CH_TOP_FRONT_CENTER; - case AE_CH_TFR: return AV_CH_TOP_FRONT_RIGHT; - case AE_CH_TBL: return AV_CH_TOP_BACK_LEFT; - case AE_CH_TBC: return AV_CH_TOP_BACK_CENTER; - case AE_CH_TBR: return AV_CH_TOP_BACK_RIGHT; - default: - return 0; + case AE_CH_FL: + return AV_CHAN_FRONT_LEFT; + case AE_CH_FR: + return AV_CHAN_FRONT_RIGHT; + case AE_CH_FC: + return AV_CHAN_FRONT_CENTER; + case AE_CH_LFE: + return AV_CHAN_LOW_FREQUENCY; + case AE_CH_BL: + return AV_CHAN_BACK_LEFT; + case AE_CH_BR: + return AV_CHAN_BACK_RIGHT; + case AE_CH_FLOC: + return AV_CHAN_FRONT_LEFT_OF_CENTER; + case AE_CH_FROC: + return AV_CHAN_FRONT_RIGHT_OF_CENTER; + case AE_CH_BC: + return AV_CHAN_BACK_CENTER; + case AE_CH_SL: + return AV_CHAN_SIDE_LEFT; + case AE_CH_SR: + return AV_CHAN_SIDE_RIGHT; + case AE_CH_TC: + return AV_CHAN_TOP_CENTER; + case AE_CH_TFL: + return AV_CHAN_TOP_FRONT_LEFT; + case AE_CH_TFC: + return AV_CHAN_TOP_FRONT_CENTER; + case AE_CH_TFR: + return AV_CHAN_TOP_FRONT_RIGHT; + case AE_CH_TBL: + return AV_CHAN_TOP_BACK_LEFT; + case AE_CH_TBC: + return AV_CHAN_TOP_BACK_CENTER; + case AE_CH_TBR: + return AV_CHAN_TOP_BACK_RIGHT; + default: + return AV_CHAN_NONE; } } int CAEUtil::GetAVChannelIndex(enum AEChannel aechannel, uint64_t layout) { - return av_get_channel_layout_channel_index(layout, GetAVChannel(aechannel)); + AVChannelLayout ch_layout = {}; + av_channel_layout_from_mask(&ch_layout, layout); + int idx = av_channel_layout_index_from_channel(&ch_layout, GetAVChannel(aechannel)); + av_channel_layout_uninit(&ch_layout); + return idx; } diff -urN xbmc/cores/AudioEngine/Utils/AEUtil.h.orig xbmc/cores/AudioEngine/Utils/AEUtil.h --- xbmc/cores/AudioEngine/Utils/AEUtil.h.orig 2023-03-11 22:16:38.000000000 +0000 +++ xbmc/cores/AudioEngine/Utils/AEUtil.h 2023-04-19 10:01:22.850626000 +0000 @@ -13,6 +13,7 @@ #include extern "C" { +#include #include } @@ -171,6 +172,7 @@ static uint64_t GetAVChannelLayout(const CAEChannelInfo &info); static CAEChannelInfo GetAEChannelLayout(uint64_t layout); static AVSampleFormat GetAVSampleFormat(AEDataFormat format); - static uint64_t GetAVChannel(enum AEChannel aechannel); + static uint64_t GetAVChannelMask(enum AEChannel aechannel); + static enum AVChannel GetAVChannel(enum AEChannel aechannel); static int GetAVChannelIndex(enum AEChannel aechannel, uint64_t layout); }; diff -urN xbmc/cores/FFmpeg.cpp.orig xbmc/cores/FFmpeg.cpp --- xbmc/cores/FFmpeg.cpp.orig 2023-03-11 22:16:38.000000000 +0000 +++ xbmc/cores/FFmpeg.cpp 2023-04-19 10:01:22.850804000 +0000 @@ -16,11 +16,29 @@ #include "utils/StringUtils.h" #include "utils/log.h" +extern "C" +{ +#include +} + #include #include static thread_local CFFmpegLog* CFFmpegLogTls; +namespace FFMPEG_HELP_TOOLS +{ + +std::string FFMpegErrorToString(int err) +{ + std::string text; + text.resize(AV_ERROR_MAX_STRING_SIZE); + av_strerror(err, text.data(), AV_ERROR_MAX_STRING_SIZE); + return text; +} + +} // namespace FFMPEG_HELP_TOOLS + void CFFmpegLog::SetLogLevel(int level) { CFFmpegLog::ClearLogLevel(); @@ -117,3 +135,128 @@ buffer.erase(0, start); } +std::tuple GetPacketExtradata(const AVPacket* pkt, + const AVCodecParserContext* parserCtx, + AVCodecContext* codecCtx) +{ + constexpr int FF_MAX_EXTRADATA_SIZE = ((1 << 28) - AV_INPUT_BUFFER_PADDING_SIZE); + + if (!pkt) + return std::make_tuple(nullptr, 0); + + uint8_t* extraData = nullptr; + int extraDataSize = 0; + + /* extract_extradata bitstream filter is implemented only + * for certain codecs, as noted in discussion of PR#21248 + */ + + AVCodecID codecId = codecCtx->codec_id; + + // clang-format off + if ( + codecId != AV_CODEC_ID_MPEG1VIDEO && + codecId != AV_CODEC_ID_MPEG2VIDEO && + codecId != AV_CODEC_ID_H264 && + codecId != AV_CODEC_ID_HEVC && + codecId != AV_CODEC_ID_MPEG4 && + codecId != AV_CODEC_ID_VC1 && + codecId != AV_CODEC_ID_AV1 && + codecId != AV_CODEC_ID_AVS2 && + codecId != AV_CODEC_ID_AVS3 && + codecId != AV_CODEC_ID_CAVS + ) + // clang-format on + return std::make_tuple(nullptr, 0); + + const AVBitStreamFilter* f = av_bsf_get_by_name("extract_extradata"); + if (!f) + return std::make_tuple(nullptr, 0); + + AVBSFContext* bsf = nullptr; + int ret = av_bsf_alloc(f, &bsf); + if (ret < 0) + return std::make_tuple(nullptr, 0); + + bsf->par_in->codec_id = codecId; + + ret = av_bsf_init(bsf); + if (ret < 0) + { + av_bsf_free(&bsf); + return std::make_tuple(nullptr, 0); + } + + AVPacket* dstPkt = av_packet_alloc(); + if (!dstPkt) + { + CLog::LogF(LOGERROR, "failed to allocate packet"); + + av_bsf_free(&bsf); + return std::make_tuple(nullptr, 0); + } + AVPacket* pktRef = dstPkt; + + ret = av_packet_ref(pktRef, pkt); + if (ret < 0) + { + av_bsf_free(&bsf); + av_packet_free(&dstPkt); + return std::make_tuple(nullptr, 0); + } + + ret = av_bsf_send_packet(bsf, pktRef); + if (ret < 0) + { + av_packet_unref(pktRef); + av_bsf_free(&bsf); + av_packet_free(&dstPkt); + return std::make_tuple(nullptr, 0); + } + + ret = 0; + while (ret >= 0) + { + ret = av_bsf_receive_packet(bsf, pktRef); + if (ret < 0) + { + if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) + break; + + continue; + } + + size_t retExtraDataSize = 0; + uint8_t* retExtraData = + av_packet_get_side_data(pktRef, AV_PKT_DATA_NEW_EXTRADATA, &retExtraDataSize); + if (retExtraData && retExtraDataSize > 0 && retExtraDataSize < FF_MAX_EXTRADATA_SIZE) + { + extraData = static_cast(av_malloc(retExtraDataSize + AV_INPUT_BUFFER_PADDING_SIZE)); + if (!extraData) + { + CLog::LogF(LOGERROR, "failed to allocate {} bytes for extradata", retExtraDataSize); + + av_packet_unref(pktRef); + av_bsf_free(&bsf); + av_packet_free(&dstPkt); + return std::make_tuple(nullptr, 0); + } + + CLog::LogF(LOGDEBUG, "fetching extradata, extradata_size({})", retExtraDataSize); + + memcpy(extraData, retExtraData, retExtraDataSize); + memset(extraData + retExtraDataSize, 0, AV_INPUT_BUFFER_PADDING_SIZE); + extraDataSize = retExtraDataSize; + + av_packet_unref(pktRef); + break; + } + + av_packet_unref(pktRef); + } + + av_bsf_free(&bsf); + av_packet_free(&dstPkt); + + return std::make_tuple(extraData, extraDataSize); +} diff -urN xbmc/cores/FFmpeg.h.orig xbmc/cores/FFmpeg.h --- xbmc/cores/FFmpeg.h.orig 2023-03-11 22:16:38.000000000 +0000 +++ xbmc/cores/FFmpeg.h 2023-04-19 10:01:22.850926000 +0000 @@ -10,6 +10,7 @@ #include "ServiceBroker.h" #include "utils/CPUInfo.h" +#include "utils/StringUtils.h" extern "C" { #include @@ -21,6 +22,26 @@ #include } +#include + +namespace FFMPEG_HELP_TOOLS +{ + +struct FFMpegException : public std::exception +{ + std::string s; + template + FFMpegException(const std::string& fmt, Args&&... args) + : s(StringUtils::Format(fmt, std::forward(args)...)) + { + } + const char* what() const noexcept override { return s.c_str(); } +}; + +std::string FFMpegErrorToString(int err); + +} // namespace FFMPEG_HELP_TOOLS + inline int PPCPUFlags() { unsigned int cpuFeatures = CServiceBroker::GetCPUInfo()->GetCPUFeatures(); @@ -51,3 +72,6 @@ int level; }; +std::tuple GetPacketExtradata(const AVPacket* pkt, + const AVCodecParserContext* parserCtx, + AVCodecContext* codecCtx); diff -urN xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp.orig xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp --- xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp.orig 2023-03-11 22:16:38.000000000 +0000 +++ xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp 2023-04-19 10:01:30.826672000 +0000 @@ -7,14 +7,16 @@ */ #include "DVDAudioCodecFFmpeg.h" -#include "ServiceBroker.h" + #include "../../DVDStreamInfo.h" -#include "utils/log.h" +#include "DVDCodecs/DVDCodecs.h" +#include "ServiceBroker.h" +#include "cores/AudioEngine/Utils/AEUtil.h" +#include "cores/FFmpeg.h" #include "settings/AdvancedSettings.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" -#include "DVDCodecs/DVDCodecs.h" -#include "cores/AudioEngine/Utils/AEUtil.h" +#include "utils/log.h" extern "C" { #include @@ -44,7 +46,7 @@ return false; } - AVCodec* pCodec = NULL; + const AVCodec* pCodec = nullptr; bool allowdtshddecode = true; // set any special options @@ -71,13 +73,28 @@ m_pCodecContext->debug = 0; m_pCodecContext->workaround_bugs = 1; +#if LIBAVCODEC_VERSION_MAJOR < 60 if (pCodec->capabilities & AV_CODEC_CAP_TRUNCATED) m_pCodecContext->flags |= AV_CODEC_FLAG_TRUNCATED; +#endif m_matrixEncoding = AV_MATRIX_ENCODING_NONE; m_channels = 0; - m_pCodecContext->channels = hints.channels; - m_hint_layout = hints.channellayout; + av_channel_layout_uninit(&m_pCodecContext->ch_layout); + + if (hints.channels > 0 && hints.channellayout > 0) + { + m_pCodecContext->ch_layout.order = AV_CHANNEL_ORDER_NATIVE; + m_pCodecContext->ch_layout.nb_channels = hints.channels; + m_pCodecContext->ch_layout.u.mask = hints.channellayout; + } + else if (hints.channels > 0) + { + av_channel_layout_default(&m_pCodecContext->ch_layout, hints.channels); + } + + m_hint_layout = m_pCodecContext->ch_layout.u.mask; + m_pCodecContext->sample_rate = hints.samplerate; m_pCodecContext->block_align = hints.blockalign; m_pCodecContext->bit_rate = hints.bitrate; @@ -259,12 +276,13 @@ m_format.m_frameSize = m_format.m_channelLayout.Count() * CAEUtil::DataFormatToBits(m_format.m_dataFormat) >> 3; - int planes = av_sample_fmt_is_planar(m_pCodecContext->sample_fmt) ? m_pFrame->channels : 1; + int channels = m_pFrame->ch_layout.nb_channels; + int planes = av_sample_fmt_is_planar(m_pCodecContext->sample_fmt) ? channels : 1; + for (int i=0; iextended_data[i]; - return m_pFrame->nb_samples * m_pFrame->channels * - av_get_bytes_per_sample(m_pCodecContext->sample_fmt); + return m_pFrame->nb_samples * channels * av_get_bytes_per_sample(m_pCodecContext->sample_fmt); } return 0; @@ -278,7 +296,7 @@ int CDVDAudioCodecFFmpeg::GetChannels() { - return m_pCodecContext->channels; + return m_pCodecContext->ch_layout.nb_channels; } int CDVDAudioCodecFFmpeg::GetSampleRate() @@ -345,28 +363,33 @@ void CDVDAudioCodecFFmpeg::BuildChannelMap() { - if (m_channels == m_pCodecContext->channels && m_layout == m_pCodecContext->channel_layout) + int codecChannels = m_pCodecContext->ch_layout.nb_channels; + uint64_t codecChannelLayout = m_pCodecContext->ch_layout.u.mask; + if (m_channels == codecChannels && m_layout == codecChannelLayout) return; //nothing to do here - m_channels = m_pCodecContext->channels; - m_layout = m_pCodecContext->channel_layout; + m_channels = codecChannels; + m_layout = codecChannelLayout; int64_t layout; - int bits = count_bits(m_pCodecContext->channel_layout); - if (bits == m_pCodecContext->channels) - layout = m_pCodecContext->channel_layout; + int bits = count_bits(codecChannelLayout); + if (bits == codecChannels) + layout = codecChannelLayout; else { CLog::Log(LOGINFO, "CDVDAudioCodecFFmpeg::GetChannelMap - FFmpeg reported {} channels, but the layout " "contains {} - trying hints", - m_pCodecContext->channels, bits); - if (static_cast(count_bits(m_hint_layout)) == m_pCodecContext->channels) + codecChannels, bits); + if (static_cast(count_bits(m_hint_layout)) == codecChannels) layout = m_hint_layout; else { - layout = av_get_default_channel_layout(m_pCodecContext->channels); + AVChannelLayout def_layout = {}; + av_channel_layout_default(&def_layout, codecChannels); + layout = def_layout.u.mask; + av_channel_layout_uninit(&def_layout); CLog::Log(LOGINFO, "Using default layout..."); } } @@ -392,7 +415,7 @@ if (layout & AV_CH_TOP_BACK_CENTER ) m_channelLayout += AE_CH_BC ; if (layout & AV_CH_TOP_BACK_RIGHT ) m_channelLayout += AE_CH_BR ; - m_channels = m_pCodecContext->channels; + m_channels = codecChannels; } CAEChannelInfo CDVDAudioCodecFFmpeg::GetChannelMap() diff -urN xbmc/cores/VideoPlayer/DVDCodecs/Overlay/DVDOverlayCodecFFmpeg.cpp.orig xbmc/cores/VideoPlayer/DVDCodecs/Overlay/DVDOverlayCodecFFmpeg.cpp --- xbmc/cores/VideoPlayer/DVDCodecs/Overlay/DVDOverlayCodecFFmpeg.cpp.orig 2023-03-11 22:16:38.000000000 +0000 +++ xbmc/cores/VideoPlayer/DVDCodecs/Overlay/DVDOverlayCodecFFmpeg.cpp 2023-04-19 10:01:22.851350000 +0000 @@ -10,6 +10,7 @@ #include "DVDOverlayImage.h" #include "DVDStreamInfo.h" +#include "cores/FFmpeg.h" #include "cores/VideoPlayer/Interface/DemuxPacket.h" #include "cores/VideoPlayer/Interface/TimingConstants.h" #include "utils/EndianSwap.h" @@ -39,7 +40,7 @@ if (hints.codec == AV_CODEC_ID_EIA_608) return false; - AVCodec* pCodec = avcodec_find_decoder(hints.codec); + const AVCodec* pCodec = avcodec_find_decoder(hints.codec); if (!pCodec) { CLog::Log(LOGDEBUG, "{} - Unable to find codec {}", __FUNCTION__, hints.codec); diff -urN xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp.orig xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp --- xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp.orig 2023-03-11 22:16:38.000000000 +0000 +++ xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp 2023-04-19 10:01:30.832626000 +0000 @@ -12,6 +12,7 @@ #include "DVDCodecs/DVDFactoryCodec.h" #include "DVDStreamInfo.h" #include "ServiceBroker.h" +#include "cores/FFmpeg.h" #include "cores/VideoPlayer/Interface/TimingConstants.h" #include "cores/VideoPlayer/VideoRenderers/RenderManager.h" #include "cores/VideoSettings.h" @@ -27,12 +28,13 @@ #include extern "C" { -#include -#include #include #include #include +#include +#include #include +#include } #ifndef TARGET_POSIX @@ -327,7 +329,7 @@ m_hints = hints; m_options = options; - AVCodec* pCodec = nullptr; + const AVCodec* pCodec = nullptr; m_iOrientation = hints.orientation; @@ -368,6 +370,10 @@ m_pCodecContext->get_format = GetFormat; m_pCodecContext->codec_tag = hints.codec_tag; +#if LIBAVCODEC_VERSION_MAJOR >= 60 + m_pCodecContext->flags = AV_CODEC_FLAG_COPY_OPAQUE; +#endif + // setup threading model if (!(hints.codecOptions & CODEC_FORCE_SOFTWARE)) { @@ -543,9 +549,10 @@ CLog::Log(LOGDEBUG, "CDVDVideoCodecFFmpeg - Updated codec: {}", m_name); } +#if LIBAVCODEC_VERSION_MAJOR < 60 union pts_union { - double pts_d; + double pts_d; int64_t pts_i; }; @@ -555,6 +562,7 @@ u.pts_d = pts; return u.pts_i; } +#endif bool CDVDVideoCodecFFmpeg::AddData(const DemuxPacket &packet) { @@ -573,7 +581,10 @@ m_started = true; m_dts = packet.dts; + +#if LIBAVCODEC_VERSION_MAJOR < 60 m_pCodecContext->reordered_opaque = pts_dtoi(packet.pts); +#endif AVPacket* avpkt = av_packet_alloc(); if (!avpkt) @@ -1048,24 +1059,27 @@ pVideoPicture->qscale_type = 0; AVFrameSideData* sd; - sd = av_frame_get_side_data(m_pFrame, AV_FRAME_DATA_QP_TABLE_PROPERTIES); + + // https://github.com/FFmpeg/FFmpeg/blob/991d417692/doc/APIchanges#L18-L20 + sd = av_frame_get_side_data(m_pFrame, AV_FRAME_DATA_VIDEO_ENC_PARAMS); if (sd) { - struct qp_properties - { - int stride; - int type; - }; + unsigned int mb_h = (m_pFrame->height + 15) / 16; + unsigned int mb_w = (m_pFrame->width + 15) / 16; + unsigned int nb_mb = mb_h * mb_w; + unsigned int block_idx; - auto qp = reinterpret_cast(sd->data); - - sd = av_frame_get_side_data(m_pFrame, AV_FRAME_DATA_QP_TABLE_DATA); - if (sd && sd->buf && qp) + auto par = reinterpret_cast(sd->data); + if (par->type == AV_VIDEO_ENC_PARAMS_MPEG2 && (par->nb_blocks == 0 || par->nb_blocks == nb_mb)) { - // this seems wrong but it's what ffmpeg does internally - pVideoPicture->qp_table = reinterpret_cast(sd->buf->data); - pVideoPicture->qstride = qp->stride; - pVideoPicture->qscale_type = qp->type; + pVideoPicture->qstride = mb_w; + pVideoPicture->qscale_type = par->type; + pVideoPicture->qp_table = static_cast(av_malloc(nb_mb)); + for (block_idx = 0; block_idx < nb_mb; block_idx++) + { + AVVideoBlockParams* b = av_video_enc_params_block(par, block_idx); + pVideoPicture->qp_table[block_idx] = par->qp + b->delta_qp; + } } } @@ -1159,8 +1173,9 @@ const AVFilter* outFilter = avfilter_get_by_name("buffersink"); // should be last filter in the graph for now std::string args = StringUtils::Format( - "{}:{}:{}:{}:{}:{}:{}", m_pCodecContext->width, m_pCodecContext->height, - m_pCodecContext->pix_fmt, m_pCodecContext->time_base.num ? m_pCodecContext->time_base.num : 1, + "video_size={}x{}:pix_fmt={}:time_base={}/{}:pixel_aspect={}/{}", m_pCodecContext->width, + m_pCodecContext->height, m_pCodecContext->pix_fmt, + m_pCodecContext->time_base.num ? m_pCodecContext->time_base.num : 1, m_pCodecContext->time_base.num ? m_pCodecContext->time_base.den : 1, m_pCodecContext->sample_aspect_ratio.num != 0 ? m_pCodecContext->sample_aspect_ratio.num : 1, m_pCodecContext->sample_aspect_ratio.num != 0 ? m_pCodecContext->sample_aspect_ratio.den : 1); diff -urN xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoPPFFmpeg.cpp.orig xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoPPFFmpeg.cpp --- xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoPPFFmpeg.cpp.orig 2023-03-11 22:16:38.000000000 +0000 +++ xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoPPFFmpeg.cpp 2023-04-19 10:01:22.851870000 +0000 @@ -118,6 +118,8 @@ m_pMode, m_pContext, pSource->pict_type | pSource->qscale_type ? PP_PICT_TYPE_QP2 : 0); + // https://github.com/FFmpeg/FFmpeg/blob/991d417692/doc/APIchanges#L18-L20 + av_free(pSource->qp_table); pPicture->SetParams(*pSource); if (pPicture->videoBuffer) diff -urN xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp.orig xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp --- xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp.orig 2023-03-11 22:16:38.000000000 +0000 +++ xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp 2023-04-19 10:01:30.833014000 +0000 @@ -973,7 +973,8 @@ m_event.Set(); m_avD3D11Context = av_d3d11va_alloc_context(); m_avD3D11Context->cfg = reinterpret_cast(av_mallocz(sizeof(D3D11_VIDEO_DECODER_CONFIG))); - m_avD3D11Context->surface = reinterpret_cast(av_mallocz_array(32, sizeof(ID3D11VideoDecoderOutputView*))); + m_avD3D11Context->surface = reinterpret_cast( + av_calloc(32, sizeof(ID3D11VideoDecoderOutputView*))); m_bufferPool.reset(); DX::Windowing()->Register(this); @@ -1538,8 +1539,6 @@ return -1; } - pic->reordered_opaque = avctx->reordered_opaque; - for (unsigned i = 0; i < 4; i++) { pic->data[i] = nullptr; @@ -1555,6 +1554,10 @@ return -1; } pic->buf[0] = buffer; + +#if LIBAVCODEC_VERSION_MAJOR < 60 + pic->reordered_opaque = avctx->reordered_opaque; +#endif Acquire(); diff -urN xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp.orig xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp --- xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp.orig 2023-03-11 22:16:38.000000000 +0000 +++ xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp 2023-04-19 10:01:30.833643000 +0000 @@ -868,7 +868,10 @@ } pic->buf[0] = buffer; +#if LIBAVCODEC_VERSION_MAJOR < 60 pic->reordered_opaque = avctx->reordered_opaque; +#endif + va->Acquire(); return 0; } @@ -1259,7 +1262,9 @@ IHardwareDecoder* CDecoder::Create(CDVDStreamInfo &hint, CProcessInfo &processInfo, AVPixelFormat fmt) { - if (fmt == AV_PIX_FMT_VAAPI_VLD && CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(SETTING_VIDEOPLAYER_USEVAAPI)) + // https://github.com/FFmpeg/FFmpeg/blob/56450a0ee4fdda160f4039fc2ae33edfd27765c9/doc/APIchanges#L18-L26 + if (fmt == AV_PIX_FMT_VAAPI && + CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(SETTING_VIDEOPLAYER_USEVAAPI)) return new VAAPI::CDecoder(processInfo); return nullptr; @@ -2966,10 +2971,11 @@ const AVFilter* srcFilter = avfilter_get_by_name("buffer"); const AVFilter* outFilter = avfilter_get_by_name("buffersink"); - std::string args = StringUtils::Format("{}:{}:{}:{}:{}:{}:{}", m_config.vidWidth, - m_config.vidHeight, AV_PIX_FMT_NV12, 1, 1, - (m_config.aspect.num != 0) ? m_config.aspect.num : 1, - (m_config.aspect.num != 0) ? m_config.aspect.den : 1); + std::string args = + StringUtils::Format("video_size={}x{}:pix_fmt={}:time_base={}/{}:pixel_aspect={}/{}", + m_config.vidWidth, m_config.vidHeight, AV_PIX_FMT_NV12, 1, 1, + (m_config.aspect.num != 0) ? m_config.aspect.num : 1, + (m_config.aspect.num != 0) ? m_config.aspect.den : 1); if (avfilter_graph_create_filter(&m_pFilterIn, srcFilter, "src", args.c_str(), NULL, m_pFilterGraph) < 0) { diff -urN xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.cpp.orig xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.cpp --- xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.cpp.orig 2023-03-11 22:16:38.000000000 +0000 +++ xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.cpp 2023-04-19 10:01:30.834410000 +0000 @@ -1045,7 +1045,10 @@ } pic->buf[0] = buffer; - pic->reordered_opaque= avctx->reordered_opaque; +#if LIBAVCODEC_VERSION_MAJOR < 60 + pic->reordered_opaque = avctx->reordered_opaque; +#endif + return 0; } diff -urN xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp.orig xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp --- xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp.orig 2023-03-11 22:16:38.000000000 +0000 +++ xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp 2023-04-19 10:01:22.852749000 +0000 @@ -10,13 +10,13 @@ #include "DVDDemuxUtils.h" #include "DVDInputStreams/DVDInputStream.h" +#include "cores/FFmpeg.h" #include "cores/VideoPlayer/Interface/TimingConstants.h" #include "utils/log.h" +#include #include -#define FF_MAX_EXTRADATA_SIZE ((1 << 28) - AV_INPUT_BUFFER_PADDING_SIZE) - class CDemuxStreamClientInternal { public: @@ -130,7 +130,7 @@ if (stream->m_context == nullptr) { - AVCodec *codec = avcodec_find_decoder(st->codec); + const AVCodec* codec = avcodec_find_decoder(st->codec); if (codec == nullptr) { CLog::Log(LOGERROR, "{} - can't find decoder", __FUNCTION__); @@ -149,17 +149,26 @@ stream->m_context->time_base.den = DVD_TIME_BASE; } - if (stream->m_parser_split && stream->m_parser->parser->split) + if (stream->m_parser_split && stream->m_parser && stream->m_parser->parser) { - int len = stream->m_parser->parser->split(stream->m_context, pkt->pData, pkt->iSize); - if (len > 0 && len < FF_MAX_EXTRADATA_SIZE) + AVPacket* avpkt = av_packet_alloc(); + if (!avpkt) { + CLog::LogF(LOGERROR, "av_packet_alloc failed: {}", strerror(errno)); + return false; + } + + avpkt->data = pkt->pData; + avpkt->size = pkt->iSize; + avpkt->dts = avpkt->pts = AV_NOPTS_VALUE; + + auto [retExtraData, len] = GetPacketExtradata(avpkt, stream->m_parser, stream->m_context); + if (len > 0) + { st->changes++; st->disabled = false; st->ExtraSize = len; - st->ExtraData = std::make_unique(len + AV_INPUT_BUFFER_PADDING_SIZE); - memcpy(st->ExtraData.get(), pkt->pData, len); - memset(st->ExtraData.get() + len, 0, AV_INPUT_BUFFER_PADDING_SIZE); + st->ExtraData = std::unique_ptr(retExtraData); stream->m_parser_split = false; change = true; CLog::Log(LOGDEBUG, "CDVDDemuxClient::ParsePacket - split extradata"); @@ -167,21 +176,12 @@ // Allow ffmpeg to transport codec information to stream->m_context if (!avcodec_open2(stream->m_context, stream->m_context->codec, nullptr)) { - AVPacket* avpkt = av_packet_alloc(); - if (!avpkt) - { - CLog::Log(LOGERROR, "CDVDDemuxClient::{} - av_packet_alloc failed: {}", __FUNCTION__, - strerror(errno)); - return false; - } - avpkt->data = pkt->pData; - avpkt->size = pkt->iSize; - avpkt->dts = avpkt->pts = AV_NOPTS_VALUE; avcodec_send_packet(stream->m_context, avpkt); avcodec_close(stream->m_context); - av_packet_free(&avpkt); } } + + av_packet_free(&avpkt); } uint8_t *outbuf = nullptr; @@ -219,10 +219,12 @@ case STREAM_AUDIO: { CDemuxStreamClientInternalTpl* sta = static_cast*>(st); - if (stream->m_context->channels != sta->iChannels && stream->m_context->channels != 0) + int streamChannels = stream->m_context->ch_layout.nb_channels; + if (streamChannels != sta->iChannels && streamChannels != 0) { - CLog::Log(LOGDEBUG, "CDVDDemuxClient::ParsePacket - ({}) channels changed from {} to {}", st->uniqueId, sta->iChannels, stream->m_context->channels); - sta->iChannels = stream->m_context->channels; + CLog::Log(LOGDEBUG, "CDVDDemuxClient::ParsePacket - ({}) channels changed from {} to {}", + st->uniqueId, sta->iChannels, streamChannels); + sta->iChannels = streamChannels; sta->changes++; sta->disabled = false; } @@ -234,7 +236,7 @@ sta->changes++; sta->disabled = false; } - if (stream->m_context->channels) + if (streamChannels) st->changes = -1; // stop parsing break; } diff -urN xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp.orig xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp --- xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp.orig 2023-03-11 22:16:38.000000000 +0000 +++ xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp 2023-04-19 10:01:30.828436000 +0000 @@ -34,10 +34,12 @@ #include #include +#include #include extern "C" { +#include "libavutil/channel_layout.h" #include "libavutil/pixdesc.h" } @@ -104,8 +106,6 @@ } } // namespace -#define FF_MAX_EXTRADATA_SIZE ((1 << 28) - AV_INPUT_BUFFER_PADDING_SIZE) - std::string CDemuxStreamAudioFFmpeg::GetStreamName() { if (!m_stream) @@ -235,7 +235,7 @@ bool CDVDDemuxFFmpeg::Open(const std::shared_ptr& pInput, bool fileinfo) { - AVInputFormat* iformat = NULL; + const AVInputFormat* iformat = nullptr; std::string strFile; m_streaminfo = !pInput->IsRealtime() && !m_reopen; m_reopen = false; @@ -323,7 +323,6 @@ } if (result < 0) { - m_pFormatContext->flags |= AVFMT_FLAG_PRIV_OPT; if (avformat_open_input(&m_pFormatContext, strFile.c_str(), iformat, &options) < 0) { CLog::Log(LOGDEBUG, "Error, could not open file {}", CURL::GetRedacted(strFile)); @@ -335,7 +334,6 @@ avformat_close_input(&m_pFormatContext); m_pFormatContext = avformat_alloc_context(); m_pFormatContext->interrupt_callback = int_cb; - m_pFormatContext->flags &= ~AVFMT_FLAG_PRIV_OPT; AVDictionary* options = GetFFMpegOptionsFromInput(); av_dict_set_int(&options, "load_all_variants", 0, AV_OPT_SEARCH_CHILDREN); if (avformat_open_input(&m_pFormatContext, strFile.c_str(), iformat, &options) < 0) @@ -422,9 +420,7 @@ // is present, we assume it is PCM audio. // AC3 is always wrapped in iec61937 (ffmpeg "spdif"), while DTS // may be just padded. - AVInputFormat* iformat2; - iformat2 = av_find_input_format("spdif"); - + const AVInputFormat* iformat2 = av_find_input_format("spdif"); if (iformat2 && iformat2->read_probe(&pd) > AVPROBE_SCORE_MAX / 4) { iformat = iformat2; @@ -544,12 +540,6 @@ m_streaminfo = true; } - if (iformat && (strcmp(iformat->name, "mov,mp4,m4a,3gp,3g2,mj2") == 0)) - { - if (URIUtils::IsRemote(strFile)) - m_pFormatContext->iformat->flags |= AVFMT_NOGENSEARCH; - } - // we need to know if this is matroska, avi or sup later m_bMatroska = strncmp(m_pFormatContext->iformat->name, "matroska", 8) == 0; // for "matroska.webm" m_bAVI = strcmp(m_pFormatContext->iformat->name, "avi") == 0; @@ -604,9 +594,6 @@ // if format can be nonblocking, let's use that m_pFormatContext->flags |= AVFMT_FLAG_NONBLOCK; - // deprecated, will be always set in future versions - m_pFormatContext->flags |= AVFMT_FLAG_KEEP_SIDE_DATA; - UpdateCurrentPTS(); // select the correct program if requested @@ -647,7 +634,10 @@ { int idx = m_pFormatContext->programs[i]->stream_index[j]; AVStream* st = m_pFormatContext->streams[idx]; - if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && st->codec_info_nb_frames > 0) || + // Related to https://patchwork.ffmpeg.org/project/ffmpeg/patch/20210429143825.53040-1-jamrial@gmail.com/ + // has been replaced with AVSTREAM_EVENT_FLAG_NEW_PACKETS. + if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && + (st->event_flags & AVSTREAM_EVENT_FLAG_NEW_PACKETS)) || (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && st->codecpar->sample_rate > 0)) { nProgram = i; @@ -1218,8 +1208,11 @@ else if (stream->type == STREAM_AUDIO) { CDemuxStreamAudioFFmpeg* audiostream = dynamic_cast(stream); - if (audiostream && (audiostream->iChannels != m_pFormatContext->streams[pPacket->iStreamId]->codecpar->channels || - audiostream->iSampleRate != m_pFormatContext->streams[pPacket->iStreamId]->codecpar->sample_rate)) + int codecparChannels = + m_pFormatContext->streams[pPacket->iStreamId]->codecpar->ch_layout.nb_channels; + if (audiostream && (audiostream->iChannels != codecparChannels || + audiostream->iSampleRate != + m_pFormatContext->streams[pPacket->iStreamId]->codecpar->sample_rate)) { // content has changed stream = AddStream(pPacket->iStreamId); @@ -1401,9 +1394,10 @@ if (idx >= 0) { AVStream* stream = m_pFormatContext->streams[idx]; - if (stream && stream->cur_dts != (int64_t)AV_NOPTS_VALUE) + + if (stream && m_pkt.pkt.dts != (int64_t)AV_NOPTS_VALUE) { - double ts = ConvertTimestamp(stream->cur_dts, stream->time_base.den, stream->time_base.num); + double ts = ConvertTimestamp(m_pkt.pkt.dts, stream->time_base.den, stream->time_base.num); m_currentPts = ts; } } @@ -1614,14 +1608,20 @@ { CDemuxStreamAudioFFmpeg* st = new CDemuxStreamAudioFFmpeg(pStream); stream = st; - st->iChannels = pStream->codecpar->channels; + int codecparChannels = pStream->codecpar->ch_layout.nb_channels; + int codecparChannelLayout = pStream->codecpar->ch_layout.u.mask; + st->iChannels = codecparChannels; + st->iChannelLayout = codecparChannelLayout; st->iSampleRate = pStream->codecpar->sample_rate; st->iBlockAlign = pStream->codecpar->block_align; st->iBitRate = static_cast(pStream->codecpar->bit_rate); st->iBitsPerSample = pStream->codecpar->bits_per_raw_sample; - st->iChannelLayout = pStream->codecpar->channel_layout; char buf[32] = {}; - av_get_channel_layout_string(buf, 31, st->iChannels, st->iChannelLayout); + // https://github.com/FFmpeg/FFmpeg/blob/6ccc3989d15/doc/APIchanges#L50-L53 + AVChannelLayout layout = {}; + av_channel_layout_from_mask(&layout, st->iChannelLayout); + av_channel_layout_describe(&layout, buf, sizeof(buf)); + av_channel_layout_uninit(&layout); st->m_channelLayoutName = buf; if (st->iBitsPerSample == 0) st->iBitsPerSample = pStream->codecpar->bits_per_coded_sample; @@ -1663,16 +1663,6 @@ st->iFpsScale = 0; } - if (pStream->codec_info_nb_frames > 0 && - pStream->codec_info_nb_frames <= 2 && - m_pInput->IsStreamType(DVDSTREAM_TYPE_DVD)) - { - CLog::Log(LOGDEBUG, "{} - fps may be unreliable since ffmpeg decoded only {} frame(s)", - __FUNCTION__, pStream->codec_info_nb_frames); - st->iFpsRate = 0; - st->iFpsScale = 0; - } - st->iWidth = pStream->codecpar->width; st->iHeight = pStream->codecpar->height; st->fAspect = SelectAspect(pStream, st->bForcedAspect); @@ -1693,7 +1683,8 @@ st->colorRange = pStream->codecpar->color_range; st->hdr_type = DetermineHdrType(pStream); - int size = 0; + // https://github.com/FFmpeg/FFmpeg/blob/release/5.0/doc/APIchanges + size_t size = 0; uint8_t* side_data = nullptr; side_data = av_stream_get_side_data(pStream, AV_PKT_DATA_MASTERING_DISPLAY_METADATA, &size); @@ -2103,7 +2094,7 @@ return strName; } - AVCodec* codec = avcodec_find_decoder(stream->codec); + const AVCodec* codec = avcodec_find_decoder(stream->codec); if (codec) strName = avcodec_get_name(codec->id); } @@ -2158,8 +2149,8 @@ if (m_pFormatContext->streams[idx]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { CDemuxStreamAudioFFmpeg* audiostream = dynamic_cast(stream); - if (audiostream && - m_pFormatContext->streams[idx]->codecpar->channels != audiostream->iChannels) + int codecparChannels = m_pFormatContext->streams[idx]->codecpar->ch_layout.nb_channels; + if (audiostream && codecparChannels != audiostream->iChannels) { return true; } @@ -2279,7 +2270,7 @@ parser->second->m_parserCtx = av_parser_init(st->codecpar->codec_id); - AVCodec* codec = avcodec_find_decoder(st->codecpar->codec_id); + const AVCodec* codec = avcodec_find_decoder(st->codecpar->codec_id); if (codec == nullptr) { CLog::Log(LOGERROR, "{} - can't find decoder", __FUNCTION__); @@ -2295,45 +2286,37 @@ if (parser->second->m_parserCtx && parser->second->m_parserCtx->parser && - parser->second->m_parserCtx->parser->split && !st->codecpar->extradata) { - int i = parser->second->m_parserCtx->parser->split(parser->second->m_codecCtx, pkt->data, pkt->size); - if (i > 0 && i < FF_MAX_EXTRADATA_SIZE) + auto [retExtraData, i] = + GetPacketExtradata(pkt, parser->second->m_parserCtx, parser->second->m_codecCtx); + if (i > 0) { - st->codecpar->extradata = (uint8_t*)av_malloc(i + AV_INPUT_BUFFER_PADDING_SIZE); - if (st->codecpar->extradata) + st->codecpar->extradata_size = i; + st->codecpar->extradata = retExtraData; + + if (parser->second->m_parserCtx->parser->parser_parse) { - CLog::Log(LOGDEBUG, - "CDVDDemuxFFmpeg::ParsePacket() fetching extradata, extradata_size({})", i); - st->codecpar->extradata_size = i; - memcpy(st->codecpar->extradata, pkt->data, i); - memset(st->codecpar->extradata + i, 0, AV_INPUT_BUFFER_PADDING_SIZE); + parser->second->m_codecCtx->extradata = st->codecpar->extradata; + parser->second->m_codecCtx->extradata_size = st->codecpar->extradata_size; + const uint8_t* outbufptr; + int bufSize; + parser->second->m_parserCtx->flags |= PARSER_FLAG_COMPLETE_FRAMES; + parser->second->m_parserCtx->parser->parser_parse(parser->second->m_parserCtx, + parser->second->m_codecCtx, &outbufptr, + &bufSize, pkt->data, pkt->size); + parser->second->m_codecCtx->extradata = nullptr; + parser->second->m_codecCtx->extradata_size = 0; - if (parser->second->m_parserCtx->parser->parser_parse) + if (parser->second->m_parserCtx->width != 0) { - parser->second->m_codecCtx->extradata = st->codecpar->extradata; - parser->second->m_codecCtx->extradata_size = st->codecpar->extradata_size; - const uint8_t* outbufptr; - int bufSize; - parser->second->m_parserCtx->flags |= PARSER_FLAG_COMPLETE_FRAMES; - parser->second->m_parserCtx->parser->parser_parse(parser->second->m_parserCtx, - parser->second->m_codecCtx, - &outbufptr, &bufSize, - pkt->data, pkt->size); - parser->second->m_codecCtx->extradata = nullptr; - parser->second->m_codecCtx->extradata_size = 0; - - if (parser->second->m_parserCtx->width != 0) - { - st->codecpar->width = parser->second->m_parserCtx->width; - st->codecpar->height = parser->second->m_parserCtx->height; - } - else - { - CLog::Log(LOGERROR, "CDVDDemuxFFmpeg::ParsePacket() invalid width/height"); - } + st->codecpar->width = parser->second->m_parserCtx->width; + st->codecpar->height = parser->second->m_parserCtx->height; } + else + { + CLog::Log(LOGERROR, "CDVDDemuxFFmpeg::ParsePacket() invalid width/height"); + } } } } @@ -2357,7 +2340,8 @@ { if (!m_startTime) { - m_startTime = av_rescale(st->cur_dts, st->time_base.num, st->time_base.den) - 0.000001; + m_startTime = + av_rescale(m_pkt.pkt.dts, st->time_base.num, st->time_base.den) - 0.000001; m_seekStream = idx; } return TRANSPORT_STREAM_STATE::READY; @@ -2377,7 +2361,8 @@ { if (!m_startTime) { - m_startTime = av_rescale(st->cur_dts, st->time_base.num, st->time_base.den) - 0.000001; + m_startTime = + av_rescale(m_pkt.pkt.dts, st->time_base.num, st->time_base.den) - 0.000001; m_seekStream = i; } return TRANSPORT_STREAM_STATE::READY; @@ -2410,7 +2395,8 @@ { if (!m_startTime) { - m_startTime = av_rescale(st->cur_dts, st->time_base.num, st->time_base.den) - 0.000001; + m_startTime = + av_rescale(m_pkt.pkt.dts, st->time_base.num, st->time_base.den) - 0.000001; m_seekStream = idx; } return TRANSPORT_STREAM_STATE::READY; @@ -2430,7 +2416,8 @@ { if (!m_startTime) { - m_startTime = av_rescale(st->cur_dts, st->time_base.num, st->time_base.den) - 0.000001; + m_startTime = + av_rescale(m_pkt.pkt.dts, st->time_base.num, st->time_base.den) - 0.000001; m_seekStream = i; } return TRANSPORT_STREAM_STATE::READY; diff -urN xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp.orig xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp --- xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp.orig 2023-03-11 22:16:38.000000000 +0000 +++ xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp 2023-04-19 10:01:22.853712000 +0000 @@ -12,6 +12,7 @@ #include "addons/addoninfo/AddonType.h" #include "addons/binary-addons/AddonDll.h" #include "addons/kodi-dev-kit/include/kodi/addon-instance/VideoCodec.h" +#include "cores/FFmpeg.h" #include "cores/VideoPlayer/DVDDemuxers/DVDDemux.h" #include "cores/VideoPlayer/DVDDemuxers/DVDDemuxUtils.h" #include "cores/VideoPlayer/Interface/DemuxCrypto.h" @@ -392,7 +393,7 @@ return nullptr; std::string codecName(stream->m_codecName); - AVCodec* codec = nullptr; + const AVCodec* codec = nullptr; if (stream->m_streamType != INPUTSTREAM_TYPE_TELETEXT && stream->m_streamType != INPUTSTREAM_TYPE_RDS && stream->m_streamType != INPUTSTREAM_TYPE_ID3) diff -urN xbmc/filesystem/AudioBookFileDirectory.cpp.orig xbmc/filesystem/AudioBookFileDirectory.cpp --- xbmc/filesystem/AudioBookFileDirectory.cpp.orig 2023-03-11 22:16:38.000000000 +0000 +++ xbmc/filesystem/AudioBookFileDirectory.cpp 2023-04-19 10:01:22.853859000 +0000 @@ -11,6 +11,7 @@ #include "TextureDatabase.h" #include "URL.h" #include "Util.h" +#include "cores/FFmpeg.h" #include "filesystem/File.h" #include "guilib/LocalizeStrings.h" #include "music/tags/MusicInfoTag.h" @@ -149,7 +150,7 @@ m_ioctx->max_packet_size = 32768; - AVInputFormat* iformat=nullptr; + const AVInputFormat* iformat = nullptr; av_probe_input_buffer(m_ioctx, &iformat, url.Get().c_str(), nullptr, 0, 0); bool contains = false; diff -urN xbmc/guilib/FFmpegImage.cpp.orig xbmc/guilib/FFmpegImage.cpp --- xbmc/guilib/FFmpegImage.cpp.orig 2023-03-11 22:16:38.000000000 +0000 +++ xbmc/guilib/FFmpegImage.cpp 2023-04-19 10:01:30.832285000 +0000 @@ -52,7 +52,7 @@ AVFrame* frame_temporary = nullptr; SwsContext* sws = nullptr; AVCodecContext* avOutctx = nullptr; - AVCodec* codec = nullptr; + const AVCodec* codec = nullptr; ~ThumbDataManagement() { av_free(intermediateBuffer); @@ -198,7 +198,7 @@ bool is_png = (bufSize > 3 && buffer[1] == 'P' && buffer[2] == 'N' && buffer[3] == 'G'); bool is_tiff = (bufSize > 2 && buffer[0] == 'I' && buffer[1] == 'I' && buffer[2] == '*'); - AVInputFormat* inp = nullptr; + const AVInputFormat* inp = nullptr; if (is_jpeg) inp = av_find_input_format("image2"); else if (m_strMimeType == "image/apng") @@ -236,7 +236,7 @@ return false; } AVCodecParameters* codec_params = m_fctx->streams[0]->codecpar; - AVCodec* codec = avcodec_find_decoder(codec_params->codec_id); + const AVCodec* codec = avcodec_find_decoder(codec_params->codec_id); m_codec_ctx = avcodec_alloc_context3(codec); if (!m_codec_ctx) { @@ -294,7 +294,15 @@ return nullptr; } //we need milliseconds - frame->pkt_duration = av_rescale_q(frame->pkt_duration, m_fctx->streams[0]->time_base, AVRational{ 1, 1000 }); + +#if LIBAVCODEC_VERSION_MAJOR < 60 + frame->pkt_duration = + av_rescale_q(frame->pkt_duration, m_fctx->streams[0]->time_base, AVRational{1, 1000}); +#else + frame->duration = + av_rescale_q(frame->duration, m_fctx->streams[0]->time_base, AVRational{1, 1000}); +#endif + m_height = frame->height; m_width = frame->width; m_originalWidth = m_width; @@ -745,7 +753,13 @@ if (avframe == nullptr) return nullptr; std::shared_ptr frame(new Frame()); + +#if LIBAVCODEC_VERSION_MAJOR < 60 frame->m_delay = (unsigned int)avframe->pkt_duration; +#else + frame->m_delay = (unsigned int)avframe->duration; +#endif + frame->m_pitch = avframe->width * 4; frame->m_pImage = (unsigned char*) av_malloc(avframe->height * frame->m_pitch); DecodeFrame(avframe, avframe->width, avframe->height, frame->m_pitch, frame->m_pImage); diff -urN xbmc/music/tags/MusicInfoTagLoaderFFmpeg.cpp.orig xbmc/music/tags/MusicInfoTagLoaderFFmpeg.cpp --- xbmc/music/tags/MusicInfoTagLoaderFFmpeg.cpp.orig 2023-03-11 22:16:38.000000000 +0000 +++ xbmc/music/tags/MusicInfoTagLoaderFFmpeg.cpp 2023-04-19 10:01:22.854258000 +0000 @@ -58,7 +58,7 @@ if (file.IoControl(IOCTRL_SEEK_POSSIBLE, NULL) != 1) ioctx->seekable = 0; - AVInputFormat* iformat=NULL; + const AVInputFormat* iformat = nullptr; av_probe_input_buffer(ioctx, &iformat, strFileName.c_str(), NULL, 0, 0); if (avformat_open_input(&fctx, strFileName.c_str(), iformat, NULL) < 0) diff -urN xbmc/video/tags/VideoTagLoaderFFmpeg.cpp.orig xbmc/video/tags/VideoTagLoaderFFmpeg.cpp --- xbmc/video/tags/VideoTagLoaderFFmpeg.cpp.orig 2023-03-11 22:16:38.000000000 +0000 +++ xbmc/video/tags/VideoTagLoaderFFmpeg.cpp 2023-04-19 10:01:22.854418000 +0000 @@ -65,7 +65,7 @@ if (m_file->IoControl(IOCTRL_SEEK_POSSIBLE, nullptr) != 1) m_ioctx->seekable = 0; - AVInputFormat* iformat = nullptr; + const AVInputFormat* iformat = nullptr; av_probe_input_buffer(m_ioctx, &iformat, m_item.GetPath().c_str(), nullptr, 0, 0); if (avformat_open_input(&m_fctx, m_item.GetPath().c_str(), iformat, nullptr) < 0) {