diff options
Diffstat (limited to 'debian/patches/workarounds/0002-ffmpeg5.patch')
-rw-r--r-- | debian/patches/workarounds/0002-ffmpeg5.patch | 2429 |
1 files changed, 2429 insertions, 0 deletions
diff --git a/debian/patches/workarounds/0002-ffmpeg5.patch b/debian/patches/workarounds/0002-ffmpeg5.patch new file mode 100644 index 0000000..64c31d2 --- /dev/null +++ b/debian/patches/workarounds/0002-ffmpeg5.patch @@ -0,0 +1,2429 @@ +From 2218c1c37c16df4ce3da34c8566f5e1335a66c01 Mon Sep 17 00:00:00 2001 +From: Alwin Esch <alwin.esch@web.de> +Date: Sun, 10 Jul 2022 18:59:52 +0200 +Subject: [PATCH 1/3] FFmpeg5 port + +--- + xbmc/cdrip/EncoderFFmpeg.cpp | 95 ++++++--------- + xbmc/cdrip/EncoderFFmpeg.h | 1 - + .../AudioEngine/Encoders/AEEncoderFFmpeg.cpp | 111 +++++++++++------- + .../AudioEngine/Engines/ActiveAE/ActiveAE.cpp | 14 +-- + xbmc/cores/FFmpeg.cpp | 14 ++- + xbmc/cores/FFmpeg.h | 26 ++++ + .../DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp | 12 +- + .../Overlay/DVDOverlayCodecFFmpeg.cpp | 3 +- + .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 36 +++++- + .../DVDCodecs/Video/DVDVideoPPFFmpeg.cpp | 5 + + .../VideoPlayer/DVDCodecs/Video/VAAPI.cpp | 10 +- + .../DVDDemuxers/DVDDemuxClient.cpp | 3 +- + .../DVDDemuxers/DVDDemuxFFmpeg.cpp | 71 +++++++++-- + .../DVDInputStreams/InputStreamAddon.cpp | 3 +- + xbmc/filesystem/AudioBookFileDirectory.cpp | 3 +- + xbmc/guilib/FFmpegImage.cpp | 6 +- + xbmc/music/tags/MusicInfoTagLoaderFFmpeg.cpp | 2 +- + xbmc/video/tags/VideoTagLoaderFFmpeg.cpp | 2 +- + 18 files changed, 281 insertions(+), 136 deletions(-) + +diff --git a/xbmc/cdrip/EncoderFFmpeg.cpp b/xbmc/cdrip/EncoderFFmpeg.cpp +index 2867b7cb67..4c0628b5cc 100644 +--- a/xbmc/cdrip/EncoderFFmpeg.cpp ++++ b/xbmc/cdrip/EncoderFFmpeg.cpp +@@ -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,23 +20,8 @@ + #include "utils/log.h" + + using namespace KODI::CDRIP; +- +-namespace +-{ +- +-struct EncoderException : public std::exception +-{ +- std::string s; +- template<typename... Args> +- EncoderException(const std::string& fmt, Args&&... args) +- : s(StringUtils::Format(fmt, std::forward<Args>(args)...)) +- { +- } +- ~EncoderException() throw() {} // Updated +- const char* what() const throw() { return s.c_str(); } +-}; +- +-} /* namespace */ ++using FFMPEG_HELP_TOOLS::FFMpegErrorToString; ++using FFMPEG_HELP_TOOLS::FFMpegException; + + bool CEncoderFFmpeg::Init() + { +@@ -54,7 +40,7 @@ bool CEncoderFFmpeg::Init() + } + 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,45 +52,45 @@ bool CEncoderFFmpeg::Init() + 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<uint8_t*>(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); ++ FFMPEG_FMT_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. */ +@@ -128,14 +114,14 @@ bool CEncoderFFmpeg::Init() + + 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,7 +136,7 @@ bool CEncoderFFmpeg::Init() + + 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; +@@ -159,8 +145,8 @@ bool CEncoderFFmpeg::Init() + + 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); + +@@ -170,14 +156,14 @@ bool CEncoderFFmpeg::Init() + m_codecCtx->sample_rate, m_codecCtx->channel_layout, m_inFormat, + m_codecCtx->sample_rate, 0, nullptr); + if (!m_swrCtx || swr_init(m_swrCtx) < 0) +- throw EncoderException("Failed to initialize the resampler"); ++ 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<uint8_t*>(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; +@@ -186,8 +172,8 @@ bool CEncoderFFmpeg::Init() + + 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 +190,7 @@ bool CEncoderFFmpeg::Init() + /* 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,7 +198,7 @@ bool CEncoderFFmpeg::Init() + : 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()); + +@@ -299,7 +285,7 @@ bool CEncoderFFmpeg::WriteFrame() + if (swr_convert(m_swrCtx, m_resampledFrame->data, m_neededFrames, + const_cast<const uint8_t**>(m_bufferFrame->extended_data), + m_neededFrames) < 0) +- throw EncoderException("Error resampling audio"); ++ throw FFMpegException("Error resampling audio"); + + frame = m_resampledFrame; + } +@@ -316,8 +302,8 @@ bool CEncoderFFmpeg::WriteFrame() + 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 +315,18 @@ bool CEncoderFFmpeg::WriteFrame() + } + 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()); + } +@@ -400,14 +385,6 @@ AVSampleFormat CEncoderFFmpeg::GetInputFormat(int inBitsPerSample) + 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 --git a/xbmc/cdrip/EncoderFFmpeg.h b/xbmc/cdrip/EncoderFFmpeg.h +index 39112ba3ba..0c2391c7ab 100644 +--- a/xbmc/cdrip/EncoderFFmpeg.h ++++ b/xbmc/cdrip/EncoderFFmpeg.h +@@ -39,7 +39,6 @@ private: + 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 --git a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp +index 09bb26a327..86f65f57f3 100644 +--- a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp ++++ b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp +@@ -10,13 +10,24 @@ + #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 <string.h> ++#include "utils/log.h" ++ ++extern "C" ++{ ++#include <libavutil/channel_layout.h> ++} ++ + #include <cassert> ++#include <string.h> ++ ++using FFMPEG_HELP_TOOLS::FFMpegErrorToString; ++using FFMPEG_HELP_TOOLS::FFMpegException; + + CAEEncoderFFmpeg::CAEEncoderFFmpeg() : m_CodecCtx(NULL), m_SwrCtx(NULL) + { +@@ -81,7 +92,7 @@ bool CAEEncoderFFmpeg::Initialize(AEAudioFormat &format, bool allow_planar_input + + bool ac3 = CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_AUDIOOUTPUT_AC3PASSTHROUGH); + +- AVCodec *codec = NULL; ++ FFMPEG_FMT_CONST AVCodec* codec = nullptr; + + /* fallback to ac3 if we support it, we might not have DTS support */ + if (ac3) +@@ -242,63 +253,77 @@ unsigned int CAEEncoderFFmpeg::GetFrames() + + 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; +- +- /* 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; ++ return size; + +- 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; ++ 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; ++ ++ avcodec_fill_audio_frame(frame, m_CodecCtx->channels, m_CodecCtx->sample_fmt, in, in_size, 0); ++ ++ pkt->size = out_size; ++ pkt->data = out; ++ ++ /* encode it */ ++ err = avcodec_send_frame(m_CodecCtx, frame); ++ if (err < 0) ++ throw FFMpegException("Error sending a frame for encoding (error '{}')", ++ FFMpegErrorToString(err)); ++ ++ while (err >= 0) ++ { ++ err = avcodec_receive_packet(m_CodecCtx, pkt); ++ if (err == AVERROR(EAGAIN) || err == AVERROR_EOF) ++ { ++ av_frame_free(&frame); ++ av_packet_free(&pkt); ++ return (err == AVERROR(EAGAIN)) ? -1 : 0; ++ } ++ else if (err < 0) ++ { ++ throw FFMpegException("Error during encoding (error '{}')", FFMpegErrorToString(err)); ++ } + +- avcodec_fill_audio_frame(frame, m_CodecCtx->channels, m_CodecCtx->sample_fmt, +- in, in_size, 0); ++ av_packet_unref(pkt); ++ } + +- /* initialize the output packet */ +- AVPacket* pkt = av_packet_alloc(); +- if (!pkt) ++ size = pkt->size; ++ } ++ 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; +- +- /* 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) + { + int size; +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp +index 3947dd5523..6000fe9c63 100644 +--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp +@@ -16,17 +16,17 @@ using namespace ActiveAE; + #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 "cores/FFmpeg.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; + +@@ -3016,8 +3016,8 @@ IAE::SoundPtr CActiveAE::MakeSound(const std::string& file) + AVFormatContext *fmt_ctx = nullptr; + AVCodecContext *dec_ctx = nullptr; + AVIOContext *io_ctx; +- AVInputFormat *io_fmt = nullptr; +- AVCodec *dec = nullptr; ++ FFMPEG_FMT_CONST AVInputFormat* io_fmt = nullptr; ++ FFMPEG_FMT_CONST AVCodec* dec = nullptr; + SampleConfig config; + + // No custom deleter until sound is registered +diff --git a/xbmc/cores/FFmpeg.cpp b/xbmc/cores/FFmpeg.cpp +index 03a29f7db4..de1765ed52 100644 +--- a/xbmc/cores/FFmpeg.cpp ++++ b/xbmc/cores/FFmpeg.cpp +@@ -21,6 +21,19 @@ + + 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(); +@@ -116,4 +129,3 @@ void ff_avutil_log(void* ptr, int level, const char* format, va_list va) + } + buffer.erase(0, start); + } +- +diff --git a/xbmc/cores/FFmpeg.h b/xbmc/cores/FFmpeg.h +index e1194d19e9..8230701ba7 100644 +--- a/xbmc/cores/FFmpeg.h ++++ b/xbmc/cores/FFmpeg.h +@@ -10,6 +10,7 @@ + + #include "ServiceBroker.h" + #include "utils/CPUInfo.h" ++#include "utils/StringUtils.h" + + extern "C" { + #include <libavcodec/avcodec.h> +@@ -21,6 +22,31 @@ extern "C" { + #include <libpostproc/postprocess.h> + } + ++// https://github.com/FFmpeg/FFmpeg/blob/56450a0ee4/doc/APIchanges#L18-L26 ++#if LIBAVFORMAT_BUILD >= AV_VERSION_INT(59, 0, 100) ++#define FFMPEG_FMT_CONST const ++#else ++#define FFMPEG_FMT_CONST ++#endif ++ ++namespace FFMPEG_HELP_TOOLS ++{ ++ ++struct FFMpegException : public std::exception ++{ ++ std::string s; ++ template<typename... Args> ++ FFMpegException(const std::string& fmt, Args&&... args) ++ : s(StringUtils::Format(fmt, std::forward<Args>(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(); +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp +index 25f3f08e1f..87e7ae2c57 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp +@@ -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 <libavutil/opt.h> +@@ -44,7 +46,7 @@ bool CDVDAudioCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options + return false; + } + +- AVCodec* pCodec = NULL; ++ FFMPEG_FMT_CONST AVCodec* pCodec = nullptr; + bool allowdtshddecode = true; + + // set any special options +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Overlay/DVDOverlayCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Overlay/DVDOverlayCodecFFmpeg.cpp +index 8c26cad306..3657fc093c 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Overlay/DVDOverlayCodecFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Overlay/DVDOverlayCodecFFmpeg.cpp +@@ -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 @@ bool CDVDOverlayCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &optio + if (hints.codec == AV_CODEC_ID_EIA_608) + return false; + +- AVCodec* pCodec = avcodec_find_decoder(hints.codec); ++ FFMPEG_FMT_CONST AVCodec* pCodec = avcodec_find_decoder(hints.codec); + if (!pCodec) + { + CLog::Log(LOGDEBUG, "{} - Unable to find codec {}", __FUNCTION__, hints.codec); +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +index 881c02ec12..21b5e834b2 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +@@ -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 <mutex> + + extern "C" { +-#include <libavutil/opt.h> +-#include <libavutil/mastering_display_metadata.h> + #include <libavfilter/avfilter.h> + #include <libavfilter/buffersink.h> + #include <libavfilter/buffersrc.h> ++#include <libavutil/mastering_display_metadata.h> ++#include <libavutil/opt.h> + #include <libavutil/pixdesc.h> ++#include <libavutil/video_enc_params.h> + } + + #ifndef TARGET_POSIX +@@ -327,7 +329,7 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options + m_hints = hints; + m_options = options; + +- AVCodec* pCodec = nullptr; ++ FFMPEG_FMT_CONST AVCodec* pCodec = nullptr; + + m_iOrientation = hints.orientation; + +@@ -1048,6 +1050,33 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(VideoPicture* pVideoPicture) + pVideoPicture->qscale_type = 0; + + AVFrameSideData* sd; ++ ++ // https://github.com/FFmpeg/FFmpeg/blob/991d417692/doc/APIchanges#L18-L20 ++ // basilgello: AV_VIDEO_ENC_PARAMS_MPEG2 is introduced in 4.4! ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(58, 134, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(56, 45, 100) ++ sd = av_frame_get_side_data(m_pFrame, AV_FRAME_DATA_VIDEO_ENC_PARAMS); ++ if (sd) ++ { ++ 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 par = reinterpret_cast<AVVideoEncParams*>(sd->data); ++ if (par->type == AV_VIDEO_ENC_PARAMS_MPEG2 && (par->nb_blocks == 0 || par->nb_blocks == nb_mb)) ++ { ++ pVideoPicture->qstride = mb_w; ++ pVideoPicture->qscale_type = par->type; ++ pVideoPicture->qp_table = static_cast<int8_t*>(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; ++ } ++ } ++ } ++#else + sd = av_frame_get_side_data(m_pFrame, AV_FRAME_DATA_QP_TABLE_PROPERTIES); + if (sd) + { +@@ -1068,6 +1097,7 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(VideoPicture* pVideoPicture) + pVideoPicture->qscale_type = qp->type; + } + } ++#endif + + pVideoPicture->pict_type = m_pFrame->pict_type; + +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoPPFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoPPFFmpeg.cpp +index a98fbb1710..3b2739cd22 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoPPFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoPPFFmpeg.cpp +@@ -118,6 +118,11 @@ void CDVDVideoPPFFmpeg::Process(VideoPicture* pPicture) + 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 ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(58, 84, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(56, 45, 100) ++ av_free(pSource->qp_table); ++#endif + + pPicture->SetParams(*pSource); + if (pPicture->videoBuffer) +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp +index 7ad891083c..eaf7b78d32 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp +@@ -1259,8 +1259,16 @@ void CDecoder::ReturnRenderPicture(CVaapiRenderPicture *renderPic) + + 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 LIBAVUTIL_BUILD >= AV_VERSION_INT(55, 8, 0) ++#define PIX_FMT_VAAPI AV_PIX_FMT_VAAPI ++#else ++#define PIX_FMT_VAAPI AV_PIX_FMT_VAAPI_VLD ++#endif ++ if (fmt == PIX_FMT_VAAPI && ++ CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(SETTING_VIDEOPLAYER_USEVAAPI)) + return new VAAPI::CDecoder(processInfo); ++#undef PIX_FMT_VAAPI + + return nullptr; + } +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +index 2bdc3ea5a9..5be134e381 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +@@ -10,6 +10,7 @@ + + #include "DVDDemuxUtils.h" + #include "DVDInputStreams/DVDInputStream.h" ++#include "cores/FFmpeg.h" + #include "cores/VideoPlayer/Interface/TimingConstants.h" + #include "utils/log.h" + +@@ -130,7 +131,7 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) + + if (stream->m_context == nullptr) + { +- AVCodec *codec = avcodec_find_decoder(st->codec); ++ FFMPEG_FMT_CONST AVCodec* codec = avcodec_find_decoder(st->codec); + if (codec == nullptr) + { + CLog::Log(LOGERROR, "{} - can't find decoder", __FUNCTION__); +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +index 739bf51922..bf6f322274 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +@@ -38,6 +38,7 @@ + + extern "C" + { ++#include "libavutil/channel_layout.h" + #include "libavutil/pixdesc.h" + } + +@@ -235,7 +236,7 @@ bool CDVDDemuxFFmpeg::Aborted() + + bool CDVDDemuxFFmpeg::Open(const std::shared_ptr<CDVDInputStream>& pInput, bool fileinfo) + { +- AVInputFormat* iformat = NULL; ++ FFMPEG_FMT_CONST AVInputFormat* iformat = nullptr; + std::string strFile; + m_streaminfo = !pInput->IsRealtime() && !m_reopen; + m_reopen = false; +@@ -422,9 +423,7 @@ bool CDVDDemuxFFmpeg::Open(const std::shared_ptr<CDVDInputStream>& pInput, bool + // 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"); +- ++ FFMPEG_FMT_CONST AVInputFormat* iformat2 = av_find_input_format("spdif"); + if (iformat2 && iformat2->read_probe(&pd) > AVPROBE_SCORE_MAX / 4) + { + iformat = iformat2; +@@ -544,11 +543,14 @@ bool CDVDDemuxFFmpeg::Open(const std::shared_ptr<CDVDInputStream>& pInput, bool + m_streaminfo = true; + } + ++ // https://github.com/FFmpeg/FFmpeg/blob/56450a0ee4/doc/APIchanges#L18-L26 ++#if LIBAVFORMAT_BUILD < AV_VERSION_INT(59, 0, 100) + if (iformat && (strcmp(iformat->name, "mov,mp4,m4a,3gp,3g2,mj2") == 0)) + { + if (URIUtils::IsRemote(strFile)) + m_pFormatContext->iformat->flags |= AVFMT_NOGENSEARCH; + } ++#endif + + // 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" +@@ -604,8 +606,11 @@ bool CDVDDemuxFFmpeg::Open(const std::shared_ptr<CDVDInputStream>& pInput, bool + // if format can be nonblocking, let's use that + m_pFormatContext->flags |= AVFMT_FLAG_NONBLOCK; + +- // deprecated, will be always set in future versions ++ // https://github.com/FFmpeg/FFmpeg/blob/d682ae70b4/doc/APIchanges#L18-L21 ++#if LIBAVFORMAT_BUILD < AV_VERSION_INT(57, 66, 105) && \ ++ LIBAVCODEC_BUILD < AV_VERSION_INT(57, 83, 101) + m_pFormatContext->flags |= AVFMT_FLAG_KEEP_SIDE_DATA; ++#endif + + UpdateCurrentPTS(); + +@@ -647,12 +652,24 @@ bool CDVDDemuxFFmpeg::Open(const std::shared_ptr<CDVDInputStream>& pInput, bool + { + int idx = m_pFormatContext->programs[i]->stream_index[j]; + AVStream* st = m_pFormatContext->streams[idx]; ++#if LIBAVFORMAT_BUILD >= AV_VERSION_INT(59, 3, 100) ++ // 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; ++ break; ++ } ++#else + if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && st->codec_info_nb_frames > 0) || + (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && st->codecpar->sample_rate > 0)) + { + nProgram = i; + break; + } ++#endif + } + } + } +@@ -1401,11 +1418,19 @@ void CDVDDemuxFFmpeg::UpdateCurrentPTS() + if (idx >= 0) + { + AVStream* stream = m_pFormatContext->streams[idx]; ++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100) ++ if (stream && m_pkt.pkt.dts != (int64_t)AV_NOPTS_VALUE) ++ { ++ double ts = ConvertTimestamp(m_pkt.pkt.dts, stream->time_base.den, stream->time_base.num); ++ m_currentPts = ts; ++ } ++#else + if (stream && stream->cur_dts != (int64_t)AV_NOPTS_VALUE) + { + double ts = ConvertTimestamp(stream->cur_dts, stream->time_base.den, stream->time_base.num); + m_currentPts = ts; + } ++#endif + } + } + +@@ -1621,7 +1646,12 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) + st->iBitsPerSample = pStream->codecpar->bits_per_raw_sample; + st->iChannelLayout = pStream->codecpar->channel_layout; + char buf[32] = {}; ++ // https://github.com/FFmpeg/FFmpeg/blob/6ccc3989d15/doc/APIchanges#L50-L53 ++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 24, 100) ++ av_channel_layout_describe(st->iChannelLayout, buf, sizeof(buf)); ++#else + av_get_channel_layout_string(buf, 31, st->iChannels, st->iChannelLayout); ++#endif + st->m_channelLayoutName = buf; + if (st->iBitsPerSample == 0) + st->iBitsPerSample = pStream->codecpar->bits_per_coded_sample; +@@ -1663,6 +1693,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) + st->iFpsScale = 0; + } + ++#if LIBAVFORMAT_BUILD < AV_VERSION_INT(59, 3, 100) + if (pStream->codec_info_nb_frames > 0 && + pStream->codec_info_nb_frames <= 2 && + m_pInput->IsStreamType(DVDSTREAM_TYPE_DVD)) +@@ -1672,6 +1703,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) + st->iFpsRate = 0; + st->iFpsScale = 0; + } ++#endif + + st->iWidth = pStream->codecpar->width; + st->iHeight = pStream->codecpar->height; +@@ -1693,7 +1725,12 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) + st->colorRange = pStream->codecpar->color_range; + st->hdr_type = DetermineHdrType(pStream); + ++ // https://github.com/FFmpeg/FFmpeg/blob/release/5.0/doc/APIchanges ++#if LIBAVFORMAT_BUILD >= AV_VERSION_INT(59, 10, 100) ++ size_t size = 0; ++#else + int size = 0; ++#endif + uint8_t* side_data = nullptr; + + side_data = av_stream_get_side_data(pStream, AV_PKT_DATA_MASTERING_DISPLAY_METADATA, &size); +@@ -2103,7 +2140,7 @@ std::string CDVDDemuxFFmpeg::GetStreamCodecName(int iStreamId) + return strName; + } + +- AVCodec* codec = avcodec_find_decoder(stream->codec); ++ FFMPEG_FMT_CONST AVCodec* codec = avcodec_find_decoder(stream->codec); + if (codec) + strName = avcodec_get_name(codec->id); + } +@@ -2279,7 +2316,7 @@ void CDVDDemuxFFmpeg::ParsePacket(AVPacket* pkt) + + parser->second->m_parserCtx = av_parser_init(st->codecpar->codec_id); + +- AVCodec* codec = avcodec_find_decoder(st->codecpar->codec_id); ++ FFMPEG_FMT_CONST AVCodec* codec = avcodec_find_decoder(st->codecpar->codec_id); + if (codec == nullptr) + { + CLog::Log(LOGERROR, "{} - can't find decoder", __FUNCTION__); +@@ -2357,7 +2394,12 @@ TRANSPORT_STREAM_STATE CDVDDemuxFFmpeg::TransportStreamAudioState() + { + if (!m_startTime) + { ++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100) ++ m_startTime = ++ av_rescale(m_pkt.pkt.dts, st->time_base.num, st->time_base.den) - 0.000001; ++#else + m_startTime = av_rescale(st->cur_dts, st->time_base.num, st->time_base.den) - 0.000001; ++#endif + m_seekStream = idx; + } + return TRANSPORT_STREAM_STATE::READY; +@@ -2377,7 +2419,12 @@ TRANSPORT_STREAM_STATE CDVDDemuxFFmpeg::TransportStreamAudioState() + { + if (!m_startTime) + { ++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100) ++ m_startTime = ++ av_rescale(m_pkt.pkt.dts, st->time_base.num, st->time_base.den) - 0.000001; ++#else + m_startTime = av_rescale(st->cur_dts, st->time_base.num, st->time_base.den) - 0.000001; ++#endif + m_seekStream = i; + } + return TRANSPORT_STREAM_STATE::READY; +@@ -2410,7 +2457,12 @@ TRANSPORT_STREAM_STATE CDVDDemuxFFmpeg::TransportStreamVideoState() + { + if (!m_startTime) + { ++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100) ++ m_startTime = ++ av_rescale(m_pkt.pkt.dts, st->time_base.num, st->time_base.den) - 0.000001; ++#else + m_startTime = av_rescale(st->cur_dts, st->time_base.num, st->time_base.den) - 0.000001; ++#endif + m_seekStream = idx; + } + return TRANSPORT_STREAM_STATE::READY; +@@ -2430,7 +2482,12 @@ TRANSPORT_STREAM_STATE CDVDDemuxFFmpeg::TransportStreamVideoState() + { + if (!m_startTime) + { ++#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100) ++ m_startTime = ++ av_rescale(m_pkt.pkt.dts, st->time_base.num, st->time_base.den) - 0.000001; ++#else + m_startTime = av_rescale(st->cur_dts, st->time_base.num, st->time_base.den) - 0.000001; ++#endif + m_seekStream = i; + } + return TRANSPORT_STREAM_STATE::READY; +diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp +index b8494e504e..392853cc68 100644 +--- a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp ++++ b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamAddon.cpp +@@ -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 @@ KODI_HANDLE CInputStreamAddon::cb_get_stream_transfer(KODI_HANDLE handle, + return nullptr; + + std::string codecName(stream->m_codecName); +- AVCodec* codec = nullptr; ++ FFMPEG_FMT_CONST AVCodec* codec = nullptr; + + if (stream->m_streamType != INPUTSTREAM_TYPE_TELETEXT && + stream->m_streamType != INPUTSTREAM_TYPE_RDS && stream->m_streamType != INPUTSTREAM_TYPE_ID3) +diff --git a/xbmc/filesystem/AudioBookFileDirectory.cpp b/xbmc/filesystem/AudioBookFileDirectory.cpp +index 04d1c14343..d82b2a9bbd 100644 +--- a/xbmc/filesystem/AudioBookFileDirectory.cpp ++++ b/xbmc/filesystem/AudioBookFileDirectory.cpp +@@ -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 @@ bool CAudioBookFileDirectory::ContainsFiles(const CURL& url) + + m_ioctx->max_packet_size = 32768; + +- AVInputFormat* iformat=nullptr; ++ FFMPEG_FMT_CONST AVInputFormat* iformat = nullptr; + av_probe_input_buffer(m_ioctx, &iformat, url.Get().c_str(), nullptr, 0, 0); + + bool contains = false; +diff --git a/xbmc/guilib/FFmpegImage.cpp b/xbmc/guilib/FFmpegImage.cpp +index fa255278b7..9d01a21f38 100644 +--- a/xbmc/guilib/FFmpegImage.cpp ++++ b/xbmc/guilib/FFmpegImage.cpp +@@ -52,7 +52,7 @@ struct ThumbDataManagement + AVFrame* frame_temporary = nullptr; + SwsContext* sws = nullptr; + AVCodecContext* avOutctx = nullptr; +- AVCodec* codec = nullptr; ++ FFMPEG_FMT_CONST AVCodec* codec = nullptr; + ~ThumbDataManagement() + { + av_free(intermediateBuffer); +@@ -198,7 +198,7 @@ bool CFFmpegImage::Initialize(unsigned char* buffer, size_t bufSize) + 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; ++ FFMPEG_FMT_CONST AVInputFormat* inp = nullptr; + if (is_jpeg) + inp = av_find_input_format("image2"); + else if (m_strMimeType == "image/apng") +@@ -236,7 +236,7 @@ bool CFFmpegImage::Initialize(unsigned char* buffer, size_t bufSize) + return false; + } + AVCodecParameters* codec_params = m_fctx->streams[0]->codecpar; +- AVCodec* codec = avcodec_find_decoder(codec_params->codec_id); ++ FFMPEG_FMT_CONST AVCodec* codec = avcodec_find_decoder(codec_params->codec_id); + m_codec_ctx = avcodec_alloc_context3(codec); + if (!m_codec_ctx) + { +diff --git a/xbmc/music/tags/MusicInfoTagLoaderFFmpeg.cpp b/xbmc/music/tags/MusicInfoTagLoaderFFmpeg.cpp +index 9bb2cdc09b..dbd8893c97 100644 +--- a/xbmc/music/tags/MusicInfoTagLoaderFFmpeg.cpp ++++ b/xbmc/music/tags/MusicInfoTagLoaderFFmpeg.cpp +@@ -58,7 +58,7 @@ bool CMusicInfoTagLoaderFFmpeg::Load(const std::string& strFileName, CMusicInfoT + if (file.IoControl(IOCTRL_SEEK_POSSIBLE, NULL) != 1) + ioctx->seekable = 0; + +- AVInputFormat* iformat=NULL; ++ FFMPEG_FMT_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 --git a/xbmc/video/tags/VideoTagLoaderFFmpeg.cpp b/xbmc/video/tags/VideoTagLoaderFFmpeg.cpp +index c1b0495179..5564696be6 100644 +--- a/xbmc/video/tags/VideoTagLoaderFFmpeg.cpp ++++ b/xbmc/video/tags/VideoTagLoaderFFmpeg.cpp +@@ -65,7 +65,7 @@ CVideoTagLoaderFFmpeg::CVideoTagLoaderFFmpeg(const CFileItem& item, + if (m_file->IoControl(IOCTRL_SEEK_POSSIBLE, nullptr) != 1) + m_ioctx->seekable = 0; + +- AVInputFormat* iformat = nullptr; ++ FFMPEG_FMT_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) + { +-- +2.35.1 + + +From 3de036ef45b0df3368997500d210090a7f6ff5e7 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Thu, 13 Oct 2022 04:56:26 +0000 +Subject: [PATCH 2/3] Use Channel Layout API if built against FFmpeg 5.1 + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/cdrip/EncoderFFmpeg.cpp | 51 +++++++++++++ + .../AudioEngine/Encoders/AEEncoderFFmpeg.cpp | 60 ++++++++++++++- + .../AudioEngine/Engines/ActiveAE/ActiveAE.cpp | 22 ++++++ + .../Engines/ActiveAE/ActiveAEFilter.cpp | 38 +++++++++- + .../ActiveAE/ActiveAEResampleFFMPEG.cpp | 55 +++++++++++++- + .../Engines/ActiveAE/ActiveAEStream.cpp | 2 +- + xbmc/cores/AudioEngine/Utils/AEUtil.cpp | 73 +++++++++++++++++-- + xbmc/cores/AudioEngine/Utils/AEUtil.h | 9 ++- + .../DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp | 58 ++++++++++++--- + .../DVDDemuxers/DVDDemuxClient.cpp | 15 +++- + .../DVDDemuxers/DVDDemuxFFmpeg.cpp | 42 +++++++++-- + 11 files changed, 388 insertions(+), 37 deletions(-) + +diff --git a/xbmc/cdrip/EncoderFFmpeg.cpp b/xbmc/cdrip/EncoderFFmpeg.cpp +index 4c0628b5cc..c05cdeab9e 100644 +--- a/xbmc/cdrip/EncoderFFmpeg.cpp ++++ b/xbmc/cdrip/EncoderFFmpeg.cpp +@@ -94,8 +94,14 @@ bool CEncoderFFmpeg::Init() + + /* Set the basic encoder parameters. + * The input file's sample rate is used to avoid a sample rate conversion. */ ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_codecCtx->ch_layout); ++ av_channel_layout_default(&m_codecCtx->ch_layout, m_iInChannels); ++#else + m_codecCtx->channels = m_iInChannels; + m_codecCtx->channel_layout = av_get_default_channel_layout(m_iInChannels); ++#endif + m_codecCtx->sample_rate = m_iInSampleRate; + m_codecCtx->sample_fmt = codec->sample_fmts[0]; + m_codecCtx->bit_rate = bitrate; +@@ -140,7 +146,14 @@ bool CEncoderFFmpeg::Init() + + m_bufferFrame->nb_samples = m_codecCtx->frame_size; + m_bufferFrame->format = m_inFormat; ++ ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_bufferFrame->ch_layout); ++ av_channel_layout_copy(&m_bufferFrame->ch_layout, &m_codecCtx->ch_layout); ++#else + m_bufferFrame->channel_layout = m_codecCtx->channel_layout; ++#endif + m_bufferFrame->sample_rate = m_codecCtx->sample_rate; + + err = av_frame_get_buffer(m_bufferFrame, 0); +@@ -152,10 +165,18 @@ bool CEncoderFFmpeg::Init() + + if (m_needConversion) + { ++#if LIBSWRESAMPLE_BUILD >= AV_VERSION_INT(4, 7, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ 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 (ret || swr_init(m_swrCtx) < 0) ++#else + m_swrCtx = swr_alloc_set_opts(nullptr, m_codecCtx->channel_layout, m_outFormat, + m_codecCtx->sample_rate, m_codecCtx->channel_layout, m_inFormat, + m_codecCtx->sample_rate, 0, nullptr); + if (!m_swrCtx || swr_init(m_swrCtx) < 0) ++#endif + throw FFMpegException("Failed to initialize the resampler"); + + m_resampledBufferSize = +@@ -167,7 +188,13 @@ bool CEncoderFFmpeg::Init() + + m_resampledFrame->nb_samples = m_neededFrames; + m_resampledFrame->format = m_outFormat; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_resampledFrame->ch_layout); ++ av_channel_layout_copy(&m_resampledFrame->ch_layout, &m_codecCtx->ch_layout); ++#else + m_resampledFrame->channel_layout = m_codecCtx->channel_layout; ++#endif + m_resampledFrame->sample_rate = m_codecCtx->sample_rate; + + err = av_frame_get_buffer(m_resampledFrame, 0); +@@ -203,11 +230,23 @@ bool CEncoderFFmpeg::Init() + CLog::Log(LOGERROR, "CEncoderFFmpeg::{} - {}", __func__, caught.what()); + + av_freep(&m_buffer); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_bufferFrame->ch_layout); ++#endif + av_frame_free(&m_bufferFrame); + swr_free(&m_swrCtx); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_resampledFrame->ch_layout); ++#endif + av_frame_free(&m_resampledFrame); + av_freep(&m_resampledBuffer); + av_free(m_bcBuffer); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_codecCtx->ch_layout); ++#endif + avcodec_free_context(&m_codecCtx); + if (m_formatCtx) + { +@@ -351,8 +390,16 @@ bool CEncoderFFmpeg::Close() + + /* Flush if needed */ + av_freep(&m_buffer); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_bufferFrame->ch_layout); ++#endif + av_frame_free(&m_bufferFrame); + swr_free(&m_swrCtx); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_resampledFrame->ch_layout); ++#endif + av_frame_free(&m_resampledFrame); + av_freep(&m_resampledBuffer); + m_needConversion = false; +@@ -364,6 +411,10 @@ bool CEncoderFFmpeg::Close() + + /* cleanup */ + av_free(m_bcBuffer); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_codecCtx->ch_layout); ++#endif + avcodec_free_context(&m_codecCtx); + av_freep(&m_formatCtx->pb); + avformat_free_context(m_formatCtx); +diff --git a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp +index 86f65f57f3..5d8ca71de1 100644 +--- a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp ++++ b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp +@@ -37,6 +37,10 @@ CAEEncoderFFmpeg::~CAEEncoderFFmpeg() + { + Reset(); + swr_free(&m_SwrCtx); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_CodecCtx->ch_layout); ++#endif + avcodec_free_context(&m_CodecCtx); + } + +@@ -113,7 +117,13 @@ bool CAEEncoderFFmpeg::Initialize(AEAudioFormat &format, bool allow_planar_input + + m_CodecCtx->bit_rate = m_BitRate; + m_CodecCtx->sample_rate = format.m_sampleRate; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_CodecCtx->ch_layout); ++ av_channel_layout_from_mask(&m_CodecCtx->ch_layout, AV_CH_LAYOUT_5POINT1_BACK); ++#else + m_CodecCtx->channel_layout = AV_CH_LAYOUT_5POINT1_BACK; ++#endif + + /* select a suitable data format */ + if (codec->sample_fmts) +@@ -190,22 +200,44 @@ bool CAEEncoderFFmpeg::Initialize(AEAudioFormat &format, bool allow_planar_input + LOGERROR, + "CAEEncoderFFmpeg::Initialize - Unable to find a suitable data format for the codec ({})", + m_CodecName); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_CodecCtx->ch_layout); ++#endif + avcodec_free_context(&m_CodecCtx); + return false; + } + } + ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ 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); ++#else + m_CodecCtx->channels = BuildChannelLayout(m_CodecCtx->channel_layout, m_Layout); ++#endif + + /* open the codec */ + if (avcodec_open2(m_CodecCtx, codec, NULL)) + { ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_CodecCtx->ch_layout); ++#endif + 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); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int channels = m_CodecCtx->ch_layout.nb_channels; ++#else ++ int channels = m_CodecCtx->channels; ++#endif ++ format.m_frameSize = channels * (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3); + format.m_channelLayout = m_Layout; + + m_CurrentFormat = format; +@@ -215,14 +247,26 @@ bool CAEEncoderFFmpeg::Initialize(AEAudioFormat &format, bool allow_planar_input + + if (m_NeedConversion) + { ++#if LIBSWRESAMPLE_BUILD >= AV_VERSION_INT(4, 7, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ 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) ++#else + 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) ++#endif + { + CLog::Log(LOGERROR, "CAEEncoderFFmpeg::Initialize - Failed to initialise resampler."); + swr_free(&m_SwrCtx); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_CodecCtx->ch_layout); ++#endif + avcodec_free_context(&m_CodecCtx); + return false; + } +@@ -276,10 +320,18 @@ int CAEEncoderFFmpeg::Encode(uint8_t *in, int in_size, uint8_t *out, int out_siz + + frame->nb_samples = m_CodecCtx->frame_size; + frame->format = m_CodecCtx->sample_fmt; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ 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; ++#else + frame->channel_layout = m_CodecCtx->channel_layout; + frame->channels = m_CodecCtx->channels; ++ int channelNum = m_CodecCtx->channels; ++#endif + +- 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); + + pkt->size = out_size; + pkt->data = out; +@@ -295,6 +347,10 @@ int CAEEncoderFFmpeg::Encode(uint8_t *in, int in_size, uint8_t *out, int out_siz + err = avcodec_receive_packet(m_CodecCtx, pkt); + if (err == AVERROR(EAGAIN) || err == AVERROR_EOF) + { ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&frame->ch_layout); ++#endif + av_frame_free(&frame); + av_packet_free(&pkt); + return (err == AVERROR(EAGAIN)) ? -1 : 0; +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp +index 6000fe9c63..9cd3bddda8 100644 +--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp +@@ -3069,8 +3069,14 @@ IAE::SoundPtr CActiveAE::MakeSound(const std::string& file) + AVCodecID codecId = fmt_ctx->streams[0]->codecpar->codec_id; + dec = avcodec_find_decoder(codecId); + config.sample_rate = fmt_ctx->streams[0]->codecpar->sample_rate; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ config.channels = fmt_ctx->streams[0]->codecpar->ch_layout.nb_channels; ++ config.channel_layout = fmt_ctx->streams[0]->codecpar->ch_layout.u.mask; ++#else + config.channels = fmt_ctx->streams[0]->codecpar->channels; + config.channel_layout = fmt_ctx->streams[0]->codecpar->channel_layout; ++#endif + } + } + if (dec == nullptr) +@@ -3086,10 +3092,22 @@ IAE::SoundPtr CActiveAE::MakeSound(const std::string& file) + + dec_ctx = avcodec_alloc_context3(dec); + dec_ctx->sample_rate = config.sample_rate; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ AVChannelLayout layout = {}; ++ if (!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); ++#else + dec_ctx->channels = config.channels; + if (!config.channel_layout) + config.channel_layout = av_get_default_channel_layout(config.channels); + dec_ctx->channel_layout = config.channel_layout; ++#endif + + AVPacket* avpkt = av_packet_alloc(); + if (!avpkt) +@@ -3156,6 +3174,10 @@ IAE::SoundPtr CActiveAE::MakeSound(const std::string& file) + + av_packet_free(&avpkt); + av_frame_free(&decoded_frame); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&dec_ctx->ch_layout); ++#endif + avcodec_free_context(&dec_ctx); + avformat_close_input(&fmt_ctx); + if (io_ctx) +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEFilter.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEFilter.cpp +index 26b669a2cf..1d79dc6db4 100644 +--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEFilter.cpp ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEFilter.cpp +@@ -12,10 +12,11 @@ + #include <algorithm> + + extern "C" { +-#include <libavfilter/avfilter.h> + #include <libavcodec/avcodec.h> ++#include <libavfilter/avfilter.h> + #include <libavfilter/buffersink.h> + #include <libavfilter/buffersrc.h> ++#include <libavutil/version.h> + #include <libswresample/swresample.h> + } + +@@ -171,7 +172,13 @@ void CActiveAEFilter::CloseFilter() + } + + if (m_pOutFrame) ++ { ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_pOutFrame->ch_layout); ++#endif + av_frame_free(&m_pOutFrame); ++ } + + if (m_pConvertFrame) + av_frame_free(&m_pConvertFrame); +@@ -205,10 +212,17 @@ int CActiveAEFilter::ProcessFilter(uint8_t **dst_buffer, int dst_samples, uint8_ + if (!frame) + return -1; + ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&frame->ch_layout); ++ av_channel_layout_from_mask(&frame->ch_layout, m_channelLayout); ++ int channels = frame->ch_layout.nb_channels; ++#else + int channels = av_get_channel_layout_nb_channels(m_channelLayout); + + frame->channel_layout = m_channelLayout; + frame->channels = channels; ++#endif + frame->sample_rate = m_sampleRate; + frame->nb_samples = src_samples; + frame->format = m_sampleFormat; +@@ -224,6 +238,10 @@ int CActiveAEFilter::ProcessFilter(uint8_t **dst_buffer, int dst_samples, uint8_ + src_buffer[0], src_bufsize, 16); + if (result < 0) + { ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&frame->ch_layout); ++#endif + av_frame_free(&frame); + CLog::Log(LOGERROR, "CActiveAEFilter::ProcessFilter - avcodec_fill_audio_frame failed"); + m_filterEof = true; +@@ -231,6 +249,10 @@ int CActiveAEFilter::ProcessFilter(uint8_t **dst_buffer, int dst_samples, uint8_ + } + + result = av_buffersrc_write_frame(m_pFilterCtxIn, frame); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&frame->ch_layout); ++#endif + av_frame_free(&frame); + if (result < 0) + { +@@ -284,7 +306,13 @@ int CActiveAEFilter::ProcessFilter(uint8_t **dst_buffer, int dst_samples, uint8_ + { + av_frame_unref(m_pOutFrame); + m_pOutFrame->format = m_sampleFormat; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_pOutFrame->ch_layout); ++ av_channel_layout_from_mask(&m_pOutFrame->ch_layout, m_channelLayout); ++#else + m_pOutFrame->channel_layout = m_channelLayout; ++#endif + m_pOutFrame->sample_rate = m_sampleRate; + result = swr_convert_frame(m_pConvertCtx, m_pOutFrame, m_pConvertFrame); + av_frame_unref(m_pConvertFrame); +@@ -302,7 +330,15 @@ int CActiveAEFilter::ProcessFilter(uint8_t **dst_buffer, int dst_samples, uint8_ + + if (m_hasData) + { ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ AVChannelLayout layout = {}; ++ av_channel_layout_from_mask(&layout, m_channelLayout); ++ int channels = layout.nb_channels; ++ av_channel_layout_uninit(&layout); ++#else + int channels = av_get_channel_layout_nb_channels(m_channelLayout); ++#endif + 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 --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp +index bfef837114..379dfe6446 100644 +--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp +@@ -11,8 +11,10 @@ + #include "utils/log.h" + + extern "C" { ++#include <libavcodec/version.h> + #include <libavutil/channel_layout.h> + #include <libavutil/opt.h> ++#include <libavutil/version.h> + #include <libswresample/swresample.h> + } + +@@ -49,15 +51,49 @@ bool CActiveAEResampleFFMPEG::Init(SampleConfig dstConfig, SampleConfig srcConfi + m_doesResample = true; + + if (m_dst_chan_layout == 0) ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ { ++ AVChannelLayout layout = {}; ++ av_channel_layout_default(&layout, m_dst_channels); ++ m_dst_chan_layout = layout.u.mask; ++ av_channel_layout_uninit(&layout); ++ } ++#else + m_dst_chan_layout = av_get_default_channel_layout(m_dst_channels); ++#endif + if (m_src_chan_layout == 0) ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ { ++ AVChannelLayout layout = {}; ++ av_channel_layout_default(&layout, m_src_channels); ++ m_src_chan_layout = layout.u.mask; ++ av_channel_layout_uninit(&layout); ++ } ++#else + m_src_chan_layout = av_get_default_channel_layout(m_src_channels); ++#endif ++ ++#if LIBSWRESAMPLE_BUILD >= AV_VERSION_INT(4, 7, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ AVChannelLayout dstChLayout = {}; ++ AVChannelLayout srcChLayout = {}; + ++ 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) ++#else + 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); + + if (!m_pContext) ++#endif + { + CLog::Log(LOGERROR, "CActiveAEResampleFFMPEG::Init - create context failed"); + return false; +@@ -126,10 +162,20 @@ bool CActiveAEResampleFFMPEG::Init(SampleConfig dstConfig, SampleConfig srcConfi + else if (upmix && m_src_channels == 2 && m_dst_channels > 2) + { + memset(m_rematrix, 0, sizeof(m_rematrix)); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&dstChLayout); ++ av_channel_layout_from_mask(&dstChLayout, m_dst_chan_layout); ++#endif + for (int out=0; out<m_dst_channels; out++) + { +- uint64_t out_chan = av_channel_layout_extract_channel(m_dst_chan_layout, out); +- switch(out_chan) ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ AVChannel outChan = av_channel_layout_channel_from_index(&dstChLayout, out); ++#else ++ uint64_t outChan = av_channel_layout_extract_channel(m_dst_chan_layout, out); ++#endif ++ switch (outChan) + { + case AV_CH_FRONT_LEFT: + case AV_CH_BACK_LEFT: +@@ -154,6 +200,11 @@ bool CActiveAEResampleFFMPEG::Init(SampleConfig dstConfig, SampleConfig srcConfi + } + } + ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&dstChLayout); ++#endif ++ + if (swr_set_matrix(m_pContext, (const double*)m_rematrix, AE_CH_MAX) < 0) + { + CLog::Log(LOGERROR, "CActiveAEResampleFFMPEG::Init - setting channel matrix failed"); +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp +index 858b0f2f22..a52ac2829f 100644 +--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp +@@ -88,7 +88,7 @@ void CActiveAEStream::InitRemapper() + for(unsigned int i=0; i<m_format.m_channelLayout.Count(); i++) + { + avLast = avCur; +- avCur = CAEUtil::GetAVChannel(m_format.m_channelLayout[i]); ++ avCur = CAEUtil::GetAVChannelMask(m_format.m_channelLayout[i]); + if(avCur < avLast) + { + needRemap = true; +diff --git a/xbmc/cores/AudioEngine/Utils/AEUtil.cpp b/xbmc/cores/AudioEngine/Utils/AEUtil.cpp +index bfa2cf9e4c..98f82816ef 100644 +--- a/xbmc/cores/AudioEngine/Utils/AEUtil.cpp ++++ b/xbmc/cores/AudioEngine/Utils/AEUtil.cpp +@@ -19,10 +19,6 @@ + #include <xmmintrin.h> + #endif + +-extern "C" { +-#include <libavutil/channel_layout.h> +-} +- + void AEDelayStatus::SetDelay(double d) + { + delay = d; +@@ -550,8 +546,15 @@ AVSampleFormat CAEUtil::GetAVSampleFormat(AEDataFormat format) + } + } + +-uint64_t CAEUtil::GetAVChannel(enum AEChannel aechannel) ++uint64_t CAEUtil::GetAVChannelMask(enum AEChannel aechannel) + { ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ enum AVChannel ch = GetAVChannel(aechannel); ++ if (ch == AV_CHAN_NONE) ++ return 0; ++ return (1ULL << ch); ++#else + switch (aechannel) + { + case AE_CH_FL: return AV_CH_FRONT_LEFT; +@@ -575,9 +578,67 @@ uint64_t CAEUtil::GetAVChannel(enum AEChannel aechannel) + default: + return 0; + } ++#endif + } + ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++enum AVChannel CAEUtil::GetAVChannel(enum AEChannel aechannel) ++{ ++ switch (aechannel) ++ { ++ 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; ++ } ++} ++#endif ++ + int CAEUtil::GetAVChannelIndex(enum AEChannel aechannel, uint64_t layout) + { +- return av_get_channel_layout_channel_index(layout, GetAVChannel(aechannel)); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ 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; ++#else ++ return av_get_channel_layout_channel_index(layout, GetAVChannelMask(aechannel)); ++#endif + } +diff --git a/xbmc/cores/AudioEngine/Utils/AEUtil.h b/xbmc/cores/AudioEngine/Utils/AEUtil.h +index 034e115ee8..8acbeec442 100644 +--- a/xbmc/cores/AudioEngine/Utils/AEUtil.h ++++ b/xbmc/cores/AudioEngine/Utils/AEUtil.h +@@ -13,7 +13,10 @@ + #include <math.h> + + extern "C" { ++#include <libavcodec/version.h> ++#include <libavutil/channel_layout.h> + #include <libavutil/samplefmt.h> ++#include <libavutil/version.h> + } + + // AV sync options +@@ -171,6 +174,10 @@ public: + 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); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ static enum AVChannel GetAVChannel(enum AEChannel aechannel); ++#endif + static int GetAVChannelIndex(enum AEChannel aechannel, uint64_t layout); + }; +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp +index 87e7ae2c57..44dcb32620 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp +@@ -78,7 +78,14 @@ bool CDVDAudioCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options + + m_matrixEncoding = AV_MATRIX_ENCODING_NONE; + m_channels = 0; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&m_pCodecContext->ch_layout); ++ m_pCodecContext->ch_layout.order = AV_CHANNEL_ORDER_NATIVE; ++ m_pCodecContext->ch_layout.nb_channels = hints.channels; ++#else + m_pCodecContext->channels = hints.channels; ++#endif + m_hint_layout = hints.channellayout; + m_pCodecContext->sample_rate = hints.samplerate; + m_pCodecContext->block_align = hints.blockalign; +@@ -261,12 +268,18 @@ int CDVDAudioCodecFFmpeg::GetData(uint8_t** dst) + 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; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int channels = m_pFrame->ch_layout.nb_channels; ++#else ++ int channels = m_pFrame->channels; ++#endif ++ int planes = av_sample_fmt_is_planar(m_pCodecContext->sample_fmt) ? channels : 1; ++ + for (int i=0; i<planes; i++) + dst[i] = m_pFrame->extended_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; +@@ -280,7 +293,12 @@ void CDVDAudioCodecFFmpeg::Reset() + + int CDVDAudioCodecFFmpeg::GetChannels() + { ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ return m_pCodecContext->ch_layout.nb_channels; ++#else + return m_pCodecContext->channels; ++#endif + } + + int CDVDAudioCodecFFmpeg::GetSampleRate() +@@ -347,28 +365,44 @@ static unsigned count_bits(int64_t value) + + void CDVDAudioCodecFFmpeg::BuildChannelMap() + { +- if (m_channels == m_pCodecContext->channels && m_layout == m_pCodecContext->channel_layout) ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int codecChannels = m_pCodecContext->ch_layout.nb_channels; ++ uint64_t codecChannelLayout = m_pCodecContext->ch_layout.u.mask; ++#else ++ int codecChannels = m_pCodecContext->channels; ++ uint64_t codecChannelLayout = m_pCodecContext->channel_layout; ++#endif ++ 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<int>(count_bits(m_hint_layout)) == m_pCodecContext->channels) ++ codecChannels, bits); ++ if (static_cast<int>(count_bits(m_hint_layout)) == codecChannels) + layout = m_hint_layout; + else + { ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ AVChannelLayout def_layout = {}; ++ av_channel_layout_default(&def_layout, codecChannels); ++ layout = def_layout.u.mask; ++ av_channel_layout_uninit(&def_layout); ++#else + layout = av_get_default_channel_layout(m_pCodecContext->channels); ++#endif + CLog::Log(LOGINFO, "Using default layout..."); + } + } +@@ -394,7 +428,7 @@ void CDVDAudioCodecFFmpeg::BuildChannelMap() + 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 --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +index 5be134e381..70f0562462 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +@@ -220,10 +220,17 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) + case STREAM_AUDIO: + { + CDemuxStreamClientInternalTpl<CDemuxStreamAudio>* sta = static_cast<CDemuxStreamClientInternalTpl<CDemuxStreamAudio>*>(st); +- if (stream->m_context->channels != sta->iChannels && stream->m_context->channels != 0) ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int streamChannels = stream->m_context->ch_layout.nb_channels; ++#else ++ int streamChannels = stream->m_context->channels; ++#endif ++ 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; + } +@@ -235,7 +242,7 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) + sta->changes++; + sta->disabled = false; + } +- if (stream->m_context->channels) ++ if (streamChannels) + st->changes = -1; // stop parsing + break; + } +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +index bf6f322274..4ad52cd32a 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +@@ -1235,8 +1235,16 @@ DemuxPacket* CDVDDemuxFFmpeg::Read() + else if (stream->type == STREAM_AUDIO) + { + CDemuxStreamAudioFFmpeg* audiostream = dynamic_cast<CDemuxStreamAudioFFmpeg*>(stream); +- if (audiostream && (audiostream->iChannels != m_pFormatContext->streams[pPacket->iStreamId]->codecpar->channels || +- audiostream->iSampleRate != m_pFormatContext->streams[pPacket->iStreamId]->codecpar->sample_rate)) ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int codecparChannels = ++ m_pFormatContext->streams[pPacket->iStreamId]->codecpar->ch_layout.nb_channels; ++#else ++ int codecparChannels = m_pFormatContext->streams[pPacket->iStreamId]->codecpar->channels; ++#endif ++ if (audiostream && (audiostream->iChannels != codecparChannels || ++ audiostream->iSampleRate != ++ m_pFormatContext->streams[pPacket->iStreamId]->codecpar->sample_rate)) + { + // content has changed + stream = AddStream(pPacket->iStreamId); +@@ -1418,6 +1426,7 @@ void CDVDDemuxFFmpeg::UpdateCurrentPTS() + if (idx >= 0) + { + AVStream* stream = m_pFormatContext->streams[idx]; ++ + #if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100) + if (stream && m_pkt.pkt.dts != (int64_t)AV_NOPTS_VALUE) + { +@@ -1639,16 +1648,28 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) + { + CDemuxStreamAudioFFmpeg* st = new CDemuxStreamAudioFFmpeg(pStream); + stream = st; +- st->iChannels = pStream->codecpar->channels; ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int codecparChannels = pStream->codecpar->ch_layout.nb_channels; ++ int codecparChannelLayout = pStream->codecpar->ch_layout.u.mask; ++#else ++ int codecparChannels = pStream->codecpar->channels; ++ int codecparChannelLayout = pStream->codecpar->channel_layout; ++#endif ++ st->iChannels = codecparChannels; ++ st->iChannelLayout = codecparChannelLayout; + st->iSampleRate = pStream->codecpar->sample_rate; + st->iBlockAlign = pStream->codecpar->block_align; + st->iBitRate = static_cast<int>(pStream->codecpar->bit_rate); + st->iBitsPerSample = pStream->codecpar->bits_per_raw_sample; +- st->iChannelLayout = pStream->codecpar->channel_layout; + char buf[32] = {}; + // https://github.com/FFmpeg/FFmpeg/blob/6ccc3989d15/doc/APIchanges#L50-L53 +-#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 24, 100) +- av_channel_layout_describe(st->iChannelLayout, buf, sizeof(buf)); ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ AVChannelLayout layout = {}; ++ av_channel_layout_from_mask(&layout, st->iChannelLayout); ++ av_channel_layout_describe(&layout, buf, sizeof(buf)); ++ av_channel_layout_uninit(&layout); + #else + av_get_channel_layout_string(buf, 31, st->iChannels, st->iChannelLayout); + #endif +@@ -2195,8 +2216,13 @@ bool CDVDDemuxFFmpeg::IsProgramChange() + if (m_pFormatContext->streams[idx]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) + { + CDemuxStreamAudioFFmpeg* audiostream = dynamic_cast<CDemuxStreamAudioFFmpeg*>(stream); +- if (audiostream && +- m_pFormatContext->streams[idx]->codecpar->channels != audiostream->iChannels) ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ int codecparChannels = m_pFormatContext->streams[idx]->codecpar->ch_layout.nb_channels; ++#else ++ int codecparChannels = m_pFormatContext->streams[idx]->codecpar->channels; ++#endif ++ if (audiostream && codecparChannels != audiostream->iChannels) + { + return true; + } +-- +2.35.1 + + +From 0a10e05700dfd12b7f5d720588b993089ea33be4 Mon Sep 17 00:00:00 2001 +From: Vasyl Gello <vasek.gello@gmail.com> +Date: Sat, 15 Oct 2022 11:46:52 +0000 +Subject: [PATCH 3/3] ffmpeg5: Get extradata with extract_extradata BSF + +Fixes the transport stream playback failures described in +https://bugs.debian.org/1016925 + +Rogo95 made an excellent technical analysis of the root cause +and reported that to the bug thread. + +Later on, James Almer (jamrial) suggested the solution to use +extract_extradata bitstream filter to replace the removed split() +function. + +Finally, I adapted the following code snippet: +https://gist.github.com/moonpfe/f6795d51294d91ee0f82f62ff6985db0 +to Kodi and tested it by playing the affected files in TS format. + +HiassofT form LibreELEC found another edge case decoding HTSP +streams from pvr.hts. The comparison of log files revealed that +the split function is also used in DVDDemuxClient. + +Signed-off-by: Vasyl Gello <vasek.gello@gmail.com> +--- + xbmc/cores/FFmpeg.cpp | 154 ++++++++++++++++++ + xbmc/cores/FFmpeg.h | 5 + + .../DVDDemuxers/DVDDemuxClient.cpp | 37 ++--- + .../DVDDemuxers/DVDDemuxFFmpeg.cpp | 61 +++---- + 4 files changed, 203 insertions(+), 54 deletions(-) + +diff --git a/xbmc/cores/FFmpeg.cpp b/xbmc/cores/FFmpeg.cpp +index de1765ed52..eb9c653fa3 100644 +--- a/xbmc/cores/FFmpeg.cpp ++++ b/xbmc/cores/FFmpeg.cpp +@@ -16,6 +16,11 @@ + #include "utils/StringUtils.h" + #include "utils/log.h" + ++extern "C" ++{ ++#include <libavcodec/bsf.h> ++} ++ + #include <map> + #include <mutex> + +@@ -129,3 +134,152 @@ void ff_avutil_log(void* ptr, int level, const char* format, va_list va) + } + buffer.erase(0, start); + } ++ ++std::tuple<uint8_t*, int> 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; ++ ++#if LIBAVFORMAT_BUILD >= AV_VERSION_INT(59, 0, 100) ++ /* 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<uint8_t*>(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); ++#else ++ if (codecCtx && parserCtx && parserCtx->parser && parserCtx->parser->split) ++ extraDataSize = parserCtx->parser->split(codecCtx, pkt->data, pkt->size); ++ ++ if (extraDataSize <= 0 || extraDataSize >= FF_MAX_EXTRADATA_SIZE) ++ { ++ CLog::LogF(LOGDEBUG, "fetched extradata of weird size {}", extraDataSize); ++ return std::make_tuple(nullptr, 0); ++ } ++ ++ extraData = static_cast<uint8_t*>(av_malloc(extraDataSize + AV_INPUT_BUFFER_PADDING_SIZE)); ++ if (!extraData) ++ { ++ CLog::LogF(LOGERROR, "failed to allocate {} bytes for extradata", extraDataSize); ++ return std::make_tuple(nullptr, 0); ++ } ++ ++ CLog::LogF(LOGDEBUG, "fetching extradata, extradata_size({})", extraDataSize); ++ ++ memcpy(extraData, pkt->data, extraDataSize); ++ memset(extraData + extraDataSize, 0, AV_INPUT_BUFFER_PADDING_SIZE); ++#endif ++ ++ return std::make_tuple(extraData, extraDataSize); ++} +diff --git a/xbmc/cores/FFmpeg.h b/xbmc/cores/FFmpeg.h +index 8230701ba7..22a253e191 100644 +--- a/xbmc/cores/FFmpeg.h ++++ b/xbmc/cores/FFmpeg.h +@@ -22,6 +22,8 @@ extern "C" { + #include <libpostproc/postprocess.h> + } + ++#include <tuple> ++ + // https://github.com/FFmpeg/FFmpeg/blob/56450a0ee4/doc/APIchanges#L18-L26 + #if LIBAVFORMAT_BUILD >= AV_VERSION_INT(59, 0, 100) + #define FFMPEG_FMT_CONST const +@@ -77,3 +79,6 @@ public: + int level; + }; + ++std::tuple<uint8_t*, int> GetPacketExtradata(const AVPacket* pkt, ++ const AVCodecParserContext* parserCtx, ++ AVCodecContext* codecCtx); +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +index 70f0562462..f42710282d 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +@@ -14,10 +14,9 @@ + #include "cores/VideoPlayer/Interface/TimingConstants.h" + #include "utils/log.h" + ++#include <tuple> + #include <utility> + +-#define FF_MAX_EXTRADATA_SIZE ((1 << 28) - AV_INPUT_BUFFER_PADDING_SIZE) +- + class CDemuxStreamClientInternal + { + public: +@@ -150,17 +149,26 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) + 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<uint8_t[]>(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<uint8_t[]>(retExtraData); + stream->m_parser_split = false; + change = true; + CLog::Log(LOGDEBUG, "CDVDDemuxClient::ParsePacket - split extradata"); +@@ -168,21 +176,12 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) + // 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; +diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +index 4ad52cd32a..3081dd8e9a 100644 +--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp ++++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +@@ -34,6 +34,7 @@ + + #include <mutex> + #include <sstream> ++#include <tuple> + #include <utility> + + extern "C" +@@ -105,8 +106,6 @@ bool AttachmentIsFont(const AVDictionaryEntry* dict) + } + } // namespace + +-#define FF_MAX_EXTRADATA_SIZE ((1 << 28) - AV_INPUT_BUFFER_PADDING_SIZE) +- + std::string CDemuxStreamAudioFFmpeg::GetStreamName() + { + if (!m_stream) +@@ -2358,44 +2357,36 @@ void CDVDDemuxFFmpeg::ParsePacket(AVPacket* pkt) + + 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) +- { +- 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); ++ st->codecpar->extradata_size = i; ++ st->codecpar->extradata = retExtraData; + +- if (parser->second->m_parserCtx->parser->parser_parse) ++ if (parser->second->m_parserCtx->parser->parser_parse) ++ { ++ 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) + { +- 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"); + } + } + } +-- +2.35.1 + +From d61499e7f8451bf080112a3f1332c8826d6ce1ac Mon Sep 17 00:00:00 2001 +From: fritsch <Peter.Fruehberger@gmail.com> +Date: Tue, 17 Jan 2023 20:28:31 +0100 +Subject: [PATCH] AEEncoderFFmpeg: Break when one packet is received + +--- + .../AudioEngine/Encoders/AEEncoderFFmpeg.cpp | 23 +++++++++---------- + 1 file changed, 11 insertions(+), 12 deletions(-) + +diff --git a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp +index ba35c9506395e..bc6ce300ad028 100644 +--- a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp ++++ b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp +@@ -333,43 +333,42 @@ int CAEEncoderFFmpeg::Encode(uint8_t *in, int in_size, uint8_t *out, int out_siz + + avcodec_fill_audio_frame(frame, channelNum, m_CodecCtx->sample_fmt, in, in_size, 0); + +- pkt->size = out_size; +- pkt->data = out; +- + /* encode it */ + err = avcodec_send_frame(m_CodecCtx, frame); + if (err < 0) + throw FFMpegException("Error sending a frame for encoding (error '{}')", + FFMpegErrorToString(err)); + +- while (err >= 0) ++ err = avcodec_receive_packet(m_CodecCtx, pkt); ++ // err < 0 - we cannot cope with it ++ // err is EAGAIN or EOF - return to caller as well ++ if (err >= 0) + { +- err = avcodec_receive_packet(m_CodecCtx, pkt); +- if (err == AVERROR(EAGAIN) || err == AVERROR_EOF) ++ if (pkt->size <= out_size) + { +-#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ +- LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) +- av_channel_layout_uninit(&frame->ch_layout); +-#endif +- av_frame_free(&frame); +- av_packet_free(&pkt); +- return (err == AVERROR(EAGAIN)) ? -1 : 0; ++ memset(out, 0, out_size); ++ memcpy(out, pkt->data, pkt->size); ++ size = pkt->size; + } +- else if (err < 0) ++ else + { +- throw FFMpegException("Error during encoding (error '{}')", FFMpegErrorToString(err)); ++ CLog::LogF(LOGERROR, "Encoded pkt size ({}) is bigger than buffer ({})", pkt->size, ++ out_size); + } + + av_packet_unref(pkt); + } +- +- size = pkt->size; + } + catch (const FFMpegException& caught) + { + CLog::Log(LOGERROR, "CAEEncoderFFmpeg::{} - {}", __func__, caught.what()); + } + ++#if LIBAVCODEC_BUILD >= AV_VERSION_INT(59, 37, 100) && \ ++ LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 28, 100) ++ av_channel_layout_uninit(&frame->ch_layout); ++#endif ++ + /* free temporary data */ + av_frame_free(&frame); |