From 9590c16111eb27ba8cb1b5c46ea57dc9052e82ed Mon Sep 17 00:00:00 2001 From: Jeffy Chen 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 --- 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 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 --- 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 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 --- 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 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 --- 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, ¶mS32); - 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, ¶mS64); - 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 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 --- 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 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 --- 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 +#include +#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 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 --- 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 #include #include +#include #include "avcodec.h" #include "decode.h" @@ -43,6 +44,8 @@ #include #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 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 --- 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 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 --- 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 #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 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 --- 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 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 --- 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 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 --- 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 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 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 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 #include @@ -26,6 +30,9 @@ #include #include #include +#include +#include +#include #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 -#include -#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 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