Merge pull request #4701 from jernejsk/deint

Allwinner: H3 and H6 HW deinterlacing support
This commit is contained in:
Christian Hewitt
2020-12-01 18:19:37 +04:00
committed by GitHub
7 changed files with 3221 additions and 0 deletions

View File

@@ -3306,6 +3306,7 @@ CONFIG_V4L_MEM2MEM_DRIVERS=y
# CONFIG_VIDEO_MEM2MEM_DEINTERLACE is not set
CONFIG_VIDEO_SUN8I_DEINTERLACE=m
CONFIG_VIDEO_SUN8I_ROTATE=m
CONFIG_VIDEO_SUN50I_DEINTERLACE=m
CONFIG_DVB_PLATFORM_DRIVERS=y
#

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,230 @@
From 6bea46839ba23bffaa093bb9ed805d571aaa66ea Mon Sep 17 00:00:00 2001
From: Alex Bee <knaerzche@gmail.com>
Date: Wed, 30 Sep 2020 21:11:34 +0200
Subject: [PATCH] libavfilter: v4l2deinterlace: dequeue both destination
buffers on time
Signed-off-by: Alex Bee <knaerzche@gmail.com>
---
libavfilter/vf_deinterlace_v4l2m2m.c | 140 +++++++++++++++++----------
1 file changed, 88 insertions(+), 52 deletions(-)
diff --git a/libavfilter/vf_deinterlace_v4l2m2m.c b/libavfilter/vf_deinterlace_v4l2m2m.c
index 1029e5b620fd..72d28333ffa7 100644
--- a/libavfilter/vf_deinterlace_v4l2m2m.c
+++ b/libavfilter/vf_deinterlace_v4l2m2m.c
@@ -89,8 +89,14 @@ typedef struct DeintV4L2M2MContextShared {
AVBufferRef *hw_frames_ctx;
- int frame_count;
- AVFrame *frames[2];
+ /*
+ * TODO: check if its really neccessary to hold this
+ * ref, it's only used for freeing av_frame on decoding
+ * end/abort
+ */
+ AVFrame *cur_in_frame;
+ AVFrame *prev_in_frame;
+ unsigned int field_order;
V4L2Queue output;
V4L2Queue capture;
@@ -557,8 +563,11 @@ static void deint_v4l2m2m_destroy_context(DeintV4L2M2MContextShared *ctx)
close(capture->buffers[i].fd);
}
- for (i = 0; i < ctx->frame_count; i++)
- av_frame_free(&ctx->frames[i]);
+ if (ctx->cur_in_frame)
+ av_frame_free(&ctx->cur_in_frame);
+
+ if (ctx->prev_in_frame)
+ av_frame_free(&ctx->prev_in_frame);
av_buffer_unref(&ctx->hw_frames_ctx);
@@ -652,49 +661,79 @@ static int deint_v4l2m2m_dequeue_frame(V4L2Queue *queue, AVFrame* frame, int tim
return 0;
}
-static int deint_v4l2m2m_dequeue(AVFilterContext *avctx, AVFrame *input_frame, int field)
+static int deint_v4l2m2m_dequeue(AVFilterContext *avctx, AVFrame *input_frame)
{
DeintV4L2M2MContext *priv = avctx->priv;
DeintV4L2M2MContextShared *ctx = priv->shared;
AVFilterLink *outlink = avctx->outputs[0];
- AVFrame *output_frame;
+ AVFrame *output_frame_1, *output_frame_2;
+ int64_t first_pts = AV_NOPTS_VALUE;
int err;
- output_frame = av_frame_alloc();
+ av_log(priv, AV_LOG_DEBUG, "input pts: %"PRId64" (field %d)\n",
+ input_frame->pts, ctx->field_order);
- if (!output_frame)
+ output_frame_1 = av_frame_alloc();
+ if (!output_frame_1)
return AVERROR(ENOMEM);
- err = deint_v4l2m2m_dequeue_frame(&ctx->capture, output_frame, 500);
+ err = deint_v4l2m2m_dequeue_frame(&ctx->capture, output_frame_1, 500);
if (err < 0) {
- av_log(priv, AV_LOG_ERROR, "no frame (field %d)\n", field);
- goto fail;
+ av_log(priv, AV_LOG_ERROR, "no 1st frame (field %d)\n", ctx->field_order);
+ goto fail_out1;
}
- err = av_frame_copy_props(output_frame, input_frame);
+ err = av_frame_copy_props(output_frame_1, input_frame);
if (err < 0)
- goto fail;
+ goto fail_out1;
- output_frame->interlaced_frame = 0;
+ output_frame_1->interlaced_frame = 0;
- if (field == 0) {
- output_frame->pts *= 2;
- } else {
- int64_t cur_pts = ctx->frames[0]->pts;
- int64_t next_pts = ctx->frames[1]->pts;
+ output_frame_2 = av_frame_alloc();
+ if (!output_frame_2) {
+ err = AVERROR(ENOMEM);
+ goto fail_out1;
+ }
+
+ err = deint_v4l2m2m_dequeue_frame(&ctx->capture, output_frame_2, 500);
+ if (err < 0) {
+ av_log(priv, AV_LOG_ERROR, "no 2nd frame (field %d)\n", ctx->field_order);
+ goto fail_out2;
+ }
+
+ err = av_frame_copy_props(output_frame_2, input_frame);
+ if (err < 0)
+ goto fail_out2;
+
+ output_frame_2->interlaced_frame = 0;
- if (next_pts != AV_NOPTS_VALUE && cur_pts != AV_NOPTS_VALUE) {
- output_frame->pts = next_pts + cur_pts;
- } else {
- output_frame->pts = AV_NOPTS_VALUE;
- }
+ if (ctx->prev_in_frame && ctx->prev_in_frame->pts != AV_NOPTS_VALUE
+ && input_frame->pts != AV_NOPTS_VALUE) {
+ first_pts = (ctx->prev_in_frame->pts + input_frame->pts) / 2;
+ av_log(priv, AV_LOG_DEBUG, "calculated first pts %"PRId64"\n", first_pts);
}
- av_log(priv, AV_LOG_DEBUG, "pts: %"PRId64" (field %d)\n", output_frame->pts, field);
- return ff_filter_frame(outlink, output_frame);
+ output_frame_1->pts = first_pts;
+
+ err = ff_filter_frame(outlink, output_frame_1);
+ if (err < 0) {
+ av_frame_free(&output_frame_2);
+ return err;
+ }
+ err = ff_filter_frame(outlink, output_frame_2);
+
+ if (err < 0)
+ return err;
+
+ av_log(priv, AV_LOG_DEBUG, "1st frame pts: %"PRId64" 2nd frame pts: %"PRId64" first pts: %"PRId64" (field %d)\n",
+ output_frame_1->pts, output_frame_2->pts, first_pts, ctx->field_order);
+
+ return 0;
-fail:
- av_frame_free(&output_frame);
+fail_out2:
+ av_frame_free(&output_frame_2);
+fail_out1:
+ av_frame_free(&output_frame_1);
return err;
}
@@ -749,20 +788,22 @@ static int deint_v4l2m2m_filter_frame(AVFilterLink *link, AVFrame *in)
V4L2Queue *output = &ctx->output;
int ret;
- av_log(priv, AV_LOG_DEBUG, "input pts: %"PRId64"\n", in->pts);
- if (!ctx->frame_count) {
+ av_log(priv, AV_LOG_DEBUG, "input pts: %"PRId64" field :%d interlaced: %d\n",
+ in->pts, in->top_field_first, in->interlaced_frame);
+
+ ctx->cur_in_frame = in;
+
+ if (ctx->field_order == V4L2_FIELD_ANY) {
AVDRMFrameDescriptor *drm_desc = (AVDRMFrameDescriptor *)in->data[0];
- unsigned int field;
-
ctx->orig_width = drm_desc->layers[0].planes[0].pitch;
ctx->orig_height = drm_desc->layers[0].planes[1].offset / ctx->orig_width;
- if (in->top_field_first)
- field = V4L2_FIELD_INTERLACED_TB;
+ if (in->top_field_first)
+ ctx->field_order = V4L2_FIELD_INTERLACED_TB;
else
- field = V4L2_FIELD_INTERLACED_BT;
+ ctx->field_order = V4L2_FIELD_INTERLACED_BT;
- ret = deint_v4l2m2m_set_format(output, field, ctx->orig_width, ctx->orig_height);
+ ret = deint_v4l2m2m_set_format(output, ctx->field_order, ctx->orig_width, ctx->orig_height);
if (ret)
return ret;
@@ -787,27 +828,19 @@ static int deint_v4l2m2m_filter_frame(AVFilterLink *link, AVFrame *in)
return ret;
}
- if (ctx->frame_count < 2) {
- ctx->frames[ctx->frame_count++] = in;
- } else {
- av_frame_free(&ctx->frames[0]);
- ctx->frames[0] = ctx->frames[1];
- ctx->frames[1] = in;
- }
-
ret = deint_v4l2m2m_enqueue(output, in);
if (ret)
return ret;
- if (ctx->frame_count == 2) {
- ret = deint_v4l2m2m_dequeue(avctx, ctx->frames[0], 0);
- if (ret)
- return ret;
+ ret = deint_v4l2m2m_dequeue(avctx, in);
+ if (ret)
+ return ret;
- ret = deint_v4l2m2m_dequeue(avctx, ctx->frames[0], 1);
- if (ret)
- return ret;
- }
+ if (ctx->prev_in_frame)
+ av_frame_free(&ctx->prev_in_frame);
+
+ ctx->prev_in_frame = in;
+ ctx->cur_in_frame = NULL;
return 0;
}
@@ -828,6 +861,9 @@ static av_cold int deint_v4l2m2m_init(AVFilterContext *avctx)
ctx->capture.ctx = ctx;
ctx->capture.num_buffers = 6;
ctx->done = 0;
+ ctx->field_order = V4L2_FIELD_ANY;
+ ctx->cur_in_frame = NULL;
+ ctx->prev_in_frame = NULL;
atomic_init(&ctx->refcount, 1);
return 0;
--
2.29.2

View File

@@ -0,0 +1,148 @@
From 6789405cbea23dd0d53ba5a6833dc2266f166ad9 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sun, 20 Oct 2019 17:10:07 +0000
Subject: [PATCH 1/2] 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 a12ef9ec1e96..2b334c95d47a 100644
--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp
+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp
@@ -27,6 +27,8 @@
extern "C"
{
#include <libavcodec/avcodec.h>
+#include <libavfilter/buffersink.h>
+#include <libavfilter/buffersrc.h>
#include <libavutil/error.h>
#include <libavutil/imgutils.h>
#include <libavutil/opt.h>
@@ -514,18 +516,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)
@@ -542,11 +556,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<AVPixelFormat>(m_pFrame->format)))
diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h
index 77d066c3d9ca..7112d1b48afb 100644
--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h
+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h
@@ -14,6 +14,11 @@
#include <memory>
+extern "C"
+{
+#include <libavfilter/avfilter.h>
+}
+
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<IVideoBufferPool> m_videoBufferPool;
};
--
2.29.2

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,35 @@
From 559f5716ee5e45e87e3bb7f7e5ded5c6116d194b Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Tue, 26 May 2020 20:08:27 +0200
Subject: [PATCH 2/2] arm64: dts: h6 deinterlace
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
index 78b1361dfbb9..d45893b7b7b8 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -152,6 +152,17 @@ mixer0_out_tcon_top_mixer0: endpoint {
};
};
+ deinterlace: deinterlace@1420000 {
+ compatible = "allwinner,sun50i-h6-deinterlace";
+ reg = <0x01420000 0x2000>;
+ clocks = <&ccu CLK_BUS_DEINTERLACE>,
+ <&ccu CLK_DEINTERLACE>,
+ <&ccu CLK_MBUS_DEINTERLACE>;
+ clock-names = "bus", "mod", "ram";
+ resets = <&ccu RST_BUS_DEINTERLACE>;
+ interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
video-codec@1c0e000 {
compatible = "allwinner,sun50i-h6-video-engine";
reg = <0x01c0e000 0x2000>;
--
2.27.0