1
0
mirror of https://github.com/libretro/Lakka-LibreELEC.git synced 2024-11-24 21:56:19 +00:00
Lakka-LibreELEC/projects/RPi/patches/kodi/0005-support-arbitrary-pixel-formats.patch
Matthias Reichl 6df596139d RPi: add kodi patch to support arbitrary pixel formats with drmprime
Signed-off-by: Matthias Reichl <hias@horus.com>
2023-03-21 17:14:17 +01:00

333 lines
13 KiB
Diff

From 4b60bcc31eddb776d0134c4f2a64ad36969bde1b Mon Sep 17 00:00:00 2001
From: Dom Cobley <popcornmix@gmail.com>
Date: Mon, 6 Feb 2023 15:19:51 +0000
Subject: [PATCH] DVDVideoCodecDRMPRIME: Add support for arbitrary output pixel
formats
This enables any ffmpeg pixel formats to be supported by DRMPRIME decoder
by creating a scale ffmpeg filter to convert it to a supported format.
This allows formats like h264 Hi10P and hevc 12-bit 444 to be software decoded,
converted and displayed through DRM.
This will be a cheaper path than disabling DRMPRIME, which is also
software decode, convert, but then needs convert to texture and display through GL.
And it happens automatically without requiring user video settings
---
.../DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp | 124 +++++++++++-------
.../DVDCodecs/Video/DVDVideoCodecDRMPRIME.h | 3 +-
2 files changed, 77 insertions(+), 50 deletions(-)
diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp
index 347dce1ae8..e071de2e53 100644
--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp
+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp
@@ -201,7 +201,7 @@ enum AVPixelFormat CDVDVideoCodecDRMPRIME::GetFormat(struct AVCodecContext* avct
{
for (int n = 0; fmt[n] != AV_PIX_FMT_NONE; n++)
{
- if (IsSupportedHwFormat(fmt[n]) || IsSupportedSwFormat(fmt[n]))
+ //if (IsSupportedHwFormat(fmt[n]) || IsSupportedSwFormat(fmt[n]))
{
CDVDVideoCodecDRMPRIME* ctx = static_cast<CDVDVideoCodecDRMPRIME*>(avctx->opaque);
ctx->UpdateProcessInfo(avctx, fmt[n]);
@@ -222,7 +222,8 @@ enum AVPixelFormat CDVDVideoCodecDRMPRIME::GetFormat(struct AVCodecContext* avct
int CDVDVideoCodecDRMPRIME::GetBuffer(struct AVCodecContext* avctx, AVFrame* frame, int flags)
{
- if (IsSupportedSwFormat(static_cast<AVPixelFormat>(frame->format)))
+ AVPixelFormat pix_fmt = static_cast<AVPixelFormat>(frame->format);
+ if (IsSupportedSwFormat(pix_fmt))
{
int width = frame->width;
int height = frame->height;
@@ -230,7 +231,7 @@ int CDVDVideoCodecDRMPRIME::GetBuffer(struct AVCodecContext* avctx, AVFrame* fra
AlignedSize(avctx, width, height);
int size;
- switch (avctx->pix_fmt)
+ switch (pix_fmt)
{
case AV_PIX_FMT_YUV420P:
case AV_PIX_FMT_YUVJ420P:
@@ -250,13 +251,12 @@ int CDVDVideoCodecDRMPRIME::GetBuffer(struct AVCodecContext* avctx, AVFrame* fra
CDVDVideoCodecDRMPRIME* ctx = static_cast<CDVDVideoCodecDRMPRIME*>(avctx->opaque);
auto buffer = dynamic_cast<CVideoBufferDMA*>(
- ctx->m_processInfo.GetVideoBufferManager().Get(avctx->pix_fmt, size, nullptr));
+ ctx->m_processInfo.GetVideoBufferManager().Get(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);
+ av_buffer_create(nullptr, 0, ReleaseBuffer, static_cast<void*>(buffer), AV_BUFFER_FLAG_READONLY);
buffer->Export(frame, width, height);
buffer->SyncStart();
@@ -611,9 +611,9 @@ bool CDVDVideoCodecDRMPRIME::SetPictureParams(VideoPicture* pVideoPicture)
buffer->SetRef(m_pFrame);
pVideoPicture->videoBuffer = buffer;
}
- else if (m_pFrame->opaque)
+ else if (IsSupportedSwFormat(static_cast<AVPixelFormat>(m_pFrame->format)))
{
- CVideoBufferDMA* buffer = static_cast<CVideoBufferDMA*>(m_pFrame->opaque);
+ CVideoBufferDMA* buffer = static_cast<CVideoBufferDMA*>(av_buffer_get_opaque(m_pFrame->buf[0]));
buffer->SetPictureParams(*pVideoPicture);
buffer->Acquire();
buffer->SyncEnd();
@@ -647,13 +647,13 @@ void CDVDVideoCodecDRMPRIME::FilterTest()
if (name.find("deinterlace") != std::string::npos)
{
- if (FilterOpen(name, true))
+ bool ret = FilterOpen(name, false, true);
+ FilterClose();
+ if (ret)
{
m_deintFilterName = name;
-
CLog::Log(LOGDEBUG, "CDVDVideoCodecDRMPRIME::{} - found deinterlacing filter {}",
__FUNCTION__, name);
-
return;
}
}
@@ -663,14 +663,31 @@ void CDVDVideoCodecDRMPRIME::FilterTest()
__FUNCTION__);
}
-bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool test)
+AVFrame *CDVDVideoCodecDRMPRIME::alloc_filter_frame(AVFilterContext * ctx, void * v, int w, int h)
+{
+ int result;
+ CDVDVideoCodecDRMPRIME* me = static_cast<CDVDVideoCodecDRMPRIME*>(v);
+ AVFrame *frame = av_frame_alloc();
+ frame->width = w;
+ frame->height = h;
+ frame->format = AV_PIX_FMT_YUV420P;
+
+ if ((result = CDVDVideoCodecDRMPRIME::GetBuffer(me->m_pCodecContext, frame, 0)) < 0)
+ {
+ CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::alloc_filter_frame - failed to GetBuffer ({})", result);
+ return nullptr;
+ }
+ return frame;
+}
+
+bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool scale, bool test)
{
int result;
if (m_pFilterGraph)
FilterClose();
- if (filters.empty())
+ if (filters.empty() && !scale)
return true;
if (!(m_pFilterGraph = avfilter_graph_alloc()))
@@ -681,13 +698,13 @@ bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool test)
const AVFilter* srcFilter = avfilter_get_by_name("buffer");
const AVFilter* outFilter = avfilter_get_by_name("buffersink");
- enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_DRM_PRIME, AV_PIX_FMT_NONE };
+ enum AVPixelFormat pix_fmts[] = { scale ? AV_PIX_FMT_YUV420P : AV_PIX_FMT_DRM_PRIME, AV_PIX_FMT_NONE };
std::string args = StringUtils::Format("video_size={}x{}:pix_fmt={}:time_base={}/{}:"
"pixel_aspect={}/{}",
m_pCodecContext->width,
m_pCodecContext->height,
- AV_PIX_FMT_DRM_PRIME,
+ scale ? m_pCodecContext->pix_fmt : AV_PIX_FMT_DRM_PRIME,
m_pCodecContext->time_base.num ?
m_pCodecContext->time_base.num : 1,
m_pCodecContext->time_base.num ?
@@ -706,7 +723,6 @@ bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool test)
CLog::Log(LOGERROR,
"CDVDVideoCodecDRMPRIME::FilterOpen - avfilter_graph_create_filter: src: {} ({})",
err, result);
- FilterClose();
return false;
}
@@ -714,7 +730,6 @@ bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool test)
if (!par)
{
CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::FilterOpen - unable to alloc buffersrc");
- FilterClose();
return false;
}
@@ -730,7 +745,6 @@ bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool test)
CLog::Log(LOGERROR,
"CDVDVideoCodecDRMPRIME::FilterOpen - av_buffersrc_parameters_set: {} ({})",
err, result);
- FilterClose();
return false;
}
av_freep(&par);
@@ -744,7 +758,6 @@ bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool test)
CLog::Log(LOGERROR,
"CDVDVideoCodecDRMPRIME::FilterOpen - avfilter_graph_create_filter: out: {} ({})",
err, result);
- FilterClose();
return false;
}
@@ -753,32 +766,46 @@ bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool test)
if (result < 0)
{
CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::FilterOpen - failed settings pix formats");
- FilterClose();
return false;
}
- AVFilterInOut* outputs = avfilter_inout_alloc();
- AVFilterInOut* inputs = avfilter_inout_alloc();
+ if (!filters.empty())
+ {
+ AVFilterInOut* outputs = avfilter_inout_alloc();
+ AVFilterInOut* inputs = avfilter_inout_alloc();
- outputs->name = av_strdup("in");
- outputs->filter_ctx = m_pFilterIn;
- outputs->pad_idx = 0;
- outputs->next = nullptr;
+ outputs->name = av_strdup("in");
+ outputs->filter_ctx = m_pFilterIn;
+ outputs->pad_idx = 0;
+ outputs->next = nullptr;
- inputs->name = av_strdup("out");
- inputs->filter_ctx = m_pFilterOut;
- inputs->pad_idx = 0;
- inputs->next = nullptr;
+ inputs->name = av_strdup("out");
+ inputs->filter_ctx = m_pFilterOut;
+ inputs->pad_idx = 0;
+ inputs->next = nullptr;
- result = avfilter_graph_parse_ptr(m_pFilterGraph, filters.c_str(), &inputs, &outputs, NULL);
- avfilter_inout_free(&outputs);
- avfilter_inout_free(&inputs);
+ result = avfilter_graph_parse_ptr(m_pFilterGraph, filters.c_str(), &inputs, &outputs, NULL);
+ avfilter_inout_free(&outputs);
+ avfilter_inout_free(&inputs);
- if (result < 0)
+ if (result < 0)
+ {
+ CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::FilterOpen - avfilter_graph_parse");
+ return false;
+ }
+ }
+ else
{
- CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::FilterOpen - avfilter_graph_parse");
- FilterClose();
- return false;
+ if ((result = av_buffersink_set_alloc_video_frame(m_pFilterOut, alloc_filter_frame, static_cast<void*>(this))) < 0)
+ {
+ CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::FilterOpen - av_buffersink_set_alloc_video_frame = {}", result);
+ return result;
+ }
+ if ((result = avfilter_link(m_pFilterIn, 0, m_pFilterOut, 0)) < 0)
+ {
+ CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::FilterOpen - avfilter_link");
+ return false;
+ }
}
if ((result = avfilter_graph_config(m_pFilterGraph, nullptr)) < 0)
@@ -787,15 +814,11 @@ bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool test)
av_strerror(result, err, AV_ERROR_MAX_STRING_SIZE);
CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::FilterOpen - avfilter_graph_config: {} ({})",
err, result);
- FilterClose();
return false;
}
if (test)
- {
- FilterClose();
return true;
- }
m_processInfo.SetVideoDeintMethod(filters);
@@ -830,16 +853,16 @@ void CDVDVideoCodecDRMPRIME::FilterClose()
CDVDVideoCodec::VCReturn CDVDVideoCodecDRMPRIME::ProcessFilterIn()
{
// sw decoded buffers need cache flush and for descripter to be set
- if (!IsSupportedHwFormat(static_cast<AVPixelFormat>(m_pFrame->format)) && m_pFrame->opaque != nullptr)
+ if (!IsSupportedHwFormat(static_cast<AVPixelFormat>(m_pFrame->format)) && IsSupportedSwFormat(static_cast<AVPixelFormat>(m_pFrame->format)))
{
- CVideoBufferDMA* buffer = static_cast<CVideoBufferDMA*>(m_pFrame->opaque);
+ CVideoBufferDMA* buffer = static_cast<CVideoBufferDMA*>(av_buffer_get_opaque(m_pFrame->buf[0]));
buffer->SetDimensions(m_pFrame->width, m_pFrame->height);
buffer->SyncEnd();
auto descriptor = buffer->GetDescriptor();
m_pFrame->data[0] = reinterpret_cast<uint8_t*>(descriptor);
+ m_pFrame->format = AV_PIX_FMT_DRM_PRIME;
}
- m_pFrame->format = AV_PIX_FMT_DRM_PRIME;
int ret = av_buffersrc_add_frame(m_pFilterIn, m_pFrame);
if (ret < 0)
{
@@ -932,25 +955,28 @@ CDVDVideoCodec::VCReturn CDVDVideoCodecDRMPRIME::GetPicture(VideoPicture* pVideo
return VC_ERROR;
}
+ // we need to scale if the buffer isn't in DRM_PRIME format
+ bool need_scale = !IsSupportedSwFormat(static_cast<AVPixelFormat>(m_pFrame->format)) && !IsSupportedHwFormat(static_cast<AVPixelFormat>(m_pFrame->format));
+
if (!m_processInfo.GetVideoInterlaced() && m_pFrame->interlaced_frame)
m_processInfo.SetVideoInterlaced(true);
std::string filterChain = GetFilterChain(m_pFrame->interlaced_frame);
- if (!filterChain.empty())
+ if (!filterChain.empty() || need_scale)
{
bool reopenFilter = false;
if (m_filters != filterChain)
reopenFilter = true;
if (m_pFilterGraph &&
- (m_pFilterIn->outputs[0]->w != m_pCodecContext->width ||
- m_pFilterIn->outputs[0]->h != m_pCodecContext->height))
+ (m_pFilterIn->outputs[0]->w != m_pFrame->width ||
+ m_pFilterIn->outputs[0]->h != m_pFrame->height))
reopenFilter = true;
- if (reopenFilter)
+ if (reopenFilter || (need_scale && m_pFilterGraph == nullptr))
{
m_filters = filterChain;
- if (!FilterOpen(filterChain, false))
+ if (!FilterOpen(filterChain, need_scale, false))
FilterClose();
}
diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h
index fab3431d40..bb88fde1f9 100644
--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h
+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h
@@ -44,7 +44,8 @@ protected:
CDVDVideoCodec::VCReturn ProcessFilterOut();
static enum AVPixelFormat GetFormat(struct AVCodecContext* avctx, const enum AVPixelFormat* fmt);
static int GetBuffer(struct AVCodecContext* avctx, AVFrame* frame, int flags);
- bool FilterOpen(const std::string& filters, bool test);
+ static AVFrame *alloc_filter_frame(AVFilterContext * ctx, void * v, int w, int h);
+ bool FilterOpen(const std::string& filters, bool scale, bool test);
void FilterClose();
void FilterTest();
std::string GetFilterChain(bool interlaced);
--
2.39.2