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<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 */
-
 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<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);
+    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<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;
-      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<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 +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 <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)
 {
 }
@@ -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 <algorithm>
 
 extern "C" {
-#include <libavfilter/avfilter.h>
 #include <libavcodec/avcodec.h>
+#include <libavfilter/avfilter.h>
 #include <libavfilter/buffersink.h>
 #include <libavfilter/buffersrc.h>
 #include <libswresample/swresample.h>
@@ -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<m_dst_channels; out++)
     {
-      uint64_t out_chan = av_channel_layout_extract_channel(m_dst_chan_layout, out);
-      switch(out_chan)
+      AVChannel outChan = av_channel_layout_channel_from_index(&dstChLayout, out);
+      switch (outChan)
       {
         case AV_CH_FRONT_LEFT:
         case AV_CH_BACK_LEFT:
@@ -153,6 +170,8 @@
           break;
       }
     }
+
+    av_channel_layout_uninit(&dstChLayout);
 
     if (swr_set_matrix(m_pContext, (const double*)m_rematrix, AE_CH_MAX) < 0)
     {
diff -urN xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp.orig xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp
--- xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp.orig	2023-03-11 22:16:38.000000000 +0000
+++ xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp	2023-04-19 10:01:22.844169000 +0000
@@ -88,7 +88,7 @@
   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 -urN xbmc/cores/AudioEngine/Utils/AEUtil.cpp.orig xbmc/cores/AudioEngine/Utils/AEUtil.cpp
--- xbmc/cores/AudioEngine/Utils/AEUtil.cpp.orig	2023-03-11 22:16:38.000000000 +0000
+++ xbmc/cores/AudioEngine/Utils/AEUtil.cpp	2023-04-19 10:01:22.850463000 +0000
@@ -19,10 +19,6 @@
 #include <xmmintrin.h>
 #endif
 
-extern "C" {
-#include <libavutil/channel_layout.h>
-}
-
 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 <math.h>
 
 extern "C" {
+#include <libavutil/channel_layout.h>
 #include <libavutil/samplefmt.h>
 }
 
@@ -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 <libavcodec/bsf.h>
+}
+
 #include <map>
 #include <mutex>
 
 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<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;
+
+  /* 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);
+
+  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 <libavcodec/avcodec.h>
@@ -21,6 +22,26 @@
 #include <libpostproc/postprocess.h>
 }
 
+#include <tuple>
+
+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();
@@ -51,3 +72,6 @@
   int level;
 };
 
+std::tuple<uint8_t*, int> 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 <libavutil/opt.h>
@@ -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; 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;
@@ -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<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
     {
-      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 <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 @@
   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<qp_properties*>(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<AVVideoEncParams*>(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<int8_t*>(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<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;
+      }
     }
   }
 
@@ -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<D3D11_VIDEO_DECODER_CONFIG*>(av_mallocz(sizeof(D3D11_VIDEO_DECODER_CONFIG)));
-  m_avD3D11Context->surface = reinterpret_cast<ID3D11VideoDecoderOutputView**>(av_mallocz_array(32, sizeof(ID3D11VideoDecoderOutputView*)));
+  m_avD3D11Context->surface = reinterpret_cast<ID3D11VideoDecoderOutputView**>(
+      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 <tuple>
 #include <utility>
 
-#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<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");
@@ -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<CDemuxStreamAudio>* sta = static_cast<CDemuxStreamClientInternalTpl<CDemuxStreamAudio>*>(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 <mutex>
 #include <sstream>
+#include <tuple>
 #include <utility>
 
 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<CDVDInputStream>& 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<CDemuxStreamAudioFFmpeg*>(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<int>(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<CDemuxStreamAudioFFmpeg*>(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> 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)
   {
