From a02f7e9844b36d99d0d30b091d5eae846a07996c Mon Sep 17 00:00:00 2001 From: Lukas Rusak Date: Sat, 23 May 2020 10:53:23 -0700 Subject: [PATCH] Merge pull request #17724 from lrusak/drm-prime-sw-buffer-object-pr-2 CDVDVideoCodecDRMPRIME: software decoding --- .../resources/strings.po | 15 +- system/settings/gbm.xml | 11 ++ .../DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp | 148 ++++++++++++++++-- .../DVDCodecs/Video/DVDVideoCodecDRMPRIME.h | 1 + 4 files changed, 156 insertions(+), 19 deletions(-) diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po index 7e9c93b8dcba8..a4642933debe1 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po @@ -7079,7 +7079,7 @@ msgstr "" #: system/settings/settings.xml msgctxt "#13430" -msgid "Allow hardware acceleration - PRIME" +msgid "Allow using DRM PRIME decoder" msgstr "" #: system/settings/settings.xml @@ -7119,7 +7119,10 @@ msgctxt "#13437" msgid "Prefer VDPAU video mixer" msgstr "" -#empty string with id 13438 +#: system/settings/settings.xml +msgctxt "#13438" +msgid "Allow hardware acceleration with DRM PRIME" +msgstr "" #: system/settings/settings.xml msgctxt "#13439" @@ -18538,7 +18541,7 @@ msgstr "" #. Description of setting with label #13430 "Allow hardware acceleration - PRIME" #: system/settings/settings.xml msgctxt "#36172" -msgid "Enable PRIME hardware decoding of video files, used if ffmpeg PRIME hwaccel is available." +msgid "Enable PRIME decoding of video files" msgstr "" #. Description of setting with label #14109 "Short date format" @@ -18815,7 +18818,11 @@ msgctxt "#36222" msgid "Don't import the guide data while playing TV to minimise CPU usage." msgstr "" -#empty string with id 36223 +#. Description of setting with label #13438 "Allow Hardware Accelleration with DRM PRIME" +#: system/settings/settings.xml +msgctxt "#36223" +msgid "Enable PRIME hardware decoding of video files, used if ffmpeg PRIME hwaccel is available." +msgstr "" #: system/settings/settings.xml msgctxt "#36224" diff --git a/system/settings/gbm.xml b/system/settings/gbm.xml index ea3092877f440..cdc6c2b284d89 100644 --- a/system/settings/gbm.xml +++ b/system/settings/gbm.xml @@ -15,6 +15,17 @@ true + + true + + + true + + + 3 + true + + false 2 diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp index 1548a54a245cd..ba3c93d89d48a 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp @@ -9,6 +9,7 @@ #include "DVDVideoCodecDRMPRIME.h" #include "ServiceBroker.h" +#include "cores/VideoPlayer/Buffers/VideoBufferDMA.h" #include "cores/VideoPlayer/Buffers/VideoBufferDRMPRIME.h" #include "cores/VideoPlayer/DVDCodecs/DVDCodecs.h" #include "cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.h" @@ -16,6 +17,7 @@ #include "settings/SettingsComponent.h" #include "settings/lib/Setting.h" #include "threads/SingleLock.h" +#include "utils/CPUInfo.h" #include "utils/log.h" #include "windowing/gbm/WinSystemGbm.h" @@ -23,12 +25,53 @@ extern "C" { #include #include +#include #include #include } using namespace KODI::WINDOWING::GBM; +namespace +{ + +constexpr const char* SETTING_VIDEOPLAYER_USEPRIMEDECODERFORHW{"videoplayer.useprimedecoderforhw"}; + +static void ReleaseBuffer(void* opaque, uint8_t* data) +{ + CVideoBufferDMA* buffer = static_cast(opaque); + buffer->Release(); +} + +static void AlignedSize(AVCodecContext* avctx, int& width, int& height) +{ + int w = width; + int h = height; + AVFrame picture; + int unaligned; + int stride_align[AV_NUM_DATA_POINTERS]; + + avcodec_align_dimensions2(avctx, &w, &h, stride_align); + + do + { + // NOTE: do not align linesizes individually, this breaks e.g. assumptions + // that linesize[0] == 2*linesize[1] in the MPEG-encoder for 4:2:2 + av_image_fill_linesizes(picture.linesize, avctx->pix_fmt, w); + // increase alignment of w for next try (rhs gives the lowest bit set in w) + w += w & ~(w - 1); + + unaligned = 0; + for (int i = 0; i < 4; i++) + unaligned |= picture.linesize[i] % stride_align[i]; + } while (unaligned); + + width = w; + height = h; +} + +} // namespace + CDVDVideoCodecDRMPRIME::CDVDVideoCodecDRMPRIME(CProcessInfo& processInfo) : CDVDVideoCodec(processInfo) { @@ -61,11 +104,23 @@ void CDVDVideoCodecDRMPRIME::Register() static bool IsSupportedHwFormat(const enum AVPixelFormat fmt) { - return fmt == AV_PIX_FMT_DRM_PRIME; + bool hw = CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool( + SETTING_VIDEOPLAYER_USEPRIMEDECODERFORHW); + + return fmt == AV_PIX_FMT_DRM_PRIME && hw; +} + +static bool IsSupportedSwFormat(const enum AVPixelFormat fmt) +{ + return fmt == AV_PIX_FMT_YUV420P || fmt == AV_PIX_FMT_YUVJ420P; } static const AVCodecHWConfig* FindHWConfig(const AVCodec* codec) { + if (!CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool( + SETTING_VIDEOPLAYER_USEPRIMEDECODERFORHW)) + return nullptr; + const AVCodecHWConfig* config = nullptr; for (int n = 0; (config = avcodec_get_hw_config(codec, n)); n++) { @@ -88,17 +143,22 @@ static const AVCodec* FindDecoder(CDVDStreamInfo& hints) const AVCodec* codec = nullptr; void* i = 0; - while ((codec = av_codec_iterate(&i))) - { - if (!av_codec_is_decoder(codec)) - continue; - if (codec->id != hints.codec) - continue; + if (!(hints.codecOptions & CODEC_FORCE_SOFTWARE)) + while ((codec = av_codec_iterate(&i))) + { + if (!av_codec_is_decoder(codec)) + continue; + if (codec->id != hints.codec) + continue; + + const AVCodecHWConfig* config = FindHWConfig(codec); + if (config) + return codec; + } - const AVCodecHWConfig* config = FindHWConfig(codec); - if (config) - return codec; - } + codec = avcodec_find_decoder(hints.codec); + if (codec && (codec->capabilities & AV_CODEC_CAP_DR1) == AV_CODEC_CAP_DR1) + return codec; return nullptr; } @@ -108,7 +168,7 @@ enum AVPixelFormat CDVDVideoCodecDRMPRIME::GetFormat(struct AVCodecContext* avct { for (int n = 0; fmt[n] != AV_PIX_FMT_NONE; n++) { - if (IsSupportedHwFormat(fmt[n])) + if (IsSupportedHwFormat(fmt[n]) || IsSupportedSwFormat(fmt[n])) { CDVDVideoCodecDRMPRIME* ctx = static_cast(avctx->opaque); ctx->UpdateProcessInfo(avctx, fmt[n]); @@ -120,6 +180,45 @@ enum AVPixelFormat CDVDVideoCodecDRMPRIME::GetFormat(struct AVCodecContext* avct return AV_PIX_FMT_NONE; } +int CDVDVideoCodecDRMPRIME::GetBuffer(struct AVCodecContext* avctx, AVFrame* frame, int flags) +{ + if (IsSupportedSwFormat(static_cast(frame->format))) + { + int width = frame->width; + int height = frame->height; + + AlignedSize(avctx, width, height); + + int size; + switch (avctx->pix_fmt) + { + case AV_PIX_FMT_YUV420P: + case AV_PIX_FMT_YUVJ420P: + size = width * height * 3 / 2; + break; + default: + return -1; + } + + CDVDVideoCodecDRMPRIME* ctx = static_cast(avctx->opaque); + auto buffer = dynamic_cast( + ctx->m_processInfo.GetVideoBufferManager().Get(avctx->pix_fmt, size, nullptr)); + if (!buffer) + return -1; + + frame->opaque = static_cast(buffer); + frame->opaque_ref = + av_buffer_create(nullptr, 0, ReleaseBuffer, frame->opaque, AV_BUFFER_FLAG_READONLY); + + buffer->Export(frame, width, height); + buffer->SyncStart(); + + return 0; + } + + return avcodec_default_get_buffer2(avctx, frame, flags); +} + bool CDVDVideoCodecDRMPRIME::Open(CDVDStreamInfo& hints, CDVDCodecOptions& options) { const AVCodec* pCodec = FindDecoder(hints); @@ -158,12 +257,15 @@ bool CDVDVideoCodecDRMPRIME::Open(CDVDStreamInfo& hints, CDVDCodecOptions& optio m_pCodecContext->pix_fmt = AV_PIX_FMT_DRM_PRIME; m_pCodecContext->opaque = static_cast(this); m_pCodecContext->get_format = GetFormat; + m_pCodecContext->get_buffer2 = GetBuffer; m_pCodecContext->codec_tag = hints.codec_tag; m_pCodecContext->coded_width = hints.width; m_pCodecContext->coded_height = hints.height; m_pCodecContext->bits_per_coded_sample = hints.bitsperpixel; m_pCodecContext->time_base.num = 1; m_pCodecContext->time_base.den = DVD_TIME_BASE; + m_pCodecContext->thread_safe_callbacks = 1; + m_pCodecContext->thread_count = CServiceBroker::GetCPUInfo()->GetCPUCount(); if (hints.extradata && hints.extrasize > 0) { @@ -180,7 +282,11 @@ bool CDVDVideoCodecDRMPRIME::Open(CDVDStreamInfo& hints, CDVDCodecOptions& optio { CLog::Log(LOGINFO, "CDVDVideoCodecDRMPRIME::{} - unable to open codec", __FUNCTION__); avcodec_free_context(&m_pCodecContext); - return false; + if (hints.codecOptions & CODEC_FORCE_SOFTWARE) + return false; + + hints.codecOptions |= CODEC_FORCE_SOFTWARE; + return Open(hints, options); } UpdateProcessInfo(m_pCodecContext, m_pCodecContext->pix_fmt); @@ -310,8 +416,9 @@ void CDVDVideoCodecDRMPRIME::SetPictureParams(VideoPicture* pVideoPicture) (static_cast(lrint(pVideoPicture->iWidth / aspect_ratio))) & -3; } - pVideoPicture->color_range = - m_pFrame->color_range == AVCOL_RANGE_JPEG || m_hints.colorRange == AVCOL_RANGE_JPEG; + pVideoPicture->color_range = m_pFrame->color_range == AVCOL_RANGE_JPEG || + m_pFrame->format == AV_PIX_FMT_YUVJ420P || + m_hints.colorRange == AVCOL_RANGE_JPEG; pVideoPicture->color_primaries = m_pFrame->color_primaries == AVCOL_PRI_UNSPECIFIED ? m_hints.colorPrimaries : m_pFrame->color_primaries; @@ -412,6 +519,17 @@ CDVDVideoCodec::VCReturn CDVDVideoCodecDRMPRIME::GetPicture(VideoPicture* pVideo buffer->SetRef(m_pFrame); pVideoPicture->videoBuffer = buffer; } + else if (m_pFrame->opaque) + { + CVideoBufferDMA* buffer = static_cast(m_pFrame->opaque); + buffer->SetPictureParams(*pVideoPicture); + buffer->Acquire(); + buffer->SyncEnd(); + buffer->SetDimensions(m_pFrame->width, m_pFrame->height); + + pVideoPicture->videoBuffer = buffer; + av_frame_unref(m_pFrame); + } if (!pVideoPicture->videoBuffer) { diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h index b7cffa40ce5e5..77d066c3d9caf 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h @@ -36,6 +36,7 @@ class CDVDVideoCodecDRMPRIME : public CDVDVideoCodec void SetPictureParams(VideoPicture* pVideoPicture); void UpdateProcessInfo(struct AVCodecContext* avctx, const enum AVPixelFormat fmt); static enum AVPixelFormat GetFormat(struct AVCodecContext* avctx, const enum AVPixelFormat* fmt); + static int GetBuffer(struct AVCodecContext* avctx, AVFrame* frame, int flags); std::string m_name; int m_codecControlFlags = 0;