mirror of
https://github.com/libretro/Lakka-LibreELEC.git
synced 2024-11-24 21:56:19 +00:00
6df596139d
Signed-off-by: Matthias Reichl <hias@horus.com>
333 lines
13 KiB
Diff
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
|
|
|