Skip to content

Commit

Permalink
Merge pull request xbmc#17724 from lrusak/drm-prime-sw-buffer-object-…
Browse files Browse the repository at this point in the history
…pr-2

CDVDVideoCodecDRMPRIME: software decoding
  • Loading branch information
lrusak authored and Maven85 committed Aug 4, 2020
1 parent 16324ea commit a02f7e9
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 19 deletions.
15 changes: 11 additions & 4 deletions addons/resource.language.en_gb/resources/strings.po
Expand Up @@ -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
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down
11 changes: 11 additions & 0 deletions system/settings/gbm.xml
Expand Up @@ -15,6 +15,17 @@
<default>true</default>
<control type="toggle" />
</setting>
<setting id="videoplayer.useprimedecoderforhw" type="boolean" parent="videoplayer.useprimedecoder" label="13438" help="36172">
<visible>true</visible>
<dependencies>
<dependency type="enable">
<condition setting="videoplayer.useprimedecoder" operator="is">true</condition>
</dependency>
</dependencies>
<level>3</level>
<default>true</default>
<control type="toggle" />
</setting>
<setting id="videoplayer.useprimerenderer" type="integer" label="13462" help="13463">
<visible>false</visible>
<level>2</level>
Expand Down
148 changes: 133 additions & 15 deletions xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp
Expand Up @@ -9,26 +9,69 @@
#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"
#include "settings/Settings.h"
#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"

extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavutil/error.h>
#include <libavutil/imgutils.h>
#include <libavutil/opt.h>
#include <libavutil/pixdesc.h>
}

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<CVideoBufferDMA*>(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)
{
Expand Down Expand Up @@ -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++)
{
Expand All @@ -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;
}
Expand All @@ -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<CDVDVideoCodecDRMPRIME*>(avctx->opaque);
ctx->UpdateProcessInfo(avctx, fmt[n]);
Expand All @@ -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<AVPixelFormat>(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<CDVDVideoCodecDRMPRIME*>(avctx->opaque);
auto buffer = dynamic_cast<CVideoBufferDMA*>(
ctx->m_processInfo.GetVideoBufferManager().Get(avctx->pix_fmt, size, nullptr));
if (!buffer)
return -1;

frame->opaque = static_cast<void*>(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);
Expand Down Expand Up @@ -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<void*>(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)
{
Expand All @@ -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);
Expand Down Expand Up @@ -310,8 +416,9 @@ void CDVDVideoCodecDRMPRIME::SetPictureParams(VideoPicture* pVideoPicture)
(static_cast<int>(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;
Expand Down Expand Up @@ -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<CVideoBufferDMA*>(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)
{
Expand Down
Expand Up @@ -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;
Expand Down

0 comments on commit a02f7e9

Please sign in to comment.