From 9b48325ed7b5d5b6210c0863e1a5e6dfb1799da6 Mon Sep 17 00:00:00 2001 From: Matthias Reichl Date: Thu, 25 Nov 2021 21:11:48 +0100 Subject: [PATCH] RPi: add kodi deinterlace patch Patch created using revisions 39292b080c..b23ff8e293 from branch gbm of https://github.com/popcornmix/xbmc.git Signed-off-by: Matthias Reichl --- .../patches/kodi/kodi-001-deinterlace.patch | 897 ++++++++++++++++++ 1 file changed, 897 insertions(+) create mode 100644 projects/RPi/patches/kodi/kodi-001-deinterlace.patch diff --git a/projects/RPi/patches/kodi/kodi-001-deinterlace.patch b/projects/RPi/patches/kodi/kodi-001-deinterlace.patch new file mode 100644 index 0000000000..20bd6c8321 --- /dev/null +++ b/projects/RPi/patches/kodi/kodi-001-deinterlace.patch @@ -0,0 +1,897 @@ +From 1700cb814868ecae8150254425048de642dcee25 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 20 Oct 2019 17:10:07 +0000 +Subject: [PATCH 1/7] WIP: DVDVideoCodecDRMPRIME: add support for filters + +--- + .../DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp | 68 ++++++++++++++++--- + .../DVDCodecs/Video/DVDVideoCodecDRMPRIME.h | 10 +++ + 2 files changed, 69 insertions(+), 9 deletions(-) + +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp +index 75a40fcd44..eb16d48a92 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp +@@ -27,6 +27,8 @@ + extern "C" + { + #include ++#include ++#include + #include + #include + #include +@@ -567,18 +569,30 @@ void CDVDVideoCodecDRMPRIME::SetPictureParams(VideoPicture* pVideoPicture) + pVideoPicture->dts = DVD_NOPTS_VALUE; + } + +-CDVDVideoCodec::VCReturn CDVDVideoCodecDRMPRIME::GetPicture(VideoPicture* pVideoPicture) ++CDVDVideoCodec::VCReturn CDVDVideoCodecDRMPRIME::ProcessFilterIn() + { +- if (m_codecControlFlags & DVD_CODEC_CTRL_DRAIN) +- Drain(); ++ if (!m_pFilterIn) ++ return VC_PICTURE; + +- if (pVideoPicture->videoBuffer) ++ int ret = av_buffersrc_add_frame(m_pFilterIn, m_pFrame); ++ if (ret < 0) + { +- pVideoPicture->videoBuffer->Release(); +- pVideoPicture->videoBuffer = nullptr; ++ char err[AV_ERROR_MAX_STRING_SIZE] = {}; ++ av_strerror(ret, err, AV_ERROR_MAX_STRING_SIZE); ++ CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::{} - buffersrc add frame failed: {} ({})", ++ __FUNCTION__, err, ret); ++ return VC_ERROR; + } + +- int ret = avcodec_receive_frame(m_pCodecContext, m_pFrame); ++ return ProcessFilterOut(); ++} ++ ++CDVDVideoCodec::VCReturn CDVDVideoCodecDRMPRIME::ProcessFilterOut() ++{ ++ if (!m_pFilterOut) ++ return VC_EOF; ++ ++ int ret = av_buffersink_get_frame(m_pFilterOut, m_pFrame); + if (ret == AVERROR(EAGAIN)) + return VC_BUFFER; + else if (ret == AVERROR_EOF) +@@ -595,11 +609,47 @@ CDVDVideoCodec::VCReturn CDVDVideoCodecDRMPRIME::GetPicture(VideoPicture* pVideo + { + char err[AV_ERROR_MAX_STRING_SIZE] = {}; + av_strerror(ret, err, AV_ERROR_MAX_STRING_SIZE); +- CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::{} - receive frame failed: {} ({})", __FUNCTION__, +- err, ret); ++ CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::{} - buffersink get frame failed: {} ({})", ++ __FUNCTION__, err, ret); + return VC_ERROR; + } + ++ return VC_PICTURE; ++} ++ ++CDVDVideoCodec::VCReturn CDVDVideoCodecDRMPRIME::GetPicture(VideoPicture* pVideoPicture) ++{ ++ if (m_codecControlFlags & DVD_CODEC_CTRL_DRAIN) ++ Drain(); ++ ++ if (pVideoPicture->videoBuffer) ++ { ++ pVideoPicture->videoBuffer->Release(); ++ pVideoPicture->videoBuffer = nullptr; ++ } ++ ++ auto result = ProcessFilterOut(); ++ if (result != VC_PICTURE) ++ { ++ int ret = avcodec_receive_frame(m_pCodecContext, m_pFrame); ++ if (ret == AVERROR(EAGAIN)) ++ return VC_BUFFER; ++ else if (ret == AVERROR_EOF) ++ return VC_EOF; ++ else if (ret) ++ { ++ char err[AV_ERROR_MAX_STRING_SIZE] = {}; ++ av_strerror(ret, err, AV_ERROR_MAX_STRING_SIZE); ++ CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::{} - receive frame failed: {} ({})", ++ __FUNCTION__, err, ret); ++ return VC_ERROR; ++ } ++ ++ result = ProcessFilterIn(); ++ if (result != VC_PICTURE) ++ return result; ++ } ++ + SetPictureParams(pVideoPicture); + + if (IsSupportedHwFormat(static_cast(m_pFrame->format))) +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h +index 42ef9b0d91..3906a306c1 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h +@@ -14,6 +14,11 @@ + + #include + ++extern "C" ++{ ++#include ++} ++ + class CDVDVideoCodecDRMPRIME : public CDVDVideoCodec + { + public: +@@ -35,6 +40,8 @@ protected: + void Drain(); + void SetPictureParams(VideoPicture* pVideoPicture); + void UpdateProcessInfo(struct AVCodecContext* avctx, const enum AVPixelFormat fmt); ++ CDVDVideoCodec::VCReturn ProcessFilterIn(); ++ CDVDVideoCodec::VCReturn ProcessFilterOut(); + static enum AVPixelFormat GetFormat(struct AVCodecContext* avctx, const enum AVPixelFormat* fmt); + static int GetBuffer(struct AVCodecContext* avctx, AVFrame* frame, int flags); + +@@ -43,5 +50,8 @@ protected: + CDVDStreamInfo m_hints; + AVCodecContext* m_pCodecContext = nullptr; + AVFrame* m_pFrame = nullptr; ++ AVFilterGraph* m_pFilterGraph = nullptr; ++ AVFilterContext* m_pFilterIn = nullptr; ++ AVFilterContext* m_pFilterOut = nullptr; + std::shared_ptr m_videoBufferPool; + }; +-- +2.30.2 + + +From 1d7c27abaa87087041fdd98adf66277f23e6c60f Mon Sep 17 00:00:00 2001 +From: Jernej Skrabec +Date: Thu, 26 Dec 2019 11:01:51 +0100 +Subject: [PATCH 2/7] WIP: DRMPRIME deinterlace filter + +--- + .../DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp | 368 +++++++++++++++--- + .../DVDCodecs/Video/DVDVideoCodecDRMPRIME.h | 9 +- + 2 files changed, 322 insertions(+), 55 deletions(-) + +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp +index eb16d48a92..d14379003d 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp +@@ -80,12 +80,15 @@ CDVDVideoCodecDRMPRIME::CDVDVideoCodecDRMPRIME(CProcessInfo& processInfo) + : CDVDVideoCodec(processInfo) + { + m_pFrame = av_frame_alloc(); ++ m_pFilterFrame = av_frame_alloc(); + m_videoBufferPool = std::make_shared(); + } + + CDVDVideoCodecDRMPRIME::~CDVDVideoCodecDRMPRIME() + { + av_frame_free(&m_pFrame); ++ av_frame_free(&m_pFilterFrame); ++ FilterClose(); + avcodec_free_context(&m_pCodecContext); + } + +@@ -354,8 +357,19 @@ bool CDVDVideoCodecDRMPRIME::Open(CDVDStreamInfo& hints, CDVDCodecOptions& optio + } + + UpdateProcessInfo(m_pCodecContext, m_pCodecContext->pix_fmt); +- m_processInfo.SetVideoDeintMethod("none"); ++ m_processInfo.SetVideoInterlaced(false); + m_processInfo.SetVideoDAR(hints.aspect); ++ m_processInfo.SetVideoDeintMethod("none"); ++ ++ FilterTest(); ++ ++ if (!m_deintFilterName.empty()) ++ { ++ std::list methods; ++ methods.push_back(EINTERLACEMETHOD::VS_INTERLACEMETHOD_DEINTERLACE); ++ m_processInfo.UpdateDeinterlacingMethods(methods); ++ m_processInfo.SetDeinterlacingMethodDefault(EINTERLACEMETHOD::VS_INTERLACEMETHOD_DEINTERLACE); ++ } + + return true; + } +@@ -431,6 +445,8 @@ void CDVDVideoCodecDRMPRIME::Reset() + return; + + Drain(); ++ m_filters.clear(); ++ FilterClose(); + + do + { +@@ -478,7 +494,7 @@ void CDVDVideoCodecDRMPRIME::Drain() + av_packet_free(&avpkt); + } + +-void CDVDVideoCodecDRMPRIME::SetPictureParams(VideoPicture* pVideoPicture) ++bool CDVDVideoCodecDRMPRIME::SetPictureParams(VideoPicture* pVideoPicture) + { + pVideoPicture->iWidth = m_pFrame->width; + pVideoPicture->iHeight = m_pFrame->height; +@@ -567,13 +583,232 @@ void CDVDVideoCodecDRMPRIME::SetPictureParams(VideoPicture* pVideoPicture) + ? DVD_NOPTS_VALUE + : static_cast(pts) * DVD_TIME_BASE / AV_TIME_BASE; + pVideoPicture->dts = DVD_NOPTS_VALUE; ++ ++ if (IsSupportedHwFormat(static_cast(m_pFrame->format))) ++ { ++ CVideoBufferDRMPRIMEFFmpeg* buffer = ++ dynamic_cast(m_videoBufferPool->Get()); ++ buffer->SetPictureParams(*pVideoPicture); ++ 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) ++ { ++ CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::{} - videoBuffer:nullptr format:{}", __FUNCTION__, ++ av_get_pix_fmt_name(static_cast(m_pFrame->format))); ++ av_frame_unref(m_pFrame); ++ return false; ++ } ++ ++ return true; + } + +-CDVDVideoCodec::VCReturn CDVDVideoCodecDRMPRIME::ProcessFilterIn() ++void CDVDVideoCodecDRMPRIME::FilterTest() ++{ ++ const AVFilter* filter; ++ void* opaque{}; ++ ++ m_deintFilterName.clear(); ++ ++ while ((filter = av_filter_iterate(&opaque)) != nullptr) ++ { ++ std::string name(filter->name); ++ ++ if (name.find("deinterlace") != std::string::npos) ++ { ++ if (FilterOpen(name, true)) ++ { ++ m_deintFilterName = name; ++ ++ CLog::Log(LOGDEBUG, "CDVDVideoCodecDRMPRIME::{} - found deinterlacing filter {}", ++ __FUNCTION__, name); ++ ++ return; ++ } ++ } ++ } ++ ++ CLog::Log(LOGDEBUG, "CDVDVideoCodecDRMPRIME::{} - no deinterlacing filter found", ++ __FUNCTION__); ++} ++ ++bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool test) ++{ ++ int result; ++ ++ if (m_pFilterGraph) ++ FilterClose(); ++ ++ if (filters.empty()) ++ return true; ++ ++ if (!(m_pFilterGraph = avfilter_graph_alloc())) ++ { ++ CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::FilterOpen - unable to alloc filter graph"); ++ return false; ++ } ++ ++ 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 }; ++ ++ std::string args = StringUtils::Format("video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:" ++ "pixel_aspect=%d/%d:sws_param=flags=2", ++ m_pCodecContext->width, ++ m_pCodecContext->height, ++ m_pCodecContext->pix_fmt, ++ m_pCodecContext->time_base.num ? ++ m_pCodecContext->time_base.num : 1, ++ m_pCodecContext->time_base.num ? ++ m_pCodecContext->time_base.den : 1, ++ m_pCodecContext->sample_aspect_ratio.num != 0 ? ++ m_pCodecContext->sample_aspect_ratio.num : 1, ++ m_pCodecContext->sample_aspect_ratio.num != 0 ? ++ m_pCodecContext->sample_aspect_ratio.den : 1); ++ ++ result = avfilter_graph_create_filter(&m_pFilterIn, srcFilter, "src", ++ args.c_str(), NULL, m_pFilterGraph); ++ if (result < 0) ++ { ++ char err[AV_ERROR_MAX_STRING_SIZE] = {}; ++ av_strerror(result, err, AV_ERROR_MAX_STRING_SIZE); ++ CLog::Log(LOGERROR, ++ "CDVDVideoCodecDRMPRIME::FilterOpen - avfilter_graph_create_filter: src: {} ({})", ++ err, result); ++ return false; ++ } ++ ++ AVBufferSrcParameters *par = av_buffersrc_parameters_alloc(); ++ if (!par) ++ { ++ CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::FilterOpen - unable to alloc buffersrc"); ++ return false; ++ } ++ ++ memset(par, 0, sizeof(*par)); ++ par->format = AV_PIX_FMT_NONE; ++ par->hw_frames_ctx = m_pCodecContext->hw_device_ctx; ++ ++ result = av_buffersrc_parameters_set(m_pFilterIn, par); ++ if (result < 0) ++ { ++ char err[AV_ERROR_MAX_STRING_SIZE] = {}; ++ av_strerror(result, err, AV_ERROR_MAX_STRING_SIZE); ++ CLog::Log(LOGERROR, ++ "CDVDVideoCodecDRMPRIME::FilterOpen - av_buffersrc_parameters_set: {} ({})", ++ err, result); ++ return false; ++ } ++ av_freep(&par); ++ ++ result = avfilter_graph_create_filter(&m_pFilterOut, outFilter, "out", ++ NULL, NULL, m_pFilterGraph); ++ if (result < 0) ++ { ++ char err[AV_ERROR_MAX_STRING_SIZE] = {}; ++ av_strerror(result, err, AV_ERROR_MAX_STRING_SIZE); ++ CLog::Log(LOGERROR, ++ "CDVDVideoCodecDRMPRIME::FilterOpen - avfilter_graph_create_filter: out: {} ({})", ++ err, result); ++ return false; ++ } ++ ++ result = av_opt_set_int_list(m_pFilterOut, "pix_fmts", &pix_fmts[0], ++ AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN); ++ if (result < 0) ++ { ++ CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::FilterOpen - failed settings pix formats"); ++ return false; ++ } ++ ++ 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; ++ ++ 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); ++ ++ if (result < 0) ++ { ++ CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::FilterOpen - avfilter_graph_parse"); ++ return false; ++ } ++ ++ if ((result = avfilter_graph_config(m_pFilterGraph, nullptr)) < 0) ++ { ++ char err[AV_ERROR_MAX_STRING_SIZE] = {}; ++ av_strerror(result, err, AV_ERROR_MAX_STRING_SIZE); ++ CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::FilterOpen - avfilter_graph_config: {} ({})", ++ err, result); ++ return false; ++ } ++ ++ if (test) ++ { ++ FilterClose(); ++ return true; ++ } ++ ++ if (filters.find("deinterlace") != std::string::npos) ++ { ++ m_processInfo.SetVideoDeintMethod(filters); ++ } ++ else ++ { ++ m_processInfo.SetVideoDeintMethod("none"); ++ } ++ ++ if (CServiceBroker::GetLogging().CanLogComponent(LOGVIDEO)) ++ { ++ char* graphDump = avfilter_graph_dump(m_pFilterGraph, nullptr); ++ if (graphDump) ++ { ++ CLog::Log(LOGDEBUG, "CDVDVideoCodecDRMPRIME::FilterOpen - Final filter graph:\n%s", ++ graphDump); ++ av_freep(&graphDump); ++ } ++ } ++ ++ return true; ++} ++ ++void CDVDVideoCodecDRMPRIME::FilterClose() + { +- if (!m_pFilterIn) +- return VC_PICTURE; ++ if (m_pFilterGraph) ++ { ++ CLog::Log(LOGDEBUG, LOGVIDEO, "CDVDVideoCodecDRMPRIME::FilterClose - Freeing filter graph"); ++ avfilter_graph_free(&m_pFilterGraph); ++ ++ // Disposed by above code ++ m_pFilterIn = nullptr; ++ m_pFilterOut = nullptr; ++ } ++} + ++CDVDVideoCodec::VCReturn CDVDVideoCodecDRMPRIME::ProcessFilterIn() ++{ + int ret = av_buffersrc_add_frame(m_pFilterIn, m_pFrame); + if (ret < 0) + { +@@ -589,21 +824,14 @@ CDVDVideoCodec::VCReturn CDVDVideoCodecDRMPRIME::ProcessFilterIn() + + CDVDVideoCodec::VCReturn CDVDVideoCodecDRMPRIME::ProcessFilterOut() + { +- if (!m_pFilterOut) +- return VC_EOF; +- +- int ret = av_buffersink_get_frame(m_pFilterOut, m_pFrame); ++ int ret = av_buffersink_get_frame(m_pFilterOut, m_pFilterFrame); + if (ret == AVERROR(EAGAIN)) + return VC_BUFFER; + else if (ret == AVERROR_EOF) + { +- if (m_codecControlFlags & DVD_CODEC_CTRL_DRAIN) +- { +- CLog::Log(LOGDEBUG, "CDVDVideoCodecDRMPRIME::{} - flush buffers", __FUNCTION__); +- avcodec_flush_buffers(m_pCodecContext); +- SetCodecControl(m_codecControlFlags & ~DVD_CODEC_CTRL_DRAIN); +- } +- return VC_EOF; ++ ret = av_buffersink_get_frame(m_pFilterOut, m_pFilterFrame); ++ if (ret < 0) ++ return VC_BUFFER; + } + else if (ret) + { +@@ -614,9 +842,27 @@ CDVDVideoCodec::VCReturn CDVDVideoCodecDRMPRIME::ProcessFilterOut() + return VC_ERROR; + } + ++ av_frame_unref(m_pFrame); ++ av_frame_move_ref(m_pFrame, m_pFilterFrame); ++ + return VC_PICTURE; + } + ++std::string CDVDVideoCodecDRMPRIME::GetFilterChain(bool interlaced) ++{ ++ // ask codec to do deinterlacing if possible ++ EINTERLACEMETHOD mInt = m_processInfo.GetVideoSettings().m_InterlaceMethod; ++ std::string filterChain; ++ ++ if (!m_processInfo.Supports(mInt)) ++ mInt = m_processInfo.GetFallbackDeintMethod(); ++ ++ if (mInt != VS_INTERLACEMETHOD_NONE && interlaced && !m_deintFilterName.empty()) ++ filterChain += m_deintFilterName; ++ ++ return filterChain; ++} ++ + CDVDVideoCodec::VCReturn CDVDVideoCodecDRMPRIME::GetPicture(VideoPicture* pVideoPicture) + { + if (m_codecControlFlags & DVD_CODEC_CTRL_DRAIN) +@@ -628,57 +874,71 @@ CDVDVideoCodec::VCReturn CDVDVideoCodecDRMPRIME::GetPicture(VideoPicture* pVideo + pVideoPicture->videoBuffer = nullptr; + } + +- auto result = ProcessFilterOut(); +- if (result != VC_PICTURE) ++ if (m_pFilterGraph) + { +- int ret = avcodec_receive_frame(m_pCodecContext, m_pFrame); +- if (ret == AVERROR(EAGAIN)) +- return VC_BUFFER; +- else if (ret == AVERROR_EOF) +- return VC_EOF; +- else if (ret) ++ auto ret = ProcessFilterOut(); ++ if (ret == VC_PICTURE) + { +- char err[AV_ERROR_MAX_STRING_SIZE] = {}; +- av_strerror(ret, err, AV_ERROR_MAX_STRING_SIZE); +- CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::{} - receive frame failed: {} ({})", +- __FUNCTION__, err, ret); +- return VC_ERROR; ++ if (!SetPictureParams(pVideoPicture)) ++ return VC_ERROR; ++ return VC_PICTURE; + } ++ else if (ret != VC_BUFFER) ++ { ++ return ret; ++ } ++ } + +- result = ProcessFilterIn(); +- if (result != VC_PICTURE) +- return result; ++ int ret = avcodec_receive_frame(m_pCodecContext, m_pFrame); ++ if (ret == AVERROR(EAGAIN)) ++ return VC_BUFFER; ++ else if (ret == AVERROR_EOF) ++ return VC_EOF; ++ else if (ret) ++ { ++ char err[AV_ERROR_MAX_STRING_SIZE] = {}; ++ av_strerror(ret, err, AV_ERROR_MAX_STRING_SIZE); ++ CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::{} - receive frame failed: {} ({})", ++ __FUNCTION__, err, ret); ++ return VC_ERROR; + } + +- SetPictureParams(pVideoPicture); ++ if (!m_processInfo.GetVideoInterlaced() && m_pFrame->interlaced_frame) ++ m_processInfo.SetVideoInterlaced(true); + +- if (IsSupportedHwFormat(static_cast(m_pFrame->format))) ++ std::string filterChain = GetFilterChain(m_pFrame->interlaced_frame); ++ if (!filterChain.empty()) + { +- CVideoBufferDRMPRIMEFFmpeg* buffer = +- dynamic_cast(m_videoBufferPool->Get()); +- buffer->SetPictureParams(*pVideoPicture); +- buffer->SetRef(m_pFrame); +- pVideoPicture->videoBuffer = buffer; ++ 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)) ++ reopenFilter = true; ++ ++ if (reopenFilter) ++ { ++ m_filters = filterChain; ++ if (!FilterOpen(filterChain, false)) ++ FilterClose(); ++ } ++ ++ if (m_pFilterGraph) ++ { ++ if (ProcessFilterIn() != VC_PICTURE) ++ return VC_NONE; ++ } + } +- else if (m_pFrame->opaque) ++ else + { +- 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); ++ m_filters.clear(); ++ FilterClose(); + } + +- if (!pVideoPicture->videoBuffer) +- { +- CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::{} - videoBuffer:nullptr format:{}", __FUNCTION__, +- av_get_pix_fmt_name(static_cast(m_pFrame->format))); +- av_frame_unref(m_pFrame); ++ if (!SetPictureParams(pVideoPicture)) + return VC_ERROR; +- } + + return VC_PICTURE; + } +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h +index 3906a306c1..87a3739193 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h +@@ -38,18 +38,25 @@ public: + + protected: + void Drain(); +- void SetPictureParams(VideoPicture* pVideoPicture); ++ bool SetPictureParams(VideoPicture* pVideoPicture); + void UpdateProcessInfo(struct AVCodecContext* avctx, const enum AVPixelFormat fmt); + CDVDVideoCodec::VCReturn ProcessFilterIn(); + 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); ++ void FilterClose(); ++ void FilterTest(); ++ std::string GetFilterChain(bool interlaced); + + std::string m_name; ++ std::string m_deintFilterName; ++ std::string m_filters; + int m_codecControlFlags = 0; + CDVDStreamInfo m_hints; + AVCodecContext* m_pCodecContext = nullptr; + AVFrame* m_pFrame = nullptr; ++ AVFrame* m_pFilterFrame = nullptr; + AVFilterGraph* m_pFilterGraph = nullptr; + AVFilterContext* m_pFilterIn = nullptr; + AVFilterContext* m_pFilterOut = nullptr; +-- +2.30.2 + + +From 83d0307544817ffdb42f273a983e7d52a3683221 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Fri, 27 Aug 2021 20:29:50 +0100 +Subject: [PATCH 3/7] DVDVideoCodecDRMPRIME: Avoid exception with + AV_PIX_FMT_NONE + +--- + .../cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp +index d14379003d..518cae8ccd 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp +@@ -607,7 +607,7 @@ bool CDVDVideoCodecDRMPRIME::SetPictureParams(VideoPicture* pVideoPicture) + if (!pVideoPicture->videoBuffer) + { + CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::{} - videoBuffer:nullptr format:{}", __FUNCTION__, +- av_get_pix_fmt_name(static_cast(m_pFrame->format))); ++ m_pFrame->format == AV_PIX_FMT_NONE ? "AV_PIX_FMT_NONE" : av_get_pix_fmt_name(static_cast(m_pFrame->format))); + av_frame_unref(m_pFrame); + return false; + } +-- +2.30.2 + + +From 4b6d9e8114ba8a41761fa07a0df8347498efbf31 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Sat, 11 Sep 2021 14:03:05 +0100 +Subject: [PATCH 4/7] CDVDVideoCodecDRMPRIME: Also support YUV420 buffers + +CDVDVideoCodecDRMPRIME: Add support for deinterlace of sw decoded buffers + +Need to call SetDimensions earlier and store the drm descriptor in expected place +--- + .../DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp +index 518cae8ccd..2d1b390bae 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp +@@ -584,7 +584,7 @@ bool CDVDVideoCodecDRMPRIME::SetPictureParams(VideoPicture* pVideoPicture) + : static_cast(pts) * DVD_TIME_BASE / AV_TIME_BASE; + pVideoPicture->dts = DVD_NOPTS_VALUE; + +- if (IsSupportedHwFormat(static_cast(m_pFrame->format))) ++ if (m_pFrame->format == AV_PIX_FMT_DRM_PRIME) + { + CVideoBufferDRMPRIMEFFmpeg* buffer = + dynamic_cast(m_videoBufferPool->Get()); +@@ -598,7 +598,6 @@ bool CDVDVideoCodecDRMPRIME::SetPictureParams(VideoPicture* pVideoPicture) + buffer->SetPictureParams(*pVideoPicture); + buffer->Acquire(); + buffer->SyncEnd(); +- buffer->SetDimensions(m_pFrame->width, m_pFrame->height); + + pVideoPicture->videoBuffer = buffer; + av_frame_unref(m_pFrame); +@@ -662,7 +661,7 @@ 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[] = { AV_PIX_FMT_DRM_PRIME, AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }; + + std::string args = StringUtils::Format("video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:" + "pixel_aspect=%d/%d:sws_param=flags=2", +@@ -903,6 +902,17 @@ CDVDVideoCodec::VCReturn CDVDVideoCodecDRMPRIME::GetPicture(VideoPicture* pVideo + return VC_ERROR; + } + ++ if (IsSupportedHwFormat(static_cast(m_pFrame->format))) ++ { ++ } ++ else if (m_pFrame->opaque) ++ { ++ CVideoBufferDMA* buffer = static_cast(m_pFrame->opaque); ++ buffer->SetDimensions(m_pFrame->width, m_pFrame->height); ++ auto descriptor = buffer->GetDescriptor(); ++ m_pFrame->data[0] = reinterpret_cast(descriptor); ++ } ++ + if (!m_processInfo.GetVideoInterlaced() && m_pFrame->interlaced_frame) + m_processInfo.SetVideoInterlaced(true); + +-- +2.30.2 + + +From 62b988c8fe50be6305aa85ecc490a8342319d7b5 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Fri, 17 Sep 2021 15:23:16 +0100 +Subject: [PATCH 5/7] DVDVideoCodecDRMPRIME: Leave deinterlace filter active on + a progressive frame + +Interlaced content often has strange mixtures of interlace and progressive frames (e.g. IIPPPPIIPPPP) +and currently we can be creating and destroying the deinterlace filter graph almost every frame. + +If it's been created, then leave it active until end of file. The frames marked as progressive should +be just copied by deinterlace filter +--- + .../DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp | 11 +++-------- + 1 file changed, 3 insertions(+), 8 deletions(-) + +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp +index 2d1b390bae..47f6c998d9 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp +@@ -935,16 +935,11 @@ CDVDVideoCodec::VCReturn CDVDVideoCodecDRMPRIME::GetPicture(VideoPicture* pVideo + FilterClose(); + } + +- if (m_pFilterGraph) +- { +- if (ProcessFilterIn() != VC_PICTURE) +- return VC_NONE; +- } + } +- else ++ if (m_pFilterGraph) + { +- m_filters.clear(); +- FilterClose(); ++ if (ProcessFilterIn() != VC_PICTURE) ++ return VC_NONE; + } + + if (!SetPictureParams(pVideoPicture)) +-- +2.30.2 + + +From 8ea862d2fbfa9da0c193f91a1156c1a7ec543016 Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Wed, 24 Nov 2021 20:21:28 +0000 +Subject: [PATCH 6/7] DVDVideoCodecDRMPRIME: Close deinterlace filter on error + +Otherwise we crash later with an invalid m_pFilterGraph pointer +--- + .../VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp +index 47f6c998d9..f2af65673f 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp +@@ -686,6 +686,7 @@ bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool test) + CLog::Log(LOGERROR, + "CDVDVideoCodecDRMPRIME::FilterOpen - avfilter_graph_create_filter: src: {} ({})", + err, result); ++ FilterClose(); + return false; + } + +@@ -693,6 +694,7 @@ bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool test) + if (!par) + { + CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::FilterOpen - unable to alloc buffersrc"); ++ FilterClose(); + return false; + } + +@@ -708,6 +710,7 @@ 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); +@@ -721,6 +724,7 @@ bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool test) + CLog::Log(LOGERROR, + "CDVDVideoCodecDRMPRIME::FilterOpen - avfilter_graph_create_filter: out: {} ({})", + err, result); ++ FilterClose(); + return false; + } + +@@ -729,6 +733,7 @@ bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool test) + if (result < 0) + { + CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::FilterOpen - failed settings pix formats"); ++ FilterClose(); + return false; + } + +@@ -752,6 +757,7 @@ bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool test) + if (result < 0) + { + CLog::Log(LOGERROR, "CDVDVideoCodecDRMPRIME::FilterOpen - avfilter_graph_parse"); ++ FilterClose(); + return false; + } + +@@ -761,6 +767,7 @@ 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; + } + +-- +2.30.2 + + +From b23ff8e293fbe30ed024ffd07abb7f8d197a6787 Mon Sep 17 00:00:00 2001 +From: Dom Cobley +Date: Wed, 24 Nov 2021 20:22:41 +0000 +Subject: [PATCH 7/7] CDVDVideoCodecDRMPRIME: Fix Format calls and some logging + +--- + .../VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp +index f2af65673f..780928fae0 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp +@@ -663,8 +663,8 @@ bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool test) + const AVFilter* outFilter = avfilter_get_by_name("buffersink"); + enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_DRM_PRIME, AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }; + +- std::string args = StringUtils::Format("video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:" +- "pixel_aspect=%d/%d:sws_param=flags=2", ++ std::string args = StringUtils::Format("video_size={}x{}:pix_fmt={}:time_base={}/{}:" ++ "pixel_aspect={}/{}:sws_param=flags=2", + m_pCodecContext->width, + m_pCodecContext->height, + m_pCodecContext->pix_fmt, +@@ -791,7 +791,7 @@ bool CDVDVideoCodecDRMPRIME::FilterOpen(const std::string& filters, bool test) + char* graphDump = avfilter_graph_dump(m_pFilterGraph, nullptr); + if (graphDump) + { +- CLog::Log(LOGDEBUG, "CDVDVideoCodecDRMPRIME::FilterOpen - Final filter graph:\n%s", ++ CLog::Log(LOGDEBUG, "CDVDVideoCodecDRMPRIME::FilterOpen - Final filter graph:\n{}", + graphDump); + av_freep(&graphDump); + } +-- +2.30.2 +