Skip to content

Commit

Permalink
HACK: avcodec/rkmppdec: Support outputing YUV420P
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
JeffyCN committed May 24, 2022
1 parent c0ef3fa commit 6f4d520
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 2 deletions.
7 changes: 6 additions & 1 deletion configure
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,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]
Expand Down Expand Up @@ -1881,6 +1882,7 @@ HWACCEL_AUTODETECT_LIBRARY_LIST="
videotoolbox
v4l2_m2m
xvmc
librga
"

# catchall list of things that require external libs to link
Expand Down Expand Up @@ -6599,10 +6601,13 @@ enabled openssl && { { check_pkg_config openssl "openssl >= 3.0.0" ope
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 && require 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

Expand Down
116 changes: 115 additions & 1 deletion libavcodec/rkmppdec.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -83,6 +88,15 @@ static uint32_t rkmpp_get_frameformat(MppFrameFormat mppformat)
}
}

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;
}
}

static int rkmpp_close_decoder(AVCodecContext *avctx)
{
RKMPPDecodeContext *rk_context = avctx->priv_data;
Expand Down Expand Up @@ -142,7 +156,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));
Expand Down Expand Up @@ -248,6 +262,93 @@ 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];
RgaSURF_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);
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 (format != RK_FORMAT_YCbCr_420_SP) {
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;
Expand Down Expand Up @@ -355,6 +456,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;
Expand Down Expand Up @@ -427,6 +538,7 @@ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout)

return 0;

out:
fail:
if (mppframe)
mpp_frame_deinit(&mppframe);
Expand Down Expand Up @@ -569,6 +681,7 @@ static void rkmpp_flush(AVCodecContext *avctx)

static const AVCodecHWConfigInternal *const rkmpp_hw_configs[] = {
HW_CONFIG_INTERNAL(DRM_PRIME),
HW_CONFIG_INTERNAL(YUV420P),
NULL
};

Expand All @@ -593,6 +706,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, \
Expand Down

0 comments on commit 6f4d520

Please sign in to comment.