summarylogtreecommitdiffstats
path: root/0002-rkmpp-4.patch
diff options
context:
space:
mode:
authorboogie2023-01-30 11:14:13 +0100
committerboogie2023-01-30 11:14:13 +0100
commitf4cc880714a8be1012e22dfcfbbc4d28ed127b86 (patch)
tree3a1e081c2b05e65e7b3099113bf3253c1e205c51 /0002-rkmpp-4.patch
downloadaur-f4cc880714a8be1012e22dfcfbbc4d28ed127b86.tar.gz
initial
Diffstat (limited to '0002-rkmpp-4.patch')
-rw-r--r--0002-rkmpp-4.patch2771
1 files changed, 2771 insertions, 0 deletions
diff --git a/0002-rkmpp-4.patch b/0002-rkmpp-4.patch
new file mode 100644
index 000000000000..5c8734c1535a
--- /dev/null
+++ b/0002-rkmpp-4.patch
@@ -0,0 +1,2771 @@
+From 9590c16111eb27ba8cb1b5c46ea57dc9052e82ed Mon Sep 17 00:00:00 2001
+From: Jeffy Chen <jeffy.chen@rock-chips.com>
+Date: Wed, 4 Sep 2019 17:24:37 +0800
+Subject: [PATCH 01/16] avcodec/rkmppdec: Clear eos flag after reset
+
+Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
+---
+ libavcodec/rkmppdec.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c
+index a60962dc86..3654437268 100644
+--- a/libavcodec/rkmppdec.c
++++ b/libavcodec/rkmppdec.c
+@@ -544,6 +544,7 @@ static void rkmpp_flush(AVCodecContext *avctx)
+ ret = decoder->mpi->reset(decoder->ctx);
+ if (ret == MPP_OK) {
+ decoder->first_packet = 1;
++ decoder->eos_reached = 0;
+ } else
+ av_log(avctx, AV_LOG_ERROR, "Failed to reset MPI (code = %d)\n", ret);
+ }
+--
+2.39.0
+
+
+From 43fc7807c58999a57d4c407dcda0d3d2fac7405b Mon Sep 17 00:00:00 2001
+From: Jeffy Chen <jeffy.chen@rock-chips.com>
+Date: Wed, 4 Sep 2019 17:27:46 +0800
+Subject: [PATCH 02/16] avcodec/rkmppdec: Compatible with old reordered_opaque
+ and pkt_pts
+
+Some users might still using these deprecated APIs.
+
+Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
+---
+ libavcodec/rkmppdec.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c
+index 3654437268..6256abe63c 100644
+--- a/libavcodec/rkmppdec.c
++++ b/libavcodec/rkmppdec.c
+@@ -93,6 +93,9 @@ static int rkmpp_write_data(AVCodecContext *avctx, uint8_t *buffer, int size, in
+ int ret;
+ MppPacket packet;
+
++ if (!pts || pts == AV_NOPTS_VALUE)
++ pts = avctx->reordered_opaque;
++
+ // create the MPP packet
+ ret = mpp_packet_init(&packet, buffer, size);
+ if (ret != MPP_OK) {
+@@ -398,6 +401,12 @@ static int rkmpp_retrieve_frame(AVCodecContext *avctx, AVFrame *frame)
+ frame->width = mpp_frame_get_width(mppframe);
+ frame->height = mpp_frame_get_height(mppframe);
+ frame->pts = mpp_frame_get_pts(mppframe);
++#if FF_API_PKT_PTS
++ FF_DISABLE_DEPRECATION_WARNINGS
++ frame->pkt_pts = frame->pts;
++ FF_ENABLE_DEPRECATION_WARNINGS
++#endif
++ frame->reordered_opaque = frame->pts;
+ frame->color_range = mpp_frame_get_color_range(mppframe);
+ frame->color_primaries = mpp_frame_get_color_primaries(mppframe);
+ frame->color_trc = mpp_frame_get_color_trc(mppframe);
+--
+2.39.0
+
+
+From 6b5e686cea5638fe6c2c92eeaaabe16d9a72121b Mon Sep 17 00:00:00 2001
+From: Jeffy Chen <jeffy.chen@rock-chips.com>
+Date: Wed, 19 May 2021 09:55:03 +0800
+Subject: [PATCH 03/16] rkmppdec: Remove frame buffer limit
+
+It would hang when reaching the limit.
+
+Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
+---
+ libavcodec/rkmppdec.c | 8 --------
+ 1 file changed, 8 deletions(-)
+
+diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c
+index 6256abe63c..96696e84dc 100644
+--- a/libavcodec/rkmppdec.c
++++ b/libavcodec/rkmppdec.c
+@@ -39,7 +39,6 @@
+ #include "libavutil/log.h"
+
+ #define RECEIVE_FRAME_TIMEOUT 100
+-#define FRAMEGROUP_MAX_FRAMES 16
+ #define INPUT_MAX_PACKETS 4
+
+ typedef struct {
+@@ -241,13 +240,6 @@ static int rkmpp_init_decoder(AVCodecContext *avctx)
+ goto fail;
+ }
+
+- ret = mpp_buffer_group_limit_config(decoder->frame_group, 0, FRAMEGROUP_MAX_FRAMES);
+- if (ret) {
+- av_log(avctx, AV_LOG_ERROR, "Failed to set buffer group limit (code = %d)\n", ret);
+- ret = AVERROR_UNKNOWN;
+- goto fail;
+- }
+-
+ decoder->first_packet = 1;
+
+ av_log(avctx, AV_LOG_DEBUG, "RKMPP decoder initialized successfully.\n");
+--
+2.39.0
+
+
+From 668ec8c36d1112c5c4939ddc3d3b7cff487cedc1 Mon Sep 17 00:00:00 2001
+From: Jeffy Chen <jeffy.chen@rock-chips.com>
+Date: Thu, 20 May 2021 10:19:15 +0800
+Subject: [PATCH 04/16] avcodec/rkmppdec: Rework decoding flow
+
+Stop using the deprecated MPP_DEC_GET_STREAM_COUNT API.
+
+Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
+---
+ libavcodec/rkmppdec.c | 526 ++++++++++++++++++++++--------------------
+ 1 file changed, 270 insertions(+), 256 deletions(-)
+
+diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c
+index 96696e84dc..7c28378120 100644
+--- a/libavcodec/rkmppdec.c
++++ b/libavcodec/rkmppdec.c
+@@ -38,17 +38,15 @@
+ #include "libavutil/imgutils.h"
+ #include "libavutil/log.h"
+
+-#define RECEIVE_FRAME_TIMEOUT 100
+-#define INPUT_MAX_PACKETS 4
+-
+ typedef struct {
+ MppCtx ctx;
+ MppApi *mpi;
+ MppBufferGroup frame_group;
+
+- char first_packet;
+- char eos_reached;
++ int8_t eos;
++ int8_t draining;
+
++ AVPacket packet;
+ AVBufferRef *frames_ref;
+ AVBufferRef *device_ref;
+ } RKMPPDecoder;
+@@ -85,47 +83,13 @@ static uint32_t rkmpp_get_frameformat(MppFrameFormat mppformat)
+ }
+ }
+
+-static int rkmpp_write_data(AVCodecContext *avctx, uint8_t *buffer, int size, int64_t pts)
++static int rkmpp_close_decoder(AVCodecContext *avctx)
+ {
+ RKMPPDecodeContext *rk_context = avctx->priv_data;
+ RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data;
+- int ret;
+- MppPacket packet;
+-
+- if (!pts || pts == AV_NOPTS_VALUE)
+- pts = avctx->reordered_opaque;
+-
+- // create the MPP packet
+- ret = mpp_packet_init(&packet, buffer, size);
+- if (ret != MPP_OK) {
+- av_log(avctx, AV_LOG_ERROR, "Failed to init MPP packet (code = %d)\n", ret);
+- return AVERROR_UNKNOWN;
+- }
+-
+- mpp_packet_set_pts(packet, pts);
+-
+- if (!buffer)
+- mpp_packet_set_eos(packet);
+
+- ret = decoder->mpi->decode_put_packet(decoder->ctx, packet);
+- if (ret != MPP_OK) {
+- if (ret == MPP_ERR_BUFFER_FULL) {
+- av_log(avctx, AV_LOG_DEBUG, "Buffer full writing %d bytes to decoder\n", size);
+- ret = AVERROR(EAGAIN);
+- } else
+- ret = AVERROR_UNKNOWN;
+- }
+- else
+- av_log(avctx, AV_LOG_DEBUG, "Wrote %d bytes to decoder\n", size);
++ av_packet_unref(&decoder->packet);
+
+- mpp_packet_deinit(&packet);
+-
+- return ret;
+-}
+-
+-static int rkmpp_close_decoder(AVCodecContext *avctx)
+-{
+- RKMPPDecodeContext *rk_context = avctx->priv_data;
+ av_buffer_unref(&rk_context->decoder_ref);
+ return 0;
+ }
+@@ -151,14 +115,32 @@ static void rkmpp_release_decoder(void *opaque, uint8_t *data)
+ av_free(decoder);
+ }
+
++static int rkmpp_prepare_decoder(AVCodecContext *avctx)
++{
++ RKMPPDecodeContext *rk_context = avctx->priv_data;
++ RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data;
++ MppPacket packet;
++ int ret;
++
++ // send extra data
++ if (avctx->extradata_size) {
++ ret = mpp_packet_init(&packet, avctx->extradata, avctx->extradata_size);
++ if (ret < 0)
++ return AVERROR_UNKNOWN;
++ ret = decoder->mpi->decode_put_packet(decoder->ctx, packet);
++ mpp_packet_deinit(&packet);
++ if (ret < 0)
++ return AVERROR_UNKNOWN;
++ }
++ return 0;
++}
++
+ static int rkmpp_init_decoder(AVCodecContext *avctx)
+ {
+ RKMPPDecodeContext *rk_context = avctx->priv_data;
+ RKMPPDecoder *decoder = NULL;
+ MppCodingType codectype = MPP_VIDEO_CodingUnused;
+ int ret;
+- RK_S64 paramS64;
+- RK_S32 paramS32;
+
+ avctx->pix_fmt = AV_PIX_FMT_DRM_PRIME;
+
+@@ -201,6 +183,9 @@ static int rkmpp_init_decoder(AVCodecContext *avctx)
+ goto fail;
+ }
+
++ ret = 1;
++ decoder->mpi->control(decoder->ctx, MPP_DEC_SET_PARSER_FAST_MODE, &ret);
++
+ // initialize mpp
+ ret = mpp_init(decoder->ctx, MPP_CTX_DEC, codectype);
+ if (ret != MPP_OK) {
+@@ -209,26 +194,9 @@ static int rkmpp_init_decoder(AVCodecContext *avctx)
+ goto fail;
+ }
+
+- // make decode calls blocking with a timeout
+- paramS32 = MPP_POLL_BLOCK;
+- ret = decoder->mpi->control(decoder->ctx, MPP_SET_OUTPUT_BLOCK, &paramS32);
+- if (ret != MPP_OK) {
+- av_log(avctx, AV_LOG_ERROR, "Failed to set blocking mode on MPI (code = %d).\n", ret);
+- ret = AVERROR_UNKNOWN;
+- goto fail;
+- }
+-
+- paramS64 = RECEIVE_FRAME_TIMEOUT;
+- ret = decoder->mpi->control(decoder->ctx, MPP_SET_OUTPUT_BLOCK_TIMEOUT, &paramS64);
+- if (ret != MPP_OK) {
+- av_log(avctx, AV_LOG_ERROR, "Failed to set block timeout on MPI (code = %d).\n", ret);
+- ret = AVERROR_UNKNOWN;
+- goto fail;
+- }
+-
+ ret = mpp_buffer_group_get_internal(&decoder->frame_group, MPP_BUFFER_TYPE_ION);
+ if (ret) {
+- av_log(avctx, AV_LOG_ERROR, "Failed to retrieve buffer group (code = %d)\n", ret);
++ av_log(avctx, AV_LOG_ERROR, "Failed to get buffer group (code = %d)\n", ret);
+ ret = AVERROR_UNKNOWN;
+ goto fail;
+ }
+@@ -240,7 +208,13 @@ static int rkmpp_init_decoder(AVCodecContext *avctx)
+ goto fail;
+ }
+
+- decoder->first_packet = 1;
++ decoder->mpi->control(decoder->ctx, MPP_DEC_SET_DISABLE_ERROR, NULL);
++
++ ret = rkmpp_prepare_decoder(avctx);
++ if (ret < 0) {
++ av_log(avctx, AV_LOG_ERROR, "Failed to prepare decoder (code = %d)\n", ret);
++ goto fail;
++ }
+
+ av_log(avctx, AV_LOG_DEBUG, "RKMPP decoder initialized successfully.\n");
+
+@@ -261,44 +235,6 @@ fail:
+ return ret;
+ }
+
+-static int rkmpp_send_packet(AVCodecContext *avctx, const AVPacket *avpkt)
+-{
+- RKMPPDecodeContext *rk_context = avctx->priv_data;
+- RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data;
+- int ret;
+-
+- // handle EOF
+- if (!avpkt->size) {
+- av_log(avctx, AV_LOG_DEBUG, "End of stream.\n");
+- decoder->eos_reached = 1;
+- ret = rkmpp_write_data(avctx, NULL, 0, 0);
+- if (ret)
+- av_log(avctx, AV_LOG_ERROR, "Failed to send EOS to decoder (code = %d)\n", ret);
+- return ret;
+- }
+-
+- // on first packet, send extradata
+- if (decoder->first_packet) {
+- if (avctx->extradata_size) {
+- ret = rkmpp_write_data(avctx, avctx->extradata,
+- avctx->extradata_size,
+- avpkt->pts);
+- if (ret) {
+- av_log(avctx, AV_LOG_ERROR, "Failed to write extradata to decoder (code = %d)\n", ret);
+- return ret;
+- }
+- }
+- decoder->first_packet = 0;
+- }
+-
+- // now send packet
+- ret = rkmpp_write_data(avctx, avpkt->data, avpkt->size, avpkt->pts);
+- if (ret && ret!=AVERROR(EAGAIN))
+- av_log(avctx, AV_LOG_ERROR, "Failed to write data to decoder (code = %d)\n", ret);
+-
+- return ret;
+-}
+-
+ static void rkmpp_release_frame(void *opaque, uint8_t *data)
+ {
+ AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)data;
+@@ -312,7 +248,7 @@ static void rkmpp_release_frame(void *opaque, uint8_t *data)
+ av_free(desc);
+ }
+
+-static int rkmpp_retrieve_frame(AVCodecContext *avctx, AVFrame *frame)
++static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout)
+ {
+ RKMPPDecodeContext *rk_context = avctx->priv_data;
+ RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data;
+@@ -327,156 +263,164 @@ static int rkmpp_retrieve_frame(AVCodecContext *avctx, AVFrame *frame)
+ MppFrameFormat mppformat;
+ uint32_t drmformat;
+
++ // should not provide any frame after EOS
++ if (decoder->eos)
++ return AVERROR_EOF;
++
++ decoder->mpi->control(decoder->ctx, MPP_SET_OUTPUT_TIMEOUT, (MppParam)&timeout);
++
+ ret = decoder->mpi->decode_get_frame(decoder->ctx, &mppframe);
+ if (ret != MPP_OK && ret != MPP_ERR_TIMEOUT) {
+- av_log(avctx, AV_LOG_ERROR, "Failed to get a frame from MPP (code = %d)\n", ret);
+- goto fail;
++ av_log(avctx, AV_LOG_ERROR, "Failed to get frame (code = %d)\n", ret);
++ return AVERROR_UNKNOWN;
+ }
+
+- if (mppframe) {
+- // Check whether we have a special frame or not
+- if (mpp_frame_get_info_change(mppframe)) {
+- AVHWFramesContext *hwframes;
++ if (!mppframe) {
++ av_log(avctx, AV_LOG_DEBUG, "Timeout getting decoded frame.\n");
++ return AVERROR(EAGAIN);
++ }
+
+- av_log(avctx, AV_LOG_INFO, "Decoder noticed an info change (%dx%d), format=%d\n",
+- (int)mpp_frame_get_width(mppframe), (int)mpp_frame_get_height(mppframe),
+- (int)mpp_frame_get_fmt(mppframe));
++ if (mpp_frame_get_eos(mppframe)) {
++ av_log(avctx, AV_LOG_DEBUG, "Received a EOS frame.\n");
++ decoder->eos = 1;
++ ret = AVERROR_EOF;
++ goto fail;
++ }
+
+- avctx->width = mpp_frame_get_width(mppframe);
+- avctx->height = mpp_frame_get_height(mppframe);
++ if (mpp_frame_get_discard(mppframe)) {
++ av_log(avctx, AV_LOG_DEBUG, "Received a discard frame.\n");
++ ret = AVERROR(EAGAIN);
++ goto fail;
++ }
+
+- decoder->mpi->control(decoder->ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL);
++ if (mpp_frame_get_errinfo(mppframe)) {
++ av_log(avctx, AV_LOG_ERROR, "Received a errinfo frame.\n");
++ ret = AVERROR_UNKNOWN;
++ goto fail;
++ }
+
+- av_buffer_unref(&decoder->frames_ref);
++ if (mpp_frame_get_info_change(mppframe)) {
++ AVHWFramesContext *hwframes;
+
+- decoder->frames_ref = av_hwframe_ctx_alloc(decoder->device_ref);
+- if (!decoder->frames_ref) {
+- ret = AVERROR(ENOMEM);
+- goto fail;
+- }
++ av_log(avctx, AV_LOG_INFO, "Decoder noticed an info change (%dx%d), format=%d\n",
++ (int)mpp_frame_get_width(mppframe), (int)mpp_frame_get_height(mppframe),
++ (int)mpp_frame_get_fmt(mppframe));
+
+- mppformat = mpp_frame_get_fmt(mppframe);
+- drmformat = rkmpp_get_frameformat(mppformat);
++ avctx->width = mpp_frame_get_width(mppframe);
++ avctx->height = mpp_frame_get_height(mppframe);
+
+- hwframes = (AVHWFramesContext*)decoder->frames_ref->data;
+- hwframes->format = AV_PIX_FMT_DRM_PRIME;
+- hwframes->sw_format = drmformat == DRM_FORMAT_NV12 ? AV_PIX_FMT_NV12 : AV_PIX_FMT_NONE;
+- hwframes->width = avctx->width;
+- hwframes->height = avctx->height;
+- ret = av_hwframe_ctx_init(decoder->frames_ref);
+- if (ret < 0)
+- goto fail;
++ decoder->mpi->control(decoder->ctx, MPP_DEC_SET_FRAME_INFO, (MppParam) mppframe);
++ decoder->mpi->control(decoder->ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL);
+
+- // here decoder is fully initialized, we need to feed it again with data
+- ret = AVERROR(EAGAIN);
+- goto fail;
+- } else if (mpp_frame_get_eos(mppframe)) {
+- av_log(avctx, AV_LOG_DEBUG, "Received a EOS frame.\n");
+- decoder->eos_reached = 1;
+- ret = AVERROR_EOF;
+- goto fail;
+- } else if (mpp_frame_get_discard(mppframe)) {
+- av_log(avctx, AV_LOG_DEBUG, "Received a discard frame.\n");
+- ret = AVERROR(EAGAIN);
+- goto fail;
+- } else if (mpp_frame_get_errinfo(mppframe)) {
+- av_log(avctx, AV_LOG_ERROR, "Received a errinfo frame.\n");
+- ret = AVERROR_UNKNOWN;
++ av_buffer_unref(&decoder->frames_ref);
++
++ decoder->frames_ref = av_hwframe_ctx_alloc(decoder->device_ref);
++ if (!decoder->frames_ref) {
++ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+- // here we should have a valid frame
+- av_log(avctx, AV_LOG_DEBUG, "Received a frame.\n");
++ mppformat = mpp_frame_get_fmt(mppframe);
++ drmformat = rkmpp_get_frameformat(mppformat);
++
++ hwframes = (AVHWFramesContext*)decoder->frames_ref->data;
++ hwframes->format = AV_PIX_FMT_DRM_PRIME;
++ hwframes->sw_format = drmformat == DRM_FORMAT_NV12 ? AV_PIX_FMT_NV12 : AV_PIX_FMT_NONE;
++ hwframes->width = avctx->width;
++ hwframes->height = avctx->height;
++ ret = av_hwframe_ctx_init(decoder->frames_ref);
++ if (!ret)
++ ret = AVERROR(EAGAIN);
++
++ goto fail;
++ }
+
+- // setup general frame fields
+- frame->format = AV_PIX_FMT_DRM_PRIME;
+- frame->width = mpp_frame_get_width(mppframe);
+- frame->height = mpp_frame_get_height(mppframe);
+- frame->pts = mpp_frame_get_pts(mppframe);
++ // here we should have a valid frame
++ av_log(avctx, AV_LOG_DEBUG, "Received a frame.\n");
++
++ // now setup the frame buffer info
++ buffer = mpp_frame_get_buffer(mppframe);
++ if (!buffer) {
++ av_log(avctx, AV_LOG_ERROR, "Failed to get the frame buffer, frame is dropped (code = %d)\n", ret);
++ ret = AVERROR(EAGAIN);
++ goto fail;
++ }
++
++ // setup general frame fields
++ frame->format = avctx->pix_fmt;
++ frame->width = mpp_frame_get_width(mppframe);
++ frame->height = mpp_frame_get_height(mppframe);
++ frame->pts = mpp_frame_get_pts(mppframe);
+ #if FF_API_PKT_PTS
+- FF_DISABLE_DEPRECATION_WARNINGS
+- frame->pkt_pts = frame->pts;
+- FF_ENABLE_DEPRECATION_WARNINGS
++ FF_DISABLE_DEPRECATION_WARNINGS;
++ frame->pkt_pts = frame->pts;
++ FF_ENABLE_DEPRECATION_WARNINGS;
+ #endif
+- frame->reordered_opaque = frame->pts;
+- frame->color_range = mpp_frame_get_color_range(mppframe);
+- frame->color_primaries = mpp_frame_get_color_primaries(mppframe);
+- frame->color_trc = mpp_frame_get_color_trc(mppframe);
+- frame->colorspace = mpp_frame_get_colorspace(mppframe);
++ frame->reordered_opaque = frame->pts;
++ frame->color_range = mpp_frame_get_color_range(mppframe);
++ frame->color_primaries = mpp_frame_get_color_primaries(mppframe);
++ frame->color_trc = mpp_frame_get_color_trc(mppframe);
++ frame->colorspace = mpp_frame_get_colorspace(mppframe);
+
+- mode = mpp_frame_get_mode(mppframe);
+- frame->interlaced_frame = ((mode & MPP_FRAME_FLAG_FIELD_ORDER_MASK) == MPP_FRAME_FLAG_DEINTERLACED);
+- frame->top_field_first = ((mode & MPP_FRAME_FLAG_FIELD_ORDER_MASK) == MPP_FRAME_FLAG_TOP_FIRST);
++ mode = mpp_frame_get_mode(mppframe);
++ frame->interlaced_frame = ((mode & MPP_FRAME_FLAG_FIELD_ORDER_MASK) == MPP_FRAME_FLAG_DEINTERLACED);
++ frame->top_field_first = ((mode & MPP_FRAME_FLAG_FIELD_ORDER_MASK) == MPP_FRAME_FLAG_TOP_FIRST);
+
+- mppformat = mpp_frame_get_fmt(mppframe);
+- drmformat = rkmpp_get_frameformat(mppformat);
++ mppformat = mpp_frame_get_fmt(mppframe);
++ drmformat = rkmpp_get_frameformat(mppformat);
+
+- // now setup the frame buffer info
+- buffer = mpp_frame_get_buffer(mppframe);
+- if (buffer) {
+- desc = av_mallocz(sizeof(AVDRMFrameDescriptor));
+- if (!desc) {
+- ret = AVERROR(ENOMEM);
+- goto fail;
+- }
++ desc = av_mallocz(sizeof(AVDRMFrameDescriptor));
++ if (!desc) {
++ ret = AVERROR(ENOMEM);
++ goto fail;
++ }
+
+- desc->nb_objects = 1;
+- desc->objects[0].fd = mpp_buffer_get_fd(buffer);
+- desc->objects[0].size = mpp_buffer_get_size(buffer);
+-
+- desc->nb_layers = 1;
+- layer = &desc->layers[0];
+- layer->format = drmformat;
+- layer->nb_planes = 2;
+-
+- layer->planes[0].object_index = 0;
+- layer->planes[0].offset = 0;
+- layer->planes[0].pitch = mpp_frame_get_hor_stride(mppframe);
+-
+- layer->planes[1].object_index = 0;
+- layer->planes[1].offset = layer->planes[0].pitch * mpp_frame_get_ver_stride(mppframe);
+- layer->planes[1].pitch = layer->planes[0].pitch;
+-
+- // we also allocate a struct in buf[0] that will allow to hold additionnal information
+- // for releasing properly MPP frames and decoder
+- framecontextref = av_buffer_allocz(sizeof(*framecontext));
+- if (!framecontextref) {
+- ret = AVERROR(ENOMEM);
+- goto fail;
+- }
++ desc->nb_objects = 1;
++ desc->objects[0].fd = mpp_buffer_get_fd(buffer);
++ desc->objects[0].size = mpp_buffer_get_size(buffer);
+
+- // MPP decoder needs to be closed only when all frames have been released.
+- framecontext = (RKMPPFrameContext *)framecontextref->data;
+- framecontext->decoder_ref = av_buffer_ref(rk_context->decoder_ref);
+- framecontext->frame = mppframe;
++ desc->nb_layers = 1;
++ layer = &desc->layers[0];
++ layer->format = drmformat;
++ layer->nb_planes = 2;
+
+- frame->data[0] = (uint8_t *)desc;
+- frame->buf[0] = av_buffer_create((uint8_t *)desc, sizeof(*desc), rkmpp_release_frame,
+- framecontextref, AV_BUFFER_FLAG_READONLY);
++ layer->planes[0].object_index = 0;
++ layer->planes[0].offset = 0;
++ layer->planes[0].pitch = mpp_frame_get_hor_stride(mppframe);
+
+- if (!frame->buf[0]) {
+- ret = AVERROR(ENOMEM);
+- goto fail;
+- }
++ layer->planes[1].object_index = 0;
++ layer->planes[1].offset = layer->planes[0].pitch * mpp_frame_get_ver_stride(mppframe);
++ layer->planes[1].pitch = layer->planes[0].pitch;
+
+- frame->hw_frames_ctx = av_buffer_ref(decoder->frames_ref);
+- if (!frame->hw_frames_ctx) {
+- ret = AVERROR(ENOMEM);
+- goto fail;
+- }
++ // we also allocate a struct in buf[0] that will allow to hold additionnal information
++ // for releasing properly MPP frames and decoder
++ framecontextref = av_buffer_allocz(sizeof(*framecontext));
++ if (!framecontextref) {
++ ret = AVERROR(ENOMEM);
++ goto fail;
++ }
+
+- return 0;
+- } else {
+- av_log(avctx, AV_LOG_ERROR, "Failed to retrieve the frame buffer, frame is dropped (code = %d)\n", ret);
+- mpp_frame_deinit(&mppframe);
+- }
+- } else if (decoder->eos_reached) {
+- return AVERROR_EOF;
+- } else if (ret == MPP_ERR_TIMEOUT) {
+- av_log(avctx, AV_LOG_DEBUG, "Timeout when trying to get a frame from MPP\n");
++ // MPP decoder needs to be closed only when all frames have been released.
++ framecontext = (RKMPPFrameContext *)framecontextref->data;
++ framecontext->decoder_ref = av_buffer_ref(rk_context->decoder_ref);
++ framecontext->frame = mppframe;
++
++ frame->data[0] = (uint8_t *)desc;
++ frame->buf[0] = av_buffer_create((uint8_t *)desc, sizeof(*desc), rkmpp_release_frame,
++ framecontextref, AV_BUFFER_FLAG_READONLY);
++
++ if (!frame->buf[0]) {
++ ret = AVERROR(ENOMEM);
++ goto fail;
+ }
+
+- return AVERROR(EAGAIN);
++ frame->hw_frames_ctx = av_buffer_ref(decoder->frames_ref);
++ if (!frame->hw_frames_ctx) {
++ ret = AVERROR(ENOMEM);
++ goto fail;
++ }
++
++ return 0;
+
+ fail:
+ if (mppframe)
+@@ -494,60 +438,130 @@ fail:
+ return ret;
+ }
+
++static int rkmpp_send_packet(AVCodecContext *avctx, AVPacket *packet)
++{
++ RKMPPDecodeContext *rk_context = avctx->priv_data;
++ RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data;
++ MppPacket mpkt;
++ int64_t pts = packet->pts;
++ int ret;
++
++ // avoid sending new data after EOS
++ if (decoder->draining)
++ return AVERROR_EOF;
++
++ if (!pts || pts == AV_NOPTS_VALUE)
++ pts = avctx->reordered_opaque;
++
++ ret = mpp_packet_init(&mpkt, packet->data, packet->size);
++ if (ret != MPP_OK) {
++ av_log(avctx, AV_LOG_ERROR, "Failed to init MPP packet (code = %d)\n", ret);
++ return AVERROR_UNKNOWN;
++ }
++
++ mpp_packet_set_pts(mpkt, pts);
++
++ ret = decoder->mpi->decode_put_packet(decoder->ctx, mpkt);
++ mpp_packet_deinit(&mpkt);
++
++ if (ret != MPP_OK) {
++ av_log(avctx, AV_LOG_DEBUG, "Buffer full\n");
++ return AVERROR(EAGAIN);
++ }
++
++ av_log(avctx, AV_LOG_DEBUG, "Wrote %d bytes to decoder\n", packet->size);
++ return 0;
++}
++
++static int rkmpp_send_eos(AVCodecContext *avctx)
++{
++ RKMPPDecodeContext *rk_context = avctx->priv_data;
++ RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data;
++ MppPacket mpkt;
++ int ret;
++
++ ret = mpp_packet_init(&mpkt, NULL, 0);
++ if (ret != MPP_OK) {
++ av_log(avctx, AV_LOG_ERROR, "Failed to init EOS packet (code = %d)\n", ret);
++ return AVERROR_UNKNOWN;
++ }
++
++ mpp_packet_set_eos(mpkt);
++
++ do {
++ ret = decoder->mpi->decode_put_packet(decoder->ctx, mpkt);
++ } while (ret != MPP_OK);
++ mpp_packet_deinit(&mpkt);
++
++ decoder->draining = 1;
++
++ return 0;
++}
++
+ static int rkmpp_receive_frame(AVCodecContext *avctx, AVFrame *frame)
+ {
+ RKMPPDecodeContext *rk_context = avctx->priv_data;
+ RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data;
+- int ret = MPP_NOK;
+- AVPacket pkt = {0};
+- RK_S32 usedslots, freeslots;
+-
+- if (!decoder->eos_reached) {
+- // we get the available slots in decoder
+- ret = decoder->mpi->control(decoder->ctx, MPP_DEC_GET_STREAM_COUNT, &usedslots);
+- if (ret != MPP_OK) {
+- av_log(avctx, AV_LOG_ERROR, "Failed to get decoder used slots (code = %d).\n", ret);
+- return ret;
+- }
++ AVPacket *packet = &decoder->packet;
++ int ret;
+
+- freeslots = INPUT_MAX_PACKETS - usedslots;
+- if (freeslots > 0) {
+- ret = ff_decode_get_packet(avctx, &pkt);
+- if (ret < 0 && ret != AVERROR_EOF) {
++ // no more frames after EOS
++ if (decoder->eos)
++ return AVERROR_EOF;
++
++ // draining remain frames
++ if (decoder->draining)
++ return rkmpp_get_frame(avctx, frame, MPP_TIMEOUT_BLOCK);
++
++ while (1) {
++ if (!packet->size) {
++ ret = ff_decode_get_packet(avctx, packet);
++ if (ret == AVERROR_EOF) {
++ av_log(avctx, AV_LOG_DEBUG, "End of stream.\n");
++ // send EOS and start draining
++ rkmpp_send_eos(avctx);
++ return rkmpp_get_frame(avctx, frame, MPP_TIMEOUT_BLOCK);
++ } else if (ret == AVERROR(EAGAIN)) {
++ // not blocking so that we can feed new data ASAP
++ return rkmpp_get_frame(avctx, frame, MPP_TIMEOUT_NON_BLOCK);
++ } else if (ret < 0) {
++ av_log(avctx, AV_LOG_ERROR, "Failed to get packet (code = %d)\n", ret);
+ return ret;
+ }
+-
+- ret = rkmpp_send_packet(avctx, &pkt);
+- av_packet_unref(&pkt);
+-
+- if (ret < 0) {
+- av_log(avctx, AV_LOG_ERROR, "Failed to send packet to decoder (code = %d)\n", ret);
++ } else {
++ // send pending data to decoder
++ ret = rkmpp_send_packet(avctx, packet);
++ if (ret == AVERROR(EAGAIN)) {
++ // some streams might need more packets to start returning frames
++ ret = rkmpp_get_frame(avctx, frame, 1);
++ if (ret != AVERROR(EAGAIN))
++ return ret;
++ } else if (ret < 0) {
++ av_log(avctx, AV_LOG_ERROR, "Failed to send data (code = %d)\n", ret);
+ return ret;
++ } else {
++ av_packet_unref(packet);
++ packet->size = 0;
+ }
+ }
+-
+- // make sure we keep decoder full
+- if (freeslots > 1)
+- return AVERROR(EAGAIN);
+ }
+-
+- return rkmpp_retrieve_frame(avctx, frame);
+ }
+
+ static void rkmpp_flush(AVCodecContext *avctx)
+ {
+ RKMPPDecodeContext *rk_context = avctx->priv_data;
+ RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data;
+- int ret = MPP_NOK;
+
+ av_log(avctx, AV_LOG_DEBUG, "Flush.\n");
+
+- ret = decoder->mpi->reset(decoder->ctx);
+- if (ret == MPP_OK) {
+- decoder->first_packet = 1;
+- decoder->eos_reached = 0;
+- } else
+- av_log(avctx, AV_LOG_ERROR, "Failed to reset MPI (code = %d)\n", ret);
++ decoder->mpi->reset(decoder->ctx);
++
++ rkmpp_prepare_decoder(avctx);
++
++ decoder->eos = 0;
++ decoder->draining = 0;
++
++ av_packet_unref(&decoder->packet);
+ }
+
+ static const AVCodecHWConfigInternal *const rkmpp_hw_configs[] = {
+--
+2.39.0
+
+
+From 3f94c029c3eeca764c63e32435e8ca8241a87dfc Mon Sep 17 00:00:00 2001
+From: Jeffy Chen <jeffy.chen@rock-chips.com>
+Date: Fri, 21 May 2021 04:23:36 +0800
+Subject: [PATCH 05/16] HACK: avcodec/rkmppdec: Force aligning coded width and
+ height to 64
+
+The chromium would try to align planes' width and height to 32, which
+might break the plane buffers' contiguous required by RGA.
+
+Passing a 64-aligned coded width and height to avoid that.
+
+Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
+---
+ libavcodec/rkmppdec.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c
+index 7c28378120..bae3ca6cb5 100644
+--- a/libavcodec/rkmppdec.c
++++ b/libavcodec/rkmppdec.c
+@@ -309,6 +309,11 @@ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout)
+ avctx->width = mpp_frame_get_width(mppframe);
+ avctx->height = mpp_frame_get_height(mppframe);
+
++ // chromium would align planes' width and height to 32, adding this
++ // hack to avoid breaking the plane buffers' contiguous.
++ avctx->coded_width = FFALIGN(avctx->width, 64);
++ avctx->coded_height = FFALIGN(avctx->height, 64);
++
+ decoder->mpi->control(decoder->ctx, MPP_DEC_SET_FRAME_INFO, (MppParam) mppframe);
+ decoder->mpi->control(decoder->ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL);
+
+--
+2.39.0
+
+
+From 804808de6c6af583b71526ff9e11196e1515e542 Mon Sep 17 00:00:00 2001
+From: Jeffy Chen <jeffy.chen@rock-chips.com>
+Date: Thu, 20 May 2021 10:20:17 +0800
+Subject: [PATCH 06/16] HACK: avcodec/rkmppdec: Support outputing YUV420P
+
+Lots of users support YUV420P format rather than DRM_PRIME.
+
+Support RGA accelerated format conversion.
+
+Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
+---
+ configure | 7 ++-
+ libavcodec/rkmppdec.c | 120 +++++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 125 insertions(+), 2 deletions(-)
+
+diff --git a/configure b/configure
+index 89af70d72f..9e08481e11 100755
+--- a/configure
++++ b/configure
+@@ -345,6 +345,7 @@ External library support:
+ --enable-omx enable OpenMAX IL code [no]
+ --enable-omx-rpi enable OpenMAX IL code for Raspberry Pi [no]
+ --enable-rkmpp enable Rockchip Media Process Platform code [no]
++ --enable-librga enable Rockchip RGA 2D accel via librga [autodetect]
+ --disable-v4l2-m2m disable V4L2 mem2mem code [autodetect]
+ --disable-vaapi disable Video Acceleration API (mainly Unix/Intel) code [autodetect]
+ --disable-vdpau disable Nvidia Video Decode and Presentation API for Unix code [autodetect]
+@@ -1848,6 +1849,7 @@ HWACCEL_AUTODETECT_LIBRARY_LIST="
+ videotoolbox
+ v4l2_m2m
+ xvmc
++ librga
+ "
+
+ # catchall list of things that require external libs to link
+@@ -6539,10 +6541,13 @@ enabled openssl && { check_pkg_config openssl openssl openssl/ssl.h OP
+ check_lib openssl openssl/ssl.h SSL_library_init -lssl -lcrypto -lws2_32 -lgdi32 ||
+ die "ERROR: openssl not found"; }
+ enabled pocketsphinx && require_pkg_config pocketsphinx pocketsphinx pocketsphinx/pocketsphinx.h ps_init
++enabled librga && check_lib librga rga/RgaApi.h c_RkRgaInit -lrga && prepend rkmpp_deps "librga"
+ enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/rk_mpi.h mpp_create &&
+ require_pkg_config rockchip_mpp "rockchip_mpp >= 1.3.7" rockchip/rk_mpi.h mpp_create &&
+ { enabled libdrm ||
+- die "ERROR: rkmpp requires --enable-libdrm"; }
++ die "ERROR: rkmpp requires --enable-libdrm"; } &&
++ { enabled librga ||
++ warn "using rkmpp without librga"; }
+ }
+ enabled vapoursynth && require_pkg_config vapoursynth "vapoursynth-script >= 42" VSScript.h vsscript_init
+
+diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c
+index bae3ca6cb5..c621e687e0 100644
+--- a/libavcodec/rkmppdec.c
++++ b/libavcodec/rkmppdec.c
+@@ -38,6 +38,11 @@
+ #include "libavutil/imgutils.h"
+ #include "libavutil/log.h"
+
++#if CONFIG_LIBRGA
++#include <rga/rga.h>
++#include <rga/RgaApi.h>
++#endif
++
+ typedef struct {
+ MppCtx ctx;
+ MppApi *mpi;
+@@ -83,6 +88,17 @@ static uint32_t rkmpp_get_frameformat(MppFrameFormat mppformat)
+ }
+ }
+
++#if CONFIG_LIBRGA
++static uint32_t rkmpp_get_rgaformat(MppFrameFormat mppformat)
++{
++ switch (mppformat) {
++ case MPP_FMT_YUV420SP: return RK_FORMAT_YCbCr_420_SP;
++ case MPP_FMT_YUV420SP_10BIT: return RK_FORMAT_YCbCr_420_SP_10B;
++ default: return RK_FORMAT_UNKNOWN;
++ }
++}
++#endif
++
+ static int rkmpp_close_decoder(AVCodecContext *avctx)
+ {
+ RKMPPDecodeContext *rk_context = avctx->priv_data;
+@@ -142,7 +158,7 @@ static int rkmpp_init_decoder(AVCodecContext *avctx)
+ MppCodingType codectype = MPP_VIDEO_CodingUnused;
+ int ret;
+
+- avctx->pix_fmt = AV_PIX_FMT_DRM_PRIME;
++ avctx->pix_fmt = ff_get_format(avctx, avctx->codec->pix_fmts);
+
+ // create a decoder and a ref to it
+ decoder = av_mallocz(sizeof(RKMPPDecoder));
+@@ -248,6 +264,95 @@ static void rkmpp_release_frame(void *opaque, uint8_t *data)
+ av_free(desc);
+ }
+
++static int rkmpp_convert_frame(AVCodecContext *avctx, AVFrame *frame,
++ MppFrame mppframe, MppBuffer buffer)
++{
++ char *src = mpp_buffer_get_ptr(buffer);
++ char *dst_y = frame->data[0];
++ char *dst_u = frame->data[1];
++ char *dst_v = frame->data[2];
++#if CONFIG_LIBRGA
++ RgaSURF_FORMAT format = rkmpp_get_rgaformat(mpp_frame_get_fmt(mppframe));
++#endif
++ int width = mpp_frame_get_width(mppframe);
++ int height = mpp_frame_get_height(mppframe);
++ int hstride = mpp_frame_get_hor_stride(mppframe);
++ int vstride = mpp_frame_get_ver_stride(mppframe);
++ int y_pitch = frame->linesize[0];
++ int u_pitch = frame->linesize[1];
++ int v_pitch = frame->linesize[2];
++ int i, j;
++
++#if CONFIG_LIBRGA
++ rga_info_t src_info = {0};
++ rga_info_t dst_info = {0};
++ int dst_height = (dst_u - dst_y) / y_pitch;
++
++ static int rga_supported = 1;
++ static int rga_inited = 0;
++
++ if (!rga_supported)
++ goto bail;
++
++ if (!rga_inited) {
++ if (c_RkRgaInit() < 0) {
++ rga_supported = 0;
++ av_log(avctx, AV_LOG_WARNING, "RGA not available\n");
++ goto bail;
++ }
++ rga_inited = 1;
++ }
++
++ if (format == RK_FORMAT_UNKNOWN)
++ goto bail;
++
++ if (u_pitch != y_pitch / 2 || v_pitch != y_pitch / 2 ||
++ dst_u != dst_y + y_pitch * dst_height ||
++ dst_v != dst_u + u_pitch * dst_height / 2)
++ goto bail;
++
++ src_info.fd = mpp_buffer_get_fd(buffer);
++ src_info.mmuFlag = 1;
++ rga_set_rect(&src_info.rect, 0, 0, width, height, hstride, vstride,
++ format);
++
++ dst_info.virAddr = dst_y;
++ dst_info.mmuFlag = 1;
++ rga_set_rect(&dst_info.rect, 0, 0, frame->width, frame->height,
++ y_pitch, dst_height, RK_FORMAT_YCbCr_420_P);
++
++ if (c_RkRgaBlit(&src_info, &dst_info, NULL) < 0)
++ goto bail;
++
++ return 0;
++
++bail:
++#endif
++ if (mpp_frame_get_fmt(mppframe) != MPP_FMT_YUV420SP) {
++ av_log(avctx, AV_LOG_WARNING, "Unable to convert\n");
++ return -1;
++ }
++
++ av_log(avctx, AV_LOG_WARNING, "Doing slow software conversion\n");
++
++ for (i = 0; i < frame->height; i++)
++ memcpy(dst_y + i * y_pitch, src + i * hstride, frame->width);
++
++ src += hstride * vstride;
++
++ for (i = 0; i < frame->height / 2; i++) {
++ for (j = 0; j < frame->width; j++) {
++ dst_u[j] = src[2 * j + 0];
++ dst_v[j] = src[2 * j + 1];
++ }
++ dst_u += u_pitch;
++ dst_v += v_pitch;
++ src += hstride;
++ }
++
++ return 0;
++}
++
+ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout)
+ {
+ RKMPPDecodeContext *rk_context = avctx->priv_data;
+@@ -355,6 +460,16 @@ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout)
+ frame->format = avctx->pix_fmt;
+ frame->width = mpp_frame_get_width(mppframe);
+ frame->height = mpp_frame_get_height(mppframe);
++
++ if (avctx->pix_fmt != AV_PIX_FMT_DRM_PRIME) {
++ ret = ff_get_buffer(avctx, frame, 0);
++ if (ret < 0)
++ goto out;
++
++ ret = rkmpp_convert_frame(avctx, frame, mppframe, buffer);
++ goto out;
++ }
++
+ frame->pts = mpp_frame_get_pts(mppframe);
+ #if FF_API_PKT_PTS
+ FF_DISABLE_DEPRECATION_WARNINGS;
+@@ -427,6 +542,7 @@ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout)
+
+ return 0;
+
++out:
+ fail:
+ if (mppframe)
+ mpp_frame_deinit(&mppframe);
+@@ -571,6 +687,7 @@ static void rkmpp_flush(AVCodecContext *avctx)
+
+ static const AVCodecHWConfigInternal *const rkmpp_hw_configs[] = {
+ HW_CONFIG_INTERNAL(DRM_PRIME),
++ HW_CONFIG_INTERNAL(YUV420P),
+ NULL
+ };
+
+@@ -595,6 +712,7 @@ static const AVCodecHWConfigInternal *const rkmpp_hw_configs[] = {
+ .priv_class = &rkmpp_##NAME##_dec_class, \
+ .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \
+ .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_DRM_PRIME, \
++ AV_PIX_FMT_YUV420P, \
+ AV_PIX_FMT_NONE}, \
+ .hw_configs = rkmpp_hw_configs, \
+ .bsfs = BSFS, \
+--
+2.39.0
+
+
+From ad6f4d3518eea4795f457b81d44d27da943be982 Mon Sep 17 00:00:00 2001
+From: Jeffy Chen <jeffy.chen@rock-chips.com>
+Date: Mon, 27 Sep 2021 10:20:54 +0800
+Subject: [PATCH 07/16] avcodec/rkmppdec: Support logging fps
+
+Set env FFMPEG_RKMPP_LOG_FPS=1 to enable it.
+
+Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
+---
+ libavcodec/rkmppdec.c | 46 +++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 46 insertions(+)
+
+diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c
+index c621e687e0..82834c27a6 100644
+--- a/libavcodec/rkmppdec.c
++++ b/libavcodec/rkmppdec.c
+@@ -25,6 +25,7 @@
+ #include <rockchip/rk_mpi.h>
+ #include <time.h>
+ #include <unistd.h>
++#include <sys/time.h>
+
+ #include "avcodec.h"
+ #include "decode.h"
+@@ -43,6 +44,8 @@
+ #include <rga/RgaApi.h>
+ #endif
+
++#define FPS_UPDATE_INTERVAL 120
++
+ typedef struct {
+ MppCtx ctx;
+ MppApi *mpi;
+@@ -54,6 +57,11 @@ typedef struct {
+ AVPacket packet;
+ AVBufferRef *frames_ref;
+ AVBufferRef *device_ref;
++
++ char print_fps;
++
++ uint64_t last_fps_time;
++ uint64_t frames;
+ } RKMPPDecoder;
+
+ typedef struct {
+@@ -156,6 +164,7 @@ static int rkmpp_init_decoder(AVCodecContext *avctx)
+ RKMPPDecodeContext *rk_context = avctx->priv_data;
+ RKMPPDecoder *decoder = NULL;
+ MppCodingType codectype = MPP_VIDEO_CodingUnused;
++ char *env;
+ int ret;
+
+ avctx->pix_fmt = ff_get_format(avctx, avctx->codec->pix_fmts);
+@@ -167,6 +176,10 @@ static int rkmpp_init_decoder(AVCodecContext *avctx)
+ goto fail;
+ }
+
++ env = getenv("FFMPEG_RKMPP_LOG_FPS");
++ if (env != NULL)
++ decoder->print_fps = !!atoi(env);
++
+ rk_context->decoder_ref = av_buffer_create((uint8_t *)decoder, sizeof(*decoder), rkmpp_release_decoder,
+ NULL, AV_BUFFER_FLAG_READONLY);
+ if (!rk_context->decoder_ref) {
+@@ -353,6 +366,36 @@ bail:
+ return 0;
+ }
+
++static void rkmpp_update_fps(AVCodecContext *avctx)
++{
++ RKMPPDecodeContext *rk_context = avctx->priv_data;
++ RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data;
++ struct timeval tv;
++ uint64_t curr_time;
++ float fps;
++
++ if (!decoder->print_fps)
++ return;
++
++ if (!decoder->last_fps_time) {
++ gettimeofday(&tv, NULL);
++ decoder->last_fps_time = tv.tv_sec * 1000 + tv.tv_usec / 1000;
++ }
++
++ if (++decoder->frames % FPS_UPDATE_INTERVAL)
++ return;
++
++ gettimeofday(&tv, NULL);
++ curr_time = tv.tv_sec * 1000 + tv.tv_usec / 1000;
++
++ fps = 1000.0f * FPS_UPDATE_INTERVAL / (curr_time - decoder->last_fps_time);
++ decoder->last_fps_time = curr_time;
++
++ av_log(avctx, AV_LOG_INFO,
++ "[FFMPEG RKMPP] FPS: %6.1f || Frames: %" PRIu64 "\n",
++ fps, decoder->frames);
++}
++
+ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout)
+ {
+ RKMPPDecodeContext *rk_context = avctx->priv_data;
+@@ -456,6 +499,8 @@ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout)
+ goto fail;
+ }
+
++ rkmpp_update_fps(avctx);
++
+ // setup general frame fields
+ frame->format = avctx->pix_fmt;
+ frame->width = mpp_frame_get_width(mppframe);
+@@ -681,6 +726,7 @@ static void rkmpp_flush(AVCodecContext *avctx)
+
+ decoder->eos = 0;
+ decoder->draining = 0;
++ decoder->last_fps_time = decoder->frames = 0;
+
+ av_packet_unref(&decoder->packet);
+ }
+--
+2.39.0
+
+
+From 8b7cfe72359520a7f1cae3b3ce935a2ea549f705 Mon Sep 17 00:00:00 2001
+From: boogie <boogiepop@gmx.com>
+Date: Thu, 5 Jan 2023 22:41:48 +0100
+Subject: [PATCH 08/16] HACK: libavcodec & rkmppdec: Add
+ FF_CODEC_CAP_CONTIGUOUS_BUFFERS
+
+Add FF_CODEC_CAP_CONTIGUOUS_BUFFERS to alloc contiguous buffers.
+
+Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
+---
+ libavcodec/decode.c | 23 +++++++++++++++++++++++
+ libavcodec/internal.h | 4 ++++
+ libavcodec/rkmppdec.c | 19 ++++++++++---------
+ 3 files changed, 37 insertions(+), 9 deletions(-)
+
+diff --git a/libavcodec/decode.c b/libavcodec/decode.c
+index 936e5d63da..dfd9ed656d 100644
+--- a/libavcodec/decode.c
++++ b/libavcodec/decode.c
+@@ -1549,6 +1549,14 @@ static int update_frame_pool(AVCodecContext *avctx, AVFrame *frame)
+
+ for (i = 0; i < 4; i++) {
+ pool->linesize[i] = linesize[i];
++
++ if (avctx->codec->caps_internal & FF_CODEC_CAP_CONTIGUOUS_BUFFERS) {
++ if (!i)
++ size[0] += size[1] + size[2] + size[3];
++ else
++ continue;
++ }
++
+ if (size[i]) {
+ if (size[i] > INT_MAX - (16 + STRIDE_ALIGN - 1)) {
+ ret = AVERROR(EINVAL);
+@@ -1675,6 +1683,21 @@ static int video_get_buffer(AVCodecContext *s, AVFrame *pic)
+
+ pic->data[i] = pic->buf[i]->data;
+ }
++
++ if (s->codec->caps_internal & FF_CODEC_CAP_CONTIGUOUS_BUFFERS) {
++ int size;
++
++ for (i = 1; i < 4; i++) {
++ pic->linesize[i] = pool->linesize[i];
++ av_buffer_unref(pic->buf[i]);
++ }
++
++ size = av_image_fill_pointers(pic->data, pic->format, pic->height,
++ pic->buf[0]->data, pic->linesize);
++ if (size < 0 || size > pic->buf[0]->size)
++ goto fail;
++ }
++
+ for (; i < AV_NUM_DATA_POINTERS; i++) {
+ pic->data[i] = NULL;
+ pic->linesize[i] = 0;
+diff --git a/libavcodec/internal.h b/libavcodec/internal.h
+index d889c1883e..47e6a1d13b 100644
+--- a/libavcodec/internal.h
++++ b/libavcodec/internal.h
+@@ -89,6 +89,10 @@
+ */
+ #define FF_CODEC_TAGS_END -1
+
++/**
++ * The decoder requires contiguous buffers.
++ */
++#define FF_CODEC_CAP_CONTIGUOUS_BUFFERS (1 << 31)
+
+ #ifdef TRACE
+ # define ff_tlog(ctx, ...) av_log(ctx, AV_LOG_TRACE, __VA_ARGS__)
+diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c
+index 82834c27a6..a05c77977d 100644
+--- a/libavcodec/rkmppdec.c
++++ b/libavcodec/rkmppdec.c
+@@ -501,20 +501,15 @@ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout)
+
+ rkmpp_update_fps(avctx);
+
+- // setup general frame fields
+- frame->format = avctx->pix_fmt;
+- frame->width = mpp_frame_get_width(mppframe);
+- frame->height = mpp_frame_get_height(mppframe);
+-
+ if (avctx->pix_fmt != AV_PIX_FMT_DRM_PRIME) {
+ ret = ff_get_buffer(avctx, frame, 0);
+ if (ret < 0)
+ goto out;
+-
+- ret = rkmpp_convert_frame(avctx, frame, mppframe, buffer);
+- goto out;
+ }
+-
++ // setup general frame fields
++ frame->format = avctx->pix_fmt;
++ frame->width = mpp_frame_get_width(mppframe);
++ frame->height = mpp_frame_get_height(mppframe);
+ frame->pts = mpp_frame_get_pts(mppframe);
+ #if FF_API_PKT_PTS
+ FF_DISABLE_DEPRECATION_WARNINGS;
+@@ -531,6 +526,11 @@ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout)
+ frame->interlaced_frame = ((mode & MPP_FRAME_FLAG_FIELD_ORDER_MASK) == MPP_FRAME_FLAG_DEINTERLACED);
+ frame->top_field_first = ((mode & MPP_FRAME_FLAG_FIELD_ORDER_MASK) == MPP_FRAME_FLAG_TOP_FIRST);
+
++ if (avctx->pix_fmt != AV_PIX_FMT_DRM_PRIME) {
++ ret = rkmpp_convert_frame(avctx, frame, mppframe, buffer);
++ goto out;
++ }
++
+ mppformat = mpp_frame_get_fmt(mppframe);
+ drmformat = rkmpp_get_frameformat(mppformat);
+
+@@ -757,6 +757,7 @@ static const AVCodecHWConfigInternal *const rkmpp_hw_configs[] = {
+ .flush = rkmpp_flush, \
+ .priv_class = &rkmpp_##NAME##_dec_class, \
+ .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \
++ .caps_internal = FF_CODEC_CAP_CONTIGUOUS_BUFFERS, \
+ .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_DRM_PRIME, \
+ AV_PIX_FMT_YUV420P, \
+ AV_PIX_FMT_NONE}, \
+--
+2.39.0
+
+
+From d1ab43ce9ccb0b832dc1bd620785a1a455e15bed Mon Sep 17 00:00:00 2001
+From: Jeffy Chen <jeffy.chen@rock-chips.com>
+Date: Mon, 13 Dec 2021 15:44:43 +0800
+Subject: [PATCH 09/16] HACK: avcodec/rkmppdec: Define DRM_FORMAT_NV12_10
+
+DRM_FORMAT_NV12_10 is a downstream custom format for Rockchip.
+
+Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
+---
+ libavcodec/rkmppdec.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c
+index a05c77977d..2aa3ee2a30 100644
+--- a/libavcodec/rkmppdec.c
++++ b/libavcodec/rkmppdec.c
+@@ -44,6 +44,10 @@
+ #include <rga/RgaApi.h>
+ #endif
+
++#ifndef DRM_FORMAT_NV12_10
++#define DRM_FORMAT_NV12_10 fourcc_code('N', 'A', '1', '2')
++#endif
++
+ #define FPS_UPDATE_INTERVAL 120
+
+ typedef struct {
+@@ -89,9 +93,7 @@ static uint32_t rkmpp_get_frameformat(MppFrameFormat mppformat)
+ {
+ switch (mppformat) {
+ case MPP_FMT_YUV420SP: return DRM_FORMAT_NV12;
+-#ifdef DRM_FORMAT_NV12_10
+ case MPP_FMT_YUV420SP_10BIT: return DRM_FORMAT_NV12_10;
+-#endif
+ default: return 0;
+ }
+ }
+--
+2.39.0
+
+
+From 486ff6b9a813c48bca125b04a33088c5b3bf512d Mon Sep 17 00:00:00 2001
+From: Jeffy Chen <jeffy.chen@rock-chips.com>
+Date: Wed, 15 Dec 2021 15:34:48 +0800
+Subject: [PATCH 10/16] avcodec/rkmppdec: Support NV16
+
+The MPP might output NV16 format.
+
+Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
+---
+ libavcodec/rkmppdec.c | 15 +++++++++++++--
+ 1 file changed, 13 insertions(+), 2 deletions(-)
+
+diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c
+index 2aa3ee2a30..82288cad03 100644
+--- a/libavcodec/rkmppdec.c
++++ b/libavcodec/rkmppdec.c
+@@ -94,6 +94,17 @@ static uint32_t rkmpp_get_frameformat(MppFrameFormat mppformat)
+ switch (mppformat) {
+ case MPP_FMT_YUV420SP: return DRM_FORMAT_NV12;
+ case MPP_FMT_YUV420SP_10BIT: return DRM_FORMAT_NV12_10;
++ case MPP_FMT_YUV422SP: return DRM_FORMAT_NV16;
++ default: return 0;
++ }
++}
++
++static uint32_t rkmpp_get_avformat(MppFrameFormat mppformat)
++{
++ switch (mppformat) {
++ case MPP_FMT_YUV420SP: return AV_PIX_FMT_NV12;
++ case MPP_FMT_YUV420SP_10BIT: return AV_PIX_FMT_NONE;
++ case MPP_FMT_YUV422SP: return AV_PIX_FMT_NV16;
+ default: return 0;
+ }
+ }
+@@ -104,6 +115,7 @@ static uint32_t rkmpp_get_rgaformat(MppFrameFormat mppformat)
+ switch (mppformat) {
+ case MPP_FMT_YUV420SP: return RK_FORMAT_YCbCr_420_SP;
+ case MPP_FMT_YUV420SP_10BIT: return RK_FORMAT_YCbCr_420_SP_10B;
++ case MPP_FMT_YUV422SP: return RK_FORMAT_YCbCr_422_SP;
+ default: return RK_FORMAT_UNKNOWN;
+ }
+ }
+@@ -476,11 +488,10 @@ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout)
+ }
+
+ mppformat = mpp_frame_get_fmt(mppframe);
+- drmformat = rkmpp_get_frameformat(mppformat);
+
+ hwframes = (AVHWFramesContext*)decoder->frames_ref->data;
+ hwframes->format = AV_PIX_FMT_DRM_PRIME;
+- hwframes->sw_format = drmformat == DRM_FORMAT_NV12 ? AV_PIX_FMT_NV12 : AV_PIX_FMT_NONE;
++ hwframes->sw_format = rkmpp_get_avformat(mppformat);
+ hwframes->width = avctx->width;
+ hwframes->height = avctx->height;
+ ret = av_hwframe_ctx_init(decoder->frames_ref);
+--
+2.39.0
+
+
+From 7bf50d04f27c963a1bac402beb04f8f13a3773a4 Mon Sep 17 00:00:00 2001
+From: Jeffy Chen <jeffy.chen@rock-chips.com>
+Date: Wed, 23 Mar 2022 14:20:16 +0800
+Subject: [PATCH 11/16] avcodec/rkmppdec: Support sync mode
+
+Some people just don't know how to handle async APIs :(
+
+Support sync mode by waiting for decode result after feeding any packets.
+
+Set env "FFMPEG_RKMPP_SYNC" to enable it.
+
+Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
+---
+ libavcodec/rkmppdec.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c
+index 82288cad03..c8b400e910 100644
+--- a/libavcodec/rkmppdec.c
++++ b/libavcodec/rkmppdec.c
+@@ -66,6 +66,8 @@ typedef struct {
+
+ uint64_t last_fps_time;
+ uint64_t frames;
++
++ char sync;
+ } RKMPPDecoder;
+
+ typedef struct {
+@@ -170,6 +172,13 @@ static int rkmpp_prepare_decoder(AVCodecContext *avctx)
+ if (ret < 0)
+ return AVERROR_UNKNOWN;
+ }
++
++ if (getenv("FFMPEG_RKMPP_SYNC")) {
++ // wait for decode result after feeding any packets
++ decoder->sync = 1;
++ ret = 1;
++ decoder->mpi->control(decoder->ctx, MPP_DEC_SET_IMMEDIATE_OUT, &ret);
++ }
+ return 0;
+ }
+
+@@ -721,6 +730,10 @@ static int rkmpp_receive_frame(AVCodecContext *avctx, AVFrame *frame)
+ } else {
+ av_packet_unref(packet);
+ packet->size = 0;
++
++ // blocked waiting for decode result
++ if (decoder->sync)
++ return rkmpp_get_frame(avctx, frame, MPP_TIMEOUT_BLOCK);
+ }
+ }
+ }
+--
+2.39.0
+
+
+From 8725010e4431bc5f8933e0389b195ba7f8a8fa46 Mon Sep 17 00:00:00 2001
+From: boogie <boogiepop@gmx.com>
+Date: Thu, 5 Jan 2023 23:04:45 +0100
+Subject: [PATCH 12/16] avcodec/rkmppdec: Add H263/MPEG1/MPEG2/MPEG4
+
+Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
+---
+ configure | 4 ++++
+ libavcodec/Makefile | 4 ++++
+ libavcodec/allcodecs.c | 4 ++++
+ libavcodec/rkmppdec.c | 8 ++++++++
+ 4 files changed, 20 insertions(+)
+
+diff --git a/configure b/configure
+index 9e08481e11..6e72375e09 100755
+--- a/configure
++++ b/configure
+@@ -3074,6 +3074,7 @@ ac3_mf_encoder_deps="mediafoundation"
+ av1_cuvid_decoder_deps="cuvid CUVIDAV1PICPARAMS"
+ h263_v4l2m2m_decoder_deps="v4l2_m2m h263_v4l2_m2m"
+ h263_v4l2m2m_encoder_deps="v4l2_m2m h263_v4l2_m2m"
++h263_rkmpp_decoder_deps="rkmpp"
+ h264_amf_encoder_deps="amf"
+ h264_crystalhd_decoder_select="crystalhd h264_mp4toannexb_bsf h264_parser"
+ h264_cuvid_decoder_deps="cuvid"
+@@ -3119,6 +3120,7 @@ mjpeg_vaapi_encoder_select="cbs_jpeg jpegtables vaapi_encode"
+ mp3_mf_encoder_deps="mediafoundation"
+ mpeg1_cuvid_decoder_deps="cuvid"
+ mpeg1_v4l2m2m_decoder_deps="v4l2_m2m mpeg1_v4l2_m2m"
++mpeg1_rkmpp_decoder_deps="rkmpp"
+ mpeg2_crystalhd_decoder_select="crystalhd"
+ mpeg2_cuvid_decoder_deps="cuvid"
+ mpeg2_mmal_decoder_deps="mmal"
+@@ -3127,6 +3129,7 @@ mpeg2_qsv_decoder_select="qsvdec"
+ mpeg2_qsv_encoder_select="qsvenc"
+ mpeg2_vaapi_encoder_select="cbs_mpeg2 vaapi_encode"
+ mpeg2_v4l2m2m_decoder_deps="v4l2_m2m mpeg2_v4l2_m2m"
++mpeg2_rkmpp_decoder_deps="rkmpp"
+ mpeg4_crystalhd_decoder_select="crystalhd"
+ mpeg4_cuvid_decoder_deps="cuvid"
+ mpeg4_mediacodec_decoder_deps="mediacodec"
+@@ -3134,6 +3137,7 @@ mpeg4_mmal_decoder_deps="mmal"
+ mpeg4_omx_encoder_deps="omx"
+ mpeg4_v4l2m2m_decoder_deps="v4l2_m2m mpeg4_v4l2_m2m"
+ mpeg4_v4l2m2m_encoder_deps="v4l2_m2m mpeg4_v4l2_m2m"
++mpeg4_rkmpp_decoder_deps="rkmpp"
+ msmpeg4_crystalhd_decoder_select="crystalhd"
+ nvenc_h264_encoder_select="h264_nvenc_encoder"
+ nvenc_hevc_encoder_select="hevc_nvenc_encoder"
+diff --git a/libavcodec/Makefile b/libavcodec/Makefile
+index b3d284d7d0..345b6a5816 100644
+--- a/libavcodec/Makefile
++++ b/libavcodec/Makefile
+@@ -364,6 +364,7 @@ OBJS-$(CONFIG_H263_ENCODER) += mpeg4video.o \
+ h263.o ituh263enc.o h263data.o
+ OBJS-$(CONFIG_H263_V4L2M2M_DECODER) += v4l2_m2m_dec.o
+ OBJS-$(CONFIG_H263_V4L2M2M_ENCODER) += v4l2_m2m_enc.o
++OBJS-$(CONFIG_H263_RKMPP_DECODER) += rkmppdec.o
+ OBJS-$(CONFIG_H264_DECODER) += h264dec.o h264_cabac.o h264_cavlc.o \
+ h264_direct.o h264_loopfilter.o \
+ h264_mb.o h264_picture.o \
+@@ -488,6 +489,7 @@ OBJS-$(CONFIG_MPEG1VIDEO_DECODER) += mpeg12dec.o mpeg12.o mpeg12data.o
+ OBJS-$(CONFIG_MPEG1VIDEO_ENCODER) += mpeg12enc.o mpeg12.o
+ OBJS-$(CONFIG_MPEG1_CUVID_DECODER) += cuviddec.o
+ OBJS-$(CONFIG_MPEG1_V4L2M2M_DECODER) += v4l2_m2m_dec.o
++OBJS-$(CONFIG_MPEG1_RKMPP_DECODER) += rkmppdec.o
+ OBJS-$(CONFIG_MPEG2_MMAL_DECODER) += mmaldec.o
+ OBJS-$(CONFIG_MPEG2_QSV_DECODER) += qsvdec.o
+ OBJS-$(CONFIG_MPEG2_QSV_ENCODER) += qsvenc_mpeg2.o
+@@ -497,6 +499,7 @@ OBJS-$(CONFIG_MPEG2_CUVID_DECODER) += cuviddec.o
+ OBJS-$(CONFIG_MPEG2_MEDIACODEC_DECODER) += mediacodecdec.o
+ OBJS-$(CONFIG_MPEG2_VAAPI_ENCODER) += vaapi_encode_mpeg2.o
+ OBJS-$(CONFIG_MPEG2_V4L2M2M_DECODER) += v4l2_m2m_dec.o
++OBJS-$(CONFIG_MPEG2_RKMPP_DECODER) += rkmppdec.o
+ OBJS-$(CONFIG_MPEG4_DECODER) += xvididct.o
+ OBJS-$(CONFIG_MPEG4_ENCODER) += mpeg4videoenc.o
+ OBJS-$(CONFIG_MPEG4_CUVID_DECODER) += cuviddec.o
+@@ -504,6 +507,7 @@ OBJS-$(CONFIG_MPEG4_MEDIACODEC_DECODER) += mediacodecdec.o
+ OBJS-$(CONFIG_MPEG4_OMX_ENCODER) += omx.o
+ OBJS-$(CONFIG_MPEG4_V4L2M2M_DECODER) += v4l2_m2m_dec.o
+ OBJS-$(CONFIG_MPEG4_V4L2M2M_ENCODER) += v4l2_m2m_enc.o
++OBJS-$(CONFIG_MPEG4_RKMPP_DECODER) += rkmppdec.o
+ OBJS-$(CONFIG_MPL2_DECODER) += mpl2dec.o ass.o
+ OBJS-$(CONFIG_MSA1_DECODER) += mss3.o
+ OBJS-$(CONFIG_MSCC_DECODER) += mscc.o
+diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
+index 2e9a3581de..5b2d8abe80 100644
+--- a/libavcodec/allcodecs.c
++++ b/libavcodec/allcodecs.c
+@@ -140,6 +140,7 @@ extern AVCodec ff_h263_decoder;
+ extern AVCodec ff_h263i_decoder;
+ extern AVCodec ff_h263p_encoder;
+ extern AVCodec ff_h263p_decoder;
++extern AVCodec ff_h263_rkmpp_decoder;
+ extern AVCodec ff_h263_v4l2m2m_decoder;
+ extern AVCodec ff_h264_decoder;
+ extern AVCodec ff_h264_crystalhd_decoder;
+@@ -199,11 +200,14 @@ extern AVCodec ff_mpeg2video_decoder;
+ extern AVCodec ff_mpeg4_encoder;
+ extern AVCodec ff_mpeg4_decoder;
+ extern AVCodec ff_mpeg4_crystalhd_decoder;
++extern AVCodec ff_mpeg4_rkmpp_decoder;
+ extern AVCodec ff_mpeg4_v4l2m2m_decoder;
+ extern AVCodec ff_mpeg4_mmal_decoder;
+ extern AVCodec ff_mpegvideo_decoder;
++extern AVCodec ff_mpeg1_rkmpp_decoder;
+ extern AVCodec ff_mpeg1_v4l2m2m_decoder;
+ extern AVCodec ff_mpeg2_mmal_decoder;
++extern AVCodec ff_mpeg2_rkmpp_decoder;
+ extern AVCodec ff_mpeg2_crystalhd_decoder;
+ extern AVCodec ff_mpeg2_v4l2m2m_decoder;
+ extern AVCodec ff_mpeg2_qsv_decoder;
+diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c
+index c8b400e910..79baab932d 100644
+--- a/libavcodec/rkmppdec.c
++++ b/libavcodec/rkmppdec.c
+@@ -83,10 +83,14 @@ typedef struct {
+ static MppCodingType rkmpp_get_codingtype(AVCodecContext *avctx)
+ {
+ switch (avctx->codec_id) {
++ case AV_CODEC_ID_H263: return MPP_VIDEO_CodingH263;
+ case AV_CODEC_ID_H264: return MPP_VIDEO_CodingAVC;
+ case AV_CODEC_ID_HEVC: return MPP_VIDEO_CodingHEVC;
+ case AV_CODEC_ID_VP8: return MPP_VIDEO_CodingVP8;
+ case AV_CODEC_ID_VP9: return MPP_VIDEO_CodingVP9;
++ case AV_CODEC_ID_MPEG1VIDEO: /* fallthrough */
++ case AV_CODEC_ID_MPEG2VIDEO: return MPP_VIDEO_CodingMPEG2;
++ case AV_CODEC_ID_MPEG4: return MPP_VIDEO_CodingMPEG4;
+ default: return MPP_VIDEO_CodingUnused;
+ }
+ }
+@@ -792,7 +796,11 @@ static const AVCodecHWConfigInternal *const rkmpp_hw_configs[] = {
+ .wrapper_name = "rkmpp", \
+ };
+
++RKMPP_DEC(h263, AV_CODEC_ID_H263, NULL)
+ RKMPP_DEC(h264, AV_CODEC_ID_H264, "h264_mp4toannexb")
+ RKMPP_DEC(hevc, AV_CODEC_ID_HEVC, "hevc_mp4toannexb")
+ RKMPP_DEC(vp8, AV_CODEC_ID_VP8, NULL)
+ RKMPP_DEC(vp9, AV_CODEC_ID_VP9, NULL)
++RKMPP_DEC(mpeg1, AV_CODEC_ID_MPEG1VIDEO, NULL)
++RKMPP_DEC(mpeg2, AV_CODEC_ID_MPEG2VIDEO, NULL)
++RKMPP_DEC(mpeg4, AV_CODEC_ID_MPEG4, "mpeg4_unpack_bframes")
+--
+2.39.0
+
+
+From a1795f4a3ea85a4b499765a66427db8d39c844da Mon Sep 17 00:00:00 2001
+From: boogie <boogiepop@gmx.com>
+Date: Fri, 6 Jan 2023 20:39:23 +0100
+Subject: [PATCH 13/16] allow nv15 and allow probing
+
+---
+ libavcodec/rkmppdec.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c
+index 79baab932d..93c426eeb3 100644
+--- a/libavcodec/rkmppdec.c
++++ b/libavcodec/rkmppdec.c
+@@ -45,7 +45,7 @@
+ #endif
+
+ #ifndef DRM_FORMAT_NV12_10
+-#define DRM_FORMAT_NV12_10 fourcc_code('N', 'A', '1', '2')
++#define DRM_FORMAT_NV12_10 fourcc_code('N', 'A', '1', '5')
+ #endif
+
+ #define FPS_UPDATE_INTERVAL 120
+@@ -786,7 +786,7 @@ static const AVCodecHWConfigInternal *const rkmpp_hw_configs[] = {
+ .receive_frame = rkmpp_receive_frame, \
+ .flush = rkmpp_flush, \
+ .priv_class = &rkmpp_##NAME##_dec_class, \
+- .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \
++ .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, \
+ .caps_internal = FF_CODEC_CAP_CONTIGUOUS_BUFFERS, \
+ .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_DRM_PRIME, \
+ AV_PIX_FMT_YUV420P, \
+--
+2.39.0
+
+
+From 73f8dc251ae7111b2f8ce9c4084071e157765e33 Mon Sep 17 00:00:00 2001
+From: boogie <boogiepop@gmx.com>
+Date: Fri, 6 Jan 2023 21:36:04 +0100
+Subject: [PATCH 14/16] priotrize the rkmpp variants first
+
+---
+ libavcodec/allcodecs.c | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
+index 5b2d8abe80..409e7f33e4 100644
+--- a/libavcodec/allcodecs.c
++++ b/libavcodec/allcodecs.c
+@@ -135,25 +135,25 @@ extern AVCodec ff_gif_encoder;
+ extern AVCodec ff_gif_decoder;
+ extern AVCodec ff_h261_encoder;
+ extern AVCodec ff_h261_decoder;
++extern AVCodec ff_h263_rkmpp_decoder;
+ extern AVCodec ff_h263_encoder;
+ extern AVCodec ff_h263_decoder;
+ extern AVCodec ff_h263i_decoder;
+ extern AVCodec ff_h263p_encoder;
+ extern AVCodec ff_h263p_decoder;
+-extern AVCodec ff_h263_rkmpp_decoder;
+ extern AVCodec ff_h263_v4l2m2m_decoder;
++extern AVCodec ff_h264_rkmpp_decoder;
+ extern AVCodec ff_h264_decoder;
+ extern AVCodec ff_h264_crystalhd_decoder;
+ extern AVCodec ff_h264_v4l2m2m_decoder;
+ extern AVCodec ff_h264_mediacodec_decoder;
+ extern AVCodec ff_h264_mmal_decoder;
+ extern AVCodec ff_h264_qsv_decoder;
+-extern AVCodec ff_h264_rkmpp_decoder;
+ extern AVCodec ff_hap_encoder;
+ extern AVCodec ff_hap_decoder;
++extern AVCodec ff_hevc_rkmpp_decoder;
+ extern AVCodec ff_hevc_decoder;
+ extern AVCodec ff_hevc_qsv_decoder;
+-extern AVCodec ff_hevc_rkmpp_decoder;
+ extern AVCodec ff_hevc_v4l2m2m_decoder;
+ extern AVCodec ff_hnm4_video_decoder;
+ extern AVCodec ff_hq_hqa_decoder;
+@@ -193,21 +193,21 @@ extern AVCodec ff_mjpegb_decoder;
+ extern AVCodec ff_mmvideo_decoder;
+ extern AVCodec ff_mobiclip_decoder;
+ extern AVCodec ff_motionpixels_decoder;
++extern AVCodec ff_mpeg1_rkmpp_decoder;
+ extern AVCodec ff_mpeg1video_encoder;
+ extern AVCodec ff_mpeg1video_decoder;
+ extern AVCodec ff_mpeg2video_encoder;
+ extern AVCodec ff_mpeg2video_decoder;
++extern AVCodec ff_mpeg4_rkmpp_decoder;
+ extern AVCodec ff_mpeg4_encoder;
+ extern AVCodec ff_mpeg4_decoder;
+ extern AVCodec ff_mpeg4_crystalhd_decoder;
+-extern AVCodec ff_mpeg4_rkmpp_decoder;
+ extern AVCodec ff_mpeg4_v4l2m2m_decoder;
+ extern AVCodec ff_mpeg4_mmal_decoder;
+ extern AVCodec ff_mpegvideo_decoder;
+-extern AVCodec ff_mpeg1_rkmpp_decoder;
+ extern AVCodec ff_mpeg1_v4l2m2m_decoder;
+-extern AVCodec ff_mpeg2_mmal_decoder;
+ extern AVCodec ff_mpeg2_rkmpp_decoder;
++extern AVCodec ff_mpeg2_mmal_decoder;
+ extern AVCodec ff_mpeg2_crystalhd_decoder;
+ extern AVCodec ff_mpeg2_v4l2m2m_decoder;
+ extern AVCodec ff_mpeg2_qsv_decoder;
+@@ -360,11 +360,11 @@ extern AVCodec ff_vp6_decoder;
+ extern AVCodec ff_vp6a_decoder;
+ extern AVCodec ff_vp6f_decoder;
+ extern AVCodec ff_vp7_decoder;
+-extern AVCodec ff_vp8_decoder;
+ extern AVCodec ff_vp8_rkmpp_decoder;
++extern AVCodec ff_vp8_decoder;
+ extern AVCodec ff_vp8_v4l2m2m_decoder;
+-extern AVCodec ff_vp9_decoder;
+ extern AVCodec ff_vp9_rkmpp_decoder;
++extern AVCodec ff_vp9_decoder;
+ extern AVCodec ff_vp9_v4l2m2m_decoder;
+ extern AVCodec ff_vqa_decoder;
+ extern AVCodec ff_webp_decoder;
+--
+2.39.0
+
+
+From 15cc4a4c861e6c0cb527e023332d875a75b6b732 Mon Sep 17 00:00:00 2001
+From: boogie <boogiepop@gmx.com>
+Date: Fri, 13 Jan 2023 22:27:01 +0100
+Subject: [PATCH 15/16] rkmpp: interface with kernel directly for rga and ditch
+ librga
+
+credit goes to icecream95: https://gitlab.com/-/snippets/2460396
+---
+ libavcodec/rga.h | 574 ++++++++++++++++++++++++++++++++++++++++++
+ libavcodec/rkmppdec.c | 272 ++++++++++++++++----
+ 2 files changed, 803 insertions(+), 43 deletions(-)
+ create mode 100644 libavcodec/rga.h
+
+diff --git a/libavcodec/rga.h b/libavcodec/rga.h
+new file mode 100644
+index 0000000000..9595558de0
+--- /dev/null
++++ b/libavcodec/rga.h
+@@ -0,0 +1,574 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++#ifndef _RGA_DRIVER_H_
++#define _RGA_DRIVER_H_
++
++/* Use 'r' as magic number */
++#define RGA_IOC_MAGIC 'r'
++#define RGA_IOW(nr, type) _IOW(RGA_IOC_MAGIC, nr, type)
++#define RGA_IOR(nr, type) _IOR(RGA_IOC_MAGIC, nr, type)
++#define RGA_IOWR(nr, type) _IOWR(RGA_IOC_MAGIC, nr, type)
++
++#define RGA_IOC_GET_DRVIER_VERSION RGA_IOR(0x1, struct rga_version_t)
++#define RGA_IOC_GET_HW_VERSION RGA_IOR(0x2, struct rga_hw_versions_t)
++#define RGA_IOC_IMPORT_BUFFER RGA_IOWR(0x3, struct rga_buffer_pool)
++#define RGA_IOC_RELEASE_BUFFER RGA_IOW(0x4, struct rga_buffer_pool)
++#define RGA_IOC_REQUEST_CREATE RGA_IOR(0x5, uint32_t)
++#define RGA_IOC_REQUEST_SUBMIT RGA_IOWR(0x6, struct rga_user_request)
++#define RGA_IOC_REQUEST_CONFIG RGA_IOWR(0x7, struct rga_user_request)
++#define RGA_IOC_REQUEST_CANCEL RGA_IOWR(0x8, uint32_t)
++
++#define RGA_BLIT_SYNC 0x5017
++#define RGA_BLIT_ASYNC 0x5018
++#define RGA_FLUSH 0x5019
++#define RGA_GET_RESULT 0x501a
++#define RGA_GET_VERSION 0x501b
++#define RGA_CACHE_FLUSH 0x501c
++
++#define RGA2_GET_VERSION 0x601b
++#define RGA_IMPORT_DMA 0x601d
++#define RGA_RELEASE_DMA 0x601e
++
++#define RGA_TASK_NUM_MAX 50
++
++#define RGA_OUT_OF_RESOURCES -10
++#define RGA_MALLOC_ERROR -11
++
++#define SCALE_DOWN_LARGE 1
++#define SCALE_UP_LARGE 1
++
++#define RGA_BUFFER_POOL_SIZE_MAX 40
++
++#define RGA3_MAJOR_VERSION_MASK (0xF0000000)
++#define RGA3_MINOR_VERSION_MASK (0x0FF00000)
++#define RGA3_SVN_VERSION_MASK (0x000FFFFF)
++
++#define RGA2_MAJOR_VERSION_MASK (0xFF000000)
++#define RGA2_MINOR_VERSION_MASK (0x00F00000)
++#define RGA2_SVN_VERSION_MASK (0x000FFFFF)
++
++#define RGA_MODE_ROTATE_0 (1<<0)
++#define RGA_MODE_ROTATE_90 (1<<1)
++#define RGA_MODE_ROTATE_180 (1<<2)
++#define RGA_MODE_ROTATE_270 (1<<3)
++#define RGA_MODE_X_MIRROR (1<<4)
++#define RGA_MODE_Y_MIRROR (1<<5)
++
++#define RGA_MODE_CSC_BT601L (1<<0)
++#define RGA_MODE_CSC_BT601F (1<<1)
++#define RGA_MODE_CSC_BT709 (1<<2)
++#define RGA_MODE_CSC_BT2020 (1<<3)
++
++#define RGA_MODE_ROTATE_MASK (\
++ RGA_MODE_ROTATE_0 | \
++ RGA_MODE_ROTATE_90 | \
++ RGA_MODE_ROTATE_180 | \
++ RGA_MODE_ROTATE_270 | \
++ RGA_MODE_X_MIRROR | \
++ RGA_MODE_Y_MIRROR)
++
++enum rga_memory_type {
++ RGA_DMA_BUFFER = 0,
++ RGA_VIRTUAL_ADDRESS,
++ RGA_PHYSICAL_ADDRESS,
++ RGA_DMA_BUFFER_PTR,
++};
++
++enum rga_scale_up_mode {
++ RGA_SCALE_UP_NONE = 0x0,
++ RGA_SCALE_UP_BIC = 0x1,
++};
++
++enum rga_scale_down_mode {
++ RGA_SCALE_DOWN_NONE = 0x0,
++ RGA_SCALE_DOWN_AVG = 0x1,
++};
++
++/* RGA process mode enum */
++enum {
++ BITBLT_MODE = 0x0,
++ COLOR_PALETTE_MODE = 0x1,
++ COLOR_FILL_MODE = 0x2,
++ /* used by rga2 */
++ UPDATE_PALETTE_TABLE_MODE = 0x6,
++ UPDATE_PATTEN_BUF_MODE = 0x7,
++}; /*render mode*/
++
++/* RGA rd_mode */
++enum {
++ RGA_RASTER_MODE = 0x1 << 0,
++ RGA_FBC_MODE = 0x1 << 1,
++ RGA_TILE_MODE = 0x1 << 2,
++};
++
++enum {
++ RGA_CONTEXT_NONE = 0x0,
++ RGA_CONTEXT_SRC_FIX_ENABLE = 0x1 << 0,
++ RGA_CONTEXT_SRC_CACHE_INFO = 0x1 << 1,
++ RGA_CONTEXT_SRC_MASK = RGA_CONTEXT_SRC_FIX_ENABLE |
++ RGA_CONTEXT_SRC_CACHE_INFO,
++ RGA_CONTEXT_PAT_FIX_ENABLE = 0x1 << 2,
++ RGA_CONTEXT_PAT_CACHE_INFO = 0x1 << 3,
++ RGA_CONTEXT_PAT_MASK = RGA_CONTEXT_PAT_FIX_ENABLE |
++ RGA_CONTEXT_PAT_CACHE_INFO,
++ RGA_CONTEXT_DST_FIX_ENABLE = 0x1 << 4,
++ RGA_CONTEXT_DST_CACHE_INFO = 0x1 << 5,
++ RGA_CONTEXT_DST_MASK = RGA_CONTEXT_DST_FIX_ENABLE |
++ RGA_CONTEXT_DST_CACHE_INFO,
++};
++
++/* RGA feature */
++enum {
++ RGA_COLOR_FILL = 0x1 << 0,
++ RGA_COLOR_PALETTE = 0x1 << 1,
++ RGA_COLOR_KEY = 0x1 << 2,
++ RGA_ROP_CALCULATE = 0x1 << 3,
++ RGA_NN_QUANTIZE = 0x1 << 4,
++ RGA_OSD_BLEND = 0x1 << 5,
++ RGA_DITHER = 0x1 << 6,
++ RGA_MOSAIC = 0x1 << 7,
++ RGA_YIN_YOUT = 0x1 << 8,
++ RGA_YUV_HDS = 0x1 << 9,
++ RGA_YUV_VDS = 0x1 << 10,
++ RGA_OSD = 0x1 << 11,
++ RGA_PRE_INTR = 0x1 << 12,
++};
++
++enum rga_surf_format {
++ RGA_FORMAT_RGBA_8888 = 0x0,
++ RGA_FORMAT_RGBX_8888 = 0x1,
++ RGA_FORMAT_RGB_888 = 0x2,
++ RGA_FORMAT_BGRA_8888 = 0x3,
++ RGA_FORMAT_RGB_565 = 0x4,
++ RGA_FORMAT_RGBA_5551 = 0x5,
++ RGA_FORMAT_RGBA_4444 = 0x6,
++ RGA_FORMAT_BGR_888 = 0x7,
++
++ RGA_FORMAT_YCbCr_422_SP = 0x8,
++ RGA_FORMAT_YCbCr_422_P = 0x9,
++ RGA_FORMAT_YCbCr_420_SP = 0xa,
++ RGA_FORMAT_YCbCr_420_P = 0xb,
++
++ RGA_FORMAT_YCrCb_422_SP = 0xc,
++ RGA_FORMAT_YCrCb_422_P = 0xd,
++ RGA_FORMAT_YCrCb_420_SP = 0xe,
++ RGA_FORMAT_YCrCb_420_P = 0xf,
++
++ RGA_FORMAT_BPP1 = 0x10,
++ RGA_FORMAT_BPP2 = 0x11,
++ RGA_FORMAT_BPP4 = 0x12,
++ RGA_FORMAT_BPP8 = 0x13,
++
++ RGA_FORMAT_Y4 = 0x14,
++ RGA_FORMAT_YCbCr_400 = 0x15,
++
++ RGA_FORMAT_BGRX_8888 = 0x16,
++
++ RGA_FORMAT_YVYU_422 = 0x18,
++ RGA_FORMAT_YVYU_420 = 0x19,
++ RGA_FORMAT_VYUY_422 = 0x1a,
++ RGA_FORMAT_VYUY_420 = 0x1b,
++ RGA_FORMAT_YUYV_422 = 0x1c,
++ RGA_FORMAT_YUYV_420 = 0x1d,
++ RGA_FORMAT_UYVY_422 = 0x1e,
++ RGA_FORMAT_UYVY_420 = 0x1f,
++
++ RGA_FORMAT_YCbCr_420_SP_10B = 0x20,
++ RGA_FORMAT_YCrCb_420_SP_10B = 0x21,
++ RGA_FORMAT_YCbCr_422_SP_10B = 0x22,
++ RGA_FORMAT_YCrCb_422_SP_10B = 0x23,
++
++ RGA_FORMAT_BGR_565 = 0x24,
++ RGA_FORMAT_BGRA_5551 = 0x25,
++ RGA_FORMAT_BGRA_4444 = 0x26,
++
++ RGA_FORMAT_ARGB_8888 = 0x28,
++ RGA_FORMAT_XRGB_8888 = 0x29,
++ RGA_FORMAT_ARGB_5551 = 0x2a,
++ RGA_FORMAT_ARGB_4444 = 0x2b,
++ RGA_FORMAT_ABGR_8888 = 0x2c,
++ RGA_FORMAT_XBGR_8888 = 0x2d,
++ RGA_FORMAT_ABGR_5551 = 0x2e,
++ RGA_FORMAT_ABGR_4444 = 0x2f,
++
++ RGA_FORMAT_RGBA_2BPP = 0x30,
++
++ RGA_FORMAT_UNKNOWN = 0x100,
++};
++
++#define RGA_SCHED_PRIORITY_DEFAULT 0
++#define RGA_SCHED_PRIORITY_MAX 6
++
++#define RGA_VERSION_SIZE 16
++#define RGA_HW_SIZE 5
++
++struct rga_version_t {
++ uint32_t major;
++ uint32_t minor;
++ uint32_t revision;
++ uint8_t str[RGA_VERSION_SIZE];
++};
++
++struct rga_hw_versions_t {
++ struct rga_version_t version[RGA_HW_SIZE];
++ uint32_t size;
++};
++
++struct rga_memory_parm {
++ uint32_t width;
++ uint32_t height;
++ uint32_t format;
++
++ uint32_t size;
++};
++
++struct rga_external_buffer {
++ uint64_t memory;
++ uint32_t type;
++
++ uint32_t handle;
++ struct rga_memory_parm memory_parm;
++
++ uint8_t reserve[252];
++};
++
++struct rga_buffer_pool {
++ uint64_t buffers_ptr;
++ uint32_t size;
++};
++
++struct rga_color_fill_t {
++ int16_t gr_x_a;
++ int16_t gr_y_a;
++ int16_t gr_x_b;
++ int16_t gr_y_b;
++ int16_t gr_x_g;
++ int16_t gr_y_g;
++ int16_t gr_x_r;
++ int16_t gr_y_r;
++};
++
++/***************************************/
++/* porting from rga.h for msg convert */
++/***************************************/
++
++struct rga_fading_t {
++ uint8_t b;
++ uint8_t g;
++ uint8_t r;
++ uint8_t res;
++};
++
++struct rga_mmu_t {
++ uint8_t mmu_en;
++ uint64_t base_addr;
++ /*
++ * [0] mmu enable [1] src_flush [2] dst_flush
++ * [3] CMD_flush [4~5] page size
++ */
++ uint32_t mmu_flag;
++};
++
++struct rga_rect_t {
++ uint16_t xmin;
++ /* width - 1 */
++ uint16_t xmax;
++ uint16_t ymin;
++ /* height - 1 */
++ uint16_t ymax;
++};
++
++struct rga_point_t {
++ uint16_t x;
++ uint16_t y;
++};
++
++struct rga_line_draw_t {
++ /* LineDraw_start_point */
++ struct rga_point_t start_point;
++ /* LineDraw_end_point */
++ struct rga_point_t end_point;
++ /* LineDraw_color */
++ uint32_t color;
++ /* (enum) LineDrawing mode sel */
++ uint32_t flag;
++ /* range 1~16 */
++ uint32_t line_width;
++};
++
++/* color space convert coefficient. */
++struct rga_csc_coe {
++ int16_t r_v;
++ int16_t g_y;
++ int16_t b_u;
++ int32_t off;
++};
++
++struct rga_full_csc {
++ uint8_t flag;
++ struct rga_csc_coe coe_y;
++ struct rga_csc_coe coe_u;
++ struct rga_csc_coe coe_v;
++};
++
++struct rga_mosaic_info {
++ uint8_t enable;
++ uint8_t mode;
++};
++
++/* MAX(min, (max - channel_value)) */
++struct rga_osd_invert_factor {
++ uint8_t alpha_max;
++ uint8_t alpha_min;
++ uint8_t yg_max;
++ uint8_t yg_min;
++ uint8_t crb_max;
++ uint8_t crb_min;
++};
++
++struct rga_color {
++ union {
++ struct {
++ uint8_t red;
++ uint8_t green;
++ uint8_t blue;
++ uint8_t alpha;
++ };
++ uint32_t value;
++ };
++};
++
++struct rga_osd_bpp2 {
++ uint8_t ac_swap; // ac swap flag
++ // 0: CA
++ // 1: AC
++ uint8_t endian_swap; // rgba2bpp endian swap
++ // 0: Big endian
++ // 1: Little endian
++ struct rga_color color0;
++ struct rga_color color1;
++};
++
++struct rga_osd_mode_ctrl {
++ uint8_t mode; // OSD cal mode:
++ // 0b'1: statistics mode
++ // 1b'1: auto inversion overlap mode
++ uint8_t direction_mode; // horizontal or vertical
++ // 0: horizontal
++ // 1: vertical
++ uint8_t width_mode; // using @fix_width or LUT width
++ // 0: fix width
++ // 1: LUT width
++ uint16_t block_fix_width; // OSD block fixed width
++ // real width = (fix_width + 1) * 2
++ uint8_t block_num; // OSD block num
++ uint16_t flags_index; // auto invert flags index
++
++ /* invertion config */
++ uint8_t color_mode; // selete color
++ // 0: src1 color
++ // 1: config data color
++ uint8_t invert_flags_mode; // invert flag selete
++ // 0: use RAM flag
++ // 1: usr last result
++ uint8_t default_color_sel; // default color mode
++ // 0: default is bright
++ // 1: default is dark
++ uint8_t invert_enable; // invert channel enable
++ // 1 << 0: alpha enable
++ // 1 << 1: Y/G disable
++ // 1 << 3: C/RB disable
++ uint8_t invert_mode; // invert cal mode
++ // 0: normal(max-data)
++ // 1: swap
++ uint8_t invert_thresh; // if luma > thresh, osd_flag to be 1
++ uint8_t unfix_index; // OSD width config index
++};
++
++struct rga_osd_info {
++ uint8_t enable;
++
++ struct rga_osd_mode_ctrl mode_ctrl;
++ struct rga_osd_invert_factor cal_factor;
++ struct rga_osd_bpp2 bpp2_info;
++
++ union {
++ struct {
++ uint32_t last_flags0;
++ uint32_t last_flags1;
++ };
++ uint64_t last_flags;
++ };
++
++ union {
++ struct {
++ uint32_t cur_flags0;
++ uint32_t cur_flags1;
++ };
++ uint64_t cur_flags;
++ };
++};
++
++struct rga_pre_intr_info {
++ uint8_t enable;
++
++ uint8_t read_intr_en;
++ uint8_t write_intr_en;
++ uint8_t read_hold_en;
++ uint32_t read_threshold;
++ uint32_t write_start;
++ uint32_t write_step;
++};
++
++struct rga_img_info_t {
++ /* yrgb mem addr */
++ uint64_t yrgb_addr;
++ /* cb/cr mem addr */
++ uint64_t uv_addr;
++ /* cr mem addr */
++ uint64_t v_addr;
++ /* definition by RK_FORMAT */
++ uint32_t format;
++
++ uint16_t act_w;
++ uint16_t act_h;
++ uint16_t x_offset;
++ uint16_t y_offset;
++
++ uint16_t vir_w;
++ uint16_t vir_h;
++
++ uint16_t endian_mode;
++ /* useless */
++ uint16_t alpha_swap;
++
++ /* used by RGA3 */
++ uint16_t rotate_mode;
++ uint16_t rd_mode;
++
++ uint16_t is_10b_compact;
++ uint16_t is_10b_endian;
++
++ uint16_t enable;
++};
++
++struct rga_req {
++ /* (enum) process mode sel */
++ uint8_t render_mode;
++
++ struct rga_img_info_t src;
++ struct rga_img_info_t dst;
++ struct rga_img_info_t pat;
++
++ /* rop4 mask addr */
++ uint64_t rop_mask_addr;
++ /* LUT addr */
++ uint64_t LUT_addr;
++
++ /* dst clip window default value is dst_vir */
++ /* value from [0, w-1] / [0, h-1]*/
++ struct rga_rect_t clip;
++
++ /* dst angle default value 0 16.16 scan from table */
++ int32_t sina;
++ /* dst angle default value 0 16.16 scan from table */
++ int32_t cosa;
++
++ /* alpha rop process flag */
++ /* ([0] = 1 alpha_rop_enable) */
++ /* ([1] = 1 rop enable) */
++ /* ([2] = 1 fading_enable) */
++ /* ([3] = 1 PD_enable) */
++ /* ([4] = 1 alpha cal_mode_sel) */
++ /* ([5] = 1 dither_enable) */
++ /* ([6] = 1 gradient fill mode sel) */
++ /* ([7] = 1 AA_enable) */
++ uint16_t alpha_rop_flag;
++
++ /* 0 nearst / 1 bilnear / 2 bicubic */
++ uint8_t scale_mode;
++
++ /* color key max */
++ uint32_t color_key_max;
++ /* color key min */
++ uint32_t color_key_min;
++
++ /* foreground color */
++ uint32_t fg_color;
++ /* background color */
++ uint32_t bg_color;
++
++ /* color fill use gradient */
++ struct rga_color_fill_t gr_color;
++
++ struct rga_line_draw_t line_draw_info;
++
++ struct rga_fading_t fading;
++
++ /* porter duff alpha mode sel */
++ uint8_t PD_mode;
++
++ /* global alpha value */
++ uint8_t alpha_global_value;
++
++ /* rop2/3/4 code scan from rop code table*/
++ uint16_t rop_code;
++
++ /* [2] 0 blur 1 sharp / [1:0] filter_type*/
++ uint8_t bsfilter_flag;
++
++ /* (enum) color palette 0/1bpp, 1/2bpp 2/4bpp 3/8bpp*/
++ uint8_t palette_mode;
++
++ /* (enum) BT.601 MPEG / BT.601 JPEG / BT.709 */
++ uint8_t yuv2rgb_mode;
++
++ /* 0/big endian 1/little endian*/
++ uint8_t endian_mode;
++
++ /* (enum) rotate mode */
++ /* 0x0, no rotate */
++ /* 0x1, rotate */
++ /* 0x2, x_mirror */
++ /* 0x3, y_mirror */
++ uint8_t rotate_mode;
++
++ /* 0 solid color / 1 pattern color */
++ uint8_t color_fill_mode;
++
++ /* mmu information */
++ struct rga_mmu_t mmu_info;
++
++ /* ([0~1] alpha mode) */
++ /* ([2~3] rop mode) */
++ /* ([4] zero mode en) */
++ /* ([5] dst alpha mode) */
++ /* ([6] alpha output mode sel) 0 src / 1 dst*/
++ uint8_t alpha_rop_mode;
++
++ uint8_t src_trans_mode;
++
++ uint8_t dither_mode;
++
++ /* full color space convert */
++ struct rga_full_csc full_csc;
++
++ int32_t in_fence_fd;
++ uint8_t core;
++ uint8_t priority;
++ int32_t out_fence_fd;
++
++ uint8_t handle_flag;
++
++ /* RGA2 1106 add */
++ struct rga_mosaic_info mosaic_info;
++
++ uint8_t uvhds_mode;
++ uint8_t uvvds_mode;
++
++ struct rga_osd_info osd_info;
++
++ struct rga_pre_intr_info pre_intr_info;
++
++ uint8_t reservr[59];
++};
++#endif /*_RGA_DRIVER_H_*/
+diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c
+index 93c426eeb3..325150f483 100644
+--- a/libavcodec/rkmppdec.c
++++ b/libavcodec/rkmppdec.c
+@@ -18,6 +18,10 @@
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
++#ifdef _POSIX_C_SOURCE
++#undef _POSIX_C_SOURCE
++#endif
++#define _POSIX_C_SOURCE 200809L /* for O_CLOEXEC */
+
+ #include <drm_fourcc.h>
+ #include <pthread.h>
+@@ -26,6 +30,9 @@
+ #include <time.h>
+ #include <unistd.h>
+ #include <sys/time.h>
++#include <sys/mman.h>
++#include <linux/dma-heap.h>
++#include <fcntl.h>
+
+ #include "avcodec.h"
+ #include "decode.h"
+@@ -38,11 +45,8 @@
+ #include "libavutil/hwcontext_drm.h"
+ #include "libavutil/imgutils.h"
+ #include "libavutil/log.h"
++#include "rga.h"
+
+-#if CONFIG_LIBRGA
+-#include <rga/rga.h>
+-#include <rga/RgaApi.h>
+-#endif
+
+ #ifndef DRM_FORMAT_NV12_10
+ #define DRM_FORMAT_NV12_10 fourcc_code('N', 'A', '1', '5')
+@@ -50,11 +54,16 @@
+
+ #define FPS_UPDATE_INTERVAL 120
+
++struct rkmpp_dma_buffer;
+ typedef struct {
+ MppCtx ctx;
+ MppApi *mpi;
+ MppBufferGroup frame_group;
+
++ int dma_fd;
++ struct rkmpp_dma_buffer *dma_cache;
++ int rga_fd;
++
+ int8_t eos;
+ int8_t draining;
+
+@@ -115,17 +124,15 @@ static uint32_t rkmpp_get_avformat(MppFrameFormat mppformat)
+ }
+ }
+
+-#if CONFIG_LIBRGA
+ static uint32_t rkmpp_get_rgaformat(MppFrameFormat mppformat)
+ {
+ switch (mppformat) {
+- case MPP_FMT_YUV420SP: return RK_FORMAT_YCbCr_420_SP;
+- case MPP_FMT_YUV420SP_10BIT: return RK_FORMAT_YCbCr_420_SP_10B;
+- case MPP_FMT_YUV422SP: return RK_FORMAT_YCbCr_422_SP;
+- default: return RK_FORMAT_UNKNOWN;
++ case MPP_FMT_YUV420SP: return RGA_FORMAT_YCbCr_420_SP;
++ case MPP_FMT_YUV420SP_10BIT: return RGA_FORMAT_YCbCr_420_SP_10B;
++ case MPP_FMT_YUV422SP: return RGA_FORMAT_YCbCr_422_SP;
++ default: return RGA_FORMAT_UNKNOWN;
+ }
+ }
+-#endif
+
+ static int rkmpp_close_decoder(AVCodecContext *avctx)
+ {
+@@ -138,6 +145,8 @@ static int rkmpp_close_decoder(AVCodecContext *avctx)
+ return 0;
+ }
+
++static void rkmpp_buffer_free(struct rkmpp_dma_buffer *buffer);
++
+ static void rkmpp_release_decoder(void *opaque, uint8_t *data)
+ {
+ RKMPPDecoder *decoder = (RKMPPDecoder *)data;
+@@ -153,6 +162,20 @@ static void rkmpp_release_decoder(void *opaque, uint8_t *data)
+ decoder->frame_group = NULL;
+ }
+
++ rkmpp_buffer_free(decoder->dma_cache);
++ decoder->dma_cache = NULL;
++
++ if (decoder->dma_fd) {
++ close(decoder->dma_fd);
++ decoder->dma_fd = 0;
++ }
++
++ if (decoder->rga_fd) {
++ close(decoder->rga_fd);
++ decoder->rga_fd = 0;
++ }
++
++
+ av_buffer_unref(&decoder->frames_ref);
+ av_buffer_unref(&decoder->device_ref);
+
+@@ -250,13 +273,27 @@ static int rkmpp_init_decoder(AVCodecContext *avctx)
+ goto fail;
+ }
+
+- ret = mpp_buffer_group_get_internal(&decoder->frame_group, MPP_BUFFER_TYPE_ION);
++ ret = mpp_buffer_group_get_internal(&decoder->frame_group,
++ MPP_BUFFER_TYPE_DMA_HEAP);
++
+ if (ret) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to get buffer group (code = %d)\n", ret);
+ ret = AVERROR_UNKNOWN;
+ goto fail;
+ }
+
++ decoder->dma_fd = open("/dev/dma_heap/system-dma32", O_RDWR);
++ if (decoder->dma_fd < 0) {
++ av_log(avctx, AV_LOG_ERROR, "Failed to open system-dma32 heap\n");
++ ret = AVERROR_UNKNOWN;
++ goto fail;
++ }
++
++ decoder->rga_fd = open("/dev/rga", O_RDWR);
++ if (decoder->dma_fd < 0) {
++ av_log(avctx, AV_LOG_WARNING, "Failed to open RGA\n");
++ }
++
+ ret = decoder->mpi->control(decoder->ctx, MPP_DEC_SET_EXT_BUF_GROUP, decoder->frame_group);
+ if (ret) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to assign buffer group (code = %d)\n", ret);
+@@ -307,13 +344,14 @@ static void rkmpp_release_frame(void *opaque, uint8_t *data)
+ static int rkmpp_convert_frame(AVCodecContext *avctx, AVFrame *frame,
+ MppFrame mppframe, MppBuffer buffer)
+ {
++ RKMPPDecodeContext *rk_context = avctx->priv_data;
++ RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data;
++
+ char *src = mpp_buffer_get_ptr(buffer);
+ char *dst_y = frame->data[0];
+ char *dst_u = frame->data[1];
+ char *dst_v = frame->data[2];
+-#if CONFIG_LIBRGA
+- RgaSURF_FORMAT format = rkmpp_get_rgaformat(mpp_frame_get_fmt(mppframe));
+-#endif
++ enum rga_surf_format format = rkmpp_get_rgaformat(mpp_frame_get_fmt(mppframe));
+ int width = mpp_frame_get_width(mppframe);
+ int height = mpp_frame_get_height(mppframe);
+ int hstride = mpp_frame_get_hor_stride(mppframe);
+@@ -321,29 +359,41 @@ static int rkmpp_convert_frame(AVCodecContext *avctx, AVFrame *frame,
+ int y_pitch = frame->linesize[0];
+ int u_pitch = frame->linesize[1];
+ int v_pitch = frame->linesize[2];
+- int i, j;
++ int i, j, ret;
+
+-#if CONFIG_LIBRGA
+- rga_info_t src_info = {0};
+- rga_info_t dst_info = {0};
+ int dst_height = (dst_u - dst_y) / y_pitch;
+
+- static int rga_supported = 1;
+- static int rga_inited = 0;
++ struct rga_req req = {
++ .src = {
++ .yrgb_addr = mpp_buffer_get_fd(buffer),
++ .v_addr = hstride * vstride,
++ .format = format,
++ .act_w = width,
++ .act_h = height,
++ .vir_w = hstride,
++ .vir_h = vstride,
++ .rd_mode = RGA_RASTER_MODE,
++ },
++ .dst = {
++ .uv_addr = (uintptr_t) dst_y,
++ .v_addr = (uintptr_t) dst_u,
++ .format = RGA_FORMAT_YCbCr_420_P,
++ .act_w = width,
++ .act_h = height,
++ .vir_w = y_pitch,
++ .vir_h = dst_height,
++ .rd_mode = RGA_RASTER_MODE,
++ },
++ .mmu_info = {
++ .mmu_en = 1,
++ .mmu_flag = 0x80000521,
++ },
++ };
+
+- if (!rga_supported)
++ if (decoder->rga_fd < 0)
+ goto bail;
+
+- if (!rga_inited) {
+- if (c_RkRgaInit() < 0) {
+- rga_supported = 0;
+- av_log(avctx, AV_LOG_WARNING, "RGA not available\n");
+- goto bail;
+- }
+- rga_inited = 1;
+- }
+-
+- if (format == RK_FORMAT_UNKNOWN)
++ if (format == RGA_FORMAT_UNKNOWN)
+ goto bail;
+
+ if (u_pitch != y_pitch / 2 || v_pitch != y_pitch / 2 ||
+@@ -351,23 +401,13 @@ static int rkmpp_convert_frame(AVCodecContext *avctx, AVFrame *frame,
+ dst_v != dst_u + u_pitch * dst_height / 2)
+ goto bail;
+
+- src_info.fd = mpp_buffer_get_fd(buffer);
+- src_info.mmuFlag = 1;
+- rga_set_rect(&src_info.rect, 0, 0, width, height, hstride, vstride,
+- format);
+-
+- dst_info.virAddr = dst_y;
+- dst_info.mmuFlag = 1;
+- rga_set_rect(&dst_info.rect, 0, 0, frame->width, frame->height,
+- y_pitch, dst_height, RK_FORMAT_YCbCr_420_P);
+-
+- if (c_RkRgaBlit(&src_info, &dst_info, NULL) < 0)
++ ret = ioctl(decoder->rga_fd, RGA_BLIT_SYNC, &req);
++ if (ret < 0)
+ goto bail;
+
+ return 0;
+
+ bail:
+-#endif
+ if (mpp_frame_get_fmt(mppframe) != MPP_FMT_YUV420SP) {
+ av_log(avctx, AV_LOG_WARNING, "Unable to convert\n");
+ return -1;
+@@ -423,6 +463,150 @@ static void rkmpp_update_fps(AVCodecContext *avctx)
+ fps, decoder->frames);
+ }
+
++struct rkmpp_dma_buffer {
++ int fd;
++ void *cpu;
++ size_t size;
++ struct rkmpp_dma_buffer **cache;
++};
++
++static void rkmpp_buffer_free(struct rkmpp_dma_buffer *buffer)
++{
++ if (!buffer)
++ return;
++
++ munmap(buffer->cpu, buffer->size);
++ close(buffer->fd);
++ av_free(buffer);
++}
++
++static void rkmpp_buffer_cache(void *opaque, uint8_t *data)
++{
++ struct rkmpp_dma_buffer *buffer = opaque;
++
++ if (!buffer)
++ return;
++
++ if (*buffer->cache)
++ rkmpp_buffer_free(buffer);
++ else
++ *buffer->cache = buffer;
++}
++
++static struct rkmpp_dma_buffer *rkmpp_buffer_alloc(RKMPPDecoder *decoder, size_t size)
++{
++ struct rkmpp_dma_buffer *buffer;
++ int ret;
++
++ struct dma_heap_allocation_data alloc = {
++ .len = size,
++ .fd_flags = O_CLOEXEC | O_RDWR,
++ };
++
++ if (decoder->dma_cache) {
++ struct rkmpp_dma_buffer *cached = decoder->dma_cache;
++ decoder->dma_cache = NULL;
++
++ if (cached->size == size) {
++ return cached;
++ }
++
++ rkmpp_buffer_free(cached);
++ }
++
++ ret = ioctl(decoder->dma_fd, DMA_HEAP_IOCTL_ALLOC, &alloc);
++ if (ret == -1)
++ return NULL;
++
++ buffer = av_mallocz(sizeof(*buffer));
++ buffer->fd = alloc.fd;
++ buffer->size = alloc.len;
++ buffer->cpu = mmap(NULL, buffer->size, PROT_READ | PROT_WRITE,
++ MAP_SHARED, buffer->fd, 0);
++ buffer->cache = &decoder->dma_cache;
++
++ return buffer;
++}
++
++static int rkmpp_get_buffer2(AVCodecContext *avctx, AVFrame *pic, int flags)
++{
++ RKMPPDecodeContext *rk_context = avctx->priv_data;
++ RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data;
++
++ int ret;
++
++ int linesize[4];
++ int stride_align[AV_NUM_DATA_POINTERS];
++ int w = pic->width;
++ int h = pic->height;
++ int unaligned;
++ ptrdiff_t linesize1[4];
++ size_t size[4];
++
++ struct rkmpp_dma_buffer *buffer;
++
++ int total;
++
++ 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
++ ret = av_image_fill_linesizes(linesize, avctx->pix_fmt, w);
++ if (ret < 0)
++ goto fail;
++ // 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 |= linesize[i] % stride_align[i];
++ } while (unaligned);
++
++ for (int i = 0; i < 4; i++)
++ linesize1[i] = linesize[i];
++ ret = av_image_fill_plane_sizes(size, avctx->pix_fmt, h, linesize1);
++ if (ret < 0)
++ goto fail;
++
++ size[0] += size[1] + size[2] + size[3];
++ size[0] += 16 + STRIDE_ALIGN - 1;
++
++ buffer = rkmpp_buffer_alloc(decoder, size[0]);
++ if (!buffer)
++ goto fail;
++
++ av_log(avctx, AV_LOG_DEBUG, "Allocated buffer of size %zi -> %p (CPU %p)\n", size[0], buffer, buffer->cpu);
++
++ memset(pic->data, 0, sizeof(pic->data));
++ pic->extended_data = pic->data;
++
++ pic->linesize[0] = linesize[0];
++ pic->buf[0] = av_buffer_create(buffer->cpu, size[0],
++ rkmpp_buffer_cache, buffer, 0);
++ pic->data[0] = pic->buf[0]->data;
++
++ for (int i = 1; i < 4; i++)
++ pic->linesize[i] = linesize[i];
++
++ total = av_image_fill_pointers(pic->data, pic->format, pic->height,
++ pic->buf[0]->data, pic->linesize);
++ if (total < 0 || total > pic->buf[0]->size)
++ goto fail;
++
++ for (int i = 4; i < AV_NUM_DATA_POINTERS; i++) {
++ pic->data[i] = NULL;
++ pic->linesize[i] = 0;
++ }
++
++ return 0;
++
++fail:
++ av_frame_unref(pic);
++ return AVERROR(ENOMEM);
++}
++
++
+ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout)
+ {
+ RKMPPDecodeContext *rk_context = avctx->priv_data;
+@@ -528,6 +712,8 @@ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout)
+ rkmpp_update_fps(avctx);
+
+ if (avctx->pix_fmt != AV_PIX_FMT_DRM_PRIME) {
++ avctx->get_buffer2 = rkmpp_get_buffer2;
++
+ ret = ff_get_buffer(avctx, frame, 0);
+ if (ret < 0)
+ goto out;
+--
+2.39.0
+
+
+From 44ccb8a4f398dbb05c2bd2fd9a0dcd56ca8ceb54 Mon Sep 17 00:00:00 2001
+From: boogie <boogiepop@gmx.com>
+Date: Tue, 17 Jan 2023 01:02:19 +0100
+Subject: [PATCH 16/16] ugliest hack: vp8&9 color space workaround
+
+---
+ libavcodec/rkmppdec.c | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c
+index 325150f483..ad9208f0e6 100644
+--- a/libavcodec/rkmppdec.c
++++ b/libavcodec/rkmppdec.c
+@@ -734,6 +734,21 @@ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout)
+ frame->color_trc = mpp_frame_get_color_trc(mppframe);
+ frame->colorspace = mpp_frame_get_colorspace(mppframe);
+
++ /* ugliest hack in the world: firefox does not probe with avformat, so it does not
++ * have any idea about the frame format, instead tries to guess with decoder profile
++ * matches. Since this decoder does not provide any profile, it just sets color pro-
++ * file to 0 which RGB. This causes funny coloring on video decode.
++ * I set this manually to most popular BT709 colorspace for VP8&9. This worksaround
++ * youtube problems, but does not work always. At least there is no need to run this
++ * on each frame... But yeah it is too late and i dont care.
++ */
++ if ((avctx->codec_id == AV_CODEC_ID_VP8 || avctx->codec_id == AV_CODEC_ID_VP9 ) \
++ && avctx->profile == FF_PROFILE_UNKNOWN && !frame->colorspace){
++ frame->color_primaries = AVCOL_PRI_BT709;
++ frame->color_trc = AVCOL_TRC_BT709;
++ frame->colorspace = AVCOL_SPC_BT709;
++ }
++
+ mode = mpp_frame_get_mode(mppframe);
+ frame->interlaced_frame = ((mode & MPP_FRAME_FLAG_FIELD_ORDER_MASK) == MPP_FRAME_FLAG_DEINTERLACED);
+ frame->top_field_first = ((mode & MPP_FRAME_FLAG_FIELD_ORDER_MASK) == MPP_FRAME_FLAG_TOP_FIRST);
+--
+2.39.0
+