Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CDVDVideoCodecDRMPRIME: software decoding #17724

Merged
merged 3 commits into from May 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 11 additions & 4 deletions addons/resource.language.en_gb/resources/strings.po
Expand Up @@ -7073,7 +7073,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 @@ -7113,7 +7113,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 @@ -18568,7 +18571,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 @@ -18845,7 +18848,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