diff options
author | boogie | 2023-08-02 08:57:04 +0200 |
---|---|---|
committer | boogie | 2023-08-02 08:57:04 +0200 |
commit | 01276b4cdf1b6467b7a8ec227f88e8a86060506f (patch) | |
tree | 36f29b28c5bb574af1b67de35ce1e29df37e865c | |
parent | ec884a607381e2a8f638428b47e7309994b58927 (diff) | |
download | aur-01276b4cdf1b6467b7a8ec227f88e8a86060506f.tar.gz |
encoder support, fix lots of stuff
-rw-r--r-- | .SRCINFO | 22 | ||||
-rw-r--r-- | PKGBUILD | 50 | ||||
-rw-r--r-- | rkmpp-6.patch | 7044 |
3 files changed, 3682 insertions, 3434 deletions
@@ -1,9 +1,9 @@ pkgbase = ffmpeg-mpp pkgdesc = Complete solution to record, convert and stream audio and video supporting rockchip MPP hardware decoder pkgver = 6.0 - pkgrel = 6 + pkgrel = 7 epoch = 2 - url = https://ffmpeg.org/ + url = https://github.com/hbiyik/ffmpeg/ arch = aarch64 arch = arm7f license = GPL3 @@ -17,7 +17,10 @@ pkgbase = ffmpeg-mpp makedepends = opencl-headers makedepends = mpp-git makedepends = libyuv + makedepends = perl + depends = aom depends = alsa-lib + depends = cairo depends = bzip2 depends = fontconfig depends = fribidi @@ -35,6 +38,7 @@ pkgbase = ffmpeg-mpp depends = libfreetype.so depends = libgl depends = libiec61883 + depends = libjxl depends = libmodplug depends = libopenmpt.so depends = libpulse @@ -62,9 +66,11 @@ pkgbase = ffmpeg-mpp depends = libxvidcore.so depends = libzimg.so depends = ocl-icd + depends = onevpl depends = opencore-amr depends = openjpeg2 depends = opus + depends = rav1e depends = sdl2 depends = speex depends = srt @@ -73,6 +79,8 @@ pkgbase = ffmpeg-mpp depends = zlib depends = mpp-git depends = libyuv + depends = librist + depends = librga-multi optdepends = avisynthplus: AviSynthPlus support optdepends = ladspa: LADSPA filters provides = libavcodec.so @@ -83,19 +91,21 @@ pkgbase = ffmpeg-mpp provides = libpostproc.so provides = libswresample.so provides = libswscale.so - provides = ffmpeg-mpp - provides = ffmpeg - conflicts = ffmpeg-mpp + provides = ffmpeg=6.0-7 + provides = ffmpeg-obs=6.0-7 conflicts = ffmpeg + conflicts = ffmpeg-mpp options = !lto options = debug options = strip source = git+https://git.ffmpeg.org/ffmpeg.git?#tag=3949db4d261748a9f34358a388ee255ad1a7f0c0 + source = obs-deps::git+https://github.com/obsproject/obs-deps.git#tag=2023-04-03 source = add-av_stream_get_first_dts-for-chromium.patch source = rkmpp-6.patch validpgpkeys = DD1EC9E8DE085C629B3E1846B18E8928B3948D64 b2sums = SKIP + b2sums = SKIP b2sums = 555274228e09a233d92beb365d413ff5c718a782008075552cafb2130a3783cf976b51dfe4513c15777fb6e8397a34122d475080f2c4483e8feea5c0d878e6de - b2sums = 4d62f7a21cf6bdb9177f931b72a8a30b9a75c0bcef84eb500feb6820e60fd95507b4d92efba5f224fb992e5170d0d8cef388c9f6326f046c1d85eacd22e50a89 + b2sums = 0109ab217541a5120588315bac4378795f7678dcde8468a408eac89523e46dcd5da903a2a28cd9da065a8f09e37e803ade9f8a0f75983dcdd92ecb83825b4081 pkgname = ffmpeg-mpp @@ -20,15 +20,18 @@ pkgname=ffmpeg-mpp pkgver=6.0 -pkgrel=6 +pkgrel=7 epoch=2 +_obs_deps_tag=2023-04-03 pkgdesc='Complete solution to record, convert and stream audio and video supporting rockchip MPP hardware decoder' arch=(aarch64 arm7f) -url=https://ffmpeg.org/ +url=https://github.com/hbiyik/ffmpeg/ license=(GPL3) options=(!lto debug strip) depends=( + aom alsa-lib + cairo bzip2 fontconfig fribidi @@ -46,6 +49,7 @@ depends=( libfreetype.so libgl libiec61883 + libjxl libmodplug libopenmpt.so libpulse @@ -73,9 +77,11 @@ depends=( libxvidcore.so libzimg.so ocl-icd + onevpl opencore-amr openjpeg2 opus + rav1e sdl2 speex srt @@ -84,6 +90,8 @@ depends=( zlib mpp-git libyuv + librist + librga-multi ) makedepends=( amf-headers @@ -96,6 +104,7 @@ makedepends=( opencl-headers mpp-git libyuv + perl ) optdepends=( 'avisynthplus: AviSynthPlus support' @@ -110,30 +119,46 @@ provides=( libpostproc.so libswresample.so libswscale.so - $pkgname - ffmpeg + "ffmpeg=${pkgver}-${pkgrel}" + "ffmpeg-obs=${pkgver}-${pkgrel}" ) conflicts=( - $pkgname ffmpeg + $pkgname ) _tag=3949db4d261748a9f34358a388ee255ad1a7f0c0 source=( git+https://git.ffmpeg.org/ffmpeg.git?#tag=${_tag} + "obs-deps::git+https://github.com/obsproject/obs-deps.git#tag=${_obs_deps_tag}" add-av_stream_get_first_dts-for-chromium.patch rkmpp-6.patch ) b2sums=('SKIP' + 'SKIP' '555274228e09a233d92beb365d413ff5c718a782008075552cafb2130a3783cf976b51dfe4513c15777fb6e8397a34122d475080f2c4483e8feea5c0d878e6de' - '4d62f7a21cf6bdb9177f931b72a8a30b9a75c0bcef84eb500feb6820e60fd95507b4d92efba5f224fb992e5170d0d8cef388c9f6326f046c1d85eacd22e50a89') + '0109ab217541a5120588315bac4378795f7678dcde8468a408eac89523e46dcd5da903a2a28cd9da065a8f09e37e803ade9f8a0f75983dcdd92ecb83825b4081') validpgpkeys=(DD1EC9E8DE085C629B3E1846B18E8928B3948D64) # Michael Niedermayer <michael@niedermayer.cc> prepare() { cd ffmpeg + # delete the newly created files after patching, so that patching can work next time + rm libavcodec/rkmpp.h || true + rm libavcodec/rkmpp.c || true + rm libavcodec/rkmppenc.c || true + rm libavcodec/rkplane.c || true + rm libavcodec/rkplane.h || true + ## Fix segfault with avisynthplus + sed -i 's/RTLD_LOCAL/RTLD_DEEPBIND/g' libavformat/avisynth.c patch -Np1 -i ../add-av_stream_get_first_dts-for-chromium.patch # https://crbug.com/1251779 patch -Np1 -i ../rkmpp-6.patch + + # This patch applies: + # - Fix decoding of certain malformed FLV files + # - Add additional CPU levels for libaom + patch -Np1 -i ../obs-deps/deps.ffmpeg/patches/FFmpeg/0001-flvdec-handle-unknown.patch + patch -Np1 -i ../obs-deps/deps.ffmpeg/patches/FFmpeg/0002-libaomenc-presets.patch } pkgver() { @@ -157,6 +182,7 @@ build() { --enable-gnutls \ --enable-gpl \ --enable-ladspa \ + --enable-libaom \ --enable-libass \ --enable-libbluray \ --enable-libbs2b \ @@ -167,6 +193,7 @@ build() { --enable-libgsm \ --enable-libiec61883 \ --enable-libjack \ + --enable-libjxl \ --enable-libmodplug \ --enable-libmp3lame \ --enable-libopencore_amrnb \ @@ -175,6 +202,7 @@ build() { --enable-libopenmpt \ --enable-libopus \ --enable-libpulse \ + --enable-librav1e \ --enable-librsvg \ --enable-libsoxr \ --enable-libspeex \ @@ -184,6 +212,7 @@ build() { --enable-libv4l2 \ --enable-libvidstab \ --enable-libvorbis \ + --enable-libvpl \ --enable-libvpx \ --enable-libwebp \ --enable-libx264 \ @@ -196,15 +225,16 @@ build() { --enable-opengl \ --enable-shared \ --enable-version3 \ + --enable-librist \ --disable-vulkan \ --enable-rkmpp $CONFIG - make -j$(nproc) - make tools/qt-faststart - make doc/ff{mpeg,play}.1 + make ${MAKEFLAGS} + make ${MAKEFLAGS} tools/qt-faststart + make ${MAKEFLAGS} doc/ff{mpeg,play}.1 } package() { - make DESTDIR="${pkgdir}" -C ffmpeg install install-man + make ${MAKEFLAGS} DESTDIR="${pkgdir}" -C ffmpeg install install-man install -Dm 755 ffmpeg/tools/qt-faststart "${pkgdir}"/usr/bin/ } diff --git a/rkmpp-6.patch b/rkmpp-6.patch index 4b906b28d652..905ec3867c77 100644 --- a/rkmpp-6.patch +++ b/rkmpp-6.patch @@ -1,161 +1,639 @@ -From e13ddabb7694f8332d95ddc4bc00e37b1f7e2a76 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/24] avcodec/rkmppdec: Clear eos flag after reset +From 3262b03e2a59ec36b3c69fc3fed6f1aa931cf69d Mon Sep 17 00:00:00 2001 +From: rigaya <rigaya34589@live.jp> +Date: Fri, 7 Apr 2023 22:45:51 +0900 +Subject: [PATCH 01/13] avdevice/v4l2: add v4l2 multi-planar API support -Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com> --- - libavcodec/rkmppdec.c | 1 + - 1 file changed, 1 insertion(+) + libavdevice/v4l2.c | 173 ++++++++++++++++++++++++++++++++------------- + 1 file changed, 124 insertions(+), 49 deletions(-) -diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c -index 8bf7c6ed16..e31e0c44dc 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; +diff --git a/libavdevice/v4l2.c b/libavdevice/v4l2.c +index 5e85d1a2b3..249bedfaaa 100644 +--- a/libavdevice/v4l2.c ++++ b/libavdevice/v4l2.c +@@ -87,14 +87,16 @@ struct video_data { + int frame_size; + int interlaced; + int top_field_first; ++ int multi_planer; + int ts_mode; + TimeFilter *timefilter; + int64_t last_time_m; + + int buffers; + atomic_int buffers_queued; +- void **buf_start; +- unsigned int *buf_len; ++ int plane_count; ++ void ***buf_start; ++ unsigned int **buf_len; + char *standard; + v4l2_std_id std_id; + int channel; +@@ -181,11 +183,12 @@ static int device_open(AVFormatContext *ctx, const char* device_path) + av_log(ctx, AV_LOG_VERBOSE, "fd:%d capabilities:%x\n", + fd, cap.capabilities); + +- if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { ++ if (!(cap.capabilities & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE))) { + av_log(ctx, AV_LOG_ERROR, "Not a video capture device.\n"); + err = AVERROR(ENODEV); + goto fail; + } ++ s->multi_planer = ((cap.capabilities & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)) == V4L2_CAP_VIDEO_CAPTURE_MPLANE) ? 1 : 0; + + if (!(cap.capabilities & V4L2_CAP_STREAMING)) { + av_log(ctx, AV_LOG_ERROR, +@@ -205,7 +208,7 @@ static int device_init(AVFormatContext *ctx, int *width, int *height, + uint32_t pixelformat) + { + struct video_data *s = ctx->priv_data; +- struct v4l2_format fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE }; ++ struct v4l2_format fmt = { .type = (s->multi_planer) ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : V4L2_BUF_TYPE_VIDEO_CAPTURE }; + int res = 0; + + fmt.fmt.pix.width = *width; +@@ -287,7 +290,7 @@ static void list_framesizes(AVFormatContext *ctx, uint32_t pixelformat) + static void list_formats(AVFormatContext *ctx, int type) + { + const struct video_data *s = ctx->priv_data; +- struct v4l2_fmtdesc vfd = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE }; ++ struct v4l2_fmtdesc vfd = { .type = (s->multi_planer) ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : V4L2_BUF_TYPE_VIDEO_CAPTURE }; + + while(!v4l2_ioctl(s->fd, VIDIOC_ENUM_FMT, &vfd)) { + enum AVCodecID codec_id = ff_fmt_v4l2codec(vfd.pixelformat); +@@ -351,7 +354,7 @@ static int mmap_init(AVFormatContext *ctx) + int i, res; + struct video_data *s = ctx->priv_data; + struct v4l2_requestbuffers req = { +- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, ++ .type = (s->multi_planer) ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : V4L2_BUF_TYPE_VIDEO_CAPTURE, + .count = desired_video_buffers, + .memory = V4L2_MEMORY_MMAP + }; +@@ -367,45 +370,71 @@ static int mmap_init(AVFormatContext *ctx) + return AVERROR(ENOMEM); + } + s->buffers = req.count; +- s->buf_start = av_malloc_array(s->buffers, sizeof(void *)); ++ s->buf_start = av_malloc_array(s->buffers, sizeof(void **)); + if (!s->buf_start) { + av_log(ctx, AV_LOG_ERROR, "Cannot allocate buffer pointers\n"); + return AVERROR(ENOMEM); + } +- s->buf_len = av_malloc_array(s->buffers, sizeof(unsigned int)); ++ s->buf_len = av_malloc_array(s->buffers, sizeof(unsigned int*)); + if (!s->buf_len) { + av_log(ctx, AV_LOG_ERROR, "Cannot allocate buffer sizes\n"); + av_freep(&s->buf_start); + return AVERROR(ENOMEM); + } + ++ s->plane_count = 0; + for (i = 0; i < req.count; i++) { ++ int total_frame_size = 0; ++ int plane_count = 0; ++ struct v4l2_plane planes[VIDEO_MAX_PLANES]; + struct v4l2_buffer buf = { +- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, +- .index = i, +- .memory = V4L2_MEMORY_MMAP ++ .type = (s->multi_planer) ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : V4L2_BUF_TYPE_VIDEO_CAPTURE, ++ .index = i, ++ .memory = V4L2_MEMORY_MMAP, ++ .m.planes = (s->multi_planer) ? planes : 0, ++ .length = (s->multi_planer) ? VIDEO_MAX_PLANES : 0 + }; + if (v4l2_ioctl(s->fd, VIDIOC_QUERYBUF, &buf) < 0) { + res = AVERROR(errno); + av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QUERYBUF): %s\n", av_err2str(res)); + return res; + } +- +- s->buf_len[i] = buf.length; +- if (s->frame_size > 0 && s->buf_len[i] < s->frame_size) { +- av_log(ctx, AV_LOG_ERROR, +- "buf_len[%d] = %d < expected frame size %d\n", +- i, s->buf_len[i], s->frame_size); ++ plane_count = (s->multi_planer) ? buf.length : 1; ++ if (s->plane_count > 0 && s->plane_count != plane_count) { ++ av_log(ctx, AV_LOG_ERROR, "Plane count differed between buffers\n"); ++ return AVERROR(EINVAL); ++ } ++ s->plane_count = plane_count; ++ s->buf_start[i] = av_malloc_array(s->plane_count, sizeof(void *)); ++ if (!s->buf_start[i]) { ++ av_log(ctx, AV_LOG_ERROR, "Cannot allocate buffer pointers\n"); + return AVERROR(ENOMEM); + } +- s->buf_start[i] = v4l2_mmap(NULL, buf.length, +- PROT_READ | PROT_WRITE, MAP_SHARED, +- s->fd, buf.m.offset); ++ s->buf_len[i] = av_malloc_array(s->plane_count, sizeof(unsigned int*)); ++ if (!s->buf_len[i]) { ++ av_log(ctx, AV_LOG_ERROR, "Cannot allocate buffer sizes\n"); ++ av_freep(&s->buf_start); ++ return AVERROR(ENOMEM); ++ } ++ for (int iplane = 0; iplane < s->plane_count; iplane++) { ++ s->buf_len[i][iplane] = (s->multi_planer) ? buf.m.planes[iplane].length : buf.length; ++ total_frame_size += s->buf_len[i][iplane]; ++ s->buf_start[i][iplane] = v4l2_mmap(NULL, s->buf_len[i][iplane], ++ PROT_READ | PROT_WRITE, MAP_SHARED, ++ s->fd, (s->multi_planer) ? buf.m.planes[iplane].m.mem_offset : buf.m.offset); ++ ++ if (s->buf_start[i] == MAP_FAILED) { ++ res = AVERROR(errno); ++ av_log(ctx, AV_LOG_ERROR, "mmap: %s\n", av_err2str(res)); ++ return res; ++ } ++ } + +- if (s->buf_start[i] == MAP_FAILED) { +- res = AVERROR(errno); +- av_log(ctx, AV_LOG_ERROR, "mmap: %s\n", av_err2str(res)); +- return res; ++ if (s->frame_size > 0 && total_frame_size < s->frame_size) { ++ av_log(ctx, AV_LOG_ERROR, ++ "buf_len[%d] = %d < expected frame size %d\n", ++ i, total_frame_size, s->frame_size); ++ return AVERROR(ENOMEM); + } + } + +@@ -432,9 +461,9 @@ static void mmap_release_buffer(void *opaque, uint8_t *data) + struct buff_data *buf_descriptor = opaque; + struct video_data *s = buf_descriptor->s; + +- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ buf.type = (s->multi_planer) ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; +- buf.index = buf_descriptor->index; ++ buf.index = buf_descriptor->index; + av_free(buf_descriptor); + + enqueue_buffer(s, &buf); +@@ -504,9 +533,12 @@ static int convert_timestamp(AVFormatContext *ctx, int64_t *ts) + static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt) + { + struct video_data *s = ctx->priv_data; ++ struct v4l2_plane planes[VIDEO_MAX_PLANES]; + struct v4l2_buffer buf = { +- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, +- .memory = V4L2_MEMORY_MMAP ++ .type = (s->multi_planer) ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : V4L2_BUF_TYPE_VIDEO_CAPTURE, ++ .memory = V4L2_MEMORY_MMAP, ++ .m.planes = (s->multi_planer) ? planes : 0, ++ .length = (s->multi_planer) ? VIDEO_MAX_PLANES : 0 + }; + struct timeval buf_ts; + int res; +@@ -544,29 +576,63 @@ static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt) } else - av_log(avctx, AV_LOG_ERROR, "Failed to reset MPI (code = %d)\n", ret); - } + #endif + { ++ int total_frame_size = 0; ++ + /* CPIA is a compressed format and we don't know the exact number of bytes + * used by a frame, so set it here as the driver announces it. */ + if (ctx->video_codec_id == AV_CODEC_ID_CPIA) + s->frame_size = buf.bytesused; + +- if (s->frame_size > 0 && buf.bytesused != s->frame_size) { ++ if (V4L2_TYPE_IS_MULTIPLANAR(buf.type)) { ++ for (int iplane = 0; iplane < buf.length; iplane++) { ++ total_frame_size += buf.m.planes[iplane].bytesused; ++ } ++ } else { ++ total_frame_size = buf.bytesused; ++ } ++ if (s->frame_size > 0 && total_frame_size != s->frame_size) { + av_log(ctx, AV_LOG_WARNING, + "Dequeued v4l2 buffer contains %d bytes, but %d were expected. Flags: 0x%08X.\n", +- buf.bytesused, s->frame_size, buf.flags); +- buf.bytesused = 0; ++ total_frame_size, s->frame_size, buf.flags); ++ if (V4L2_TYPE_IS_MULTIPLANAR(buf.type)) { ++ for (int iplane = 0; iplane < buf.length; iplane++) { ++ buf.m.planes[iplane].bytesused = 0; ++ } ++ } else { ++ buf.bytesused = 0; ++ } + } + } + +- /* Image is at s->buff_start[buf.index] */ +- if (atomic_load(&s->buffers_queued) == FFMAX(s->buffers / 8, 1)) { +- /* when we start getting low on queued buffers, fall back on copying data */ +- res = av_new_packet(pkt, buf.bytesused); +- if (res < 0) { +- av_log(ctx, AV_LOG_ERROR, "Error allocating a packet.\n"); +- enqueue_buffer(s, &buf); +- return res; ++ if (atomic_load(&s->buffers_queued) == FFMAX(s->buffers / 8, 1) || V4L2_TYPE_IS_MULTIPLANAR(buf.type)) { ++ if (V4L2_TYPE_IS_MULTIPLANAR(buf.type)) { ++ int totalbytes = 0; ++ for (int iplane = 0; iplane < buf.length; iplane++) { ++ totalbytes += buf.m.planes[iplane].bytesused; ++ } ++ res = av_new_packet(pkt, totalbytes); ++ if (res < 0) { ++ av_log(ctx, AV_LOG_ERROR, "Error allocating a packet.\n"); ++ enqueue_buffer(s, &buf); ++ return res; ++ } ++ totalbytes = 0; ++ for (int iplane = 0; iplane < buf.length; iplane++) { ++ struct v4l2_plane *plane = &buf.m.planes[iplane]; ++ memcpy(pkt->data + totalbytes, s->buf_start[buf.index][plane->data_offset], plane->bytesused); ++ totalbytes += plane->bytesused; ++ } ++ } else { ++ /* Image is at s->buff_start[buf.index] */ ++ /* when we start getting low on queued buffers, fall back on copying data */ ++ res = av_new_packet(pkt, buf.bytesused); ++ if (res < 0) { ++ av_log(ctx, AV_LOG_ERROR, "Error allocating a packet.\n"); ++ enqueue_buffer(s, &buf); ++ return res; ++ } ++ memcpy(pkt->data, s->buf_start[buf.index][0], buf.bytesused); + } +- memcpy(pkt->data, s->buf_start[buf.index], buf.bytesused); + + res = enqueue_buffer(s, &buf); + if (res) { +@@ -576,7 +642,7 @@ static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt) + } else { + struct buff_data *buf_descriptor; + +- pkt->data = s->buf_start[buf.index]; ++ pkt->data = s->buf_start[buf.index][0]; + pkt->size = buf.bytesused; + + buf_descriptor = av_malloc(sizeof(struct buff_data)); +@@ -614,10 +680,13 @@ static int mmap_start(AVFormatContext *ctx) + int i, res; + + for (i = 0; i < s->buffers; i++) { ++ struct v4l2_plane planes[VIDEO_MAX_PLANES]; + struct v4l2_buffer buf = { +- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, +- .index = i, +- .memory = V4L2_MEMORY_MMAP ++ .type = (s->multi_planer) ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : V4L2_BUF_TYPE_VIDEO_CAPTURE, ++ .index = i, ++ .memory = V4L2_MEMORY_MMAP, ++ .m.planes = (s->multi_planer) ? planes : 0, ++ .length = (s->multi_planer) ? VIDEO_MAX_PLANES : 0 + }; + + if (v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf) < 0) { +@@ -629,7 +698,7 @@ static int mmap_start(AVFormatContext *ctx) + } + atomic_store(&s->buffers_queued, s->buffers); + +- type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ type = (s->multi_planer) ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (v4l2_ioctl(s->fd, VIDIOC_STREAMON, &type) < 0) { + res = AVERROR(errno); + av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_STREAMON): %s\n", +@@ -645,13 +714,19 @@ static void mmap_close(struct video_data *s) + enum v4l2_buf_type type; + int i; + +- type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ type = (s->multi_planer) ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : V4L2_BUF_TYPE_VIDEO_CAPTURE; + /* We do not check for the result, because we could + * not do anything about it anyway... + */ + v4l2_ioctl(s->fd, VIDIOC_STREAMOFF, &type); + for (i = 0; i < s->buffers; i++) { +- v4l2_munmap(s->buf_start[i], s->buf_len[i]); ++ for (int iplane = 0; iplane < s->plane_count; iplane++) { ++ v4l2_munmap(s->buf_start[i][iplane], s->buf_len[i][iplane]); ++ } ++ } ++ for (int iplane = 0; iplane < s->plane_count; iplane++) { ++ av_freep(&s->buf_start[iplane]); ++ av_freep(&s->buf_len[iplane]); + } + av_freep(&s->buf_start); + av_freep(&s->buf_len); +@@ -732,7 +807,7 @@ static int v4l2_set_parameters(AVFormatContext *ctx) + tpf = &streamparm.parm.capture.timeperframe; + } + +- streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ streamparm.type = (s->multi_planer) ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (v4l2_ioctl(s->fd, VIDIOC_G_PARM, &streamparm) < 0) { + ret = AVERROR(errno); + av_log(ctx, AV_LOG_WARNING, "ioctl(VIDIOC_G_PARM): %s\n", av_err2str(ret)); +@@ -920,7 +995,7 @@ static int v4l2_read_header(AVFormatContext *ctx) + } + + if (!s->width && !s->height) { +- struct v4l2_format fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE }; ++ struct v4l2_format fmt = { .type = (s->multi_planer) ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : V4L2_BUF_TYPE_VIDEO_CAPTURE }; + + av_log(ctx, AV_LOG_VERBOSE, + "Querying the device for the current frame size\n"); -- -2.40.0 +2.41.0 + + +From 16f078866ae21f5a0c34897b14af1d975f1ae203 Mon Sep 17 00:00:00 2001 +From: rigaya <rigaya34589@live.jp> +Date: Fri, 7 Apr 2023 22:47:10 +0900 +Subject: [PATCH 02/13] avdevice/v4l2: add nv16, nv24 support + +--- + libavdevice/v4l2-common.c | 2 ++ + 1 file changed, 2 insertions(+) +diff --git a/libavdevice/v4l2-common.c b/libavdevice/v4l2-common.c +index b5b4448a31..1926179fdc 100644 +--- a/libavdevice/v4l2-common.c ++++ b/libavdevice/v4l2-common.c +@@ -49,6 +49,8 @@ const struct fmt_map ff_fmt_conversion_table[] = { + #ifdef V4L2_PIX_FMT_Z16 + { AV_PIX_FMT_GRAY16LE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_Z16 }, + #endif ++ { AV_PIX_FMT_NV24, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_NV24 }, ++ { AV_PIX_FMT_NV16, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_NV16 }, + { AV_PIX_FMT_NV12, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_NV12 }, + { AV_PIX_FMT_NONE, AV_CODEC_ID_MJPEG, V4L2_PIX_FMT_MJPEG }, + { AV_PIX_FMT_NONE, AV_CODEC_ID_MJPEG, V4L2_PIX_FMT_JPEG }, +-- +2.41.0 -From 32c3c2a06887dce24c73a8fb65fd90f0d47dc53f 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/24] avcodec/rkmppdec: Compatible with old reordered_opaque - and pkt_pts -Some users might still using these deprecated APIs. +From 7e3c98159375a5466c03b1853daaca212bf2008b Mon Sep 17 00:00:00 2001 +From: rigaya <rigaya34589@live.jp> +Date: Sat, 8 Apr 2023 09:48:45 +0900 +Subject: [PATCH 03/13] avdevice/v4l2: add option to ignore input error + (-ignore_input_error). -Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com> +Some device returns error with VIDIOC_S_INPUT, VIDIOC_G_INPUT. --- - libavcodec/rkmppdec.c | 4 ++++ - 1 file changed, 4 insertions(+) + libavdevice/v4l2.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) -diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c -index e31e0c44dc..4b4b17c342 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,7 @@ 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); -+ 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); +diff --git a/libavdevice/v4l2.c b/libavdevice/v4l2.c +index 249bedfaaa..9bdcc324ae 100644 +--- a/libavdevice/v4l2.c ++++ b/libavdevice/v4l2.c +@@ -89,6 +89,7 @@ struct video_data { + int top_field_first; + int multi_planer; + int ts_mode; ++ int ignore_input_error; + TimeFilter *timefilter; + int64_t last_time_m; + +@@ -810,7 +811,7 @@ static int v4l2_set_parameters(AVFormatContext *ctx) + streamparm.type = (s->multi_planer) ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (v4l2_ioctl(s->fd, VIDIOC_G_PARM, &streamparm) < 0) { + ret = AVERROR(errno); +- av_log(ctx, AV_LOG_WARNING, "ioctl(VIDIOC_G_PARM): %s\n", av_err2str(ret)); ++ av_log(ctx, AV_LOG_WARNING, "ioctl(VIDIOC_G_PARM): %s\n", av_err2str(ret)); + } else if (framerate_q.num && framerate_q.den) { + if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) { + tpf = &streamparm.parm.capture.timeperframe; +@@ -940,8 +941,10 @@ static int v4l2_read_header(AVFormatContext *ctx) + av_log(ctx, AV_LOG_DEBUG, "Selecting input_channel: %d\n", s->channel); + if (v4l2_ioctl(s->fd, VIDIOC_S_INPUT, &s->channel) < 0) { + res = AVERROR(errno); +- av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_S_INPUT): %s\n", av_err2str(res)); +- goto fail; ++ av_log(ctx, (s->ignore_input_error) ? AV_LOG_WARNING : AV_LOG_ERROR, "ioctl(VIDIOC_S_INPUT): %s\n", av_err2str(res)); ++ if (!s->ignore_input_error) { ++ goto fail; ++ } + } + } else { + /* get current video input */ +@@ -1183,6 +1186,7 @@ static const AVOption options[] = { + { "pixel_format", "set preferred pixel format", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, + { "input_format", "set preferred pixel format (for raw video) or codec name", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, + { "framerate", "set frame rate", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, ++ { "ignore_input_error", "ignore input error", OFFSET(ignore_input_error), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, DEC }, + + { "list_formats", "list available formats and exit", OFFSET(list_format), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, DEC, "list_formats" }, + { "all", "show all available formats", OFFSET(list_format), AV_OPT_TYPE_CONST, {.i64 = V4L_ALLFORMATS }, 0, INT_MAX, DEC, "list_formats" }, -- -2.40.0 +2.41.0 + + +From 6dfc851fa786023ba4d036f4b0a699dc2599d804 Mon Sep 17 00:00:00 2001 +From: rigaya <rigaya34589@live.jp> +Date: Sat, 8 Apr 2023 09:49:05 +0900 +Subject: [PATCH 04/13] avdevice/v4l2: estimate framerate from dv-timings when + VIDIOC_G_PARM returns error. +--- + libavdevice/v4l2.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/libavdevice/v4l2.c b/libavdevice/v4l2.c +index 9bdcc324ae..2146c6cd57 100644 +--- a/libavdevice/v4l2.c ++++ b/libavdevice/v4l2.c +@@ -810,8 +810,38 @@ static int v4l2_set_parameters(AVFormatContext *ctx) + + streamparm.type = (s->multi_planer) ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (v4l2_ioctl(s->fd, VIDIOC_G_PARM, &streamparm) < 0) { ++ // for error cases, try to get frame rate from VIDIOC_G_DV_TIMINGS ++ struct v4l2_dv_timings timings; + ret = AVERROR(errno); ++ if (v4l2_ioctl(s->fd, VIDIOC_G_DV_TIMINGS, &timings) == 0) { ++ const int total_width = timings.bt.width + timings.bt.hfrontporch + timings.bt.hsync + timings.bt.hbackporch; ++ const int total_height = timings.bt.height + timings.bt.vfrontporch + timings.bt.vsync + timings.bt.vbackporch; ++ int64_t framerate_den = 1001; ++ int64_t framerate_num = av_rescale(timings.bt.pixelclock, framerate_den, (int64_t)total_width * total_height); ++ framerate_num = ((framerate_num + 5) / 10) * 10; // round by 10 ++ if (framerate_num % 1000 == 0) { ++ tpf->numerator = framerate_den; ++ tpf->denominator = framerate_num; ++ } else { ++ int framerate_num_dst = 0, framerate_den_dst = 0; ++ framerate_den = 1000; ++ framerate_num = av_rescale(timings.bt.pixelclock, framerate_den, (int64_t)total_width * total_height); ++ framerate_num = ((framerate_num + 5) / 10) * 10; // round by 10 ++ av_reduce(&framerate_num_dst, &framerate_den_dst, framerate_num, framerate_den, INT_MAX); ++ tpf->numerator = framerate_den_dst; ++ tpf->denominator = framerate_num_dst; ++ } ++ av_log(ctx, AV_LOG_WARNING, "ioctl(VIDIOC_G_PARM): %s, estimated framerate %d/%d from dv timings.\n", ++ av_err2str(ret), tpf->denominator, tpf->numerator); ++ } else if (framerate_q.num && framerate_q.den) { ++ // use user defined framerate for further error cases. ++ tpf->numerator = framerate_q.num; ++ tpf->denominator = framerate_q.den; ++ av_log(ctx, AV_LOG_WARNING, "ioctl(VIDIOC_G_PARM): %s, using framerate %d/%d\n", ++ av_err2str(ret), framerate_q.num, framerate_q.den); ++ } else { + av_log(ctx, AV_LOG_WARNING, "ioctl(VIDIOC_G_PARM): %s\n", av_err2str(ret)); ++ } + } else if (framerate_q.num && framerate_q.den) { + if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) { + tpf = &streamparm.parm.capture.timeperframe; +-- +2.41.0 -From 1839dfc7860999826e5152c0b96938d8772a4739 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/24] rkmppdec: Remove frame buffer limit -It would hang when reaching the limit. +From 6b8f166c76fe3e7cdb57811d09a64162169a2ff1 Mon Sep 17 00:00:00 2001 +From: boogie <boogiepop@gmx.com> +Date: Sat, 17 Jun 2023 18:56:02 +0200 +Subject: [PATCH 05/13] v4l2: use always channel 0 if driver does not return + it. Always ignore device select / set errors -Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com> --- - libavcodec/rkmppdec.c | 8 -------- - 1 file changed, 8 deletions(-) + libavdevice/v4l2.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) -diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c -index 4b4b17c342..d8f48f36b9 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; +diff --git a/libavdevice/v4l2.c b/libavdevice/v4l2.c +index 2146c6cd57..6b7c5dbc20 100644 +--- a/libavdevice/v4l2.c ++++ b/libavdevice/v4l2.c +@@ -980,8 +980,11 @@ static int v4l2_read_header(AVFormatContext *ctx) + /* get current video input */ + if (v4l2_ioctl(s->fd, VIDIOC_G_INPUT, &s->channel) < 0) { + res = AVERROR(errno); +- av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_G_INPUT): %s\n", av_err2str(res)); +- goto fail; ++ av_log(ctx, (s->ignore_input_error) ? AV_LOG_WARNING : AV_LOG_ERROR, "ioctl(VIDIOC_G_INPUT): %s\n", av_err2str(res)); ++ if (!s->ignore_input_error) ++ goto fail; ++ else ++ s->channel = 0; + } } -- 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; +@@ -1216,7 +1219,7 @@ static const AVOption options[] = { + { "pixel_format", "set preferred pixel format", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, + { "input_format", "set preferred pixel format (for raw video) or codec name", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, + { "framerate", "set frame rate", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, +- { "ignore_input_error", "ignore input error", OFFSET(ignore_input_error), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, DEC }, ++ { "ignore_input_error", "ignore input error", OFFSET(ignore_input_error), AV_OPT_TYPE_BOOL, {.i64 = 1 }, 0, 1, DEC }, - av_log(avctx, AV_LOG_DEBUG, "RKMPP decoder initialized successfully.\n"); + { "list_formats", "list available formats and exit", OFFSET(list_format), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, DEC, "list_formats" }, + { "all", "show all available formats", OFFSET(list_format), AV_OPT_TYPE_CONST, {.i64 = V4L_ALLFORMATS }, 0, INT_MAX, DEC, "list_formats" }, -- -2.40.0 - +2.41.0 -From 076cca4ad14ac04297aa2cf9786cb7b9b80be07b 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/24] avcodec/rkmppdec: Rework decoding flow -Stop using the deprecated MPP_DEC_GET_STREAM_COUNT API. +From 0f71b074a151ae47006a40ae4a2c8c8a434c3d94 Mon Sep 17 00:00:00 2001 +From: boogie <boogiepop@gmx.com> +Date: Mon, 24 Jul 2023 16:05:01 +0200 +Subject: [PATCH 06/13] remove old rkmpp -Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com> --- - libavcodec/rkmppdec.c | 520 ++++++++++++++++++++++-------------------- - 1 file changed, 267 insertions(+), 253 deletions(-) + libavcodec/rkmppdec.c | 587 ------------------------------------------ + 1 file changed, 587 deletions(-) + delete mode 100644 libavcodec/rkmppdec.c diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c -index d8f48f36b9..d3c13297d2 100644 +deleted file mode 100644 +index 8bf7c6ed16..0000000000 --- a/libavcodec/rkmppdec.c -+++ b/libavcodec/rkmppdec.c -@@ -38,17 +38,15 @@ - #include "libavutil/imgutils.h" - #include "libavutil/log.h" - ++++ /dev/null +@@ -1,587 +0,0 @@ +-/* +- * RockChip MPP Video Decoder +- * Copyright (c) 2017 Lionel CHAZALLON +- * +- * This file is part of FFmpeg. +- * +- * FFmpeg is free software; you can redistribute it and/or +- * modify it under the terms of the GNU Lesser General Public +- * License as published by the Free Software Foundation; either +- * version 2.1 of the License, or (at your option) any later version. +- * +- * FFmpeg is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- * Lesser General Public License for more details. +- * +- * You should have received a copy of the GNU Lesser General Public +- * License along with FFmpeg; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +- */ +- +-#include <drm_fourcc.h> +-#include <pthread.h> +-#include <rockchip/mpp_buffer.h> +-#include <rockchip/rk_mpi.h> +-#include <time.h> +-#include <unistd.h> +- +-#include "avcodec.h" +-#include "codec_internal.h" +-#include "decode.h" +-#include "hwconfig.h" +-#include "libavutil/buffer.h" +-#include "libavutil/common.h" +-#include "libavutil/frame.h" +-#include "libavutil/hwcontext.h" +-#include "libavutil/hwcontext_drm.h" +-#include "libavutil/imgutils.h" +-#include "libavutil/log.h" +- -#define RECEIVE_FRAME_TIMEOUT 100 +-#define FRAMEGROUP_MAX_FRAMES 16 -#define INPUT_MAX_PACKETS 4 - - typedef struct { - MppCtx ctx; - MppApi *mpi; - MppBufferGroup frame_group; - +-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) - } - } - +- +- AVBufferRef *frames_ref; +- AVBufferRef *device_ref; +-} RKMPPDecoder; +- +-typedef struct { +- AVClass *av_class; +- AVBufferRef *decoder_ref; +-} RKMPPDecodeContext; +- +-typedef struct { +- MppFrame frame; +- AVBufferRef *decoder_ref; +-} RKMPPFrameContext; +- +-static MppCodingType rkmpp_get_codingtype(AVCodecContext *avctx) +-{ +- switch (avctx->codec_id) { +- 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; +- default: return MPP_VIDEO_CodingUnused; +- } +-} +- +-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; +- } +-} +- -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; +-{ +- 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); @@ -184,63 +662,93 @@ index d8f48f36b9..d3c13297d2 100644 - - return ret; -} -+ av_packet_unref(&decoder->packet); - +- -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; +- av_buffer_unref(&rk_context->decoder_ref); +- return 0; +-} +- +-static void rkmpp_release_decoder(void *opaque, uint8_t *data) +-{ +- RKMPPDecoder *decoder = (RKMPPDecoder *)data; +- +- if (decoder->mpi) { +- decoder->mpi->reset(decoder->ctx); +- mpp_destroy(decoder->ctx); +- decoder->ctx = NULL; +- } +- +- if (decoder->frame_group) { +- mpp_buffer_group_put(decoder->frame_group); +- decoder->frame_group = NULL; +- } +- +- av_buffer_unref(&decoder->frames_ref); +- av_buffer_unref(&decoder->device_ref); +- +- av_free(decoder); +-} +- +-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; - } - +- +- avctx->pix_fmt = AV_PIX_FMT_DRM_PRIME; +- +- // create a decoder and a ref to it +- decoder = av_mallocz(sizeof(RKMPPDecoder)); +- if (!decoder) { +- ret = AVERROR(ENOMEM); +- goto fail; +- } +- +- 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) { +- av_free(decoder); +- ret = AVERROR(ENOMEM); +- goto fail; +- } +- +- av_log(avctx, AV_LOG_DEBUG, "Initializing RKMPP decoder.\n"); +- +- codectype = rkmpp_get_codingtype(avctx); +- if (codectype == MPP_VIDEO_CodingUnused) { +- av_log(avctx, AV_LOG_ERROR, "Unknown codec type (%d).\n", avctx->codec_id); +- ret = AVERROR_UNKNOWN; +- goto fail; +- } +- +- ret = mpp_check_support_format(MPP_CTX_DEC, codectype); +- if (ret != MPP_OK) { +- av_log(avctx, AV_LOG_ERROR, "Codec type (%d) unsupported by MPP\n", avctx->codec_id); +- ret = AVERROR_UNKNOWN; +- goto fail; +- } +- +- // Create the MPP context +- ret = mpp_create(&decoder->ctx, &decoder->mpi); +- if (ret != MPP_OK) { +- av_log(avctx, AV_LOG_ERROR, "Failed to create MPP context (code = %d).\n", ret); +- ret = AVERROR_UNKNOWN; +- goto fail; +- } +- +- // initialize mpp +- ret = mpp_init(decoder->ctx, MPP_CTX_DEC, codectype); +- if (ret != MPP_OK) { +- av_log(avctx, AV_LOG_ERROR, "Failed to initialize MPP context (code = %d).\n", ret); +- ret = AVERROR_UNKNOWN; +- goto fail; +- } +- - // make decode calls blocking with a timeout - paramS32 = MPP_POLL_BLOCK; - ret = decoder->mpi->control(decoder->ctx, MPP_SET_OUTPUT_BLOCK, ¶mS32); @@ -258,32 +766,48 @@ index d8f48f36b9..d3c13297d2 100644 - goto fail; - } - - ret = mpp_buffer_group_get_internal(&decoder->frame_group, MPP_BUFFER_TYPE_ION); - if (ret) { +- 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; - } - +- ret = AVERROR_UNKNOWN; +- goto fail; +- } +- +- 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); +- ret = AVERROR_UNKNOWN; +- 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; -+ 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; - } - +- +- av_log(avctx, AV_LOG_DEBUG, "RKMPP decoder initialized successfully.\n"); +- +- decoder->device_ref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_DRM); +- if (!decoder->device_ref) { +- ret = AVERROR(ENOMEM); +- goto fail; +- } +- ret = av_hwdevice_ctx_init(decoder->device_ref); +- if (ret < 0) +- goto fail; +- +- return 0; +- +-fail: +- av_log(avctx, AV_LOG_ERROR, "Failed to initialize RKMPP decoder.\n"); +- rkmpp_close_decoder(avctx); +- return ret; +-} +- -static int rkmpp_send_packet(AVCodecContext *avctx, const AVPacket *avpkt) -{ - RKMPPDecodeContext *rk_context = avctx->priv_data; @@ -322,88 +846,65 @@ index d8f48f36b9..d3c13297d2 100644 - 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 void rkmpp_release_frame(void *opaque, uint8_t *data) +-{ +- AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)data; +- AVBufferRef *framecontextref = (AVBufferRef *)opaque; +- RKMPPFrameContext *framecontext = (RKMPPFrameContext *)framecontextref->data; +- +- mpp_frame_deinit(&framecontext->frame); +- av_buffer_unref(&framecontext->decoder_ref); +- av_buffer_unref(&framecontextref); +- +- 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,151 +263,159 @@ 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) { +-{ +- RKMPPDecodeContext *rk_context = avctx->priv_data; +- RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data; +- RKMPPFrameContext *framecontext = NULL; +- AVBufferRef *framecontextref = NULL; +- int ret; +- MppFrame mppframe = NULL; +- MppBuffer buffer = NULL; +- AVDRMFrameDescriptor *desc = NULL; +- AVDRMLayerDescriptor *layer = NULL; +- int mode; +- MppFrameFormat mppformat; +- uint32_t drmformat; +- +- 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; @@ -412,9 +913,7 @@ index d8f48f36b9..d3c13297d2 100644 - 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; @@ -430,49 +929,29 @@ index d8f48f36b9..d3c13297d2 100644 - } 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; - } - +- 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); - +- - // 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); -- 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); -+ 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); - +- - 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); -+ goto fail; -+ } - +- - mppformat = mpp_frame_get_fmt(mppframe); - drmformat = rkmpp_get_frameformat(mppformat); -+ // 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) { @@ -481,14 +960,7 @@ index d8f48f36b9..d3c13297d2 100644 - ret = AVERROR(ENOMEM); - goto fail; - } -+ // 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; -+ } - +- - desc->nb_objects = 1; - desc->objects[0].fd = mpp_buffer_get_fd(buffer); - desc->objects[0].size = mpp_buffer_get_size(buffer); @@ -513,63 +985,27 @@ index d8f48f36b9..d3c13297d2 100644 - ret = AVERROR(ENOMEM); - 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); -+ 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); -+ -+ mppformat = mpp_frame_get_fmt(mppframe); -+ drmformat = rkmpp_get_frameformat(mppformat); -+ -+ desc = av_mallocz(sizeof(AVDRMFrameDescriptor)); -+ if (!desc) { -+ ret = AVERROR(ENOMEM); -+ goto fail; -+ } - +- - // 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_objects = 1; -+ desc->objects[0].fd = mpp_buffer_get_fd(buffer); -+ desc->objects[0].size = mpp_buffer_get_size(buffer); - +- - 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); -+ desc->nb_layers = 1; -+ layer = &desc->layers[0]; -+ layer->format = drmformat; -+ layer->nb_planes = 2; - +- - if (!frame->buf[0]) { - ret = AVERROR(ENOMEM); - goto fail; - } -+ layer->planes[0].object_index = 0; -+ layer->planes[0].offset = 0; -+ layer->planes[0].pitch = mpp_frame_get_hor_stride(mppframe); - +- - frame->hw_frames_ctx = av_buffer_ref(decoder->frames_ref); - if (!frame->hw_frames_ctx) { - 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; - +- - return 0; - } else { - av_log(avctx, AV_LOG_ERROR, "Failed to retrieve the frame buffer, frame is dropped (code = %d)\n", ret); @@ -579,107 +1015,30 @@ index d8f48f36b9..d3c13297d2 100644 - 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"); -+ // 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 AVERROR(EAGAIN); -+ // 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; -+ } -+ -+ 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) -@@ -489,60 +433,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; +- +-fail: +- if (mppframe) +- mpp_frame_deinit(&mppframe); +- +- if (framecontext) +- av_buffer_unref(&framecontext->decoder_ref); +- +- if (framecontextref) +- av_buffer_unref(&framecontextref); +- +- if (desc) +- av_free(desc); +- +- return ret; +-} +- +-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; @@ -691,817 +1050,131 @@ index d8f48f36b9..d3c13297d2 100644 - 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; - } +- 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; - } - } +- return ret; +- } +- } - - // 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; +-} +- +-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"); - +- +- 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.40.0 - - -From 3f3e229c729d779ff1b4bc6ec8abc11e2b2b078b 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/24] 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 d3c13297d2..c767fc8f1b 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.40.0 - - -From fdf094ef3e983706e28f7f77d96284de554612d9 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/24] 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 | 121 +++++++++++++++++++++++++++++++++++++++++- - 2 files changed, 126 insertions(+), 2 deletions(-) - -diff --git a/configure b/configure -index b6616f00b6..b2b6d45e78 100755 ---- a/configure -+++ b/configure -@@ -349,6 +349,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] -@@ -1892,6 +1893,7 @@ HWACCEL_AUTODETECT_LIBRARY_LIST=" - videotoolbox - vulkan - v4l2_m2m -+ librga - " - - # catchall list of things that require external libs to link -@@ -6789,10 +6791,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 && 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 c767fc8f1b..2bcc357c36 100644 ---- a/libavcodec/rkmppdec.c -+++ b/libavcodec/rkmppdec.c -@@ -28,6 +28,7 @@ - - #include "avcodec.h" - #include "codec_internal.h" -+#include "internal.h" - #include "decode.h" - #include "hwconfig.h" - #include "libavutil/buffer.h" -@@ -38,6 +39,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 +89,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 +159,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 +265,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 +461,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); - frame->reordered_opaque = frame->pts; - frame->color_range = mpp_frame_get_color_range(mppframe); -@@ -422,6 +538,7 @@ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout) - - return 0; - -+out: - fail: - if (mppframe) - mpp_frame_deinit(&mppframe); -@@ -566,6 +683,7 @@ static void rkmpp_flush(AVCodecContext *avctx) - - static const AVCodecHWConfigInternal *const rkmpp_hw_configs[] = { - HW_CONFIG_INTERNAL(DRM_PRIME), -+ HW_CONFIG_INTERNAL(YUV420P), - NULL - }; - -@@ -590,6 +708,7 @@ static const AVCodecHWConfigInternal *const rkmpp_hw_configs[] = { - .p.priv_class = &rkmpp_##NAME##_dec_class, \ - .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \ - .p.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.40.0 - - -From 6f54c9ff2d603000d3ee112c584b4d76a23bfd5f 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/24] 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 2bcc357c36..41e17422a0 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 "codec_internal.h" -@@ -44,6 +45,8 @@ - #include <rga/RgaApi.h> - #endif - -+#define FPS_UPDATE_INTERVAL 120 -+ - typedef struct { - MppCtx ctx; - MppApi *mpi; -@@ -55,6 +58,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 { -@@ -157,6 +165,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); -@@ -168,6 +177,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) { -@@ -354,6 +367,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; -@@ -457,6 +500,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); -@@ -677,6 +722,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.40.0 - - -From 8b3fb18571d3dcf1f561f413c07aec7412046ea7 Mon Sep 17 00:00:00 2001 -From: Jeffy Chen <jeffy.chen@rock-chips.com> -Date: Mon, 27 Sep 2021 11:06:11 +0800 -Subject: [PATCH 08/24] 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/codec_internal.h | 4 ++++ - libavcodec/get_buffer.c | 24 ++++++++++++++++++++++++ - libavcodec/rkmppdec.c | 19 ++++++++++--------- - 3 files changed, 38 insertions(+), 9 deletions(-) - -diff --git a/libavcodec/codec_internal.h b/libavcodec/codec_internal.h -index 130a7dc3cd..ed0dea86de 100644 ---- a/libavcodec/codec_internal.h -+++ b/libavcodec/codec_internal.h -@@ -80,6 +80,10 @@ - * Codec supports embedded ICC profiles (AV_FRAME_DATA_ICC_PROFILE). - */ - #define FF_CODEC_CAP_ICC_PROFILES (1 << 9) -+/** -+ * The decoder requires contiguous buffers. -+ */ -+#define FF_CODEC_CAP_CONTIGUOUS_BUFFERS (1 << 28) - /** - * The encoder has AV_CODEC_CAP_DELAY set, but does not actually have delay - it - * only wants to be flushed at the end to update some context variables (e.g. -diff --git a/libavcodec/get_buffer.c b/libavcodec/get_buffer.c -index a04fd878de..c6a1983f7e 100644 ---- a/libavcodec/get_buffer.c -+++ b/libavcodec/get_buffer.c -@@ -32,6 +32,7 @@ - - #include "avcodec.h" - #include "internal.h" -+#include "codec_internal.h" - - typedef struct FramePool { - /** -@@ -147,6 +148,14 @@ FF_ENABLE_DEPRECATION_WARNINGS - - for (i = 0; i < 4; i++) { - pool->linesize[i] = linesize[i]; -+ -+ if (ffcodec(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); -@@ -265,6 +274,21 @@ static int video_get_buffer(AVCodecContext *s, AVFrame *pic) - - pic->data[i] = pic->buf[i]->data; - } -+ -+ if (ffcodec(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/rkmppdec.c b/libavcodec/rkmppdec.c -index 41e17422a0..01ab7e5492 100644 ---- a/libavcodec/rkmppdec.c -+++ b/libavcodec/rkmppdec.c -@@ -502,20 +502,16 @@ 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); - frame->reordered_opaque = frame->pts; - frame->color_range = mpp_frame_get_color_range(mppframe); -@@ -527,6 +523,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); - -@@ -759,7 +760,7 @@ static const AVCodecHWConfigInternal *const rkmpp_hw_configs[] = { - .hw_configs = rkmpp_hw_configs, \ - .bsfs = BSFS, \ - .p.wrapper_name = "rkmpp", \ +-} +- +-static const AVCodecHWConfigInternal *const rkmpp_hw_configs[] = { +- HW_CONFIG_INTERNAL(DRM_PRIME), +- NULL +-}; +- +-#define RKMPP_DEC_CLASS(NAME) \ +- static const AVClass rkmpp_##NAME##_dec_class = { \ +- .class_name = "rkmpp_" #NAME "_dec", \ +- .version = LIBAVUTIL_VERSION_INT, \ +- }; +- +-#define RKMPP_DEC(NAME, ID, BSFS) \ +- RKMPP_DEC_CLASS(NAME) \ +- const FFCodec ff_##NAME##_rkmpp_decoder = { \ +- .p.name = #NAME "_rkmpp", \ +- CODEC_LONG_NAME(#NAME " (rkmpp)"), \ +- .p.type = AVMEDIA_TYPE_VIDEO, \ +- .p.id = ID, \ +- .priv_data_size = sizeof(RKMPPDecodeContext), \ +- .init = rkmpp_init_decoder, \ +- .close = rkmpp_close_decoder, \ +- FF_CODEC_RECEIVE_FRAME_CB(rkmpp_receive_frame), \ +- .flush = rkmpp_flush, \ +- .p.priv_class = &rkmpp_##NAME##_dec_class, \ +- .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \ +- .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_DRM_PRIME, \ +- AV_PIX_FMT_NONE}, \ +- .hw_configs = rkmpp_hw_configs, \ +- .bsfs = BSFS, \ +- .p.wrapper_name = "rkmpp", \ - .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, \ -+ .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_CONTIGUOUS_BUFFERS \ - }; - - RKMPP_DEC(h264, AV_CODEC_ID_H264, "h264_mp4toannexb") --- -2.40.0 - - -From 8e916a6896d847d4cda4d455ad47e188c1825337 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/24] HACK: avcodec/rkmppdec: Support NV15 - -NV15 is the official DRM fourcc for Arm's NV12 10LE40 format. - -Fallback to NA12 for older Rockchip BSP kernel. - -Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com> ---- - libavcodec/rkmppdec.c | 9 ++++++--- - 1 file changed, 6 insertions(+), 3 deletions(-) - -diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c -index 01ab7e5492..403f5339a9 100644 ---- a/libavcodec/rkmppdec.c -+++ b/libavcodec/rkmppdec.c -@@ -45,6 +45,11 @@ - #include <rga/RgaApi.h> - #endif - -+// HACK: Older BSP kernel use NA12 for NV15. -+#ifndef DRM_FORMAT_NV15 // fourcc_code('N', 'V', '1', '5') -+#define DRM_FORMAT_NV15 fourcc_code('N', 'A', '1', '2') -+#endif -+ - #define FPS_UPDATE_INTERVAL 120 - - typedef struct { -@@ -90,9 +95,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 -+ case MPP_FMT_YUV420SP_10BIT: return DRM_FORMAT_NV15; - default: return 0; - } - } --- -2.40.0 - - -From c9d8ec349c5b766dffafbddbe3b1ef0e57b24456 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/24] 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 403f5339a9..770c4ef71c 100644 ---- a/libavcodec/rkmppdec.c -+++ b/libavcodec/rkmppdec.c -@@ -96,6 +96,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_NV15; -+ 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; - } - } -@@ -106,6 +117,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; - } - } -@@ -478,11 +490,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.40.0 - - -From 06e79e58f08c7426681497aa1f653ba1cc116947 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/24] 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 770c4ef71c..9539a48817 100644 ---- a/libavcodec/rkmppdec.c -+++ b/libavcodec/rkmppdec.c -@@ -68,6 +68,8 @@ typedef struct { - - uint64_t last_fps_time; - uint64_t frames; -+ -+ char sync; - } RKMPPDecoder; - - typedef struct { -@@ -172,6 +174,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; - } - -@@ -719,6 +728,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); - } - } - } +- }; +- +-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) -- -2.40.0 +2.41.0 -From ba5c782b923192e820b5c08aff61da5133b2dd1a Mon Sep 17 00:00:00 2001 -From: Jeffy Chen <jeffy.chen@rock-chips.com> -Date: Wed, 25 May 2022 12:35:53 +0800 -Subject: [PATCH 12/24] avcodec/rkmppdec: Add H263/MPEG1/MPEG2/MPEG4 +From d0260e7573b9695e738e4b9a3ae02616fbeaacf0 Mon Sep 17 00:00:00 2001 +From: boogie <boogiepop@gmx.com> +Date: Mon, 24 Jul 2023 16:01:21 +0200 +Subject: [PATCH 07/13] prepare buildsystem for rkmpp -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(+) + configure | 18 +++++++++++++++++- + libavcodec/Makefile | 16 ++++++++++++---- + 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/configure b/configure -index b2b6d45e78..8dd4294f28 100755 +index b6616f00b6..9bbf39b9ce 100755 --- a/configure +++ b/configure -@@ -3165,6 +3165,7 @@ av1_nvenc_encoder_deps="nvenc NV_ENC_PIC_PARAMS_AV1" +@@ -3161,8 +3161,10 @@ av1_mediacodec_decoder_deps="mediacodec" + av1_mediacodec_decoder_extralibs="-landroid" + av1_nvenc_encoder_deps="nvenc NV_ENC_PIC_PARAMS_AV1" av1_nvenc_encoder_select="atsc_a53" ++av1_rkmpp_decoder_deps="rkmpp" 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" -@@ -3218,6 +3219,7 @@ mjpeg_vaapi_encoder_select="cbs_jpeg jpegtables vaapi_encode" +@@ -3182,6 +3184,8 @@ h264_qsv_decoder_select="h264_mp4toannexb_bsf qsvdec" + h264_qsv_encoder_select="atsc_a53 qsvenc" + h264_rkmpp_decoder_deps="rkmpp" + h264_rkmpp_decoder_select="h264_mp4toannexb_bsf" ++h264_rkmpp_encoder_deps="rkmpp" ++h264_rkmpp_encoder_select="h264_mp4toannexb_bsf" + h264_vaapi_encoder_select="atsc_a53 cbs_h264 vaapi_encode" + h264_v4l2m2m_decoder_deps="v4l2_m2m h264_v4l2_m2m" + h264_v4l2m2m_decoder_select="h264_mp4toannexb_bsf" +@@ -3202,6 +3206,8 @@ hevc_qsv_decoder_select="hevc_mp4toannexb_bsf qsvdec" + hevc_qsv_encoder_select="hevcparse qsvenc" + hevc_rkmpp_decoder_deps="rkmpp" + hevc_rkmpp_decoder_select="hevc_mp4toannexb_bsf" ++hevc_rkmpp_encoder_deps="rkmpp" ++hevc_rkmpp_encoder_select="hevc_mp4toannexb_bsf" + hevc_vaapi_encoder_deps="VAEncPictureParameterBufferHEVC" + hevc_vaapi_encoder_select="atsc_a53 cbs_h265 vaapi_encode" + hevc_v4l2m2m_decoder_deps="v4l2_m2m hevc_v4l2_m2m" +@@ -3216,6 +3222,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" @@ -1509,7 +1182,7 @@ index b2b6d45e78..8dd4294f28 100755 mpeg2_crystalhd_decoder_select="crystalhd" mpeg2_cuvid_decoder_deps="cuvid" mpeg2_mmal_decoder_deps="mmal" -@@ -3226,6 +3228,7 @@ mpeg2_qsv_decoder_select="qsvdec" +@@ -3224,6 +3231,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" @@ -1517,7 +1190,7 @@ index b2b6d45e78..8dd4294f28 100755 mpeg4_crystalhd_decoder_select="crystalhd" mpeg4_cuvid_decoder_deps="cuvid" mpeg4_mediacodec_decoder_deps="mediacodec" -@@ -3233,6 +3236,7 @@ mpeg4_mmal_decoder_deps="mmal" +@@ -3231,6 +3239,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" @@ -1525,252 +1198,130 @@ index b2b6d45e78..8dd4294f28 100755 msmpeg4_crystalhd_decoder_select="crystalhd" vc1_crystalhd_decoder_select="crystalhd" vc1_cuvid_decoder_deps="cuvid" +@@ -3241,6 +3250,7 @@ vp8_cuvid_decoder_deps="cuvid" + vp8_mediacodec_decoder_deps="mediacodec" + vp8_qsv_decoder_select="qsvdec" + vp8_rkmpp_decoder_deps="rkmpp" ++vp8_rkmpp_encoder_deps="rkmpp" + vp8_vaapi_encoder_deps="VAEncPictureParameterBufferVP8" + vp8_vaapi_encoder_select="vaapi_encode" + vp8_v4l2m2m_decoder_deps="v4l2_m2m vp8_v4l2_m2m" +@@ -6791,8 +6801,14 @@ enabled openssl && { { check_pkg_config openssl "openssl >= 3.0.0" ope + enabled pocketsphinx && require_pkg_config pocketsphinx pocketsphinx pocketsphinx/pocketsphinx.h ps_init + 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 && ++ { check_lib librga rga/RgaApi.h c_RkRgaInit -lrga || ++ die "ERROR: librga is necessary for rkmpp"; } && ++ prepend rkmpp_deps "librga" && ++ { check_lib libyuv libyuv/planar_functions.h SplitUVPlane -lyuv || ++ die "ERROR: libyuv is necessary for rkmpp"; } && ++ prepend rkmpp_deps "libyuv" && + { enabled libdrm || +- die "ERROR: rkmpp requires --enable-libdrm"; } ++ die "ERROR: rkmpp requires --enable-libdrm"; } + } + enabled vapoursynth && require_pkg_config vapoursynth "vapoursynth-script >= 42" VSScript.h vsscript_init + diff --git a/libavcodec/Makefile b/libavcodec/Makefile -index 389253f5d0..504a31e83e 100644 +index 389253f5d0..5462385307 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile -@@ -397,6 +397,7 @@ OBJS-$(CONFIG_H263_ENCODER) += mpeg4video.o \ +@@ -255,6 +255,7 @@ OBJS-$(CONFIG_AV1_CUVID_DECODER) += cuviddec.o + OBJS-$(CONFIG_AV1_MEDIACODEC_DECODER) += mediacodecdec.o + OBJS-$(CONFIG_AV1_NVENC_ENCODER) += nvenc_av1.o nvenc.o + OBJS-$(CONFIG_AV1_QSV_ENCODER) += qsvenc_av1.o ++OBJS-$(CONFIG_AV1_RKMPP_DECODER) += rkmpp.o rkplane.o rkmppdec.o + OBJS-$(CONFIG_AVRN_DECODER) += avrndec.o + OBJS-$(CONFIG_AVRP_DECODER) += r210dec.o + OBJS-$(CONFIG_AVRP_ENCODER) += r210enc.o +@@ -397,6 +398,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_H263_RKMPP_DECODER) += rkmpp.o rkplane.o 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 \ -@@ -529,6 +530,7 @@ OBJS-$(CONFIG_MPEG1VIDEO_DECODER) += mpeg12dec.o mpeg12.o mpeg12data.o +@@ -412,7 +414,8 @@ OBJS-$(CONFIG_H264_NVENC_ENCODER) += nvenc_h264.o nvenc.o + OBJS-$(CONFIG_H264_OMX_ENCODER) += omx.o + OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec.o + OBJS-$(CONFIG_H264_QSV_ENCODER) += qsvenc_h264.o +-OBJS-$(CONFIG_H264_RKMPP_DECODER) += rkmppdec.o ++OBJS-$(CONFIG_H264_RKMPP_DECODER) += rkmpp.o rkplane.o rkmppdec.o ++OBJS-$(CONFIG_H264_RKMPP_ENCODER) += rkmpp.o rkplane.o rkmppenc.o + OBJS-$(CONFIG_H264_VAAPI_ENCODER) += vaapi_encode_h264.o h264_levels.o \ + h2645data.o + OBJS-$(CONFIG_H264_VIDEOTOOLBOX_ENCODER) += videotoolboxenc.o +@@ -437,7 +440,8 @@ OBJS-$(CONFIG_HEVC_NVENC_ENCODER) += nvenc_hevc.o nvenc.o + OBJS-$(CONFIG_HEVC_QSV_DECODER) += qsvdec.o + OBJS-$(CONFIG_HEVC_QSV_ENCODER) += qsvenc_hevc.o hevc_ps_enc.o \ + hevc_data.o +-OBJS-$(CONFIG_HEVC_RKMPP_DECODER) += rkmppdec.o ++OBJS-$(CONFIG_HEVC_RKMPP_DECODER) += rkmpp.o rkplane.o rkmppdec.o ++OBJS-$(CONFIG_HEVC_RKMPP_ENCODER) += rkmpp.o rkplane.o rkmppenc.o + OBJS-$(CONFIG_HEVC_VAAPI_ENCODER) += vaapi_encode_h265.o h265_profile_level.o \ + h2645data.o + OBJS-$(CONFIG_HEVC_V4L2M2M_DECODER) += v4l2_m2m_dec.o +@@ -529,6 +533,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_MPEG1_RKMPP_DECODER) += rkmpp.o rkplane.o rkmppdec.o OBJS-$(CONFIG_MPEG2_MMAL_DECODER) += mmaldec.o OBJS-$(CONFIG_MPEG2_QSV_DECODER) += qsvdec.o OBJS-$(CONFIG_MPEG2_QSV_ENCODER) += qsvenc_mpeg2.o -@@ -539,12 +541,14 @@ OBJS-$(CONFIG_MPEG2_MEDIACODEC_DECODER) += mediacodecdec.o +@@ -539,12 +544,14 @@ 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_MPEG4_DECODER) += mpeg4videodsp.o xvididct.o -+OBJS-$(CONFIG_MPEG2_RKMPP_DECODER) += rkmppdec.o ++OBJS-$(CONFIG_MPEG2_RKMPP_DECODER) += rkmpp.o rkplane.o rkmppdec.o OBJS-$(CONFIG_MPEG4_ENCODER) += mpeg4videoenc.o OBJS-$(CONFIG_MPEG4_CUVID_DECODER) += cuviddec.o 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_MPEG4_RKMPP_DECODER) += rkmpp.o rkplane.o 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 e593ad19af..84e57b3e1b 100644 ---- a/libavcodec/allcodecs.c -+++ b/libavcodec/allcodecs.c -@@ -150,6 +150,7 @@ extern const FFCodec ff_h263i_decoder; - extern const FFCodec ff_h263p_encoder; - extern const FFCodec ff_h263p_decoder; - extern const FFCodec ff_h263_v4l2m2m_decoder; -+extern const FFCodec ff_h263_rkmpp_decoder; - extern const FFCodec ff_h264_decoder; - extern const FFCodec ff_h264_crystalhd_decoder; - extern const FFCodec ff_h264_v4l2m2m_decoder; -@@ -212,13 +213,16 @@ extern const FFCodec ff_mpeg4_decoder; - extern const FFCodec ff_mpeg4_crystalhd_decoder; - extern const FFCodec ff_mpeg4_v4l2m2m_decoder; - extern const FFCodec ff_mpeg4_mmal_decoder; -+extern const AVCodec ff_mpeg4_rkmpp_decoder; - extern const FFCodec ff_mpegvideo_decoder; - extern const FFCodec ff_mpeg1_v4l2m2m_decoder; -+extern const AVCodec ff_mpeg1_rkmpp_decoder; - extern const FFCodec ff_mpeg2_mmal_decoder; - extern const FFCodec ff_mpeg2_crystalhd_decoder; - extern const FFCodec ff_mpeg2_v4l2m2m_decoder; - extern const FFCodec ff_mpeg2_qsv_decoder; - extern const FFCodec ff_mpeg2_mediacodec_decoder; -+extern const AVCodec ff_mpeg2_rkmpp_decoder; - extern const FFCodec ff_msa1_decoder; - extern const FFCodec ff_mscc_decoder; - extern const FFCodec ff_msmpeg4v1_decoder; -diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c -index 9539a48817..cd03174ee2 100644 ---- a/libavcodec/rkmppdec.c -+++ b/libavcodec/rkmppdec.c -@@ -85,10 +85,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; - } - } -@@ -790,7 +794,11 @@ static const AVCodecHWConfigInternal *const rkmpp_hw_configs[] = { - .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_CONTIGUOUS_BUFFERS \ - }; - -+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.40.0 - - -From 27822b4269a2f5b7062c50b4ce4363a4f52f6cc6 Mon Sep 17 00:00:00 2001 -From: Jeffy Chen <jeffy.chen@rock-chips.com> -Date: Sun, 29 Jan 2023 17:50:14 +0800 -Subject: [PATCH 13/24] avcodec/rkmppdec: Add AV1 - -Note: For new chips like rk3588. - -Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com> ---- - configure | 1 + - libavcodec/Makefile | 1 + - libavcodec/allcodecs.c | 1 + - libavcodec/rkmppdec.c | 6 ++++-- - 4 files changed, 7 insertions(+), 2 deletions(-) - -diff --git a/configure b/configure -index 8dd4294f28..3804f193a5 100755 ---- a/configure -+++ b/configure -@@ -3163,6 +3163,7 @@ av1_mediacodec_decoder_deps="mediacodec" - av1_mediacodec_decoder_extralibs="-landroid" - av1_nvenc_encoder_deps="nvenc NV_ENC_PIC_PARAMS_AV1" - av1_nvenc_encoder_select="atsc_a53" -+av1_rkmpp_decoder_deps="rkmpp" - h263_v4l2m2m_decoder_deps="v4l2_m2m h263_v4l2_m2m" - h263_v4l2m2m_encoder_deps="v4l2_m2m h263_v4l2_m2m" - h263_rkmpp_decoder_deps="rkmpp" -diff --git a/libavcodec/Makefile b/libavcodec/Makefile -index 504a31e83e..af0cbbbfe1 100644 ---- a/libavcodec/Makefile -+++ b/libavcodec/Makefile -@@ -255,6 +255,7 @@ OBJS-$(CONFIG_AV1_CUVID_DECODER) += cuviddec.o - OBJS-$(CONFIG_AV1_MEDIACODEC_DECODER) += mediacodecdec.o - OBJS-$(CONFIG_AV1_NVENC_ENCODER) += nvenc_av1.o nvenc.o - OBJS-$(CONFIG_AV1_QSV_ENCODER) += qsvenc_av1.o -+OBJS-$(CONFIG_AV1_RKMPP_DECODER) += rkmppdec.o - OBJS-$(CONFIG_AVRN_DECODER) += avrndec.o - OBJS-$(CONFIG_AVRP_DECODER) += r210dec.o - OBJS-$(CONFIG_AVRP_ENCODER) += r210enc.o -diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c -index 84e57b3e1b..dd8164d2b1 100644 ---- a/libavcodec/allcodecs.c -+++ b/libavcodec/allcodecs.c -@@ -842,6 +842,7 @@ extern const FFCodec ff_av1_nvenc_encoder; - extern const FFCodec ff_av1_qsv_decoder; - extern const FFCodec ff_av1_qsv_encoder; - extern const FFCodec ff_av1_amf_encoder; -+extern const FFCodec ff_av1_rkmpp_decoder; - extern const FFCodec ff_libopenh264_encoder; - extern const FFCodec ff_libopenh264_decoder; - extern const FFCodec ff_h264_amf_encoder; -diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c -index cd03174ee2..32fe1ede6a 100644 ---- a/libavcodec/rkmppdec.c -+++ b/libavcodec/rkmppdec.c -@@ -88,6 +88,7 @@ static MppCodingType rkmpp_get_codingtype(AVCodecContext *avctx) - 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_AV1: return MPP_VIDEO_CodingAV1; - case AV_CODEC_ID_VP8: return MPP_VIDEO_CodingVP8; - case AV_CODEC_ID_VP9: return MPP_VIDEO_CodingVP9; - case AV_CODEC_ID_MPEG1VIDEO: /* fallthrough */ -@@ -168,8 +169,8 @@ static int rkmpp_prepare_decoder(AVCodecContext *avctx) - MppPacket packet; - int ret; - -- // send extra data -- if (avctx->extradata_size) { -+ // HACK: somehow MPP cannot handle extra data for AV1 -+ if (avctx->extradata_size && avctx->codec_id != AV_CODEC_ID_AV1) { - ret = mpp_packet_init(&packet, avctx->extradata, avctx->extradata_size); - if (ret < 0) - return AVERROR_UNKNOWN; -@@ -797,6 +798,7 @@ static const AVCodecHWConfigInternal *const rkmpp_hw_configs[] = { - 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(av1, AV_CODEC_ID_AV1, NULL) - RKMPP_DEC(vp8, AV_CODEC_ID_VP8, NULL) - RKMPP_DEC(vp9, AV_CODEC_ID_VP9, NULL) - RKMPP_DEC(mpeg1, AV_CODEC_ID_MPEG1VIDEO, NULL) --- -2.40.0 - - -From 07bad22a207711d9860d5d66191a865f32d59881 Mon Sep 17 00:00:00 2001 -From: Jeffy Chen <jeffy.chen@rock-chips.com> -Date: Mon, 27 Mar 2023 17:44:09 +0800 -Subject: [PATCH 14/24] rkmppdec: Ignore special MPP format masks - -We should use the basic format in format conversion. - -Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com> ---- - libavcodec/rkmppdec.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c -index 32fe1ede6a..dcaea9d435 100644 ---- a/libavcodec/rkmppdec.c -+++ b/libavcodec/rkmppdec.c -@@ -100,7 +100,7 @@ static MppCodingType rkmpp_get_codingtype(AVCodecContext *avctx) - - static uint32_t rkmpp_get_frameformat(MppFrameFormat mppformat) - { -- switch (mppformat) { -+ switch (mppformat & MPP_FRAME_FMT_MASK) { - case MPP_FMT_YUV420SP: return DRM_FORMAT_NV12; - case MPP_FMT_YUV420SP_10BIT: return DRM_FORMAT_NV15; - case MPP_FMT_YUV422SP: return DRM_FORMAT_NV16; -@@ -110,7 +110,7 @@ static uint32_t rkmpp_get_frameformat(MppFrameFormat mppformat) - - static uint32_t rkmpp_get_avformat(MppFrameFormat mppformat) - { -- switch (mppformat) { -+ switch (mppformat & MPP_FRAME_FMT_MASK) { - 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; -@@ -121,7 +121,7 @@ static uint32_t rkmpp_get_avformat(MppFrameFormat mppformat) - #if CONFIG_LIBRGA - static uint32_t rkmpp_get_rgaformat(MppFrameFormat mppformat) - { -- switch (mppformat) { -+ switch (mppformat & MPP_FRAME_FMT_MASK) { - 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; +@@ -765,7 +772,8 @@ OBJS-$(CONFIG_VP8_DECODER) += vp8.o vpx_rac.o + OBJS-$(CONFIG_VP8_CUVID_DECODER) += cuviddec.o + OBJS-$(CONFIG_VP8_MEDIACODEC_DECODER) += mediacodecdec.o + OBJS-$(CONFIG_VP8_QSV_DECODER) += qsvdec.o +-OBJS-$(CONFIG_VP8_RKMPP_DECODER) += rkmppdec.o ++OBJS-$(CONFIG_VP8_RKMPP_DECODER) += rkmpp.o rkplane.o rkmppdec.o ++OBJS-$(CONFIG_VP8_RKMPP_ENCODER) += rkmpp.o rkplane.o rkmppenc.o + OBJS-$(CONFIG_VP8_VAAPI_ENCODER) += vaapi_encode_vp8.o + OBJS-$(CONFIG_VP8_V4L2M2M_DECODER) += v4l2_m2m_dec.o + OBJS-$(CONFIG_VP8_V4L2M2M_ENCODER) += v4l2_m2m_enc.o +@@ -774,7 +782,7 @@ OBJS-$(CONFIG_VP9_DECODER) += vp9.o vp9data.o vp9dsp.o vp9lpf.o vp9r + vp9dsp_8bpp.o vp9dsp_10bpp.o vp9dsp_12bpp.o + OBJS-$(CONFIG_VP9_CUVID_DECODER) += cuviddec.o + OBJS-$(CONFIG_VP9_MEDIACODEC_DECODER) += mediacodecdec.o +-OBJS-$(CONFIG_VP9_RKMPP_DECODER) += rkmppdec.o ++OBJS-$(CONFIG_VP9_RKMPP_DECODER) += rkmpp.o rkplane.o rkmppdec.o + OBJS-$(CONFIG_VP9_VAAPI_ENCODER) += vaapi_encode_vp9.o + OBJS-$(CONFIG_VP9_QSV_ENCODER) += qsvenc_vp9.o + OBJS-$(CONFIG_VPLAYER_DECODER) += textdec.o ass.o -- -2.40.0 +2.41.0 -From 5910b3c4944c51a762175c461eec4f4781a3234f Mon Sep 17 00:00:00 2001 +From ebd97550cf3a9a1902b5a58566caa846f9ad2114 Mon Sep 17 00:00:00 2001 From: boogie <boogiepop@gmx.com> -Date: Thu, 20 Apr 2023 15:23:26 +0200 -Subject: [PATCH 15/24] Prioritize RKMPP decoders first +Date: Mon, 24 Jul 2023 16:14:02 +0200 +Subject: [PATCH 08/13] register all codec as highest prio --- - libavcodec/allcodecs.c | 19 ++++++++++--------- - 1 file changed, 10 insertions(+), 9 deletions(-) + libavcodec/allcodecs.c | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c -index dd8164d2b1..ba08c937d2 100644 +index e593ad19af..082c4b8e29 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c -@@ -34,6 +34,16 @@ +@@ -34,6 +34,20 @@ #include "codec_id.h" #include "codec_internal.h" @@ -1784,18 +1335,14 @@ index dd8164d2b1..ba08c937d2 100644 +extern const FFCodec ff_vp8_rkmpp_decoder; +extern const FFCodec ff_vp9_rkmpp_decoder; + ++extern const FFCodec ff_vp8_rkmpp_encoder; ++extern const FFCodec ff_h264_rkmpp_encoder; ++extern const FFCodec ff_hevc_rkmpp_encoder; ++ extern const FFCodec ff_a64multi_encoder; extern const FFCodec ff_a64multi5_encoder; extern const FFCodec ff_aasc_decoder; -@@ -150,7 +160,6 @@ extern const FFCodec ff_h263i_decoder; - extern const FFCodec ff_h263p_encoder; - extern const FFCodec ff_h263p_decoder; - extern const FFCodec ff_h263_v4l2m2m_decoder; --extern const FFCodec ff_h263_rkmpp_decoder; - extern const FFCodec ff_h264_decoder; - extern const FFCodec ff_h264_crystalhd_decoder; - extern const FFCodec ff_h264_v4l2m2m_decoder; -@@ -158,12 +167,10 @@ extern const FFCodec ff_h264_mediacodec_decoder; +@@ -157,12 +171,10 @@ extern const FFCodec ff_h264_mediacodec_decoder; extern const FFCodec ff_h264_mediacodec_encoder; extern const FFCodec ff_h264_mmal_decoder; extern const FFCodec ff_h264_qsv_decoder; @@ -1808,24 +1355,7 @@ index dd8164d2b1..ba08c937d2 100644 extern const FFCodec ff_hevc_v4l2m2m_decoder; extern const FFCodec ff_hnm4_video_decoder; extern const FFCodec ff_hq_hqa_decoder; -@@ -213,16 +220,13 @@ extern const FFCodec ff_mpeg4_decoder; - extern const FFCodec ff_mpeg4_crystalhd_decoder; - extern const FFCodec ff_mpeg4_v4l2m2m_decoder; - extern const FFCodec ff_mpeg4_mmal_decoder; --extern const AVCodec ff_mpeg4_rkmpp_decoder; - extern const FFCodec ff_mpegvideo_decoder; - extern const FFCodec ff_mpeg1_v4l2m2m_decoder; --extern const AVCodec ff_mpeg1_rkmpp_decoder; - extern const FFCodec ff_mpeg2_mmal_decoder; - extern const FFCodec ff_mpeg2_crystalhd_decoder; - extern const FFCodec ff_mpeg2_v4l2m2m_decoder; - extern const FFCodec ff_mpeg2_qsv_decoder; - extern const FFCodec ff_mpeg2_mediacodec_decoder; --extern const AVCodec ff_mpeg2_rkmpp_decoder; - extern const FFCodec ff_msa1_decoder; - extern const FFCodec ff_mscc_decoder; - extern const FFCodec ff_msmpeg4v1_decoder; -@@ -381,10 +385,8 @@ extern const FFCodec ff_vp6a_decoder; +@@ -377,10 +389,8 @@ extern const FFCodec ff_vp6a_decoder; extern const FFCodec ff_vp6f_decoder; extern const FFCodec ff_vp7_decoder; extern const FFCodec ff_vp8_decoder; @@ -1836,1643 +1366,2270 @@ index dd8164d2b1..ba08c937d2 100644 extern const FFCodec ff_vp9_v4l2m2m_decoder; extern const FFCodec ff_vqa_decoder; extern const FFCodec ff_vqc_decoder; -@@ -842,7 +844,6 @@ extern const FFCodec ff_av1_nvenc_encoder; - extern const FFCodec ff_av1_qsv_decoder; - extern const FFCodec ff_av1_qsv_encoder; - extern const FFCodec ff_av1_amf_encoder; --extern const FFCodec ff_av1_rkmpp_decoder; - extern const FFCodec ff_libopenh264_encoder; - extern const FFCodec ff_libopenh264_decoder; - extern const FFCodec ff_h264_amf_encoder; -- -2.40.0 +2.41.0 -From 035feef7fdc3ed1378b13ce8d28ad4237cac48b2 Mon Sep 17 00:00:00 2001 +From a82dd80d7c3f267cef6ef88bd0b6852fe73bcdea Mon Sep 17 00:00:00 2001 From: boogie <boogiepop@gmx.com> -Date: Fri, 7 Apr 2023 16:20:13 +0200 -Subject: [PATCH 16/24] Remove librga +Date: Mon, 24 Jul 2023 16:10:39 +0200 +Subject: [PATCH 09/13] intiial up to: eb34616ece746ae58030fd4601e802dacb0d3ee2 --- - configure | 7 +---- - libavcodec/rkmppdec.c | 68 +------------------------------------------ - 2 files changed, 2 insertions(+), 73 deletions(-) + libavcodec/codec_internal.h | 4 + + libavcodec/get_buffer.c | 24 ++ + libavcodec/rkmpp.c | 272 +++++++++++++++ + libavcodec/rkmpp.h | 281 +++++++++++++++ + libavcodec/rkmppdec.c | 335 ++++++++++++++++++ + libavcodec/rkmppenc.c | 628 +++++++++++++++++++++++++++++++++ + libavcodec/rkplane.c | 676 ++++++++++++++++++++++++++++++++++++ + libavcodec/rkplane.h | 17 + + 8 files changed, 2237 insertions(+) + create mode 100644 libavcodec/rkmpp.c + create mode 100644 libavcodec/rkmpp.h + create mode 100644 libavcodec/rkmppdec.c + create mode 100644 libavcodec/rkmppenc.c + create mode 100644 libavcodec/rkplane.c + create mode 100644 libavcodec/rkplane.h -diff --git a/configure b/configure -index 3804f193a5..84c6850fca 100755 ---- a/configure -+++ b/configure -@@ -349,7 +349,6 @@ 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] -@@ -1893,7 +1892,6 @@ HWACCEL_AUTODETECT_LIBRARY_LIST=" - videotoolbox - vulkan - v4l2_m2m -- librga - " - - # catchall list of things that require external libs to link -@@ -6796,13 +6794,10 @@ 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 && 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"; } && -- { enabled librga || -- warn "using rkmpp without librga"; } -+ die "ERROR: rkmpp requires --enable-libdrm"; } - } - enabled vapoursynth && require_pkg_config vapoursynth "vapoursynth-script >= 42" VSScript.h vsscript_init - -diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c -index dcaea9d435..908ab3963b 100644 ---- a/libavcodec/rkmppdec.c -+++ b/libavcodec/rkmppdec.c -@@ -40,11 +40,6 @@ - #include "libavutil/imgutils.h" - #include "libavutil/log.h" - --#if CONFIG_LIBRGA --#include <rga/rga.h> --#include <rga/RgaApi.h> --#endif -- - // HACK: Older BSP kernel use NA12 for NV15. - #ifndef DRM_FORMAT_NV15 // fourcc_code('N', 'V', '1', '5') - #define DRM_FORMAT_NV15 fourcc_code('N', 'A', '1', '2') -@@ -118,18 +113,6 @@ static uint32_t rkmpp_get_avformat(MppFrameFormat mppformat) - } - } - --#if CONFIG_LIBRGA --static uint32_t rkmpp_get_rgaformat(MppFrameFormat mppformat) --{ -- switch (mppformat & MPP_FRAME_FMT_MASK) { -- 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; -- } --} --#endif -- - static int rkmpp_close_decoder(AVCodecContext *avctx) - { - RKMPPDecodeContext *rk_context = avctx->priv_data; -@@ -314,9 +297,6 @@ static int rkmpp_convert_frame(AVCodecContext *avctx, AVFrame *frame, - 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); -@@ -326,51 +306,6 @@ static int rkmpp_convert_frame(AVCodecContext *avctx, AVFrame *frame, - 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; -@@ -533,7 +468,7 @@ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout) - if (avctx->pix_fmt != AV_PIX_FMT_DRM_PRIME) { - ret = ff_get_buffer(avctx, frame, 0); - if (ret < 0) -- goto out; -+ goto fail; - } - - // setup general frame fields -@@ -612,7 +547,6 @@ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout) - - return 0; +diff --git a/libavcodec/codec_internal.h b/libavcodec/codec_internal.h +index 130a7dc3cd..ed0dea86de 100644 +--- a/libavcodec/codec_internal.h ++++ b/libavcodec/codec_internal.h +@@ -80,6 +80,10 @@ + * Codec supports embedded ICC profiles (AV_FRAME_DATA_ICC_PROFILE). + */ + #define FF_CODEC_CAP_ICC_PROFILES (1 << 9) ++/** ++ * The decoder requires contiguous buffers. ++ */ ++#define FF_CODEC_CAP_CONTIGUOUS_BUFFERS (1 << 28) + /** + * The encoder has AV_CODEC_CAP_DELAY set, but does not actually have delay - it + * only wants to be flushed at the end to update some context variables (e.g. +diff --git a/libavcodec/get_buffer.c b/libavcodec/get_buffer.c +index a04fd878de..c6a1983f7e 100644 +--- a/libavcodec/get_buffer.c ++++ b/libavcodec/get_buffer.c +@@ -32,6 +32,7 @@ --out: - fail: - if (mppframe) - mpp_frame_deinit(&mppframe); --- -2.40.0 - - -From 3a656a5cf3545ebcfec88ca9b2ca4fad2ff3f286 Mon Sep 17 00:00:00 2001 -From: boogie <boogiepop@gmx.com> -Date: Sun, 16 Apr 2023 19:17:44 +0200 -Subject: [PATCH 17/24] Faster sw conversion with libyuv using SIMD - ---- - configure | 3 +++ - libavcodec/rkmppdec.c | 47 ++++++++++++++++++++----------------------- - 2 files changed, 25 insertions(+), 25 deletions(-) - -diff --git a/configure b/configure -index 84c6850fca..7b7c4c0872 100755 ---- a/configure -+++ b/configure -@@ -6796,6 +6796,9 @@ enabled openssl && { { check_pkg_config openssl "openssl >= 3.0.0" ope - enabled pocketsphinx && require_pkg_config pocketsphinx pocketsphinx pocketsphinx/pocketsphinx.h ps_init - 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 && -+ { check_lib libyuv libyuv/planar_functions.h SplitUVPlane -lyuv || -+ die "ERROR: libyuv is necessary for rkmpp"; } && -+ prepend rkmpp_deps "libyuv" && - { enabled libdrm || - die "ERROR: rkmpp requires --enable-libdrm"; } - } -diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c -index 908ab3963b..1cca4b6e7d 100644 ---- a/libavcodec/rkmppdec.c -+++ b/libavcodec/rkmppdec.c -@@ -39,6 +39,7 @@ - #include "libavutil/hwcontext_drm.h" - #include "libavutil/imgutils.h" - #include "libavutil/log.h" -+#include "libyuv/planar_functions.h" + #include "avcodec.h" + #include "internal.h" ++#include "codec_internal.h" - // HACK: Older BSP kernel use NA12 for NV15. - #ifndef DRM_FORMAT_NV15 // fourcc_code('N', 'V', '1', '5') -@@ -290,44 +291,41 @@ static void rkmpp_release_frame(void *opaque, uint8_t *data) - av_free(desc); - } + typedef struct FramePool { + /** +@@ -147,6 +148,14 @@ FF_ENABLE_DEPRECATION_WARNINGS -+static void rkmpp_release_buffer(void *opaque, uint8_t *data) -+{ -+ MppFrame mppframe = opaque; -+ mpp_frame_deinit(&mppframe); -+} + for (i = 0; i < 4; i++) { + pool->linesize[i] = linesize[i]; + - 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]; -- 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 (mpp_frame_get_fmt(mppframe) != MPP_FMT_YUV420SP) { -- av_log(avctx, AV_LOG_WARNING, "Unable to convert\n"); -- return -1; -+ //data[0] points to buf[1] where the mppbuffer is referenced for y plane -+ //so that we can still use y plane without extra copies -+ //data[1,2] points to allready allocated AVBuffer Pool (buf[0]), we will convert to -+ //that buffer only u+v planes, which is half the size operation -+ frame->data[0] = mpp_buffer_get_ptr(buffer); -+ frame->buf[1] = av_buffer_create(frame->data[0], mpp_buffer_get_size(buffer), -+ rkmpp_release_buffer, mppframe, -+ AV_BUFFER_FLAG_READONLY); -+ if (!frame->buf[1]) { -+ return AVERROR(ENOMEM); - } -- -- 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); -+ frame->linesize[0] = hstride; -+ av_log(avctx, AV_LOG_WARNING, "Doing software conversion for uv planes\n"); - - 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; -- } -- -+ SplitUVPlane(src, hstride, dst_u, u_pitch, dst_v, v_pitch, -+ (frame->width + 1) >> 1, (frame->height + 1) >> 1); - return 0; - } - -@@ -487,8 +485,7 @@ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout) - frame->top_field_first = ((mode & MPP_FRAME_FLAG_FIELD_ORDER_MASK) == MPP_FRAME_FLAG_TOP_FIRST); ++ if (ffcodec(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); +@@ -265,6 +274,21 @@ static int video_get_buffer(AVCodecContext *s, AVFrame *pic) - if (avctx->pix_fmt != AV_PIX_FMT_DRM_PRIME) { -- ret = rkmpp_convert_frame(avctx, frame, mppframe, buffer); -- goto out; -+ return rkmpp_convert_frame(avctx, frame, mppframe, buffer); + pic->data[i] = pic->buf[i]->data; } - - mppformat = mpp_frame_get_fmt(mppframe); --- -2.40.0 - - -From ebe5776cef27e618ac8b75450f43ead8b0cb6b13 Mon Sep 17 00:00:00 2001 -From: boogie <boogiepop@gmx.com> -Date: Tue, 18 Apr 2023 19:05:56 +0200 -Subject: [PATCH 18/24] Use internal rga to convert from mppbuffer to avbuffer - ---- - libavcodec/rga.h | 574 ++++++++++++++++++++++++++++++++++++++++++ - libavcodec/rkmppdec.c | 80 +++++- - 2 files changed, 653 insertions(+), 1 deletion(-) - create mode 100644 libavcodec/rga.h - -diff --git a/libavcodec/rga.h b/libavcodec/rga.h ++ ++ if (ffcodec(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/rkmpp.c b/libavcodec/rkmpp.c new file mode 100644 -index 0000000000..9595558de0 +index 0000000000..b76dc1a868 --- /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, ++++ b/libavcodec/rkmpp.c +@@ -0,0 +1,272 @@ ++/* ++ * RockChip MPP Video Codec ++ * Copyright (c) 2023 Huseyin BIYIK ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++#include <fcntl.h> ++#include <time.h> ++#include "rkmpp.h" ++ ++static rkformat rkformats[13] = { ++ { .av = AV_PIX_FMT_YUV420P, .mpp = MPP_FMT_YUV420P, .drm = DRM_FORMAT_YUV420, .rga = RK_FORMAT_YCbCr_420_P}, ++ { .av = AV_PIX_FMT_YUV422P, .mpp = MPP_FMT_YUV422P, .drm = DRM_FORMAT_YUV422, .rga = RK_FORMAT_YCbCr_422_P}, ++ { .av = AV_PIX_FMT_NV12, .mpp = MPP_FMT_YUV420SP, .drm = DRM_FORMAT_NV12, .rga = RK_FORMAT_YCbCr_420_SP}, ++ { .av = AV_PIX_FMT_NV16, .mpp = MPP_FMT_YUV422SP, .drm = DRM_FORMAT_NV16, .rga = RK_FORMAT_YCbCr_422_SP}, ++ { .av = AV_PIX_FMT_NONE, .mpp = MPP_FMT_YUV420SP_10BIT, .drm = DRM_FORMAT_NV15, .rga = RK_FORMAT_YCbCr_420_SP_10B}, ++ { .av = AV_PIX_FMT_BGR24, .mpp = MPP_FMT_BGR888, .drm = DRM_FORMAT_BGR888, .rga = RK_FORMAT_BGR_888}, ++ { .av = AV_PIX_FMT_BGR0, .mpp = MPP_FMT_BGRA8888, .drm = DRM_FORMAT_XRGB8888, .rga = RK_FORMAT_BGRX_8888}, ++ { .av = AV_PIX_FMT_BGRA, .mpp = MPP_FMT_BGRA8888, .drm = DRM_FORMAT_ARGB8888, .rga = RK_FORMAT_BGRA_8888}, ++ { .av = AV_PIX_FMT_BGR565, .mpp = MPP_FMT_BGR565, .drm = DRM_FORMAT_BGR565, .rga = RK_FORMAT_BGR_565}, ++ { .av = AV_PIX_FMT_YUYV422, .mpp = MPP_FMT_YUV422_YUYV, .drm = DRM_FORMAT_YUYV, .rga = RK_FORMAT_YUYV_422}, ++ { .av = AV_PIX_FMT_UYVY422, .mpp = MPP_FMT_YUV422_UYVY, .drm = DRM_FORMAT_UYVY, .rga = RK_FORMAT_UYVY_422}, ++ { .av = AV_PIX_FMT_NV24, .mpp = MPP_FMT_YUV444SP, .drm = DRM_FORMAT_NV24, .rga = RK_FORMAT_UNKNOWN}, ++ { .av = AV_PIX_FMT_YUV444P, .mpp = MPP_FMT_YUV444P, .drm = DRM_FORMAT_YUV444, .rga = RK_FORMAT_UNKNOWN}, +}; + -+enum rga_scale_up_mode { -+ RGA_SCALE_UP_NONE = 0x0, -+ RGA_SCALE_UP_BIC = 0x1, -+}; ++#define GETFORMAT(NAME, TYPE)\ ++int rkmpp_get_##NAME##_format(rkformat *format, TYPE informat){ \ ++ for(int i=0; i < 13; i++){ \ ++ if(rkformats[i].NAME == informat){ \ ++ format->av = rkformats[i].av;\ ++ format->mpp = rkformats[i].mpp;\ ++ format->drm = rkformats[i].drm;\ ++ format->rga = rkformats[i].rga;\ ++ return 0;\ ++ }\ ++ }\ ++ return -1;\ ++} + -+enum rga_scale_down_mode { -+ RGA_SCALE_DOWN_NONE = 0x0, -+ RGA_SCALE_DOWN_AVG = 0x1, -+}; ++GETFORMAT(drm, uint32_t) ++GETFORMAT(mpp, MppFrameFormat) ++GETFORMAT(rga, enum _Rga_SURF_FORMAT) ++GETFORMAT(av, enum AVPixelFormat) + -+/* 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, -+}; ++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_AV1: return MPP_VIDEO_CodingAV1; ++ 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; ++ } ++} + -+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, -+}; ++int rkmpp_close_codec(AVCodecContext *avctx) ++{ ++ RKMPPCodecContext *rk_context = avctx->priv_data; ++ RKMPPCodec *codec = (RKMPPCodec *)rk_context->codec_ref->data; + -+/* 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, -+}; ++ av_packet_unref(&codec->lastpacket); ++ av_frame_unref(&codec->lastframe); + -+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, -+}; ++ av_buffer_unref(&rk_context->codec_ref); ++ return 0; ++} + -+#define RGA_SCHED_PRIORITY_DEFAULT 0 -+#define RGA_SCHED_PRIORITY_MAX 6 ++void rkmpp_release_codec(void *opaque, uint8_t *data) ++{ ++ RKMPPCodec *codec = (RKMPPCodec *)data; + -+#define RGA_VERSION_SIZE 16 -+#define RGA_HW_SIZE 5 ++ if (codec->mpi) { ++ codec->mpi->reset(codec->ctx); ++ mpp_destroy(codec->ctx); ++ codec->ctx = NULL; ++ } + -+struct rga_version_t { -+ uint32_t major; -+ uint32_t minor; -+ uint32_t revision; -+ uint8_t str[RGA_VERSION_SIZE]; -+}; ++ if (codec->buffer_group) { ++ mpp_buffer_group_put(codec->buffer_group); ++ codec->buffer_group = NULL; ++ } + -+struct rga_hw_versions_t { -+ struct rga_version_t version[RGA_HW_SIZE]; -+ uint32_t size; -+}; ++ if(codec->hwframes_ref) ++ av_buffer_unref(&codec->hwframes_ref); ++ if(codec->hwdevice_ref) ++ av_buffer_unref(&codec->hwdevice_ref); + -+struct rga_memory_parm { -+ uint32_t width; -+ uint32_t height; -+ uint32_t format; ++ av_free(codec); ++} + -+ uint32_t size; -+}; ++int rkmpp_init_codec(AVCodecContext *avctx) ++{ ++ RKMPPCodecContext *rk_context = avctx->priv_data; ++ RKMPPCodec *codec = NULL; ++ MppCodingType codectype = MPP_VIDEO_CodingUnused; ++ char *env; ++ int ret; + -+struct rga_external_buffer { -+ uint64_t memory; -+ uint32_t type; ++ // create a codec and a ref to it ++ codec = av_mallocz(sizeof(RKMPPCodec)); ++ if (!codec) { ++ ret = AVERROR(ENOMEM); ++ goto fail; ++ } + -+ uint32_t handle; -+ struct rga_memory_parm memory_parm; ++ rk_context->codec_ref = av_buffer_create((uint8_t *)codec, sizeof(*codec), rkmpp_release_codec, ++ NULL, AV_BUFFER_FLAG_READONLY); ++ if (!rk_context->codec_ref) { ++ av_free(codec); ++ ret = AVERROR(ENOMEM); ++ goto fail; ++ } + -+ uint8_t reserve[252]; -+}; ++ env = getenv("FFMPEG_RKMPP_LOG_FPS"); ++ if (env != NULL) ++ codec->print_fps = !!atoi(env); + -+struct rga_buffer_pool { -+ uint64_t buffers_ptr; -+ uint32_t size; -+}; ++ av_log(avctx, AV_LOG_DEBUG, "Initializing RKMPP Codec.\n"); + -+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; -+}; ++ codectype = rkmpp_get_codingtype(avctx); ++ if (codectype == MPP_VIDEO_CodingUnused) { ++ av_log(avctx, AV_LOG_ERROR, "Unknown codec type (%d).\n", avctx->codec_id); ++ ret = AVERROR_UNKNOWN; ++ goto fail; ++ } + -+/***************************************/ -+/* porting from rga.h for msg convert */ -+/***************************************/ ++ ret = mpp_check_support_format(codec->mppctxtype, codectype); ++ if (ret != MPP_OK) { ++ av_log(avctx, AV_LOG_ERROR, "Codec type (%d) unsupported by MPP\n", avctx->codec_id); ++ ret = AVERROR_UNKNOWN; ++ goto fail; ++ } + -+struct rga_fading_t { -+ uint8_t b; -+ uint8_t g; -+ uint8_t r; -+ uint8_t res; -+}; ++ // Create the MPP context ++ ret = mpp_create(&codec->ctx, &codec->mpi); ++ if (ret != MPP_OK) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to create MPP context (code = %d).\n", ret); ++ ret = AVERROR_UNKNOWN; ++ goto fail; ++ } + -+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; -+}; ++ if(ffcodec(avctx->codec)->cb_type == FF_CODEC_CB_TYPE_RECEIVE_FRAME){ ++ codec->init_callback = rkmpp_init_decoder; ++ codec->mppctxtype = MPP_CTX_DEC; + -+struct rga_rect_t { -+ uint16_t xmin; -+ /* width - 1 */ -+ uint16_t xmax; -+ uint16_t ymin; -+ /* height - 1 */ -+ uint16_t ymax; -+}; ++ ret = 1; ++ codec->mpi->control(codec->ctx, MPP_DEC_SET_PARSER_FAST_MODE, &ret); ++ ++ avctx->pix_fmt = ff_get_format(avctx, avctx->codec->pix_fmts); ++ ++ // override the the pixfmt according env variable ++ env = getenv("FFMPEG_RKMPP_PIXFMT"); ++ if(env != NULL){ ++ if(!strcmp(env, "YUV420P")) ++ avctx->pix_fmt = AV_PIX_FMT_YUV420P; ++ else if (!strcmp(env, "NV12")) ++ avctx->pix_fmt = AV_PIX_FMT_NV12; ++ else if(!strcmp(env, "DRMPRIME")) ++ avctx->pix_fmt = AV_PIX_FMT_DRM_PRIME; ++ } ++ } else if ((ffcodec(avctx->codec)->cb_type == FF_CODEC_CB_TYPE_ENCODE)){ ++ codec->mppctxtype = MPP_CTX_ENC; ++ codec->init_callback = rkmpp_init_encoder; ++ } else { ++ ret = AVERROR(ENOMEM); ++ av_log(avctx, AV_LOG_DEBUG, "RKMPP Codec can not determine if the mode is decoder or encoder\n"); ++ goto fail; ++ } + -+struct rga_point_t { -+ uint16_t x; -+ uint16_t y; -+}; ++ av_log(avctx, AV_LOG_INFO, "Picture format is %s.\n", av_get_pix_fmt_name(avctx->pix_fmt)); + -+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; -+}; ++ // initialize mpp ++ ret = mpp_init(codec->ctx, codec->mppctxtype, codectype); ++ if (ret != MPP_OK) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to initialize MPP context (code = %d).\n", ret); ++ ret = AVERROR_UNKNOWN; ++ goto fail; ++ } + -+/* color space convert coefficient. */ -+struct rga_csc_coe { -+ int16_t r_v; -+ int16_t g_y; -+ int16_t b_u; -+ int32_t off; -+}; ++ env = getenv("FFMPEG_RKMPP_NORGA"); ++ if(env != NULL){ ++ codec->norga = 1; ++ av_log(avctx, AV_LOG_INFO, "Bypassing RGA and using libyuv soft conversion\n"); ++ } + -+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; -+}; ++ ret = mpp_buffer_group_get_internal(&codec->buffer_group, MPP_BUFFER_TYPE_DRM | MPP_BUFFER_FLAGS_DMA32); ++ if (ret) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to get buffer group (code = %d)\n", ret); ++ ret = AVERROR_UNKNOWN; ++ goto fail; ++ } ++ ++ ret = codec->init_callback(avctx); ++ if(ret){ ++ av_log(avctx, AV_LOG_ERROR, "Failed to init Codec (code = %d).\n", ret); ++ goto fail; ++ } ++ ++ return 0; + -+struct rga_mosaic_info { -+ uint8_t enable; -+ uint8_t mode; ++fail: ++ av_log(avctx, AV_LOG_ERROR, "Failed to initialize RKMPP Codec.\n"); ++ rkmpp_close_codec(avctx); ++ return ret; ++} ++ ++void rkmpp_flush(AVCodecContext *avctx) ++{ ++ RKMPPCodecContext *rk_context = avctx->priv_data; ++ RKMPPCodec *codec = (RKMPPCodec *)rk_context->codec_ref->data; ++ ++ av_log(avctx, AV_LOG_DEBUG, "Flush.\n"); ++ ++ codec->mpi->reset(codec->ctx); ++ codec->norga = codec->last_frame_time = codec->frames = codec->hascfg = 0; ++ ++ av_packet_unref(&codec->lastpacket); ++ av_frame_unref(&codec->lastframe); ++} ++ ++uint64_t rkmpp_update_latency(AVCodecContext *avctx, int latency) ++{ ++ RKMPPCodecContext *rk_context = avctx->priv_data; ++ RKMPPCodec *codec = (RKMPPCodec *)rk_context->codec_ref->data; ++ struct timespec tv; ++ uint64_t curr_time; ++ float fps = 0.0f; ++ ++ if (!codec->print_fps) ++ return 0; ++ ++ clock_gettime(CLOCK_MONOTONIC, &tv); ++ curr_time = tv.tv_sec * 10e5 + tv.tv_nsec / 10e2; ++ if (latency == -1){ ++ latency = codec->last_frame_time ? curr_time - codec->last_frame_time : 0; ++ codec->last_frame_time = curr_time; ++ codec->latencies[codec->frames % RKMPP_FPS_FRAME_MACD] = latency; ++ return latency; ++ } else if (latency == 0 || codec->frames < RKMPP_FPS_FRAME_MACD) { ++ fps = -1.0f; ++ } else { ++ for(int i = 0; i < RKMPP_FPS_FRAME_MACD; i++) { ++ fps += codec->latencies[i]; ++ } ++ fps = RKMPP_FPS_FRAME_MACD * 1000000.0f / fps; ++ } ++ av_log(avctx, AV_LOG_INFO, ++ "[FFMPEG RKMPP] FPS(MACD%d): %6.1f || Frames: %" PRIu64 " || Latency: %d us || Buffer Delay %" PRIu64 "us\n", ++ RKMPP_FPS_FRAME_MACD, fps, codec->frames, latency, (uint64_t)(curr_time - codec->last_frame_time)); ++ ++ return 0; ++} +diff --git a/libavcodec/rkmpp.h b/libavcodec/rkmpp.h +new file mode 100644 +index 0000000000..c09ef5b564 +--- /dev/null ++++ b/libavcodec/rkmpp.h +@@ -0,0 +1,281 @@ ++#include <drm_fourcc.h> ++#include <rockchip/rk_mpi.h> ++#include <unistd.h> ++#include <stdint.h> ++ ++#include "internal.h" ++#include "codec_internal.h" ++#include "avcodec.h" ++#include "hwconfig.h" ++#include "decode.h" ++#include "encode.h" ++#include "rga/RgaApi.h" ++#include "libavutil/macros.h" ++#include "libavutil/log.h" ++#include "libavutil/opt.h" ++#include "libavutil/buffer.h" ++#include "libavutil/pixfmt.h" ++#include "libavutil/pixdesc.h" ++#include "libavutil/hwcontext_drm.h" ++ ++// HACK: Older BSP kernel use NA12 for NV15. ++#ifndef DRM_FORMAT_NV15 // fourcc_code('N', 'V', '1', '5') ++#define DRM_FORMAT_NV15 fourcc_code('N', 'A', '1', '2') ++#endif ++ ++#define RKMPP_FPS_FRAME_MACD 30 ++#define RKMPP_STRIDE_ALIGN 16 ++#define RKMPP_RGA_MIN_SIZE 128 ++#define RKMPP_RGA_MAX_SIZE 4096 ++#define RKMPP_MPPFRAME_BUFINDEX 7 ++#define HDR_SIZE 1024 ++#define QMAX_H26x 51 ++#define QMIN_H26x 10 ++#define QMAX_VPx 127 ++#define QMIN_VPx 40 ++#define QMAX_JPEG 99 ++#define QMIN_JPEG 1 ++ ++ ++#define DRMFORMATNAME(buf, format) \ ++ buf[0] = format & 0xff; \ ++ buf[1] = (format >> 8) & 0xff; \ ++ buf[2] = (format >> 16) & 0xff; \ ++ buf[3] = (format >> 24) & 0x7f; \ ++ ++typedef struct { ++ AVClass *av_class; ++ AVBufferRef *codec_ref; ++ int rc_mode; ++ int profile; ++ int qmin; ++ int qmax; ++ int level; ++ int coder; ++ int dct8x8; ++ enum AVPixelFormat postrga_format; ++ int postrga_width; ++ int postrga_height; ++} RKMPPCodecContext; ++ ++typedef struct { ++ MppCtx ctx; ++ MppApi *mpi; ++ MppBufferGroup buffer_group; ++ MppCtxType mppctxtype; ++ MppEncCfg enccfg; ++ int hascfg; ++ int64_t ptsstep; ++ int64_t pts; ++ ++ AVPacket lastpacket; ++ AVFrame lastframe; ++ AVBufferRef *hwframes_ref; ++ AVBufferRef *hwdevice_ref; ++ ++ char print_fps; ++ uint64_t last_frame_time; ++ uint64_t frames; ++ uint64_t latencies[RKMPP_FPS_FRAME_MACD]; ++ ++ int8_t norga; ++ int (*init_callback)(struct AVCodecContext *avctx); ++} RKMPPCodec; ++ ++typedef struct { ++ enum AVPixelFormat av; ++ MppFrameFormat mpp; ++ uint32_t drm; ++ enum _Rga_SURF_FORMAT rga; ++} rkformat; ++ ++MppCodingType rkmpp_get_codingtype(AVCodecContext *avctx); ++int rkmpp_get_drm_format(rkformat *format, uint32_t informat); ++int rkmpp_get_mpp_format(rkformat *format, MppFrameFormat informat); ++int rkmpp_get_rga_format(rkformat *format, enum _Rga_SURF_FORMAT informat); ++int rkmpp_get_av_format(rkformat *format, enum AVPixelFormat informat); ++int rkmpp_init_encoder(AVCodecContext *avctx); ++int rkmpp_encode(AVCodecContext *avctx, AVPacket *packet, const AVFrame *frame, int *got_packet); ++int rkmpp_init_decoder(AVCodecContext *avctx); ++int rkmpp_receive_frame(AVCodecContext *avctx, AVFrame *frame); ++int rkmpp_init_codec(AVCodecContext *avctx); ++int rkmpp_close_codec(AVCodecContext *avctx); ++void rkmpp_release_codec(void *opaque, uint8_t *data); ++void rkmpp_flush(AVCodecContext *avctx); ++uint64_t rkmpp_update_latency(AVCodecContext *avctx, int latency); ++ ++#define OFFSET(x) offsetof(RKMPPCodecContext, x) ++#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM ++ ++#define ENCODEROPTS() \ ++ { "rc_mode", "Set rate control mode", OFFSET(rc_mode), AV_OPT_TYPE_INT, \ ++ { .i64 = MPP_ENC_RC_MODE_CBR }, MPP_ENC_RC_MODE_VBR, MPP_ENC_RC_MODE_BUTT, VE, "rc_mode"}, \ ++ {"VBR", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MPP_ENC_RC_MODE_VBR }, 0, 0, VE, "rc_mode" }, \ ++ {"CBR", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MPP_ENC_RC_MODE_CBR }, 0, 0, VE, "rc_mode" }, \ ++ {"CQP", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MPP_ENC_RC_MODE_FIXQP }, 0, 0, VE, "rc_mode" }, \ ++ {"AVBR", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MPP_ENC_RC_MODE_AVBR }, 0, 0, VE, "rc_mode" }, \ ++ { "quality_min", "Minimum Quality", OFFSET(qmin), AV_OPT_TYPE_INT, \ ++ { .i64=50 }, 0, 100, VE, "qmin"}, \ ++ { "quality_max", "Maximum Quality", OFFSET(qmax), AV_OPT_TYPE_INT, \ ++ { .i64=100 }, 0, 100, VE, "qmax"}, \ ++ { "width", "scale to Width", OFFSET(postrga_width), AV_OPT_TYPE_INT, \ ++ { .i64=0 }, 0, RKMPP_RGA_MAX_SIZE, VE, "width"}, \ ++ { "height", "scale to Height", OFFSET(postrga_height), AV_OPT_TYPE_INT, \ ++ { .i64=0 }, 0, RKMPP_RGA_MAX_SIZE, VE, "height"}, ++ ++static const AVOption options_h264_encoder[] = { ++ ENCODEROPTS() ++ { "profile", "Set profile restrictions", OFFSET(profile), AV_OPT_TYPE_INT, ++ { .i64=FF_PROFILE_H264_HIGH }, -1, FF_PROFILE_H264_HIGH, VE, "profile"}, ++ { "baseline", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_H264_BASELINE}, INT_MIN, INT_MAX, VE, "profile" }, ++ { "main", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_H264_MAIN}, INT_MIN, INT_MAX, VE, "profile" }, ++ { "high", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_H264_HIGH}, INT_MIN, INT_MAX, VE, "profile" }, ++ { "level", "Compression Level", OFFSET(level), AV_OPT_TYPE_INT, ++ { .i64 = 0 }, FF_LEVEL_UNKNOWN, 0xff, VE, "level"}, ++ { "1", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 10 }, 0, 0, VE, "level"}, ++ { "1.1", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 11 }, 0, 0, VE, "level"}, ++ { "1.2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 12 }, 0, 0, VE, "level"}, ++ { "1.3", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 13 }, 0, 0, VE, "level"}, ++ { "2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 20 }, 0, 0, VE, "level"}, ++ { "2.1", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 21 }, 0, 0, VE, "level"}, ++ { "2.2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 22 }, 0, 0, VE, "level"}, ++ { "3", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 30 }, 0, 0, VE, "level"}, ++ { "3.1", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 31 }, 0, 0, VE, "level"}, ++ { "3.2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 32 }, 0, 0, VE, "level"}, ++ { "4", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 40 }, 0, 0, VE, "level"}, ++ { "4.1", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 41 }, 0, 0, VE, "level"}, ++ { "4.2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 42 }, 0, 0, VE, "level"}, ++ { "5", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 50 }, 0, 0, VE, "level"}, ++ { "5.1", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 51 }, 0, 0, VE, "level"}, ++ { "5.2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 52 }, 0, 0, VE, "level"}, ++ { "6", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 60 }, 0, 0, VE, "level"}, ++ { "6.1", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 61 }, 0, 0, VE, "level"}, ++ { "6.2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 62 }, 0, 0, VE, "level"}, ++ { "coder", "Entropy coder type (from 0 to 1) (default cabac)", OFFSET(coder), AV_OPT_TYPE_INT, ++ { .i64 = 1 }, 0, 1, VE, "coder"}, ++ { "cavlc", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, VE, "coder" }, ++ { "cabac", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, VE, "coder" }, ++ { "8x8dct", "High profile 8x8 transform.", OFFSET(dct8x8), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE}, ++ { NULL } +}; + -+/* 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; ++static const AVOption options_hevc_encoder[] = { ++ ENCODEROPTS() ++ { "level", "Compression Level", OFFSET(level), AV_OPT_TYPE_INT, ++ { .i64 = 0 }, FF_LEVEL_UNKNOWN, 0xff, VE, "level"}, ++ { "1", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 30 }, 0, 0, VE, "level"}, ++ { "2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 60 }, 0, 0, VE, "level"}, ++ { "2.1", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 63 }, 0, 0, VE, "level"}, ++ { "3", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 90 }, 0, 0, VE, "level"}, ++ { "3.1", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 93 }, 0, 0, VE, "level"}, ++ { "4", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 120 }, 0, 0, VE, "level"}, ++ { "4.1", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 123 }, 0, 0, VE, "level"}, ++ { "5", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 150 }, 0, 0, VE, "level"}, ++ { "5.1", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 153 }, 0, 0, VE, "level"}, ++ { "5.2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 156 }, 0, 0, VE, "level"}, ++ { "6", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 180 }, 0, 0, VE, "level"}, ++ { "6.1", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 183 }, 0, 0, VE, "level"}, ++ { "6.2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 186 }, 0, 0, VE, "level"}, ++ { "8.5", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 255 }, 0, 0, VE, "level"}, ++ { NULL } +}; + -+struct rga_color { -+ union { -+ struct { -+ uint8_t red; -+ uint8_t green; -+ uint8_t blue; -+ uint8_t alpha; -+ }; -+ uint32_t value; -+ }; ++static const AVOption options_vp8_encoder[] = { ++ ENCODEROPTS() ++ { NULL } +}; + -+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; ++#define DECODEROPTIONS(NAME, TYPE) \ ++static const AVOption options_##NAME##_##TYPE[] = { \ ++ { NULL } \ ++ }; ++ ++DECODEROPTIONS(h263, decoder); ++DECODEROPTIONS(h264, decoder); ++DECODEROPTIONS(hevc, decoder); ++DECODEROPTIONS(av1, decoder); ++DECODEROPTIONS(vp8, decoder); ++DECODEROPTIONS(vp9, decoder); ++DECODEROPTIONS(mpeg1, decoder); ++DECODEROPTIONS(mpeg2, decoder); ++DECODEROPTIONS(mpeg4, decoder); ++ ++static const FFCodecDefault rkmpp_enc_defaults[] = { ++ { "b", "6M" }, ++ { "g", "60" }, ++ { NULL } +}; + -+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 ++static const enum AVPixelFormat rkmppvepu1formats[] = { ++ AV_PIX_FMT_NV16, ++ AV_PIX_FMT_YUV422P, ++ AV_PIX_FMT_YUYV422, ++ AV_PIX_FMT_UYVY422, ++ AV_PIX_FMT_BGRA, ++ AV_PIX_FMT_BGR0, ++ AV_PIX_FMT_NV12, ++ AV_PIX_FMT_YUV420P, ++ AV_PIX_FMT_DRM_PRIME, ++ AV_PIX_FMT_NONE, +}; + -+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; -+ }; ++static const enum AVPixelFormat rkmppvepu5formats[] = { ++ AV_PIX_FMT_NV24, ++ AV_PIX_FMT_YUV444P, ++ AV_PIX_FMT_NV16, ++ AV_PIX_FMT_YUV422P, ++ AV_PIX_FMT_BGR24, ++ AV_PIX_FMT_YUYV422, ++ AV_PIX_FMT_UYVY422, ++ AV_PIX_FMT_BGRA, ++ AV_PIX_FMT_BGR0, ++ AV_PIX_FMT_NV12, ++ AV_PIX_FMT_YUV420P, ++ AV_PIX_FMT_DRM_PRIME, ++ AV_PIX_FMT_NONE, +}; + -+struct rga_pre_intr_info { -+ uint8_t enable; ++#define RKMPP_CODEC(NAME, ID, BSFS, TYPE) \ ++ static const AVClass rkmpp_##NAME##_##TYPE##_class = { \ ++ .class_name = "rkmpp_" #NAME "_" #TYPE, \ ++ .item_name = av_default_item_name,\ ++ .option = options_##NAME##_##TYPE, \ ++ .version = LIBAVUTIL_VERSION_INT, \ ++ }; \ ++ const FFCodec ff_##NAME##_rkmpp_##TYPE = { \ ++ .p.name = #NAME "_rkmpp_" #TYPE, \ ++ CODEC_LONG_NAME(#NAME " (rkmpp " #TYPE " )"), \ ++ .p.type = AVMEDIA_TYPE_VIDEO, \ ++ .p.id = ID, \ ++ .priv_data_size = sizeof(RKMPPCodecContext), \ ++ .init = rkmpp_init_codec, \ ++ .close = rkmpp_close_codec, \ ++ .flush = rkmpp_flush, \ ++ .p.priv_class = &rkmpp_##NAME##_##TYPE##_class, \ ++ .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_CONTIGUOUS_BUFFERS, \ ++ .bsfs = BSFS, \ ++ .p.wrapper_name = "rkmpp", ++ ++ ++#define RKMPP_DEC(NAME, ID, BSFS) \ ++ RKMPP_CODEC(NAME, ID, BSFS, decoder) \ ++ FF_CODEC_RECEIVE_FRAME_CB(rkmpp_receive_frame), \ ++ .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \ ++ .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_DRM_PRIME, \ ++ AV_PIX_FMT_NV12, \ ++ AV_PIX_FMT_YUV420P, \ ++ AV_PIX_FMT_NONE}, \ ++ .hw_configs = (const AVCodecHWConfigInternal *const []) { HW_CONFIG_INTERNAL(DRM_PRIME), \ ++ HW_CONFIG_INTERNAL(NV12), \ ++ NULL}, \ ++ }; + -+ 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; -+}; ++#define RKMPP_ENC(NAME, ID, VEPU) \ ++ RKMPP_CODEC(NAME, ID, NULL, encoder) \ ++ FF_CODEC_ENCODE_CB(rkmpp_encode), \ ++ .p.capabilities = AV_CODEC_CAP_HARDWARE, \ ++ .defaults = rkmpp_enc_defaults, \ ++ .p.pix_fmts = rkmpp##VEPU##formats, \ ++ .hw_configs = (const AVCodecHWConfigInternal *const []) { HW_CONFIG_INTERNAL(NV12), \ ++ NULL}, \ ++ }; +diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c +new file mode 100644 +index 0000000000..acec713140 +--- /dev/null ++++ b/libavcodec/rkmppdec.c +@@ -0,0 +1,335 @@ ++/* ++ * RockChip MPP Video Decoder ++ * Copyright (c) 2017 Lionel CHAZALLON ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++#include "rkmpp.h" ++#include "rkplane.h" + -+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; ++int rkmpp_init_decoder(AVCodecContext *avctx){ ++ RKMPPCodecContext *rk_context = avctx->priv_data; ++ RKMPPCodec *codec = (RKMPPCodec *)rk_context->codec_ref->data; + -+ uint16_t vir_w; -+ uint16_t vir_h; ++ int ret; + -+ uint16_t endian_mode; -+ /* useless */ -+ uint16_t alpha_swap; ++ ret = codec->mpi->control(codec->ctx, MPP_DEC_SET_EXT_BUF_GROUP, codec->buffer_group); ++ if (ret) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to assign buffer group (code = %d)\n", ret); ++ return AVERROR_UNKNOWN; ++ } + -+ /* used by RGA3 */ -+ uint16_t rotate_mode; -+ uint16_t rd_mode; ++ codec->mpi->control(codec->ctx, MPP_DEC_SET_DISABLE_ERROR, NULL); ++ if (ret < 0) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to prepare Codec (code = %d)\n", ret); ++ return AVERROR_UNKNOWN; ++ } + -+ uint16_t is_10b_compact; -+ uint16_t is_10b_endian; ++ avctx->coded_width = FFALIGN(avctx->width, 64); ++ avctx->coded_height = FFALIGN(avctx->height, 64); + -+ uint16_t enable; -+}; ++ codec->hwdevice_ref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_DRM); ++ if (!codec->hwdevice_ref) { ++ return AVERROR(ENOMEM); ++ } + -+struct rga_req { -+ /* (enum) process mode sel */ -+ uint8_t render_mode; ++ ret = av_hwdevice_ctx_init(codec->hwdevice_ref); ++ if (ret < 0) ++ return ret; + -+ struct rga_img_info_t src; -+ struct rga_img_info_t dst; -+ struct rga_img_info_t pat; ++ av_buffer_unref(&codec->hwframes_ref); ++ codec->hwframes_ref = av_hwframe_ctx_alloc(codec->hwdevice_ref); ++ if (!codec->hwframes_ref) { ++ return AVERROR(ENOMEM); ++ } + -+ /* rop4 mask addr */ -+ uint64_t rop_mask_addr; -+ /* LUT addr */ -+ uint64_t LUT_addr; ++ return 0; ++} + -+ /* dst clip window default value is dst_vir */ -+ /* value from [0, w-1] / [0, h-1]*/ -+ struct rga_rect_t clip; ++static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout) ++{ ++ RKMPPCodecContext *rk_context = avctx->priv_data; ++ RKMPPCodec *codec = (RKMPPCodec *)rk_context->codec_ref->data; ++ MppFrameFormat mpp_format; ++ MppFrame mppframe = NULL; ++ MppBuffer buffer = NULL; ++ rkformat format; ++ int ret, latency; ++ int mpp_width, mpp_height, mpp_mode; ++ enum AVColorRange mpp_color_range; ++ enum AVColorPrimaries mpp_color_primaries; ++ enum AVColorTransferCharacteristic mpp_color_trc; ++ enum AVColorSpace mpp_color_space; ++ int64_t mpp_pts; ++ ++ codec->mpi->control(codec->ctx, MPP_SET_OUTPUT_TIMEOUT, (MppParam)&timeout); ++ ++ ret = codec->mpi->decode_get_frame(codec->ctx, &mppframe); ++ if (ret != MPP_OK && ret != MPP_ERR_TIMEOUT) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to get frame (code = %d)\n", ret); ++ return AVERROR_UNKNOWN; ++ } + -+ /* 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; ++ if (!mppframe) { ++ av_log(avctx, AV_LOG_DEBUG, "Timeout getting decoded frame.\n"); ++ return AVERROR(EAGAIN); ++ } + -+ /* 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; ++ if (mpp_frame_get_eos(mppframe)) { ++ av_log(avctx, AV_LOG_DEBUG, "Received a EOS frame.\n"); ++ ret = AVERROR_EOF; ++ goto clean; ++ } + -+ /* 0 nearst / 1 bilnear / 2 bicubic */ -+ uint8_t scale_mode; ++ if (mpp_frame_get_discard(mppframe)) { ++ av_log(avctx, AV_LOG_DEBUG, "Received a discard frame.\n"); ++ ret = AVERROR(EAGAIN); ++ goto clean; ++ } + -+ /* color key max */ -+ uint32_t color_key_max; -+ /* color key min */ -+ uint32_t color_key_min; ++ if (mpp_frame_get_errinfo(mppframe)) { ++ av_log(avctx, AV_LOG_ERROR, "Received a errinfo frame.\n"); ++ ret = AVERROR_UNKNOWN; ++ goto clean; ++ } + -+ /* foreground color */ -+ uint32_t fg_color; -+ /* background color */ -+ uint32_t bg_color; ++ mpp_format = mpp_frame_get_fmt(mppframe) & MPP_FRAME_FMT_MASK; + -+ /* color fill use gradient */ -+ struct rga_color_fill_t gr_color; ++ if (mpp_frame_get_info_change(mppframe)) { ++ if(codec->hascfg) ++ ret = AVERROR(EAGAIN); ++ else{ ++ if (avctx->pix_fmt == AV_PIX_FMT_DRM_PRIME){ ++ char drmname[4]; ++ AVHWFramesContext *hwframes; ++ rkmpp_get_mpp_format(&format, mpp_format); ++ DRMFORMATNAME(drmname, format.drm) ++ ++ hwframes = (AVHWFramesContext*)codec->hwframes_ref->data; ++ hwframes->format = AV_PIX_FMT_DRM_PRIME; ++ hwframes->sw_format = format.av; ++ hwframes->width = avctx->width; ++ hwframes->height = avctx->height; ++ ret = av_hwframe_ctx_init(codec->hwframes_ref); ++ // FIXME: handle error ++ av_log(avctx, AV_LOG_INFO, "Decoder is set to DRM Prime with format %s.\n", drmname); ++ } else if (mpp_format == MPP_FMT_YUV420SP_10BIT) ++ av_log(avctx, AV_LOG_WARNING, "10bit NV15 plane will be downgraded to 8bit %s.\n", av_get_pix_fmt_name(avctx->pix_fmt)); ++ codec->hascfg = 1; ++ } + -+ struct rga_line_draw_t line_draw_info; ++ av_log(avctx, AV_LOG_INFO, "Decoder noticed an info change\n"); ++ codec->mpi->control(codec->ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL); ++ goto clean; ++ } + -+ struct rga_fading_t fading; ++ // here we should have a valid frame ++ av_log(avctx, AV_LOG_DEBUG, "Received a frame.\n"); + -+ /* porter duff alpha mode sel */ -+ uint8_t PD_mode; ++ // 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 clean; ++ } + -+ /* global alpha value */ -+ uint8_t alpha_global_value; ++ latency = rkmpp_update_latency(avctx, -1); ++ mpp_pts = mpp_frame_get_pts(mppframe); ++ mpp_width = mpp_frame_get_width(mppframe); ++ mpp_height = mpp_frame_get_height(mppframe); ++ mpp_color_range = mpp_frame_get_color_range(mppframe); ++ mpp_color_primaries = mpp_frame_get_color_primaries(mppframe); ++ mpp_color_trc = mpp_frame_get_color_trc(mppframe); ++ mpp_color_space = mpp_frame_get_colorspace(mppframe); ++ mpp_mode = mpp_frame_get_mode(mppframe); + -+ /* rop2/3/4 code scan from rop code table*/ -+ uint16_t rop_code; ++ if (avctx->pix_fmt == AV_PIX_FMT_DRM_PRIME){ ++ ret = import_mpp_to_drm(avctx, mppframe, frame); ++ } else if (mpp_format == MPP_FMT_YUV420SP_10BIT && avctx->pix_fmt == AV_PIX_FMT_NV12){ ++ ret = mpp_nv15_av_nv12(avctx, mppframe, frame); ++ } else if (mpp_format == MPP_FMT_YUV420SP_10BIT && avctx->pix_fmt == AV_PIX_FMT_YUV420P){ ++ ret = mpp_nv15_av_yuv420p(avctx, mppframe, frame); ++ } else if (mpp_format == MPP_FMT_YUV420SP && avctx->pix_fmt == AV_PIX_FMT_NV12){ ++ ret = mpp_nv12_av_nv12(avctx, mppframe, frame); ++ } else { ++ rkmpp_get_mpp_format(&format, mpp_format); ++ ret = convert_mpp_to_av(avctx, mppframe, frame, format.av, avctx->pix_fmt); ++ } + -+ /* [2] 0 blur 1 sharp / [1:0] filter_type*/ -+ uint8_t bsfilter_flag; ++ if(ret < 0){ ++ av_log(avctx, AV_LOG_ERROR, "Failed set frame buffer (code = %d)\n", ret); ++ return ret; ++ } + -+ /* (enum) color palette 0/1bpp, 1/2bpp 2/4bpp 3/8bpp*/ -+ uint8_t palette_mode; ++ // setup general frame fields ++ frame->format = avctx->pix_fmt; ++ frame->width = mpp_width; ++ frame->height = mpp_height; ++ frame->color_range = mpp_color_range; ++ frame->color_primaries = mpp_color_primaries; ++ frame->color_trc = mpp_color_trc; ++ frame->colorspace = mpp_color_space; ++ frame->pts = mpp_pts; + -+ /* (enum) BT.601 MPEG / BT.601 JPEG / BT.709 */ -+ uint8_t yuv2rgb_mode; ++ // when mpp can not determine the color space, it returns reserved (0) value ++ // firefox does not understand this and instead expect unspecified (2) values ++ frame->color_primaries = frame->color_primaries == AVCOL_PRI_RESERVED0 ? AVCOL_PRI_UNSPECIFIED : frame->color_primaries; ++ frame->color_trc = frame->color_trc == AVCOL_TRC_RESERVED0 ? AVCOL_TRC_UNSPECIFIED : frame->color_trc; ++ frame->colorspace = frame->colorspace == AVCOL_SPC_RGB ? AVCOL_SPC_UNSPECIFIED: frame->color_trc; + -+ /* 0/big endian 1/little endian*/ -+ uint8_t endian_mode; ++ frame->interlaced_frame = ((mpp_mode & MPP_FRAME_FLAG_FIELD_ORDER_MASK) == MPP_FRAME_FLAG_DEINTERLACED); ++ frame->top_field_first = ((mpp_mode & MPP_FRAME_FLAG_FIELD_ORDER_MASK) == MPP_FRAME_FLAG_TOP_FIRST); + -+ /* (enum) rotate mode */ -+ /* 0x0, no rotate */ -+ /* 0x1, rotate */ -+ /* 0x2, x_mirror */ -+ /* 0x3, y_mirror */ -+ uint8_t rotate_mode; ++ codec->frames++; ++ rkmpp_update_latency(avctx, latency); ++ return 0; + -+ /* 0 solid color / 1 pattern color */ -+ uint8_t color_fill_mode; ++clean: ++ if (mppframe) ++ mpp_frame_deinit(&mppframe); ++ return ret; ++} + -+ /* mmu information */ -+ struct rga_mmu_t mmu_info; ++static int rkmpp_send_packet(AVCodecContext *avctx, AVPacket *packet) ++{ ++ RKMPPCodecContext *rk_context = avctx->priv_data; ++ RKMPPCodec *codec = (RKMPPCodec *)rk_context->codec_ref->data; ++ MppPacket mpkt; ++ int64_t pts = packet->pts; ++ int ret; + -+ /* ([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; ++ if(pts == AV_NOPTS_VALUE || pts < 0){ ++ if(!codec->ptsstep && avctx->framerate.den && avctx->framerate.num){ ++ int64_t x = avctx->pkt_timebase.den * (int64_t)avctx->framerate.den; ++ int64_t y = avctx->pkt_timebase.num * (int64_t)avctx->framerate.num; ++ codec->ptsstep = x / y; ++ } ++ if(codec->ptsstep && (packet->dts == AV_NOPTS_VALUE || packet->dts < 0)){ ++ pts = codec->pts; ++ codec->pts += codec->ptsstep; ++ } else { ++ codec->pts = packet->dts; ++ pts = packet->dts; ++ } ++ } + -+ uint8_t src_trans_mode; ++ 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; ++ } + -+ uint8_t dither_mode; ++ mpp_packet_set_pts(mpkt, pts); + -+ /* full color space convert */ -+ struct rga_full_csc full_csc; ++ ret = codec->mpi->decode_put_packet(codec->ctx, mpkt); ++ mpp_packet_deinit(&mpkt); + -+ int32_t in_fence_fd; -+ uint8_t core; -+ uint8_t priority; -+ int32_t out_fence_fd; ++ if (ret != MPP_OK) { ++ av_log(avctx, AV_LOG_TRACE, "Decoder buffer full\n"); ++ return AVERROR(EAGAIN); ++ } + -+ uint8_t handle_flag; ++ av_log(avctx, AV_LOG_DEBUG, "Wrote %d bytes to decoder\n", packet->size); ++ return 0; ++} + -+ /* RGA2 1106 add */ -+ struct rga_mosaic_info mosaic_info; ++static int rkmpp_send_eos(AVCodecContext *avctx) ++{ ++ RKMPPCodecContext *rk_context = avctx->priv_data; ++ RKMPPCodec *codec = (RKMPPCodec *)rk_context->codec_ref->data; ++ MppPacket mpkt; ++ int ret; + -+ uint8_t uvhds_mode; -+ uint8_t uvvds_mode; ++ 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; ++ } + -+ struct rga_osd_info osd_info; ++ mpp_packet_set_eos(mpkt); + -+ struct rga_pre_intr_info pre_intr_info; ++ do { ++ ret = codec->mpi->decode_put_packet(codec->ctx, mpkt); ++ } while (ret != MPP_OK); ++ mpp_packet_deinit(&mpkt); + -+ uint8_t reservr[59]; -+}; -+#endif /*_RGA_DRIVER_H_*/ -diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c -index 1cca4b6e7d..e3e51d9973 100644 ---- a/libavcodec/rkmppdec.c -+++ b/libavcodec/rkmppdec.c -@@ -26,6 +26,7 @@ - #include <time.h> - #include <unistd.h> - #include <sys/time.h> -+#include <fcntl.h> - - #include "avcodec.h" - #include "codec_internal.h" -@@ -40,6 +41,7 @@ - #include "libavutil/imgutils.h" - #include "libavutil/log.h" - #include "libyuv/planar_functions.h" -+#include "rga.h" - - // HACK: Older BSP kernel use NA12 for NV15. - #ifndef DRM_FORMAT_NV15 // fourcc_code('N', 'V', '1', '5') -@@ -55,6 +57,7 @@ typedef struct { - - int8_t eos; - int8_t draining; -+ int8_t softconvert; - - AVPacket packet; - AVBufferRef *frames_ref; -@@ -66,6 +69,8 @@ typedef struct { - uint64_t frames; - - char sync; ++ return 0; ++} + -+ int rga_fd; - } RKMPPDecoder; - - typedef struct { -@@ -114,6 +119,16 @@ static uint32_t rkmpp_get_avformat(MppFrameFormat mppformat) - } - } - -+static uint32_t rkmpp_get_rgaformat(MppFrameFormat mppformat) ++int rkmpp_receive_frame(AVCodecContext *avctx, AVFrame *frame) +{ -+ switch (mppformat & MPP_FRAME_FMT_MASK) { -+ 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; ++ AVCodecInternal *avci = avctx->internal; ++ RKMPPCodecContext *rk_context = avctx->priv_data; ++ RKMPPCodec *codec = (RKMPPCodec *)rk_context->codec_ref->data; ++ AVPacket *packet = &codec->lastpacket; ++ int ret_send, ret_get; ++ ++ // get packet if not already available from previous iteration ++ if (!avci->draining){ ++ if(!packet->size){ ++ switch(ff_decode_get_packet(avctx, packet)){ ++ case AVERROR_EOF: ++ av_log(avctx, AV_LOG_DEBUG, "Decoder Draining.\n"); ++ return rkmpp_send_eos(avctx); ++ case AVERROR(EAGAIN): ++ av_log(avctx, AV_LOG_TRACE, "Decoder Can't get packet retrying.\n"); ++ return AVERROR(EAGAIN); ++ } ++ } ++ ++sendpacket: ++ // there is definitely a packet to send to decoder here ++ ret_send = rkmpp_send_packet(avctx, packet); ++ if (ret_send == 0){ ++ // send successful, continue until decoder input buffer is full ++ av_packet_unref(packet); ++ return AVERROR(EAGAIN); ++ } else if (ret_send < 0 && ret_send != AVERROR(EAGAIN)) { ++ // something went wrong, raise error ++ av_log(avctx, AV_LOG_ERROR, "Decoder Failed to send data (code = %d)\n", ret_send); ++ return ret_send; ++ } + } ++ ++ // were here only when draining and buffer is full ++ ret_get = rkmpp_get_frame(avctx, frame, MPP_TIMEOUT_BLOCK); ++ ++ if (ret_get == AVERROR_EOF){ ++ av_log(avctx, AV_LOG_DEBUG, "Decoder is at EOS.\n"); ++ // this is not likely but lets handle it in case synchronization issues of mpp ++ } else if (ret_get == AVERROR(EAGAIN) && ret_send == AVERROR(EAGAIN)) ++ goto sendpacket; ++ // only for logging ++ else if (ret_get < 0 && ret_get != AVERROR(EAGAIN)) // FIXME ++ av_log(avctx, AV_LOG_ERROR, "Decoder Failed to get frame (code = %d)\n", ret_get); ++ ++ return ret_get; +} + - static int rkmpp_close_decoder(AVCodecContext *avctx) - { - RKMPPDecodeContext *rk_context = avctx->priv_data; -@@ -140,6 +155,11 @@ static void rkmpp_release_decoder(void *opaque, uint8_t *data) - decoder->frame_group = NULL; - } - -+ if (decoder->rga_fd) { -+ close(decoder->rga_fd); -+ decoder->rga_fd = 0; ++ ++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(av1, AV_CODEC_ID_AV1, NULL) ++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") ++ +diff --git a/libavcodec/rkmppenc.c b/libavcodec/rkmppenc.c +new file mode 100644 +index 0000000000..b611e9451b +--- /dev/null ++++ b/libavcodec/rkmppenc.c +@@ -0,0 +1,628 @@ ++/* ++ * RockChip MPP Video Decoder ++ * Copyright (c) 2023 Huseyin BIYIK ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++#include "rkmpp.h" ++#include "rkplane.h" ++ ++static int rkmpp_config_withframe(AVCodecContext *avctx, MppFrame mppframe, AVFrame *frame){ ++ RKMPPCodecContext *rk_context = avctx->priv_data; ++ RKMPPCodec *codec = (RKMPPCodec *)rk_context->codec_ref->data; ++ MppEncCfg cfg = codec->enccfg; ++ ++ if(codec->hascfg == 0){ ++ rkformat format; ++ ++ int ret; ++ if(frame->time_base.num && frame->time_base.den){ ++ avctx->time_base.num = frame->time_base.num; ++ avctx->time_base.den = frame->time_base.den; ++ } else { ++ avctx->time_base.num = avctx->framerate.den; ++ avctx->time_base.den = avctx->framerate.num; ++ } ++ ++ mpp_enc_cfg_set_s32(cfg, "prep:width", mpp_frame_get_width(mppframe)); ++ mpp_enc_cfg_set_s32(cfg, "prep:height", mpp_frame_get_height(mppframe)); ++ mpp_enc_cfg_set_s32(cfg, "prep:hor_stride", mpp_frame_get_hor_stride(mppframe)); ++ mpp_enc_cfg_set_s32(cfg, "prep:ver_stride", mpp_frame_get_ver_stride(mppframe)); ++ mpp_enc_cfg_set_s32(cfg, "prep:format", mpp_frame_get_fmt(mppframe) & MPP_FRAME_FMT_MASK); ++ ret = codec->mpi->control(codec->ctx, MPP_ENC_SET_CFG, cfg); ++ if (ret != MPP_OK) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to config with frame (code = %d).\n", ret); ++ return AVERROR_UNKNOWN; ++ } ++ codec->hascfg = 1; ++ rkmpp_get_mpp_format(&format, mpp_frame_get_fmt(mppframe)); ++ av_log(avctx, AV_LOG_INFO, "Reconfigured with w=%d, h=%d, format=%s.\n", mpp_frame_get_width(mppframe), ++ mpp_frame_get_height(mppframe), av_get_pix_fmt_name(format.av)); ++ return 0; + } ++ return 0; ++} + - av_buffer_unref(&decoder->frames_ref); - av_buffer_unref(&decoder->device_ref); - -@@ -244,6 +264,11 @@ static int rkmpp_init_decoder(AVCodecContext *avctx) - goto fail; - } - -+ decoder->rga_fd = open("/dev/rga", O_RDWR); -+ if (decoder->rga_fd < 0) { -+ av_log(avctx, AV_LOG_WARNING, "Failed to open RGA, Falling back to libyuv\n"); ++static int rkmpp_config(AVCodecContext *avctx){ ++ RKMPPCodecContext *rk_context = avctx->priv_data; ++ RKMPPCodec *codec = (RKMPPCodec *)rk_context->codec_ref->data; ++ MppEncCfg cfg = codec->enccfg; ++ RK_U32 rc_mode, split_mode, split_arg, split_out, fps_num, fps_den; ++ MppCodingType coding_type = rkmpp_get_codingtype(avctx); ++ MppEncHeaderMode header_mode; ++ MppEncSeiMode sei_mode; ++ int ret, max_bps, min_bps, qmin, qmax; ++ ++ //prep config ++ mpp_enc_cfg_set_s32(cfg, "prep:width", avctx->width); ++ mpp_enc_cfg_set_s32(cfg, "prep:height", avctx->height); ++ mpp_enc_cfg_set_s32(cfg, "prep:hor_stride", FFALIGN(avctx->width, RKMPP_STRIDE_ALIGN)); ++ mpp_enc_cfg_set_s32(cfg, "prep:ver_stride", FFALIGN(avctx->height, RKMPP_STRIDE_ALIGN)); ++ // later to be reconfigured with the first frame received ++ mpp_enc_cfg_set_s32(cfg, "prep:format", MPP_FMT_YUV420SP); ++ mpp_enc_cfg_set_s32(cfg, "prep:mirroring", 0); ++ mpp_enc_cfg_set_s32(cfg, "prep:rotation", 0); ++ mpp_enc_cfg_set_s32(cfg, "prep:flip", 0); ++ ++ //rc config ++ // make sure time base of avctx is synced to input frames ++ av_reduce(&fps_num, &fps_den, avctx->time_base.den, avctx->time_base.num, 65535); ++ ++ /* fix input / output frame rate */ ++ mpp_enc_cfg_set_s32(cfg, "rc:fps_in_flex", 0); ++ mpp_enc_cfg_set_s32(cfg, "rc:fps_in_num", fps_num); ++ mpp_enc_cfg_set_s32(cfg, "rc:fps_in_denorm", fps_den); ++ mpp_enc_cfg_set_s32(cfg, "rc:fps_out_flex", 0); ++ mpp_enc_cfg_set_s32(cfg, "rc:fps_out_num",fps_num); ++ mpp_enc_cfg_set_s32(cfg, "rc:fps_out_denorm", fps_den); ++ ++ mpp_enc_cfg_set_s32(cfg, "rc:gop", FFMAX(avctx->gop_size, 1)); ++ ++ // config rc: mode ++ rc_mode = rk_context->rc_mode; ++ if(rc_mode == MPP_ENC_RC_MODE_BUTT) ++ rc_mode = MPP_ENC_RC_MODE_CBR; ++ ++ switch(rc_mode){ ++ case MPP_ENC_RC_MODE_VBR: ++ av_log(avctx, AV_LOG_INFO, "Rate Control mode is set to VBR\n"); break; ++ case MPP_ENC_RC_MODE_CBR: ++ av_log(avctx, AV_LOG_INFO, "Rate Control mode is set to CBR\n"); break; ++ case MPP_ENC_RC_MODE_FIXQP: ++ av_log(avctx, AV_LOG_INFO, "Rate Control mode is set to CQP\n"); break; ++ case MPP_ENC_RC_MODE_AVBR: ++ av_log(avctx, AV_LOG_INFO, "Rate Control mode is set to AVBR\n"); break; + } + - 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); -@@ -300,14 +325,67 @@ static void rkmpp_release_buffer(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]; -+ enum rga_surf_format rgaformat = 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]; - ++ mpp_enc_cfg_set_u32(cfg, "rc:mode", rc_mode); ++ ++ // config rc: bps ++ mpp_enc_cfg_set_u32(cfg, "rc:bps_target", avctx->bit_rate); ++ ++ switch (rc_mode) { ++ case MPP_ENC_RC_MODE_FIXQP : { ++ /* do not setup bitrate on FIXQP mode */ ++ min_bps = max_bps = avctx->bit_rate; ++ break; ++ } ++ case MPP_ENC_RC_MODE_CBR : { ++ /* CBR mode has narrow bound */ ++ max_bps = avctx->bit_rate * 17 / 16; ++ min_bps = avctx->bit_rate * 15 / 16; ++ break; ++ } ++ case MPP_ENC_RC_MODE_VBR : ++ case MPP_ENC_RC_MODE_AVBR : { ++ /* VBR mode has wide bound */ ++ max_bps = avctx->bit_rate * 17 / 16; ++ min_bps = avctx->bit_rate * 1 / 16; ++ break; ++ } ++ default : { ++ /* default use CBR mode */ ++ max_bps = avctx->bit_rate * 17 / 16; ++ min_bps = avctx->bit_rate * 15 / 16; ++ break; ++ } ++ } ++ ++ mpp_enc_cfg_set_s32(cfg, "rc:bps_max", max_bps); ++ mpp_enc_cfg_set_s32(cfg, "rc:bps_min", min_bps); ++ ++ av_log(avctx, AV_LOG_INFO, "Bitrate Target/Min/Max is set to %ld/%d/%d\n", avctx->bit_rate, min_bps, max_bps); ++ ++ // config rc: drop behaviour ++ mpp_enc_cfg_set_u32(cfg, "rc:drop_mode", MPP_ENC_RC_DROP_FRM_DISABLED); ++ mpp_enc_cfg_set_u32(cfg, "rc:drop_thd", 20); // 20% of max bps ++ mpp_enc_cfg_set_u32(cfg, "rc:drop_gap", 1); // Do not continuous drop frame ++ ++ // config rc: qp ++ switch (coding_type) { ++ case MPP_VIDEO_CodingAVC : ++ case MPP_VIDEO_CodingHEVC : { ++ qmax = QMIN_H26x + (100 - rk_context->qmin) * (QMAX_H26x - QMIN_H26x) / 100; ++ qmin = QMIN_H26x + (100 - rk_context->qmax) * (QMAX_H26x - QMIN_H26x) / 100; ++ switch (rc_mode) { ++ case MPP_ENC_RC_MODE_FIXQP : { ++ mpp_enc_cfg_set_s32(cfg, "rc:qp_init", qmin); ++ mpp_enc_cfg_set_s32(cfg, "rc:qp_max", qmin); ++ mpp_enc_cfg_set_s32(cfg, "rc:qp_min", qmin); ++ mpp_enc_cfg_set_s32(cfg, "rc:qp_max_i", qmin); ++ mpp_enc_cfg_set_s32(cfg, "rc:qp_min_i", qmin); ++ mpp_enc_cfg_set_s32(cfg, "rc:qp_ip", 0); ++ break; ++ } ++ case MPP_ENC_RC_MODE_CBR : ++ case MPP_ENC_RC_MODE_VBR : ++ case MPP_ENC_RC_MODE_AVBR : { ++ mpp_enc_cfg_set_s32(cfg, "rc:qp_init", qmin); ++ mpp_enc_cfg_set_s32(cfg, "rc:qp_max", qmax); ++ mpp_enc_cfg_set_s32(cfg, "rc:qp_min", qmin); ++ mpp_enc_cfg_set_s32(cfg, "rc:qp_max_i",qmax); ++ mpp_enc_cfg_set_s32(cfg, "rc:qp_min_i", qmin); ++ mpp_enc_cfg_set_s32(cfg, "rc:qp_ip", 2); ++ break; ++ } ++ default : { ++ av_log(avctx, AV_LOG_ERROR, "Unsupported Encoder Mode %d.\n", rc_mode); ++ break; ++ } ++ } ++ break; ++ } ++ case MPP_VIDEO_CodingVP8 : { ++ // vp8 only setup base qp range ++ qmax = QMIN_VPx + (100 - rk_context->qmin) * (QMAX_VPx - QMIN_VPx) / 100; ++ qmin = QMIN_VPx + (100 - rk_context->qmax) * (QMAX_VPx - QMIN_VPx) / 100; ++ mpp_enc_cfg_set_s32(cfg, "rc:qp_init", qmin); ++ mpp_enc_cfg_set_s32(cfg, "rc:qp_max", qmax); ++ mpp_enc_cfg_set_s32(cfg, "rc:qp_min", qmin); ++ mpp_enc_cfg_set_s32(cfg, "rc:qp_max_i", qmax); ++ mpp_enc_cfg_set_s32(cfg, "rc:qp_min_i", qmin); ++ mpp_enc_cfg_set_s32(cfg, "rc:qp_ip", 6); ++ break; ++ } ++ case MPP_VIDEO_CodingMJPEG : { ++ qmax = QMIN_JPEG + (100 - rk_context->qmin) * (QMAX_JPEG - QMIN_JPEG) / 100; ++ qmin = QMIN_JPEG + (100 - rk_context->qmax) * (QMAX_JPEG- QMIN_JPEG) / 100; ++ // jpeg use special codec config to control qtable ++ mpp_enc_cfg_set_s32(cfg, "jpeg:q_factor", 80); ++ mpp_enc_cfg_set_s32(cfg, "jpeg:qf_max", qmax); ++ mpp_enc_cfg_set_s32(cfg, "jpeg:qf_min", qmin); ++ break; ++ } ++ default : { ++ break; ++ } ++ } ++ ++ // setup codec ++ mpp_enc_cfg_set_s32(cfg, "codec:type", coding_type); ++ switch (coding_type) { ++ case MPP_VIDEO_CodingAVC : { ++ avctx->profile = rk_context->profile; ++ avctx->level = rk_context->level; ++ mpp_enc_cfg_set_s32(cfg, "h264:profile", avctx->profile); ++ mpp_enc_cfg_set_s32(cfg, "h264:level", avctx->level); ++ mpp_enc_cfg_set_s32(cfg, "h264:cabac_en", rk_context->coder); ++ mpp_enc_cfg_set_s32(cfg, "h264:cabac_idc", 0); ++ mpp_enc_cfg_set_s32(cfg, "h264:trans8x8", rk_context->dct8x8 && avctx->profile == FF_PROFILE_H264_HIGH ? 1 : 0); ++ switch(avctx->profile){ ++ case FF_PROFILE_H264_BASELINE: av_log(avctx, AV_LOG_INFO, "Profile is set to BASELINE\n"); break; ++ case FF_PROFILE_H264_MAIN: av_log(avctx, AV_LOG_INFO, "Profile is set to MAIN\n"); break; ++ case FF_PROFILE_H264_HIGH: ++ av_log(avctx, AV_LOG_INFO, "Profile is set to HIGH\n"); ++ if(rk_context->dct8x8) ++ av_log(avctx, AV_LOG_INFO, "8x8 Transform is enabled\n"); ++ break; ++ } ++ av_log(avctx, AV_LOG_INFO, "Level is set to %d\n", avctx->level); ++ if(rk_context->coder) ++ av_log(avctx, AV_LOG_INFO, "Coder is set to CABAC\n"); ++ else ++ av_log(avctx, AV_LOG_INFO, "Coder is set to CAVLC\n"); ++ break; ++ } ++ case MPP_VIDEO_CodingHEVC : { ++ avctx->profile = FF_PROFILE_HEVC_MAIN; ++ avctx->level = rk_context->level; ++ mpp_enc_cfg_set_s32(cfg, "h265:profile", avctx->profile); ++ mpp_enc_cfg_set_s32(cfg, "h265:level", avctx->level); ++ switch(avctx->profile){ ++ case FF_PROFILE_HEVC_MAIN: av_log(avctx, AV_LOG_INFO, "Profile is set to MAIN\n"); break; ++ case FF_PROFILE_HEVC_MAIN_10: av_log(avctx, AV_LOG_INFO, "Profile is set to MAIN 10\n"); break; ++ } ++ av_log(avctx, AV_LOG_INFO, "Level is set to %d\n", avctx->level == 255 ? 85 : avctx->level / 3); ++ break; ++ } ++ case MPP_VIDEO_CodingMJPEG : ++ case MPP_VIDEO_CodingVP8 : ++ mpp_enc_cfg_set_s32(cfg, "vp8:disable_ivf", 1); ++ break; ++ default : { ++ av_log(avctx, AV_LOG_ERROR, "Unsupported coding type for config (code = %d).\n", coding_type); ++ break; ++ } ++ } ++ ++ av_log(avctx, AV_LOG_INFO, "Quality Min/Max is set to %d%%(Quant=%d) / %d%%(Quant=%d)\n", ++ rk_context->qmin, qmax, rk_context->qmax, qmin); ++ ++ split_mode = 0; ++ split_arg = 0; ++ split_out = 0; ++ ++ if (split_mode) { ++ mpp_enc_cfg_set_s32(cfg, "split:mode", split_mode); ++ mpp_enc_cfg_set_s32(cfg, "split:arg", split_arg); ++ mpp_enc_cfg_set_s32(cfg, "split:out", split_out); ++ } ++ ++ ret = codec->mpi->control(codec->ctx, MPP_ENC_SET_CFG, cfg); ++ if (ret != MPP_OK) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to set cfg on MPI (code = %d).\n", ret); ++ return AVERROR_UNKNOWN; ++ } ++ ++ sei_mode = MPP_ENC_SEI_MODE_DISABLE; ++ ret = codec->mpi->control(codec->ctx, MPP_ENC_SET_SEI_CFG, &sei_mode); ++ if (ret != MPP_OK) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to set sei cfg on MPI (code = %d).\n", ret); ++ return AVERROR_UNKNOWN; ++ } ++ ++ header_mode = MPP_ENC_HEADER_MODE_EACH_IDR; ++ if (coding_type == MPP_VIDEO_CodingAVC || coding_type == MPP_VIDEO_CodingHEVC) { ++ ret = codec->mpi->control(codec->ctx, MPP_ENC_SET_HEADER_MODE, &header_mode); ++ if (ret) { ++ av_log(avctx, AV_LOG_ERROR, "Failed header mode on MPI (code = %d).\n", ret); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++//https://github.com/rockchip-linux/mpp/issues/417 ++//Encoder does not support 422 planes, but we can do this with rga ++//FIX-ME: NV12/YUV422P do not have libyuv fallbacks when encoding vp8 ++static int check_vp8_planes(AVCodecContext *avctx, enum AVPixelFormat pix_fmt){ ++ MppCodingType coding_type = rkmpp_get_codingtype(avctx); ++ RKMPPCodecContext *rk_context = avctx->priv_data; ++ ++ if(coding_type == MPP_VIDEO_CodingVP8 && ++ (pix_fmt == AV_PIX_FMT_NV16 || ++ pix_fmt == AV_PIX_FMT_YUV422P)){ ++ rk_context->postrga_format = AV_PIX_FMT_NV12; ++ ++ if (avctx->width < RKMPP_RGA_MIN_SIZE || avctx->width > RKMPP_RGA_MAX_SIZE){ ++ av_log(avctx, AV_LOG_ERROR, "Frame width (%d) not in rga scalable range (%d - %d)\n", ++ avctx->width, RKMPP_RGA_MIN_SIZE, RKMPP_RGA_MAX_SIZE); ++ return -1; ++ } else ++ rk_context->postrga_width = avctx->width; ++ ++ if (avctx->height < RKMPP_RGA_MIN_SIZE || avctx->height > RKMPP_RGA_MAX_SIZE){ ++ av_log(avctx, AV_LOG_ERROR, "Frame height (%d) not in rga scalable range (%d - %d)\n", ++ avctx->height, RKMPP_RGA_MIN_SIZE, RKMPP_RGA_MAX_SIZE); ++ return -1; ++ } else ++ rk_context->postrga_height = avctx->height; ++ } else ++ rk_context->postrga_format = AV_PIX_FMT_NONE; ++ return 0; ++} ++ ++static int check_scaling(AVCodecContext *avctx, enum AVPixelFormat pix_fmt){ ++ RKMPPCodecContext *rk_context = avctx->priv_data; ++ ++ if(rk_context->postrga_width || rk_context->postrga_height){ ++ if(pix_fmt != AV_PIX_FMT_NV16 && pix_fmt != AV_PIX_FMT_NV12 && ++ pix_fmt != AV_PIX_FMT_YUV422P && pix_fmt != AV_PIX_FMT_YUV420P){ ++ av_log(avctx, AV_LOG_ERROR, "Scaling is only supported for NV12,NV16,YUV420P,YUV422P. %s requested\n", ++ av_get_pix_fmt_name(pix_fmt)); ++ return -1; ++ } ++ // align it to accepted RGA range ++ rk_context->postrga_width = FFMAX(rk_context->postrga_width, RKMPP_RGA_MIN_SIZE); ++ rk_context->postrga_height = FFMAX(rk_context->postrga_height, RKMPP_RGA_MIN_SIZE); ++ rk_context->postrga_width = FFMIN(rk_context->postrga_width, RKMPP_RGA_MAX_SIZE); ++ rk_context->postrga_height = FFMIN(rk_context->postrga_height, RKMPP_RGA_MAX_SIZE); ++ avctx->width = rk_context->postrga_width; ++ avctx->height = rk_context->postrga_height; ++ if(rk_context->postrga_format == AV_PIX_FMT_NONE) ++ rk_context->postrga_format = pix_fmt; ++ } ++ return 0; ++} ++ ++int rkmpp_init_encoder(AVCodecContext *avctx){ ++ RKMPPCodecContext *rk_context = avctx->priv_data; ++ RKMPPCodec *codec = (RKMPPCodec *)rk_context->codec_ref->data; ++ MppCodingType coding_type = rkmpp_get_codingtype(avctx); ++ RK_U8 enc_hdr_buf[HDR_SIZE]; ++ MppPacket packet = NULL; ++ size_t packetlen; ++ void *packetpos; + int ret; ++ int input_timeout = 500; + -+ int dst_height = (dst_u - dst_y) / y_pitch; -+ -+ if (decoder->softconvert || decoder->rga_fd < 0) -+ goto softconvert; -+ -+ struct rga_req req = { -+ .src = { -+ .yrgb_addr = mpp_buffer_get_fd(buffer), -+ .v_addr = hstride * vstride, -+ .format = rgaformat, -+ .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, -+ }, -+ }; ++ // ENCODER SETUP ++ ret = mpp_enc_cfg_init(&codec->enccfg); ++ if (ret) { ++ av_log(avctx, AV_LOG_ERROR, "Codec failed to initialize encoder config (code = %d)\n", ret); ++ ret = AVERROR_UNKNOWN; ++ goto fail; ++ } ++ ++ ret = codec->mpi->control(codec->ctx, MPP_ENC_GET_CFG, codec->enccfg); ++ if (ret) { ++ av_log(avctx, AV_LOG_ERROR, "Codec failed to get encoder config (code = %d)\n", ret); ++ ret = AVERROR_UNKNOWN; ++ goto fail; ++ } ++ ++ if(avctx->pix_fmt != AV_PIX_FMT_DRM_PRIME){ ++ if(check_vp8_planes(avctx, avctx->pix_fmt)){ ++ ret = AVERROR_UNKNOWN; ++ goto fail; ++ } ++ if(check_scaling(avctx, avctx->pix_fmt)){ ++ ret = AVERROR_UNKNOWN; ++ goto fail; ++ } ++ } ++ ++ if(rkmpp_config(avctx)){ ++ ret = AVERROR_UNKNOWN; ++ goto fail; ++ } ++ ++ // copy sps/pps/vps to extradata for h26x ++ if(coding_type == MPP_VIDEO_CodingAVC || coding_type == MPP_VIDEO_CodingHEVC){ ++ memset(enc_hdr_buf, 0 , HDR_SIZE); + -+ ret = ioctl(decoder->rga_fd, RGA_BLIT_SYNC, &req); -+ if (ret < 0){ -+ decoder->softconvert = 1; -+ av_log(avctx, AV_LOG_WARNING, "RGA failed with code %d, falling back to soft conversion of uv planes\n"); -+ goto softconvert; ++ ret = mpp_packet_init(&packet, (void *)enc_hdr_buf, HDR_SIZE); ++ if (!packet) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to init extra info packet (code = %d).\n", ret); ++ ret = AVERROR_UNKNOWN; ++ goto fail; ++ } ++ ++ mpp_packet_set_length(packet, 0); ++ ret = codec->mpi->control(codec->ctx, MPP_ENC_GET_HDR_SYNC, packet); ++ if (ret != MPP_OK) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to get extra info on MPI (code = %d).\n", ret); ++ ret = AVERROR_UNKNOWN; ++ goto fail; ++ } ++ ++ /* get and write sps/pps for H.264/H.265 */ ++ packetpos = mpp_packet_get_pos(packet); ++ packetlen = mpp_packet_get_length(packet); ++ ++ if (avctx->extradata != NULL) { ++ av_free(avctx->extradata); ++ avctx->extradata = NULL; ++ } ++ avctx->extradata = av_malloc(packetlen + AV_INPUT_BUFFER_PADDING_SIZE); ++ if (avctx->extradata == NULL) { ++ ret = AVERROR(ENOMEM); ++ goto fail; ++ } ++ avctx->extradata_size = packetlen + AV_INPUT_BUFFER_PADDING_SIZE; ++ memcpy(avctx->extradata, packetpos, packetlen); ++ memset(avctx->extradata + packetlen, 0, AV_INPUT_BUFFER_PADDING_SIZE); ++ mpp_packet_deinit(&packet); + } + -+ rkmpp_release_buffer(mppframe, NULL); ++ codec->mpi->control(codec->ctx, MPP_SET_INPUT_TIMEOUT, &input_timeout); + return 0; + -+softconvert: - //data[0] points to buf[1] where the mppbuffer is referenced for y plane - //so that we can still use y plane without extra copies - //data[1,2] points to allready allocated AVBuffer Pool (buf[0]), we will convert to -@@ -320,7 +398,6 @@ static int rkmpp_convert_frame(AVCodecContext *avctx, AVFrame *frame, - return AVERROR(ENOMEM); - } - frame->linesize[0] = hstride; -- av_log(avctx, AV_LOG_WARNING, "Doing software conversion for uv planes\n"); - - src += hstride * vstride; - -@@ -686,6 +763,7 @@ static void rkmpp_flush(AVCodecContext *avctx) - - decoder->eos = 0; - decoder->draining = 0; -+ decoder->softconvert = 0; - decoder->last_fps_time = decoder->frames = 0; - - av_packet_unref(&decoder->packet); --- -2.40.0 - - -From 21644b8342b95bc75b2b2b4e1cddd37ab8668283 Mon Sep 17 00:00:00 2001 -From: boogie <boogiepop@gmx.com> -Date: Tue, 18 Apr 2023 23:20:13 +0200 -Subject: [PATCH 19/24] rework receive frame without any loop and more - statefull flow remove draining flags which is no more necessary with the new - flow remove sync mode, this is useless - ---- - libavcodec/rkmppdec.c | 114 +++++++++++++----------------------------- - 1 file changed, 36 insertions(+), 78 deletions(-) - -diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c -index e3e51d9973..bd87d74e39 100644 ---- a/libavcodec/rkmppdec.c -+++ b/libavcodec/rkmppdec.c -@@ -56,7 +56,6 @@ typedef struct { - MppBufferGroup frame_group; - - int8_t eos; -- int8_t draining; - int8_t softconvert; - - AVPacket packet; -@@ -68,8 +67,6 @@ typedef struct { - uint64_t last_fps_time; - uint64_t frames; - -- char sync; -- - int rga_fd; - } RKMPPDecoder; - -@@ -166,33 +163,6 @@ 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; -- -- // HACK: somehow MPP cannot handle extra data for AV1 -- if (avctx->extradata_size && avctx->codec_id != AV_CODEC_ID_AV1) { -- 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; -- } -- -- 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; --} -- - static int rkmpp_init_decoder(AVCodecContext *avctx) - { - RKMPPDecodeContext *rk_context = avctx->priv_data; -@@ -278,7 +248,6 @@ static int rkmpp_init_decoder(AVCodecContext *avctx) - - 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; -@@ -378,7 +347,7 @@ static int rkmpp_convert_frame(AVCodecContext *avctx, AVFrame *frame, - ret = ioctl(decoder->rga_fd, RGA_BLIT_SYNC, &req); - if (ret < 0){ - decoder->softconvert = 1; -- av_log(avctx, AV_LOG_WARNING, "RGA failed with code %d, falling back to soft conversion of uv planes\n"); -+ av_log(avctx, AV_LOG_WARNING, "RGA failed with code %d, falling back to soft conversion of uv planes\n", ret); - goto softconvert; - } - -@@ -645,10 +614,6 @@ static int rkmpp_send_packet(AVCodecContext *avctx, AVPacket *packet) - 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; - -@@ -692,8 +657,6 @@ static int rkmpp_send_eos(AVCodecContext *avctx) - } while (ret != MPP_OK); - mpp_packet_deinit(&mpkt); - -- decoder->draining = 1; -- - return 0; - } - -@@ -703,51 +666,48 @@ static int rkmpp_receive_frame(AVCodecContext *avctx, AVFrame *frame) - RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data; - AVPacket *packet = &decoder->packet; - int ret; -+ int gettimeout = MPP_TIMEOUT_NON_BLOCK;; - -- // 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); -+ // get packet if not already available from previous iteration -+ if (!packet->size){ -+ ret = ff_decode_get_packet(avctx, packet); -+ if (ret == AVERROR_EOF) { -+ av_log(avctx, AV_LOG_DEBUG, "Draining.\n"); -+ // send EOS and start draining -+ rkmpp_send_eos(avctx); -+ // we can get all the decoder backlog blocking here -+ gettimeout = MPP_TIMEOUT_BLOCK; ++fail: ++ av_log(avctx, AV_LOG_ERROR, "Failed to initialize RKMPP Codec.\n"); ++ if(packet) ++ mpp_packet_deinit(&packet); ++ return ret; ++} ++ ++static void rkmpp_release_packet_buf(void *opaque, uint8_t *data){ ++ MppPacket mpppacket = opaque; ++ mpp_packet_deinit(&mpppacket); ++} ++ ++static int rkmpp_send_frame(AVCodecContext *avctx, AVFrame *frame){ ++ RKMPPCodecContext *rk_context = avctx->priv_data; ++ RKMPPCodec *codec = (RKMPPCodec *)rk_context->codec_ref->data; ++ MppFrame mppframe = NULL; ++ rkformat format; ++ int ret=0, keepframe=0; ++ ++ // EOS frame, avframe=NULL ++ if (!frame) { ++ av_log(avctx, AV_LOG_DEBUG, "End of stream.\n"); ++ mpp_frame_init(&mppframe); ++ mpp_frame_set_eos(mppframe, 1); ++ } else { ++ if (avctx->pix_fmt == AV_PIX_FMT_DRM_PRIME){ ++ // the frame is coming from a DRMPRIME enabled decoder, no copy necessary ++ // just import existing fd and buffer to mmpp ++ mppframe = import_drm_to_mpp(avctx, frame); ++ } else { ++ // the frame is coming from a RKMPP decoder, no copy necessary ++ // use existing mppframe which is atatched to ++ // RKMPP_MPPFRAME_BUFINDEX of the frame buffers ++ // those frames need to be cleaned by the decoder itself therefore dont clean them ++ mppframe = get_mppframe_from_av(frame); ++ if(mppframe) ++ keepframe = 1; ++ else ++ // soft frames needs to be copied to a buffer region where mpp supports. ++ // a copy is necessary here ++ mppframe = create_mpp_frame(frame->width, frame->height, avctx->pix_fmt, codec->buffer_group, NULL, frame); ++ } ++ ++ if(!mppframe){ ++ ret = AVERROR_UNKNOWN; ++ goto clean; ++ } ++ ++ rkmpp_get_mpp_format(&format, mpp_frame_get_fmt(mppframe)); ++ ++ if(check_vp8_planes(avctx, format.av)){ ++ ret = AVERROR_UNKNOWN; ++ goto clean; ++ } ++ if(check_scaling(avctx, format.av)){ ++ ret = AVERROR_UNKNOWN; ++ goto clean; ++ } ++ ++ if(rk_context->postrga_format != AV_PIX_FMT_NONE || rk_context->postrga_width || rk_context->postrga_height){ ++ MppFrame postmppframe = NULL; ++ ++ postmppframe = create_mpp_frame(rk_context->postrga_width , rk_context->postrga_height, rk_context->postrga_format, ++ codec->buffer_group, NULL, NULL); ++ ++ if(!postmppframe){ ++ ret = AVERROR_UNKNOWN; ++ av_log(avctx, AV_LOG_ERROR, "Error creating post mpp frame\n"); ++ goto clean; ++ } ++ ++ ret = rga_convert_mpp_mpp(avctx, mppframe, postmppframe); ++ if(ret){ ++ mpp_frame_deinit(&postmppframe); ++ av_log(avctx, AV_LOG_ERROR, "Error applying Post RGA\n"); ++ goto clean; ++ } ++ ++ if(!keepframe) ++ mpp_frame_deinit(&mppframe); ++ else ++ keepframe = 0; ++ ++ mppframe = postmppframe; + } ++ ++ mpp_frame_set_pts(mppframe, frame->pts); + } - -- 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; -- } -+ // when there are packets available to push to decoder -+ if (packet->size) { -+ ret = rkmpp_send_packet(avctx, packet); -+ if (ret == AVERROR(EAGAIN)) { -+ // decoder input buffer is full, no need to poll packets unless we receive a frame -+ gettimeout = MPP_TIMEOUT_BLOCK; -+ } else if (ret < 0) { -+ // error handling -+ av_log(avctx, AV_LOG_ERROR, "Failed to send data (code = %d)\n", ret); -+ return 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; -- -- // blocked waiting for decode result -- if (decoder->sync) -- return rkmpp_get_frame(avctx, frame, MPP_TIMEOUT_BLOCK); -- } -+ // successful decoder write -+ av_packet_unref(packet); - } - } + -+ // always try to consume decoder because it is more likely to be full rather than the packet inputs -+ // decoder is the bottleneck here -+ ret = rkmpp_get_frame(avctx, frame, gettimeout); -+ if (ret == AVERROR_EOF) { -+ av_log(avctx, AV_LOG_DEBUG, "End of Stream.\n"); -+ return rkmpp_get_frame(avctx, frame, MPP_TIMEOUT_BLOCK); ++ ret = rkmpp_config_withframe(avctx, mppframe, frame); ++ if(ret){ ++ ret = AVERROR_UNKNOWN; ++ goto clean; + } + ++ // put the frame in encoder ++ ret = codec->mpi->encode_put_frame(codec->ctx, mppframe); ++ ++ if (ret != MPP_OK) { ++ av_log(avctx, AV_LOG_DEBUG, "Encoder buffer full\n"); ++ ret = AVERROR(EAGAIN); ++ } else ++ av_log(avctx, AV_LOG_DEBUG, "Wrote %ld bytes to encoder\n", mpp_frame_get_buf_size(mppframe)); ++ ++clean: ++ if(!keepframe) ++ mpp_frame_deinit(&mppframe); + return ret; - } - - static void rkmpp_flush(AVCodecContext *avctx) -@@ -759,11 +719,9 @@ static void rkmpp_flush(AVCodecContext *avctx) - - decoder->mpi->reset(decoder->ctx); - -- rkmpp_prepare_decoder(avctx); -- - decoder->eos = 0; -- decoder->draining = 0; - decoder->softconvert = 0; ++} + - decoder->last_fps_time = decoder->frames = 0; - - av_packet_unref(&decoder->packet); --- -2.40.0 - - -From f46c90307798f98cdf2b0d15d5b8905e4db83cf6 Mon Sep 17 00:00:00 2001 -From: boogie <boogiepop@gmx.com> -Date: Fri, 28 Apr 2023 23:28:14 +0200 -Subject: [PATCH 20/24] rework on flow nv12 output support without rga hdr to - sdr conversion support with rga3 - ---- - libavcodec/rkmppdec.c | 541 ++++++++++++++++++++++++------------------ - 1 file changed, 314 insertions(+), 227 deletions(-) - -diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c -index bd87d74e39..f71511d0d0 100644 ---- a/libavcodec/rkmppdec.c -+++ b/libavcodec/rkmppdec.c -@@ -41,6 +41,8 @@ - #include "libavutil/imgutils.h" - #include "libavutil/log.h" - #include "libyuv/planar_functions.h" -+#include "libyuv/scale_uv.h" -+#include "libyuv/scale.h" - #include "rga.h" - - // HACK: Older BSP kernel use NA12 for NV15. -@@ -48,7 +50,7 @@ - #define DRM_FORMAT_NV15 fourcc_code('N', 'A', '1', '2') - #endif - --#define FPS_UPDATE_INTERVAL 120 -+#define FPS_UPDATE_INTERVAL 60 - - typedef struct { - MppCtx ctx; -@@ -56,7 +58,6 @@ typedef struct { - MppBufferGroup frame_group; - - int8_t eos; -- int8_t softconvert; - - AVPacket packet; - AVBufferRef *frames_ref; -@@ -67,7 +68,16 @@ typedef struct { - uint64_t last_fps_time; - uint64_t frames; - -+ uint32_t mpp_format; -+ uint32_t rga_informat; -+ uint32_t rga_outformat; -+ uint32_t drm_format; -+ uint32_t sw_format; - int rga_fd; -+ int8_t rgafbc; -+ int8_t norga; -+ int (*buffer_callback)(struct AVCodecContext *avctx, struct AVFrame *frame, MppFrame mppframe); + - } RKMPPDecoder; - - typedef struct { -@@ -96,36 +106,6 @@ static MppCodingType rkmpp_get_codingtype(AVCodecContext *avctx) - } - } - --static uint32_t rkmpp_get_frameformat(MppFrameFormat mppformat) --{ -- switch (mppformat & MPP_FRAME_FMT_MASK) { -- case MPP_FMT_YUV420SP: return DRM_FORMAT_NV12; -- case MPP_FMT_YUV420SP_10BIT: return DRM_FORMAT_NV15; -- case MPP_FMT_YUV422SP: return DRM_FORMAT_NV16; -- default: return 0; -- } --} -- --static uint32_t rkmpp_get_avformat(MppFrameFormat mppformat) --{ -- switch (mppformat & MPP_FRAME_FMT_MASK) { -- 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; -- } --} -- --static uint32_t rkmpp_get_rgaformat(MppFrameFormat mppformat) --{ -- switch (mppformat & MPP_FRAME_FMT_MASK) { -- 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; -- } --} -- - static int rkmpp_close_decoder(AVCodecContext *avctx) - { - RKMPPDecodeContext *rk_context = avctx->priv_data; -@@ -163,6 +143,141 @@ static void rkmpp_release_decoder(void *opaque, uint8_t *data) - av_free(decoder); - } - -+static void rkmpp_release_drmbuf(void *opaque, uint8_t *data) -+{ -+ AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)data; -+ AVBufferRef *framecontextref = (AVBufferRef *)opaque; -+ RKMPPFrameContext *framecontext = (RKMPPFrameContext *)framecontextref->data; ++static int rkmpp_get_packet(AVCodecContext *avctx, AVPacket *packet, int timeout){ ++ RKMPPCodecContext *rk_context = avctx->priv_data; ++ RKMPPCodec *codec = (RKMPPCodec *)rk_context->codec_ref->data; ++ MppPacket mpppacket = NULL; ++ MppMeta meta = NULL; ++ int ret, keyframe=0; + -+ mpp_frame_deinit(&framecontext->frame); -+ av_buffer_unref(&framecontext->decoder_ref); -+ av_buffer_unref(&framecontextref); ++ codec->mpi->control(codec->ctx, MPP_SET_OUTPUT_TIMEOUT, (MppParam)&timeout); + -+ av_free(desc); ++ ret = codec->mpi->encode_get_packet(codec->ctx, &mpppacket); ++ ++ // rest of above code is never tested most likely broken ++ if (ret != MPP_OK && ret != MPP_ERR_TIMEOUT) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to get packet (code = %d)\n", ret); ++ return AVERROR(EAGAIN); ++ } ++ ++ if (!mpppacket) { ++ av_log(avctx, AV_LOG_DEBUG, "Timeout getting encoded packet.\n"); ++ return AVERROR(EAGAIN); ++ } ++ ++ // TO-DO: Handle EOS ++ if (mpp_packet_get_eos(mpppacket)) { ++ av_log(avctx, AV_LOG_DEBUG, "Received an EOS packet.\n"); ++ ret = AVERROR_EOF; ++ goto fail; ++ } ++ ++ av_log(avctx, AV_LOG_DEBUG, "Received a packet.\n"); ++ ++ packet->data = mpp_packet_get_data(mpppacket); ++ packet->size = mpp_packet_get_length(mpppacket); ++ packet->buf = av_buffer_create(packet->data, packet->size, rkmpp_release_packet_buf, ++ mpppacket, AV_BUFFER_FLAG_READONLY); ++ if (!packet->buf) { ++ ret = AVERROR(ENOMEM); ++ goto fail; ++ } ++ ++ //FIXME: This is low-res and does not cover b-frames. ++ packet->time_base.num = avctx->time_base.num; ++ packet->time_base.den = avctx->time_base.den; ++ packet->pts = mpp_packet_get_pts(mpppacket); ++ packet->dts = mpp_packet_get_pts(mpppacket); ++ codec->frames++; ++ ++ meta = mpp_packet_get_meta(mpppacket); ++ if (meta) ++ mpp_meta_get_s32(meta, KEY_OUTPUT_INTRA, &keyframe); ++ if (keyframe) ++ packet->flags |= AV_PKT_FLAG_KEY; ++ ++ return 0; ++fail: ++ if (mpppacket) ++ mpp_packet_deinit(&mpppacket); ++ return ret; ++} ++ ++ ++int rkmpp_encode(AVCodecContext *avctx, AVPacket *packet, const AVFrame *frame, int *got_packet){ ++ int ret; ++ ++ ret = rkmpp_send_frame(avctx, (AVFrame *)frame); ++ if (ret) ++ return ret; ++ ++ ret = rkmpp_get_packet(avctx, packet, MPP_TIMEOUT_BLOCK); ++ if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { ++ *got_packet = 0; ++ } else if (ret) { ++ return ret; ++ } else { ++ *got_packet = 1; ++ } ++ return 0; +} + -+static void rkmpp_release_buf(void *opaque, uint8_t *data) ++RKMPP_ENC(h264, AV_CODEC_ID_H264, vepu5) ++RKMPP_ENC(hevc, AV_CODEC_ID_HEVC, vepu5) ++RKMPP_ENC(vp8, AV_CODEC_ID_VP8, vepu1) +diff --git a/libavcodec/rkplane.c b/libavcodec/rkplane.c +new file mode 100644 +index 0000000000..e8063d8a6c +--- /dev/null ++++ b/libavcodec/rkplane.c +@@ -0,0 +1,676 @@ ++/* ++ * RockChip MPP Plane Conversions ++ * Copyright (c) 2023 Huseyin BYIIK ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++ ++/* ++ * Mpp decoder/encoder outputs & inputs generally semi-planar pictures ++ * FFmpeg on the other hand uses planar pictures. Normally libavfilter has ++ * several filters to handle this conversion however it is not cpu affective ++ * This file handles several plane conversion with hardware accelerated RGA chip in ++ * rockchip socs, whenever there is a failure it falls back to libyuv which is SIMD ++ * optimized plane conversion library. Failure is expected time to time, because ++ * RGA is not always consistent in between kernel versions of rockchips downstream ++ * ++ * Normally both RGA and enhancements in libyuv should be a part or libavfilter, but ++ * currently this is easier. May be in future someone take this up and move to avfilter. ++ */ ++ ++#include <fcntl.h> ++#include "rkmpp.h" ++#include "rkplane.h" ++#include "libyuv/planar_functions.h" ++#include "libyuv/scale_uv.h" ++#include "libyuv/scale.h" ++ ++ ++#define AV_VSTRIDE(AVFRAME) (FFALIGN(AVFRAME->buf[0] && AVFRAME->buf[1] ? AVFRAME->buf[0]->size / AVFRAME->linesize[0] : (AVFRAME->data[1] - AVFRAME->data[0]) / AVFRAME->linesize[0], 16)) ++ ++static void rkmpp_release_mppframe(void *opaque, uint8_t *data) +{ + MppFrame mppframe = opaque; + mpp_frame_deinit(&mppframe); +} + -+static int rkmpp_set_nv12_buf(AVCodecContext *avctx, AVFrame *frame, MppFrame mppframe) ++static void rkmpp_release_drm_desc(void *opaque, uint8_t *data) +{ -+ RKMPPDecodeContext *rk_context = avctx->priv_data; -+ RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data; ++ AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)opaque; ++ av_free(desc); ++} ++ ++ ++static int set_mppframe_to_avbuff(MppFrame mppframe, AVFrame * frame){ ++ int i; ++ ++ for(i=0; i<5; i++){ ++ if(i > 3) ++ return -1; ++ else if(!frame->buf[i]) ++ break; ++ } ++ ++ frame->buf[i] = av_buffer_create(mppframe, mpp_frame_get_buf_size(mppframe), ++ rkmpp_release_mppframe, mppframe, AV_BUFFER_FLAG_READONLY); ++ ++ return i; ++} ++ ++static int set_drmdesc_to_avbuff(AVDRMFrameDescriptor *desc, AVFrame *frame){ ++ int i; ++ ++ for(i=0; i<5; i++){ ++ if(i > 3) ++ return -1; ++ else if(!frame->buf[i]) ++ break; ++ } ++ ++ frame->buf[i] = av_buffer_create((unsigned char *) desc, sizeof(AVDRMFrameDescriptor), ++ rkmpp_release_drm_desc, desc, AV_BUFFER_FLAG_READONLY); ++ ++ return i; ++} ++ ++static int rga_scale(uint64_t src_fd, uint64_t src_y, uint16_t src_width, uint16_t src_height, uint16_t src_hstride, uint16_t src_vstride, ++ uint64_t dst_fd, uint64_t dst_y, uint16_t dst_width, uint16_t dst_height, uint16_t dst_hstride, uint16_t dst_vstride, ++ enum _Rga_SURF_FORMAT informat, enum _Rga_SURF_FORMAT outformat){ ++ rga_info_t src = {0}; ++ rga_info_t dst = {0}; ++ ++ if(dst_hstride < dst_width) ++ dst_width = FFALIGN(dst_width, RKMPP_STRIDE_ALIGN); ++ if(dst_vstride < dst_height) ++ dst_height = FFALIGN(dst_height, RKMPP_STRIDE_ALIGN); ++ if(src_hstride < src_width) ++ src_width = FFALIGN(src_width, RKMPP_STRIDE_ALIGN); ++ if(src_vstride < src_height) ++ src_height = FFALIGN(src_height, RKMPP_STRIDE_ALIGN); ++ ++ src.fd = src_fd; ++ src.virAddr = (void *)src_y; ++ src.mmuFlag = 1; ++ src.format = informat; ++ rga_set_rect(&src.rect, 0, 0, ++ src_width, src_height, src_hstride, src_vstride, informat); ++ ++ dst.fd = dst_fd; ++ dst.virAddr = (void *)dst_y; ++ dst.mmuFlag = 1; ++ dst.format = outformat; ++ rga_set_rect(&dst.rect, 0, 0, ++ dst_width, dst_height, dst_hstride, dst_vstride, outformat); ++ ++ return c_RkRgaBlit(&src, &dst, NULL); ++} ++ ++int rga_convert_mpp_mpp(AVCodecContext *avctx, MppFrame in_mppframe, MppFrame out_mppframe){ ++ RKMPPCodecContext *rk_context = avctx->priv_data; ++ RKMPPCodec *codec = (RKMPPCodec *)rk_context->codec_ref->data; ++ rkformat informat, outformat; ++ ++ if (!codec->norga){ ++ if(!out_mppframe) ++ return -1; ++ rkmpp_get_mpp_format(&informat, mpp_frame_get_fmt(in_mppframe) & MPP_FRAME_FMT_MASK); ++ rkmpp_get_mpp_format(&outformat, mpp_frame_get_fmt(out_mppframe) & MPP_FRAME_FMT_MASK); ++ if(rga_scale(mpp_buffer_get_fd(mpp_frame_get_buffer(in_mppframe)), 0, ++ mpp_frame_get_width(in_mppframe), mpp_frame_get_height(in_mppframe), ++ mpp_frame_get_hor_stride(in_mppframe), mpp_frame_get_ver_stride(in_mppframe), ++ mpp_buffer_get_fd(mpp_frame_get_buffer(out_mppframe)), 0, ++ mpp_frame_get_width(out_mppframe), mpp_frame_get_height(out_mppframe), ++ mpp_frame_get_hor_stride(out_mppframe), mpp_frame_get_ver_stride(out_mppframe), ++ informat.rga, ++ outformat.rga)){ ++ av_log(avctx, AV_LOG_WARNING, "RGA failed falling back to soft conversion\n"); ++ codec->norga = 1; // fallback to soft conversion ++ return -1; ++ } else ++ return 0; ++ } ++ ++ return -1; ++} ++ ++static int rga_convert_mpp_av(AVCodecContext *avctx, MppFrame mppframe, AVFrame *frame, ++ enum AVPixelFormat informat, enum AVPixelFormat outformat){ ++ RKMPPCodecContext *rk_context = avctx->priv_data; ++ RKMPPCodec *codec = (RKMPPCodec *)rk_context->codec_ref->data; ++ MppBuffer buffer = mpp_frame_get_buffer(mppframe); ++ rkformat inrkformat, outrkformat; ++ ++ rkmpp_get_av_format(&inrkformat, informat); ++ rkmpp_get_av_format(&outrkformat, outformat); ++ ++ if (!codec->norga){ ++ if(rga_scale(mpp_buffer_get_fd(buffer), 0, ++ mpp_frame_get_width(mppframe), mpp_frame_get_height(mppframe), ++ mpp_frame_get_hor_stride(mppframe), mpp_frame_get_ver_stride(mppframe), ++ 0, (uint64_t) frame->data[0], ++ frame->width, frame->height, ++ frame->linesize[0], AV_VSTRIDE(frame), ++ inrkformat.rga, outrkformat.rga)){ ++ av_log(avctx, AV_LOG_WARNING, "RGA failed falling back to soft conversion\n"); ++ codec->norga = 1; // fallback to soft conversion ++ return -1; ++ } ++ } else ++ return -1; + ++ return 0; ++} ++ ++static int mpp_nv12_av_yuv420p_soft(MppFrame mppframe, AVFrame *frame){ ++ // warning: mpp frame must not be released until displayed + MppBuffer buffer = mpp_frame_get_buffer(mppframe); -+ int width = mpp_frame_get_width(mppframe); + int hstride = mpp_frame_get_hor_stride(mppframe); + int vstride = mpp_frame_get_ver_stride(mppframe); ++ int ret; + -+ frame->data[0] = mpp_buffer_get_ptr(buffer); // y -+ frame->data[1] = frame->data[0] + hstride * vstride; // u + v -+ frame->extended_data = frame->data; ++ frame->data[0] = mpp_buffer_get_ptr(buffer); // use existing y plane ++ frame->linesize[0] = hstride; + -+ frame->linesize[0] = hstride; -+ frame->linesize[1] = hstride; ++ // convert only uv plane from semi-planar to planar ++ SplitUVPlane(frame->data[0] + hstride * vstride, hstride, ++ frame->data[1], frame->linesize[1], frame->data[2], frame->linesize[2], ++ (frame->width + 1) >> 1, (frame->height + 1) >> 1); + -+ frame->buf[0] = av_buffer_create(frame->data[0], mpp_buffer_get_size(buffer), -+ rkmpp_release_buf, mppframe, -+ AV_BUFFER_FLAG_READONLY); -+ if (!frame->buf[0]) { -+ return AVERROR(ENOMEM); ++ ret = set_mppframe_to_avbuff(mppframe, frame); ++ if(ret >= 0) ++ frame->data[RKMPP_MPPFRAME_BUFINDEX] = frame->buf[ret]->data; ++ return ret; ++} ++ ++static int mpp_nv16_av_yuv420p_soft(MppFrame mppframe, AVFrame *frame){ ++ // warning: mpp frame must not be released until displayed ++ MppBuffer buffer = mpp_frame_get_buffer(mppframe); ++ int hstride = mpp_frame_get_hor_stride(mppframe); ++ int vstride = mpp_frame_get_ver_stride(mppframe); ++ char *src = (char *)mpp_buffer_get_ptr(buffer) + hstride * vstride; ++ int ret; ++ ++ // scale down uv plane by 2 and write it to y plane of avbuffer temporarily ++ UVScale(src, hstride, frame->width, frame->height, ++ frame->data[0], frame->linesize[0], ++ (frame->width + 1) >> 1, (frame->height + 1) >> 1, kFilterNone); ++ ++ // convert uv plane from semi-planar to planar ++ SplitUVPlane(frame->data[0], frame->linesize[0], ++ frame->data[1], frame->linesize[1], frame->data[2], frame->linesize[2], ++ (frame->width + 1) >> 1, (frame->height + 1) >> 1); ++ ++ // use existing y plane from mppbuffer ++ frame->data[0] = mpp_buffer_get_ptr(buffer); ++ frame->linesize[0] = hstride; ++ ++ ret = set_mppframe_to_avbuff(mppframe, frame); ++ if(ret >= 0) ++ frame->data[RKMPP_MPPFRAME_BUFINDEX] = frame->buf[ret]->data; ++ return ret; ++} ++ ++static int mpp_nv16_av_nv12_soft(MppFrame mppframe, AVFrame *frame){ ++ // warning: mpp frame must not be released until displayed ++ MppBuffer buffer = mpp_frame_get_buffer(mppframe); ++ int hstride = mpp_frame_get_hor_stride(mppframe); ++ int vstride = mpp_frame_get_ver_stride(mppframe); ++ char *src = (char *)mpp_buffer_get_ptr(buffer) + hstride * vstride; ++ int ret; ++ ++ // scale down uv plane by 2 and write it to uv plane of avbuffer ++ UVScale(src, hstride, frame->width, frame->height, ++ frame->data[1], frame->linesize[0], ++ (frame->width + 1) >> 1, (frame->height + 1) >> 1, kFilterNone); ++ ++ // use existing y plane from mppbuffer ++ frame->data[0] = mpp_buffer_get_ptr(buffer); ++ frame->linesize[0] = hstride; ++ ++ ret = set_mppframe_to_avbuff(mppframe, frame); ++ if(ret >= 0) ++ frame->data[RKMPP_MPPFRAME_BUFINDEX] = frame->buf[ret]->data; ++ return ret; ++} ++ ++MppFrame create_mpp_frame(int width, int height, enum AVPixelFormat avformat, MppBufferGroup buffer_group, AVDRMFrameDescriptor *desc, AVFrame *frame){ ++ MppFrame mppframe = NULL; ++ MppBuffer mppbuffer = NULL; ++ rkformat format; ++ int avmap[3][4]; //offset, dststride, width, height of max 3 planes ++ int size, ret, hstride, vstride; ++ int hstride_mult = 1; ++ int planes = 2; ++ int haspitch = 0; ++ int overshoot = 1024; ++ ++ ret = mpp_frame_init(&mppframe); ++ ++ if (ret) { ++ goto clean; ++ } ++ ++ vstride = FFALIGN(height, RKMPP_STRIDE_ALIGN); ++ ++ switch(avformat){ ++ case AV_PIX_FMT_NV12: ++ planes = 2; ++ hstride = FFALIGN(width, RKMPP_STRIDE_ALIGN); ++ // y plane ++ avmap[0][0] = 0; ++ avmap[0][1] = hstride; ++ avmap[0][2] = width, ++ avmap[0][3] = height; ++ // uv plane ++ avmap[1][0] = hstride * vstride; // uv offset = y plane size ++ avmap[1][1] = hstride; // uv stride = hstride ++ avmap[1][2] = width; // uv width = width ++ avmap[1][3] = (height + 1)>> 1; // uv height = height / 2 ++ size = avmap[1][0] + ((avmap[1][0] + 1) >> 1) + overshoot; // total size = y+uv planesize ++ break; ++ case AV_PIX_FMT_YUV420P: ++ planes = 3; ++ hstride = FFALIGN(width, RKMPP_STRIDE_ALIGN); ++ // y plane ++ avmap[0][0] = 0; ++ avmap[0][1] = hstride; ++ avmap[0][2] = width, ++ avmap[0][3] = height; ++ // u plane ++ avmap[1][0] = hstride * vstride; // u offset = y plane size ++ avmap[1][1] = (hstride + 1)>> 1; // u stride = hstride / 2 ++ avmap[1][2] = (width + 1)>> 1; // u width = width / 2 ++ avmap[1][3] = (height + 1)>> 1; // u height = height / 2 ++ // v plane ++ avmap[2][0] = avmap[1][0] + ((avmap[1][0] + 1) >> 2); // v offset = y+u plane size ++ avmap[2][1] = avmap[1][1]; // v stride = hstride / 2 ++ avmap[2][2] = avmap[1][2]; // v width = width / 2 ++ avmap[2][3] = avmap[1][3]; // v height = height / 2 ++ size = avmap[2][0] + ((avmap[1][0] + 1) >> 2) + overshoot; // total size = y+u+v planesize ++ break; ++ case AV_PIX_FMT_NV16: ++ planes = 2; ++ hstride = FFALIGN(width, RKMPP_STRIDE_ALIGN); ++ // y plane ++ avmap[0][0] = 0; ++ avmap[0][1] = hstride; ++ avmap[0][2] = width, ++ avmap[0][3] = height; ++ // uv plane ++ avmap[1][0] = hstride * vstride; // uv offset = y plane size ++ avmap[1][1] = hstride; // uv stride = hstride ++ avmap[1][2] = width; // uv width = width ++ avmap[1][3] = height; // uv height = height ++ size = avmap[1][0] * 2 + overshoot; // total size = y+uv planesize ++ break; ++ case AV_PIX_FMT_YUV422P: ++ planes = 3; ++ hstride = FFALIGN(width, RKMPP_STRIDE_ALIGN); ++ //y plane ++ avmap[0][0] = 0; ++ avmap[0][1] = hstride; ++ avmap[0][2] = width, ++ avmap[0][3] = height; ++ //u plane ++ avmap[1][0] = hstride * vstride; // u offset = y plane size ++ avmap[1][1] = (hstride + 1)>> 1; // u stride = hstride / 2 ++ avmap[1][2] = width; // u width = width ++ avmap[1][3] = height; // u height = height ++ //v plane ++ avmap[2][0] = avmap[1][0] + ((avmap[1][0] + 1) >> 1); // v offset = y+u plane size ++ avmap[2][1] = avmap[1][1]; // v stride = hstride ++ avmap[2][2] = avmap[1][2]; // v width = width ++ avmap[2][3] = avmap[1][3]; // v height = height / 2 ++ size = avmap[1][0] * 2 + overshoot; // total size = y+u+v planesize ++ break; ++ case AV_PIX_FMT_NV24: ++ planes = 2; ++ hstride = FFALIGN(width, RKMPP_STRIDE_ALIGN); ++ // y plane ++ avmap[0][0] = 0; ++ avmap[0][1] = hstride; ++ avmap[0][2] = width, ++ avmap[0][3] = height; ++ // uv plane ++ avmap[1][0] = hstride * vstride; // uv offset = y plane size ++ avmap[1][1] = hstride << 1; // uv stride = hstride * 2 ++ avmap[1][2] = width << 1; // uv width = width * 2 ++ avmap[1][3] = height; // uv height = height ++ size = avmap[1][0] * 3 + overshoot; // total size = y+u+v planesize ++ break; ++ case AV_PIX_FMT_YUV444P: ++ planes = 3; ++ hstride = FFALIGN(width, RKMPP_STRIDE_ALIGN); ++ //y plane ++ avmap[0][0] = 0; ++ avmap[0][1] = hstride; ++ avmap[0][2] = width, ++ avmap[0][3] = height; ++ //u plane ++ avmap[1][0] = hstride * vstride; // u offset = y plane size ++ avmap[1][1] = hstride; // u stride = hstride ++ avmap[1][2] = width; // u width = width ++ avmap[1][3] = height; // u height = height ++ //v plane ++ avmap[2][0] = avmap[1][0] * 2; // v offset = y+u plane size ++ avmap[2][1] = avmap[1][1]; // v stride = hstride ++ avmap[2][2] = avmap[1][2]; // v width = width ++ avmap[2][3] = avmap[1][3]; // v height = height ++ size = avmap[1][0] * 3 + overshoot; // total size = y+u+v planesize ++ break; ++ case AV_PIX_FMT_YUYV422: ++ case AV_PIX_FMT_UYVY422: ++ planes = 1; ++ haspitch = 1; ++ hstride_mult = 2; ++ hstride = FFALIGN(width * hstride_mult, RKMPP_STRIDE_ALIGN); ++ avmap[0][0] = 0; ++ avmap[0][1] = hstride; ++ avmap[0][2] = width << 1, ++ avmap[0][3] = height; ++ size = hstride * vstride; ++ break; ++ case AV_PIX_FMT_RGB24: ++ case AV_PIX_FMT_BGR24: ++ haspitch = 1; ++ hstride_mult = 3; ++ hstride = FFALIGN(width * hstride_mult, RKMPP_STRIDE_ALIGN); ++ avmap[0][0] = 0; ++ avmap[0][1] = hstride; ++ avmap[0][2] = width * 3, ++ avmap[0][3] = height; ++ size = hstride * vstride; ++ planes = 1; ++ break; ++ case AV_PIX_FMT_0RGB: ++ case AV_PIX_FMT_0BGR: ++ case AV_PIX_FMT_BGR0: ++ case AV_PIX_FMT_RGB0: ++ case AV_PIX_FMT_ARGB: ++ case AV_PIX_FMT_ABGR: ++ case AV_PIX_FMT_BGRA: ++ case AV_PIX_FMT_RGBA: ++ haspitch = 1; ++ hstride_mult = 4; ++ hstride = FFALIGN(width * hstride_mult, RKMPP_STRIDE_ALIGN); ++ avmap[0][0] = 0; ++ avmap[0][1] = hstride; ++ avmap[0][2] = width << 2, ++ avmap[0][3] = height; ++ size = hstride * vstride; ++ planes = 1; ++ break; + } + -+ return 0; ++ if(desc){ ++ MppBufferInfo info; ++ AVDRMLayerDescriptor *layer = &desc->layers[0]; ++ rkmpp_get_drm_format(&format, layer->format); ++ ++ size = desc->objects[0].size; ++ if(haspitch) ++ hstride = layer->planes[0].pitch; ++ else ++ hstride = layer->planes[0].pitch * hstride_mult; ++ ++ if(planes == 1) ++ vstride = size / hstride; ++ else ++ vstride = layer->planes[1].offset / hstride; ++ ++ memset(&info, 0, sizeof(info)); ++ info.type = MPP_BUFFER_TYPE_DRM; ++ info.size = size; ++ info.fd = desc->objects[0].fd; ++ ++ ret = mpp_buffer_import(&mppbuffer, &info); ++ rkmpp_get_drm_format(&format, layer->format); ++ } else { ++ ret = mpp_buffer_get(buffer_group, &mppbuffer, size); ++ rkmpp_get_av_format(&format, avformat); ++ } ++ ++ if (ret) ++ goto clean; ++ ++ mpp_frame_set_width(mppframe, width); ++ mpp_frame_set_height(mppframe, height); ++ mpp_frame_set_fmt(mppframe, format.mpp); ++ mpp_frame_set_hor_stride(mppframe, hstride); ++ mpp_frame_set_ver_stride(mppframe, vstride); ++ mpp_frame_set_buffer(mppframe, mppbuffer); ++ mpp_frame_set_buf_size(mppframe, size); ++ mpp_buffer_put(mppbuffer); ++ ++ if(frame){ ++ for(int i = 0; i < planes; i++){ ++ CopyPlane(frame->data[i], frame->linesize[i], ++ (char *)mpp_buffer_get_ptr(mppbuffer) + avmap[i][0], avmap[i][1], avmap[i][2], avmap[i][3]); ++ } ++ } ++ ++ return mppframe; ++ ++clean: ++ if(mppbuffer) ++ mpp_buffer_put(mppbuffer); ++ if(mppframe) ++ mpp_frame_deinit(&mppframe); ++ return mppframe; +} ++//for decoder ++int mpp_nv15_av_yuv420p(AVCodecContext *avctx, MppFrame mppframe, AVFrame *frame){ ++ // rga1 which supports yuv420P output does not support nv15 input ++ // therefore this first converts NV15->NV12 with rga2 than NV12 -> yuv420P with libyuv ++ RKMPPCodecContext *rk_context = avctx->priv_data; ++ RKMPPCodec *codec = (RKMPPCodec *)rk_context->codec_ref->data; ++ MppFrame nv12frame = create_mpp_frame(mpp_frame_get_width(mppframe), mpp_frame_get_height(mppframe), ++ AV_PIX_FMT_NV12, codec->buffer_group, NULL, NULL); ++ int ret = rga_convert_mpp_mpp(avctx, mppframe, nv12frame); ++ ++ rkmpp_release_mppframe(mppframe, NULL); ++ ++ if(!ret){ ++ // if there is no avbuffer for frame, claim it ++ if(!frame->buf[0]) ++ ff_get_buffer(avctx, frame, 0); ++ // due to hdr being mostly 8k, rga1 the only rga support yuv420p output ++ // wont convert this, therefore always use soft conv. ++ ret = mpp_nv12_av_yuv420p_soft(nv12frame, frame); ++ } else { ++ if(nv12frame) ++ rkmpp_release_mppframe(nv12frame, NULL); ++ av_log(avctx, AV_LOG_ERROR, "RGA failed to convert NV15 -> YUV420P. No Soft Conversion Possible\n"); ++ } + -+static int rkmpp_rga_convert_buf(AVCodecContext *avctx, AVFrame *frame, MppFrame mppframe) -+{ -+ RKMPPDecodeContext *rk_context = avctx->priv_data; -+ RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data; ++ return ret; ++} + ++//for decoder ++int mpp_nv12_av_nv12(AVCodecContext *avctx, MppFrame mppframe, AVFrame *frame){ + MppBuffer buffer = mpp_frame_get_buffer(mppframe); -+ char *src = mpp_buffer_get_ptr(buffer); -+ 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 ret; + -+ ret = ff_get_buffer(avctx, frame, 0); -+ if (ret < 0) -+ return ret; ++ frame->data[0] = mpp_buffer_get_ptr(buffer); // y ++ frame->data[1] = frame->data[0] + hstride * vstride; // u + v ++ frame->extended_data = frame->data; + -+ if (!decoder->norga && decoder->rga_fd >= 0){ -+ struct rga_req req = { -+ .src = { -+ .yrgb_addr = mpp_buffer_get_fd(buffer), -+ .v_addr = hstride * vstride, -+ .format = decoder->rga_informat, -+ .act_w = width, -+ .act_h = height, -+ .vir_w = hstride, -+ .vir_h = vstride, -+ .rd_mode = RGA_RASTER_MODE, -+ }, -+ .dst = { -+ .uv_addr = (uintptr_t) frame->data[0], -+ .v_addr = (uintptr_t) frame->data[1], -+ .format = decoder->rga_outformat, -+ .act_w = width, -+ .act_h = height, -+ .vir_w = frame->linesize[0], -+ .vir_h = (frame->data[1] - frame->data[0]) / frame->linesize[0], -+ .rd_mode = RGA_RASTER_MODE, -+ }, -+ .mmu_info = { -+ .mmu_en = 1, -+ .mmu_flag = 0x80000521, -+ }, -+ }; ++ frame->linesize[0] = hstride; ++ frame->linesize[1] = hstride; + -+ ret = ioctl(decoder->rga_fd, RGA_BLIT_SYNC, &req); -+ if (ret < 0){ -+ decoder->norga = 1; -+ av_log(avctx, AV_LOG_WARNING, "RGA failed with code %d, falling back to soft conversion\n", ret); -+ } else { -+ rkmpp_release_buf(mppframe, NULL); -+ return 0; -+ } ++ ret = set_mppframe_to_avbuff(mppframe, frame); ++ if(ret >= 0) ++ frame->data[RKMPP_MPPFRAME_BUFINDEX] = frame->buf[ret]->data; ++ return ret; ++} ++//for decoder ++int mpp_nv15_av_nv12(AVCodecContext *avctx, MppFrame mppframe, AVFrame *frame){ ++ RKMPPCodecContext *rk_context = avctx->priv_data; ++ RKMPPCodec *codec = (RKMPPCodec *)rk_context->codec_ref->data; ++ MppFrame nv12frame = create_mpp_frame(mpp_frame_get_width(mppframe), mpp_frame_get_height(mppframe), ++ AV_PIX_FMT_NV12, codec->buffer_group, NULL, NULL); ++ int ret = rga_convert_mpp_mpp(avctx, mppframe, nv12frame); ++ ++ rkmpp_release_mppframe(mppframe, NULL); ++ ++ if(!ret){ ++ ret = mpp_nv12_av_nv12(avctx, nv12frame, frame); ++ } else { ++ if(nv12frame) ++ rkmpp_release_mppframe(nv12frame, NULL); ++ av_log(avctx, AV_LOG_ERROR, "RGA failed to convert NV15 -> NV12. No Soft Conversion Possible\n"); + } + -+ if ((decoder->norga || decoder->rga_fd < 0) && decoder->rga_outformat == RGA_FORMAT_YCbCr_420_P){ -+ //data[0] points to buf[1] where the mppbuffer is referenced for y plane -+ //so that we can still use y plane without extra copies -+ //data[1,2] points to allready allocated AVBuffer Pool (buf[0]), we will convert to -+ //that buffer only u+v planes, which is half the size operation -+ frame->data[0] = mpp_buffer_get_ptr(buffer); -+ frame->buf[1] = av_buffer_create(frame->data[0], mpp_buffer_get_size(buffer), -+ rkmpp_release_buf, mppframe, -+ AV_BUFFER_FLAG_READONLY); -+ if (!frame->buf[1]) { -+ return AVERROR(ENOMEM); -+ } -+ frame->linesize[0] = hstride; -+ -+ src += hstride * vstride; -+ if(decoder->rga_informat == RGA_FORMAT_YCbCr_422_SP){ -+ /* In case the input format has 4:2:2 UV planes, it will have double the size of 4:2:0 UV Planes -+ * Therefore we scale them to the half the size to the unused FFbuffer's Y Plane (We are using MPP 's Y) -+ * Then we convert to Planar in the next step. Normally it should be possible to this in 1 step -+ * But i can not find a way to do it in 1 step using libyuv. But thats fine enough -+ */ -+ UVScale(src, hstride, frame->width, frame->height, -+ frame->buf[0]->data, hstride, -+ (frame->width + 1) >> 1, (frame->height + 1) >> 1, kFilterNone); -+ src = frame->buf[0]->data; ++ return ret; ++} ++ ++int convert_mpp_to_av(AVCodecContext *avctx, MppFrame mppframe, AVFrame *frame, ++ enum AVPixelFormat informat, enum AVPixelFormat outformat){ ++ int ret = 0; ++ ++ if(!frame->buf[0]) ++ ff_get_buffer(avctx, frame, 0); ++ ++ if(rga_convert_mpp_av(avctx, mppframe, frame, informat, outformat)){ ++ if (informat == AV_PIX_FMT_NV16 && outformat == AV_PIX_FMT_NV12) ++ ret = mpp_nv16_av_nv12_soft(mppframe, frame); ++ else if (informat == AV_PIX_FMT_NV16 && outformat == AV_PIX_FMT_YUV420P) ++ ret = mpp_nv16_av_yuv420p_soft(mppframe, frame); ++ else if (informat == AV_PIX_FMT_NV12 && outformat == AV_PIX_FMT_YUV420P) ++ ret = mpp_nv12_av_yuv420p_soft(mppframe, frame); ++ else { ++ ret = -1; ++ av_log(avctx, AV_LOG_ERROR, "No software conversion for %s -> %s available\n", ++ av_get_pix_fmt_name(informat), av_get_pix_fmt_name(outformat)); + } -+ SplitUVPlane(src, hstride, frame->data[1], frame->linesize[1], frame->data[2], frame->linesize[2], -+ (frame->width + 1) >> 1, (frame->height + 1) >> 1); -+ return 0; ++ } else{ ++ ret = set_mppframe_to_avbuff(mppframe, frame); ++ if(ret >= 0) ++ frame->data[RKMPP_MPPFRAME_BUFINDEX] = frame->buf[ret]->data; + } + -+ return AVERROR_UNKNOWN; ++ if (ret < 0) ++ rkmpp_release_mppframe(mppframe, NULL); ++ return ret; +} + - static int rkmpp_init_decoder(AVCodecContext *avctx) - { - RKMPPDecodeContext *rk_context = avctx->priv_data; -@@ -234,9 +349,14 @@ static int rkmpp_init_decoder(AVCodecContext *avctx) - goto fail; - } - -- decoder->rga_fd = open("/dev/rga", O_RDWR); -- if (decoder->rga_fd < 0) { -- av_log(avctx, AV_LOG_WARNING, "Failed to open RGA, Falling back to libyuv\n"); -+ env = getenv("FFMPEG_RKMPP_NORGA"); -+ if (env != NULL) -+ decoder->rga_fd = -1; -+ else { -+ decoder->rga_fd = open("/dev/rga", O_RDWR); -+ if (decoder->rga_fd < 0) { -+ av_log(avctx, AV_LOG_WARNING, "Failed to open RGA, Falling back to libyuv\n"); ++MppFrame import_drm_to_mpp(AVCodecContext *avctx, AVFrame *frame){ ++ RKMPPCodecContext *rk_context = avctx->priv_data; ++ RKMPPCodec *codec = (RKMPPCodec *)rk_context->codec_ref->data; ++ MppFrame mppframe = NULL; ++ AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor*) frame->data[0]; ++ AVDRMLayerDescriptor *layer = &desc->layers[0]; ++ rkformat format; ++ char drmname[4]; ++ DRMFORMATNAME(drmname, layer->format) ++ ++ if(rkmpp_get_drm_format(&format, layer->format)){ ++ av_log(avctx, AV_LOG_ERROR, "Unsupported DRM Format %s\n", drmname); ++ return NULL; ++ } ++ ++ if(format.drm == DRM_FORMAT_NV15){ ++ // encoder does not support 10bit frames, we down scale them to 8bit ++ MppFrame nv15frame = create_mpp_frame(frame->width, frame->height, AV_PIX_FMT_NONE, NULL, desc, NULL); ++ if(nv15frame){ ++ mppframe = create_mpp_frame(frame->width, frame->height, AV_PIX_FMT_NV12, codec->buffer_group, NULL, NULL); ++ if(mppframe && rga_convert_mpp_mpp(avctx, nv15frame, mppframe)) ++ rkmpp_release_mppframe(mppframe, NULL); ++ rkmpp_release_mppframe(nv15frame, NULL); + } - } - - ret = decoder->mpi->control(decoder->ctx, MPP_DEC_SET_EXT_BUF_GROUP, decoder->frame_group); -@@ -272,109 +392,6 @@ fail: - return ret; - } - --static void rkmpp_release_frame(void *opaque, uint8_t *data) --{ -- AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)data; -- AVBufferRef *framecontextref = (AVBufferRef *)opaque; -- RKMPPFrameContext *framecontext = (RKMPPFrameContext *)framecontextref->data; -- -- mpp_frame_deinit(&framecontext->frame); -- av_buffer_unref(&framecontext->decoder_ref); -- av_buffer_unref(&framecontextref); -- -- av_free(desc); --} -- --static void rkmpp_release_buffer(void *opaque, uint8_t *data) --{ -- MppFrame mppframe = opaque; -- mpp_frame_deinit(&mppframe); --} -- --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]; -- enum rga_surf_format rgaformat = 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 ret; -- -- int dst_height = (dst_u - dst_y) / y_pitch; -- -- if (decoder->softconvert || decoder->rga_fd < 0) -- goto softconvert; -- -- struct rga_req req = { -- .src = { -- .yrgb_addr = mpp_buffer_get_fd(buffer), -- .v_addr = hstride * vstride, -- .format = rgaformat, -- .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, -- }, -- }; -- -- ret = ioctl(decoder->rga_fd, RGA_BLIT_SYNC, &req); -- if (ret < 0){ -- decoder->softconvert = 1; -- av_log(avctx, AV_LOG_WARNING, "RGA failed with code %d, falling back to soft conversion of uv planes\n", ret); -- goto softconvert; -- } -- -- rkmpp_release_buffer(mppframe, NULL); -- return 0; -- --softconvert: -- //data[0] points to buf[1] where the mppbuffer is referenced for y plane -- //so that we can still use y plane without extra copies -- //data[1,2] points to allready allocated AVBuffer Pool (buf[0]), we will convert to -- //that buffer only u+v planes, which is half the size operation -- frame->data[0] = mpp_buffer_get_ptr(buffer); -- frame->buf[1] = av_buffer_create(frame->data[0], mpp_buffer_get_size(buffer), -- rkmpp_release_buffer, mppframe, -- AV_BUFFER_FLAG_READONLY); -- if (!frame->buf[1]) { -- return AVERROR(ENOMEM); -- } -- frame->linesize[0] = hstride; -- -- src += hstride * vstride; -- -- SplitUVPlane(src, hstride, dst_u, u_pitch, dst_v, v_pitch, -- (frame->width + 1) >> 1, (frame->height + 1) >> 1); -- return 0; --} -- - static void rkmpp_update_fps(AVCodecContext *avctx) - { - RKMPPDecodeContext *rk_context = avctx->priv_data; -@@ -405,20 +422,151 @@ static void rkmpp_update_fps(AVCodecContext *avctx) - fps, decoder->frames); - } - --static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout) -+static int rkmpp_set_drm_buf(AVCodecContext *avctx, AVFrame *frame, MppFrame mppframe) - { - RKMPPDecodeContext *rk_context = avctx->priv_data; - RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data; - RKMPPFrameContext *framecontext = NULL; - AVBufferRef *framecontextref = NULL; ++ } else { ++ mppframe = create_mpp_frame(frame->width, frame->height, format.av, NULL, desc, NULL); ++ } ++ ++ return mppframe; ++} ++ ++int import_mpp_to_drm(AVCodecContext *avctx, MppFrame mppframe, AVFrame *frame) ++{ ++ // mppframe & desc is cleared when AVFrame is released ++ RKMPPCodecContext *rk_context = avctx->priv_data; ++ RKMPPCodec *codec = (RKMPPCodec *)rk_context->codec_ref->data; + AVDRMFrameDescriptor *desc = NULL; + AVDRMLayerDescriptor *layer = NULL; ++ rkformat format; + MppBuffer buffer = mpp_frame_get_buffer(mppframe); - int ret; ++ int hstride = mpp_frame_get_hor_stride(mppframe); ++ int vstride = mpp_frame_get_ver_stride(mppframe); ++ int ret; ++ ++ rkmpp_get_mpp_format(&format, mpp_frame_get_fmt(mppframe) & MPP_FRAME_FMT_MASK); ++ ++ if(set_mppframe_to_avbuff(mppframe, frame) < 0){ ++ ret = AVERROR(ENOMEM); ++ goto error; ++ } + + desc = av_mallocz(sizeof(AVDRMFrameDescriptor)); -+ if (!desc) { ++ if (!desc || set_drmdesc_to_avbuff(desc, frame) < 0) { + ret = AVERROR(ENOMEM); -+ goto fail; ++ goto error; + } + + desc->nb_objects = 1; @@ -3481,566 +3638,617 @@ index bd87d74e39..f71511d0d0 100644 + + desc->nb_layers = 1; + layer = &desc->layers[0]; -+ layer->format = decoder->drm_format; ++ layer->format = format.drm; + 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[0].pitch = hstride; + + 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; -+ } -+ -+ // 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; ++ layer->planes[1].offset = hstride * vstride; ++ layer->planes[1].pitch = hstride; + + frame->data[0] = (uint8_t *)desc; -+ frame->buf[0] = av_buffer_create((uint8_t *)desc, sizeof(*desc), rkmpp_release_drmbuf, -+ framecontextref, AV_BUFFER_FLAG_READONLY); -+ -+ if (!frame->buf[0]) { -+ ret = AVERROR(ENOMEM); -+ goto fail; -+ } + -+ frame->hw_frames_ctx = av_buffer_ref(decoder->frames_ref); ++ frame->hw_frames_ctx = av_buffer_ref(codec->hwframes_ref); + if (!frame->hw_frames_ctx) { + ret = AVERROR(ENOMEM); -+ goto fail; ++ goto error; + } + + return 0; + -+fail: -+ if (framecontext) -+ av_buffer_unref(&framecontext->decoder_ref); -+ -+ if (framecontextref) -+ av_buffer_unref(&framecontextref); -+ ++error: ++ av_log(avctx, AV_LOG_ERROR, "Memory Error during importing mpp frame to drmprime\n"); ++ if (mppframe) ++ rkmpp_release_mppframe(mppframe, NULL); + if (desc) -+ av_free(desc); ++ rkmpp_release_drm_desc(desc, NULL); + + return ret; +} + -+static int set_buffer_callback(RKMPPDecoder *decoder, AVCodecContext *avctx){ -+ if (avctx->pix_fmt == AV_PIX_FMT_DRM_PRIME){ -+ decoder->buffer_callback = rkmpp_set_drm_buf; -+ switch(decoder->mpp_format){ -+ case MPP_FMT_YUV420SP_10BIT: -+ decoder->drm_format = DRM_FORMAT_NV15; -+ decoder->sw_format = AV_PIX_FMT_NONE; -+ av_log(avctx, AV_LOG_INFO, "Decoder is set to use DRMPrime with NV15.\n"); -+ return 0; -+ case MPP_FMT_YUV420SP: -+ decoder->drm_format = DRM_FORMAT_NV12; -+ decoder->sw_format = AV_PIX_FMT_NV12; -+ av_log(avctx, AV_LOG_INFO, "Decoder is set to use DRMPrime with NV12.\n"); -+ return 0; -+ case MPP_FMT_YUV422SP: -+ decoder->drm_format = DRM_FORMAT_NV16; -+ decoder->sw_format = AV_PIX_FMT_NV16; -+ av_log(avctx, AV_LOG_INFO, "Decoder is set to use DRMPrime with NV16.\n"); -+ return 0; -+ } -+ } else if(avctx->pix_fmt == AV_PIX_FMT_NV12){ -+ decoder->rga_outformat = RGA_FORMAT_YCbCr_420_SP; -+ switch(decoder->mpp_format){ -+ case MPP_FMT_YUV420SP_10BIT: -+ decoder->rga_informat = RGA_FORMAT_YCbCr_420_SP_10B; -+ decoder->buffer_callback = rkmpp_rga_convert_buf; -+ av_log(avctx, AV_LOG_INFO, "Decoder is set to use AVBuffer with NV15->NV12 conversion through RGA3.\n"); -+ return 0; -+ case MPP_FMT_YUV420SP: -+ decoder->buffer_callback = rkmpp_set_nv12_buf; -+ av_log(avctx, AV_LOG_INFO, "Decoder is set to use MppBuffer with NV12.\n"); -+ return 0; -+ case MPP_FMT_YUV422SP: -+ decoder->rga_informat = RGA_FORMAT_YCbCr_422_SP; -+ decoder->buffer_callback = rkmpp_rga_convert_buf; -+ av_log(avctx, AV_LOG_INFO, "Decoder is set to use AVBuffer with NV16->NV12 conversion through RGA3.\n"); -+ return 0; -+ } -+ } else if (avctx->pix_fmt == AV_PIX_FMT_YUV420P){ -+ decoder->rga_outformat = RGA_FORMAT_YCbCr_420_P; -+ switch(decoder->mpp_format){ -+ case MPP_FMT_YUV420SP: -+ decoder->rga_informat = RGA_FORMAT_YCbCr_420_SP; -+ break; -+ case MPP_FMT_YUV422SP: -+ decoder->rga_informat = RGA_FORMAT_YCbCr_422_SP; -+ break; -+ } -+ if(decoder->rga_informat){ -+ decoder->buffer_callback = rkmpp_rga_convert_buf; -+ if(decoder->norga || decoder->rga_fd < 0) -+ av_log(avctx, AV_LOG_INFO, "Decoder is set to use AVBuffer with NV12->YUV420P conversion through libyuv.\n"); -+ else -+ av_log(avctx, AV_LOG_INFO, "Decoder is set to use AVBuffer with NV12->YUV420P conversion through RGA2.\n"); -+ return 0; -+ } ++MppFrame get_mppframe_from_av(AVFrame *frame){ ++ if(frame->data[RKMPP_MPPFRAME_BUFINDEX]){ ++ rkmpp_frame_type * mppframe = (rkmpp_frame_type *) frame->data[RKMPP_MPPFRAME_BUFINDEX]; ++ if(mppframe->name && !strcmp(mppframe->name, "mpp_frame") && ++ mpp_frame_get_fmt(frame->data[RKMPP_MPPFRAME_BUFINDEX]) != MPP_FMT_YUV420SP_10BIT) ++ return frame->data[RKMPP_MPPFRAME_BUFINDEX]; + } -+ av_log(avctx, AV_LOG_ERROR, "Unknown MPP format:%d and AVFormat:%d.\n", decoder->mpp_format, avctx->pix_fmt); -+ return AVERROR_UNKNOWN; ++ return NULL; +} -+ -+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; - MppFrame mppframe = NULL; - MppBuffer buffer = NULL; -- AVDRMFrameDescriptor *desc = NULL; -- AVDRMLayerDescriptor *layer = NULL; -- int mode; -- MppFrameFormat mppformat; -- uint32_t drmformat; -+ int ret, mode; - - // should not provide any frame after EOS - if (decoder->eos) -@@ -458,6 +606,7 @@ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout) - - if (mpp_frame_get_info_change(mppframe)) { - AVHWFramesContext *hwframes; -+ decoder->mpp_format = mpp_frame_get_fmt(mppframe) & MPP_FRAME_FMT_MASK; - - 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), -@@ -474,6 +623,10 @@ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout) - decoder->mpi->control(decoder->ctx, MPP_DEC_SET_FRAME_INFO, (MppParam) mppframe); - decoder->mpi->control(decoder->ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL); - -+ ret = set_buffer_callback(decoder, avctx); -+ if (ret) -+ goto fail; -+ - av_buffer_unref(&decoder->frames_ref); - - decoder->frames_ref = av_hwframe_ctx_alloc(decoder->device_ref); -@@ -482,11 +635,9 @@ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout) - goto fail; - } - -- mppformat = mpp_frame_get_fmt(mppframe); -- - hwframes = (AVHWFramesContext*)decoder->frames_ref->data; - hwframes->format = AV_PIX_FMT_DRM_PRIME; -- hwframes->sw_format = rkmpp_get_avformat(mppformat); -+ hwframes->sw_format = decoder->sw_format; - hwframes->width = avctx->width; - hwframes->height = avctx->height; - ret = av_hwframe_ctx_init(decoder->frames_ref); -@@ -509,10 +660,17 @@ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout) - - rkmpp_update_fps(avctx); - -- if (avctx->pix_fmt != AV_PIX_FMT_DRM_PRIME) { -- ret = ff_get_buffer(avctx, frame, 0); -- if (ret < 0) -- goto fail; -+ if(!decoder->buffer_callback){ -+ ret = AVERROR_UNKNOWN; -+ av_log(avctx, AV_LOG_ERROR, "Decoder has no valid buffer_callback\n"); -+ goto fail; -+ } -+ -+ ret = decoder->buffer_callback(avctx, frame, mppframe); -+ -+ if(ret){ -+ av_log(avctx, AV_LOG_ERROR, "Failed set frame buffer (code = %d)\n", ret); -+ goto fail; - } - - // setup general frame fields -@@ -530,79 +688,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) { -- return rkmpp_convert_frame(avctx, frame, mppframe, buffer); -- } -- -- mppformat = mpp_frame_get_fmt(mppframe); -- drmformat = rkmpp_get_frameformat(mppformat); -- -- 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; -- } -- -- // 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; -- } -- -- 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) - mpp_frame_deinit(&mppframe); -- -- if (framecontext) -- av_buffer_unref(&framecontext->decoder_ref); -- -- if (framecontextref) -- av_buffer_unref(&framecontextref); -- -- if (desc) -- av_free(desc); -- - return ret; - } - -@@ -720,19 +810,13 @@ static void rkmpp_flush(AVCodecContext *avctx) - decoder->mpi->reset(decoder->ctx); - - decoder->eos = 0; -- decoder->softconvert = 0; -+ decoder->norga = 0; - - decoder->last_fps_time = decoder->frames = 0; - - av_packet_unref(&decoder->packet); - } - --static const AVCodecHWConfigInternal *const rkmpp_hw_configs[] = { -- HW_CONFIG_INTERNAL(DRM_PRIME), -- HW_CONFIG_INTERNAL(YUV420P), -- NULL --}; -- - #define RKMPP_DEC_CLASS(NAME) \ - static const AVClass rkmpp_##NAME##_dec_class = { \ - .class_name = "rkmpp_" #NAME "_dec", \ -@@ -754,9 +838,12 @@ static const AVCodecHWConfigInternal *const rkmpp_hw_configs[] = { - .p.priv_class = &rkmpp_##NAME##_dec_class, \ - .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \ - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_DRM_PRIME, \ -+ AV_PIX_FMT_NV12, \ - AV_PIX_FMT_YUV420P, \ - AV_PIX_FMT_NONE}, \ -- .hw_configs = rkmpp_hw_configs, \ -+ .hw_configs = (const AVCodecHWConfigInternal *const []) { HW_CONFIG_INTERNAL(DRM_PRIME), \ -+ HW_CONFIG_INTERNAL(NV12), \ -+ NULL}, \ - .bsfs = BSFS, \ - .p.wrapper_name = "rkmpp", \ - .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | FF_CODEC_CAP_CONTIGUOUS_BUFFERS \ +diff --git a/libavcodec/rkplane.h b/libavcodec/rkplane.h +new file mode 100644 +index 0000000000..f52d29228b +--- /dev/null ++++ b/libavcodec/rkplane.h +@@ -0,0 +1,17 @@ ++#include <rockchip/rk_mpi.h> ++#include "avcodec.h" ++ ++typedef struct { ++ char *name; ++} rkmpp_frame_type; ++ ++int rga_convert_mpp_mpp(AVCodecContext *avctx, MppFrame in_mppframe, MppFrame out_mppframe); ++int mpp_nv15_av_yuv420p(AVCodecContext *avctx, MppFrame mppframe, AVFrame *frame); ++int mpp_nv15_av_nv12(AVCodecContext *avctx, MppFrame mppframe, AVFrame *frame); ++int mpp_nv12_av_nv12(AVCodecContext *avctx, MppFrame mppframe, AVFrame *frame); ++int convert_mpp_to_av(AVCodecContext *avctx, MppFrame mppframe, AVFrame *frame, ++ enum AVPixelFormat informat, enum AVPixelFormat outformat); ++MppFrame create_mpp_frame(int width, int height, enum AVPixelFormat avformat, MppBufferGroup buffer_group, AVDRMFrameDescriptor *desc, AVFrame *frame); ++MppFrame import_drm_to_mpp(AVCodecContext *avctx, AVFrame *frame); ++int import_mpp_to_drm(AVCodecContext *avctx, MppFrame mppframe, AVFrame *frame); ++MppFrame get_mppframe_from_av(AVFrame *frame); -- -2.40.0 +2.41.0 -From 3493b0fb8f50a57ce94c3544dfe899afe7800822 Mon Sep 17 00:00:00 2001 +From 15e6c6593aa50e89c62274399055da5325aa2887 Mon Sep 17 00:00:00 2001 From: boogie <boogiepop@gmx.com> -Date: Sun, 30 Apr 2023 16:52:57 +0200 -Subject: [PATCH 21/24] more verbose stats with latency and MACD FPS +Date: Mon, 24 Jul 2023 19:27:37 +0200 +Subject: [PATCH 10/13] lavu/hwcontext_drm: Add internal frame allocation --- - libavcodec/rkmppdec.c | 56 ++++++++++++++++++++++++------------------- - 1 file changed, 31 insertions(+), 25 deletions(-) + libavutil/hwcontext_drm.c | 322 +++++++++++++++++++++++++++++++++++++- + libavutil/hwcontext_drm.h | 14 +- + 2 files changed, 328 insertions(+), 8 deletions(-) -diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c -index f71511d0d0..ecee5dd338 100644 ---- a/libavcodec/rkmppdec.c -+++ b/libavcodec/rkmppdec.c -@@ -50,7 +50,7 @@ - #define DRM_FORMAT_NV15 fourcc_code('N', 'A', '1', '2') - #endif +diff --git a/libavutil/hwcontext_drm.c b/libavutil/hwcontext_drm.c +index 7a9fdbd263..2d1962c9c0 100644 +--- a/libavutil/hwcontext_drm.c ++++ b/libavutil/hwcontext_drm.c +@@ -18,6 +18,7 @@ --#define FPS_UPDATE_INTERVAL 60 -+#define FPS_FRAME_MACD 30 + #include "config.h" - typedef struct { - MppCtx ctx; -@@ -65,8 +65,9 @@ typedef struct { ++#define _GNU_SOURCE + #include <fcntl.h> + #include <sys/mman.h> + #include <unistd.h> +@@ -30,7 +31,7 @@ + #include <sys/ioctl.h> + #endif - char print_fps; +-#include <drm.h> ++#include <drm_fourcc.h> + #include <xf86drm.h> -- uint64_t last_fps_time; -+ uint64_t last_frame_time; - uint64_t frames; -+ uint64_t latencies[FPS_FRAME_MACD]; + #include "avassert.h" +@@ -39,6 +40,103 @@ + #include "hwcontext_internal.h" + #include "imgutils.h" - uint32_t mpp_format; - uint32_t rga_informat; -@@ -392,34 +393,37 @@ fail: - return ret; - } ++/** ++ * Copy from libdrm_macros.h while is not exposed by libdrm, ++ * be replaced by #include "libdrm_macros.h" someday. ++ */ ++ ++/** ++ * Static (compile-time) assertion. ++ * Basically, use COND to dimension an array. If COND is false/zero the ++ * array size will be -1 and we'll get a compilation error. ++ */ ++#define STATIC_ASSERT(COND) \ ++ do { \ ++ (void) sizeof(char [1 - 2*!(COND)]); \ ++ } while (0) ++ ++#if defined(ANDROID) && !defined(__LP64__) ++#include <errno.h> /* for EINVAL */ ++ ++extern void *__mmap2(void *, size_t, int, int, int, size_t); ++ ++static inline void *drm_mmap(void *addr, size_t length, int prot, int flags, ++ int fd, loff_t offset) ++{ ++ /* offset must be aligned to 4096 (not necessarily the page size) */ ++ if (offset & 4095) { ++ errno = EINVAL; ++ return MAP_FAILED; ++ } ++ ++ return __mmap2(addr, length, prot, flags, fd, (size_t) (offset >> 12)); ++} ++ ++# define drm_munmap(addr, length) \ ++ munmap(addr, length) ++ ++#else ++ ++/* assume large file support exists */ ++# define drm_mmap(addr, length, prot, flags, fd, offset) \ ++ mmap(addr, length, prot, flags, fd, offset) ++ ++static inline int drm_munmap(void *addr, size_t length) ++{ ++ /* Copied from configure code generated by AC_SYS_LARGEFILE */ ++#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + \ ++ (((off_t) 1 << 31) << 31)) ++ STATIC_ASSERT(LARGE_OFF_T % 2147483629 == 721 && ++ LARGE_OFF_T % 2147483647 == 1); ++#undef LARGE_OFF_T ++ ++ return munmap(addr, length); ++} ++#endif ++ ++// default ++static int card_index = 0; ++ ++static const struct { ++ enum AVPixelFormat pixfmt; ++ uint32_t drm_format; ++} supported_formats[] = { ++ { AV_PIX_FMT_NV12, DRM_FORMAT_NV12, }, ++//#ifdef DRM_FORMAT_NV12_10 ++// { AV_PIX_FMT_P010LE, DRM_FORMAT_NV12_10, }, ++// { AV_PIX_FMT_P010BE, DRM_FORMAT_NV12_10 | DRM_FORMAT_BIG_ENDIAN }, ++//#endif ++ { AV_PIX_FMT_NV21, DRM_FORMAT_NV21, }, ++ { AV_PIX_FMT_YUV420P, DRM_FORMAT_YUV420, }, ++ { AV_PIX_FMT_YUYV422, DRM_FORMAT_YUYV, }, ++ { AV_PIX_FMT_YVYU422, DRM_FORMAT_YVYU, }, ++ { AV_PIX_FMT_UYVY422, DRM_FORMAT_UYVY, }, ++ { AV_PIX_FMT_NV16, DRM_FORMAT_NV16, }, ++ { AV_PIX_FMT_YUV422P, DRM_FORMAT_YUV422, }, ++#ifdef DRM_FORMAT_R16 ++ { AV_PIX_FMT_GRAY16LE, DRM_FORMAT_R16, }, ++ { AV_PIX_FMT_GRAY16BE, DRM_FORMAT_R16 | DRM_FORMAT_BIG_ENDIAN }, ++#endif ++ { AV_PIX_FMT_BGR8, DRM_FORMAT_BGR233, }, ++ { AV_PIX_FMT_RGB555LE, DRM_FORMAT_XRGB1555, }, ++ { AV_PIX_FMT_RGB555BE, DRM_FORMAT_XRGB1555 | DRM_FORMAT_BIG_ENDIAN }, ++ { AV_PIX_FMT_BGR555LE, DRM_FORMAT_XBGR1555, }, ++ { AV_PIX_FMT_BGR555BE, DRM_FORMAT_XBGR1555 | DRM_FORMAT_BIG_ENDIAN }, ++ { AV_PIX_FMT_RGB565LE, DRM_FORMAT_RGB565, }, ++ { AV_PIX_FMT_RGB565BE, DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN }, ++ { AV_PIX_FMT_BGR565LE, DRM_FORMAT_BGR565, }, ++ { AV_PIX_FMT_BGR565BE, DRM_FORMAT_BGR565 | DRM_FORMAT_BIG_ENDIAN }, ++ { AV_PIX_FMT_RGB24, DRM_FORMAT_RGB888, }, ++ { AV_PIX_FMT_BGR24, DRM_FORMAT_BGR888, }, ++ { AV_PIX_FMT_0RGB, DRM_FORMAT_BGRX8888, }, ++ { AV_PIX_FMT_0BGR, DRM_FORMAT_RGBX8888, }, ++ { AV_PIX_FMT_RGB0, DRM_FORMAT_XBGR8888, }, ++ { AV_PIX_FMT_BGR0, DRM_FORMAT_XRGB8888, }, ++ { AV_PIX_FMT_ARGB, DRM_FORMAT_BGRA8888, }, ++ { AV_PIX_FMT_ABGR, DRM_FORMAT_RGBA8888, }, ++ { AV_PIX_FMT_RGBA, DRM_FORMAT_ABGR8888, }, ++ { AV_PIX_FMT_BGRA, DRM_FORMAT_ARGB8888, }, ++}; --static void rkmpp_update_fps(AVCodecContext *avctx) -+static uint64_t rkmpp_update_latency(AVCodecContext *avctx, uint64_t latency) + static void drm_device_free(AVHWDeviceContext *hwdev) { - RKMPPDecodeContext *rk_context = avctx->priv_data; - RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data; -- struct timeval tv; -+ struct timespec tv; - uint64_t curr_time; -- float fps; -+ float fps = 0.0f; - - 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; +@@ -52,7 +150,14 @@ static int drm_device_create(AVHWDeviceContext *hwdev, const char *device, + { + AVDRMDeviceContext *hwctx = hwdev->hwctx; + drmVersionPtr version; - -- gettimeofday(&tv, NULL); -- curr_time = tv.tv_sec * 1000 + tv.tv_usec / 1000; -+ return 0; - -- fps = 1000.0f * FPS_UPDATE_INTERVAL / (curr_time - decoder->last_fps_time); -- decoder->last_fps_time = curr_time; -+ clock_gettime(CLOCK_MONOTONIC, &tv); -+ curr_time = tv.tv_sec * 10e5 + tv.tv_nsec / 10e2; -+ if (latency == -1){ -+ latency = decoder->last_frame_time ? curr_time - decoder->last_frame_time : 0; -+ decoder->last_frame_time = curr_time; -+ decoder->latencies[++decoder->frames % FPS_FRAME_MACD] = latency; -+ return latency; -+ } else if (latency == 0 || decoder->frames < FPS_FRAME_MACD) { -+ fps = -1.0f; -+ } else { -+ for(int i = 0; i < FPS_FRAME_MACD; i++) { -+ fps += decoder->latencies[i]; -+ } -+ fps = FPS_FRAME_MACD * 1000000.0f / fps; -+ } -+ av_log(avctx, AV_LOG_INFO, -+ "[FFMPEG RKMPP] FPS(MACD%d): %6.1f || Frames: %" PRIu64 " || Latency: %" PRIu64 "us || Buffer Delay %" PRIu64 "us\n", -+ FPS_FRAME_MACD, fps, decoder->frames, latency, (uint64_t)(curr_time - decoder->last_frame_time)); ++ char drm_dev[] = "/dev/dri/card0000"; ++ uint64_t has_dumb; ++ ++ if (!device) { ++ snprintf(drm_dev, sizeof(drm_dev), DRM_DEV_NAME, DRM_DIR_NAME, ++ card_index); ++ device = drm_dev; ++ } + hwctx->fd = open(device, O_RDWR); + if (hwctx->fd < 0) + return AVERROR(errno); +@@ -72,11 +177,219 @@ static int drm_device_create(AVHWDeviceContext *hwdev, const char *device, + + drmFreeVersion(version); + ++ if (drmGetCap(hwctx->fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0 || ++ !has_dumb) { ++ av_log(hwdev, AV_LOG_ERROR, "drm device '%s' " ++ "does not support dumb buffers\n", device); ++ close(hwctx->fd); ++ return AVERROR(EINVAL); ++ } ++ + hwdev->free = &drm_device_free; -- av_log(avctx, AV_LOG_INFO, -- "[FFMPEG RKMPP] FPS: %6.1f || Frames: %" PRIu64 "\n", -- fps, decoder->frames); -+ return 0; + return 0; } - static int rkmpp_set_drm_buf(AVCodecContext *avctx, AVFrame *frame, MppFrame mppframe) -@@ -566,7 +570,7 @@ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout) - RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data; - MppFrame mppframe = NULL; - MppBuffer buffer = NULL; -- int ret, mode; -+ int ret, mode, latency; - - // should not provide any frame after EOS - if (decoder->eos) -@@ -658,7 +662,7 @@ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout) - goto fail; - } - -- rkmpp_update_fps(avctx); -+ latency = rkmpp_update_latency(avctx, -1); - - if(!decoder->buffer_callback){ - ret = AVERROR_UNKNOWN; -@@ -673,6 +677,8 @@ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout) - goto fail; - } - -+ latency = rkmpp_update_latency(avctx, latency); -+ - // setup general frame fields - frame->format = avctx->pix_fmt; - frame->width = mpp_frame_get_width(mppframe); -@@ -812,7 +818,7 @@ static void rkmpp_flush(AVCodecContext *avctx) - decoder->eos = 0; - decoder->norga = 0; - -- decoder->last_fps_time = decoder->frames = 0; -+ decoder->last_frame_time = decoder->frames = 0; ++static int drm_frames_get_constraints(AVHWDeviceContext *hwdev, ++ const void *hwconfig, ++ AVHWFramesConstraints *constraints) ++{ ++ int i; ++ ++ constraints->min_width = 16; ++ constraints->min_height = 16; ++ ++ constraints->valid_hw_formats = ++ av_malloc_array(2, sizeof(enum AVPixelFormat)); ++ if (!constraints->valid_hw_formats) ++ return AVERROR(ENOMEM); ++ constraints->valid_hw_formats[0] = AV_PIX_FMT_DRM_PRIME; ++ constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE; ++ ++ constraints->valid_sw_formats = ++ av_malloc_array(FF_ARRAY_ELEMS(supported_formats) + 1, ++ sizeof(enum AVPixelFormat)); ++ if (!constraints->valid_sw_formats) ++ return AVERROR(ENOMEM); ++ for(i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) ++ constraints->valid_sw_formats[i] = supported_formats[i].pixfmt; ++ constraints->valid_sw_formats[i] = AV_PIX_FMT_NONE; ++ ++ return 0; ++} ++ ++static void free_drm_frame_descriptor(AVDRMDeviceContext *hwctx, ++ AVDRMFrameDescriptor *desc) ++{ ++ int i; ++ if (!desc) ++ return; ++ ++ for (i = 0; i < desc->nb_objects; i++) { ++ AVDRMObjectDescriptor *object = &desc->objects[i]; ++ if (object->ptr) ++ drm_munmap(object->ptr, object->size); ++ if (object->fd > 0) { ++ int ret; ++ uint32_t handle = 0; ++ ++ ret = drmPrimeFDToHandle(hwctx->fd, object->fd, &handle); ++ if (ret) ++ av_log(NULL, AV_LOG_WARNING, ++ "Failed to convert drm fd to handle: %m\n"); ++ if (handle > 0) { ++ struct drm_mode_destroy_dumb data = { ++ .handle = handle, ++ }; ++ ret = drmIoctl(hwctx->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &data); ++ if (ret) ++ av_log(NULL, AV_LOG_WARNING, ++ "Failed to free drm handle: %m\n"); ++ } ++ ++ ret = close(object->fd); ++ if (ret) ++ av_log(NULL, AV_LOG_WARNING, ++ "Failed to close drm buffer fd = %d: %m\n", object->fd); ++ } ++ } ++ ++ memset(desc, 0, sizeof(*desc)); ++ av_free(desc); ++} ++ ++static void drm_buffer_free(void *opaque, uint8_t *data) ++{ ++ AVHWFramesContext *hwfc = opaque; ++ AVDRMDeviceContext *hwctx = hwfc->device_ctx->hwctx; ++ AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)data; ++ ++ free_drm_frame_descriptor(hwctx, desc); ++} ++ ++static AVBufferRef *drm_pool_alloc(void *opaque, size_t size) ++{ ++ int ret; ++ AVHWFramesContext *hwfc = opaque; ++ AVDRMDeviceContext *hwctx = hwfc->device_ctx->hwctx; ++ AVDRMFrameDescriptor *desc; ++ AVDRMLayerDescriptor *layer; ++ AVBufferRef *ref; ++ ++ int i; ++ const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(hwfc->sw_format); ++ struct drm_mode_create_dumb dmcb; ++ struct drm_mode_map_dumb dmmd; ++ ++ desc = av_mallocz(sizeof(*desc)); ++ if (!desc) ++ return NULL; ++ ++ memset(&dmcb, 0, sizeof(struct drm_mode_create_dumb)); ++ dmcb.bpp = av_get_bits_per_pixel(pixdesc); ++ dmcb.width = FFALIGN(hwfc->width, 16); ++ dmcb.height = FFALIGN(hwfc->height, 16); ++ ret = drmIoctl(hwctx->fd, DRM_IOCTL_MODE_CREATE_DUMB, &dmcb); ++ if (ret < 0) { ++ av_log(hwfc, AV_LOG_ERROR, ++ "Failed to create dumb<w,h,bpp: %d,%d,%d>: %m.\n", ++ dmcb.width, dmcb.height, dmcb.bpp); ++ goto fail; ++ } ++ av_assert0(dmcb.size >= dmcb.width * dmcb.height * dmcb.bpp / 8); ++ ++ desc->nb_objects = 1; ++ desc->nb_layers = 1; ++ ret = drmPrimeHandleToFD(hwctx->fd, dmcb.handle, DRM_CLOEXEC | DRM_RDWR, ++ &desc->objects[0].fd); ++ if (ret) { ++ av_log(hwfc, AV_LOG_ERROR, "Failed to convert handle to fd: %m\n"); ++ goto fail; ++ } ++ memset(&dmmd, 0, sizeof(dmmd)); ++ dmmd.handle = dmcb.handle; ++ ++ ret = drmIoctl(hwctx->fd, DRM_IOCTL_MODE_MAP_DUMB, &dmmd); ++ if (ret) { ++ av_log(hwfc, AV_LOG_ERROR, "Failed to map dumb: %m\n"); ++ goto fail; ++ } ++ ++ // default read and write ++ desc->objects[0].ptr = drm_mmap(NULL, dmcb.size, PROT_READ | PROT_WRITE, ++ MAP_SHARED, hwctx->fd, dmmd.offset); ++ if (desc->objects[0].ptr == MAP_FAILED) { ++ av_log(hwfc, AV_LOG_ERROR, "Failed to drm_mmap: %m\n"); ++ goto fail; ++ } ++ ++ desc->objects[0].size = dmcb.size; ++ ++ layer = &desc->layers[0]; ++ for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) { ++ if (supported_formats[i].pixfmt == hwfc->sw_format) { ++ layer->format = supported_formats[i].drm_format; ++ break; ++ } ++ } ++ layer->nb_planes = av_pix_fmt_count_planes(hwfc->sw_format); ++ layer->planes[0].object_index = 0; ++ layer->planes[0].offset = 0; ++ layer->planes[0].pitch = ++ av_image_get_linesize(hwfc->sw_format, hwfc->width, 0); ++ ++ for (i = 1; i < layer->nb_planes; i++) { ++ layer->planes[i].object_index = 0; ++ layer->planes[i].offset = layer->planes[i-1].pitch * hwfc->height; ++ layer->planes[i].pitch = ++ av_image_get_linesize(hwfc->sw_format, hwfc->width, i); ++ } ++ ++ ref = av_buffer_create((uint8_t*)desc, sizeof(*desc), drm_buffer_free, ++ opaque, 0); ++ if (!ref) { ++ av_log(hwfc, AV_LOG_ERROR, "Failed to create drm buffer.\n"); ++ goto fail; ++ } ++ ++ return ref; ++ ++fail: ++ free_drm_frame_descriptor(hwctx, desc); ++ return NULL; ++} ++ ++static int drm_frames_init(AVHWFramesContext *hwfc) ++{ ++ int i; ++ if (hwfc->pool) { ++ // has been set outside? ++ return 0; ++ } ++ ++ for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) ++ if (supported_formats[i].pixfmt == hwfc->sw_format) ++ break; ++ if (i >= FF_ARRAY_ELEMS(supported_formats)) { ++ av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n", ++ av_get_pix_fmt_name(hwfc->sw_format)); ++ return AVERROR(EINVAL); ++ } ++ ++ hwfc->internal->pool_internal = ++ av_buffer_pool_init2(sizeof(AVDRMFrameDescriptor), hwfc, drm_pool_alloc, ++ NULL); ++ if (!hwfc->internal->pool_internal) { ++ av_log(hwfc, AV_LOG_ERROR, "Failed to create drm buffer pool.\n"); ++ return AVERROR(ENOMEM); ++ } ++ ++ return 0; ++} ++ ++static void drm_frames_uninit(AVHWFramesContext *hwfc av_unused) ++{} ++ + static int drm_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame) + { + frame->buf[0] = av_buffer_pool_get(hwfc->pool); +@@ -309,8 +622,11 @@ const HWContextType ff_hwcontext_type_drm = { + + .device_create = &drm_device_create, + +- .frames_get_buffer = &drm_get_buffer, ++ .frames_get_constraints = &drm_frames_get_constraints, + ++ .frames_get_buffer = &drm_get_buffer, ++ .frames_init = &drm_frames_init, ++ .frames_uninit = &drm_frames_uninit, + .transfer_get_formats = &drm_transfer_get_formats, + .transfer_data_to = &drm_transfer_data_to, + .transfer_data_from = &drm_transfer_data_from, +diff --git a/libavutil/hwcontext_drm.h b/libavutil/hwcontext_drm.h +index 42709f215e..80f2e8597e 100644 +--- a/libavutil/hwcontext_drm.h ++++ b/libavutil/hwcontext_drm.h +@@ -25,11 +25,6 @@ + /** + * @file + * API-specific header for AV_HWDEVICE_TYPE_DRM. +- * +- * Internal frame allocation is not currently supported - all frames +- * must be allocated by the user. Thus AVHWFramesContext is always +- * NULL, though this may change if support for frame allocation is +- * added in future. + */ - av_packet_unref(&decoder->packet); - } + enum { +@@ -50,6 +45,12 @@ typedef struct AVDRMObjectDescriptor { + * DRM PRIME fd for the object. + */ + int fd; ++ /** ++ * DRM PRIME mapped virtual ptr for above fd. ++ * ++ * The content of this buffer must be readonly when acting decoder's out buffer. ++ */ ++ void *ptr; + /** + * Total size of the object. + * +@@ -141,10 +142,13 @@ typedef struct AVDRMFrameDescriptor { + AVDRMObjectDescriptor objects[AV_DRM_MAX_PLANES]; + /** + * Number of layers in the frame. ++ * ++ * Set by users if need more than 1. + */ + int nb_layers; + /** + * Array of layers in the frame. ++ * NOTE: total planes of layers must not be more than AV_NUM_DATA_POINTERS. + */ + AVDRMLayerDescriptor layers[AV_DRM_MAX_PLANES]; + } AVDRMFrameDescriptor; -- -2.40.0 +2.41.0 -From 893dca97e199609f22a73082af1eba87b6512530 Mon Sep 17 00:00:00 2001 +From 02c903151922d7f1427fbf56312585ca94237a56 Mon Sep 17 00:00:00 2001 From: boogie <boogiepop@gmx.com> -Date: Mon, 1 May 2023 19:00:21 +0200 -Subject: [PATCH 22/24] Allow users to choose pix_fmt using - "FFMPEG_RKMPP_PIXFMT" env variable. Valid options are: YUV420P, YUV420PSOFT, - NV12, DRMPRIME. Case sensitive +Date: Mon, 24 Jul 2023 22:19:14 +0200 +Subject: [PATCH 11/13] add yuv444 & nv24 support for drm hwcontext --- - libavcodec/rkmppdec.c | 25 +++++++++++++++++++------ - 1 file changed, 19 insertions(+), 6 deletions(-) + libavutil/hwcontext_drm.c | 2 ++ + 1 file changed, 2 insertions(+) -diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c -index ecee5dd338..4f9ecb0155 100644 ---- a/libavcodec/rkmppdec.c -+++ b/libavcodec/rkmppdec.c -@@ -75,7 +75,6 @@ typedef struct { - uint32_t drm_format; - uint32_t sw_format; - int rga_fd; -- int8_t rgafbc; - int8_t norga; - int (*buffer_callback)(struct AVCodecContext *avctx, struct AVFrame *frame, MppFrame mppframe); - -@@ -287,8 +286,6 @@ static int rkmpp_init_decoder(AVCodecContext *avctx) - char *env; - int ret; - -- avctx->pix_fmt = ff_get_format(avctx, avctx->codec->pix_fmts); -- - // create a decoder and a ref to it - decoder = av_mallocz(sizeof(RKMPPDecoder)); - if (!decoder) { -@@ -350,8 +347,24 @@ static int rkmpp_init_decoder(AVCodecContext *avctx) - goto fail; - } - -- env = getenv("FFMPEG_RKMPP_NORGA"); -- if (env != NULL) -+ avctx->pix_fmt = ff_get_format(avctx, avctx->codec->pix_fmts); -+ -+ // override the the pixfmt according env variable -+ env = getenv("FFMPEG_RKMPP_PIXFMT"); -+ if(env != NULL){ -+ if(!strcmp(env, "YUV420P")) -+ avctx->pix_fmt = AV_PIX_FMT_YUV420P; -+ else if (!strcmp(env, "NV12")) -+ avctx->pix_fmt = AV_PIX_FMT_NV12; -+ else if(!strcmp(env, "DRMPRIME")) -+ avctx->pix_fmt = AV_PIX_FMT_DRM_PRIME; -+ else if(!strcmp(env, "YUV420PSOFT")){ -+ avctx->pix_fmt = AV_PIX_FMT_YUV420P; -+ decoder->norga = 1; -+ } -+ } -+ -+ if (decoder->norga) - decoder->rga_fd = -1; - else { - decoder->rga_fd = open("/dev/rga", O_RDWR); -@@ -844,8 +857,8 @@ static void rkmpp_flush(AVCodecContext *avctx) - .p.priv_class = &rkmpp_##NAME##_dec_class, \ - .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \ - .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_DRM_PRIME, \ -- AV_PIX_FMT_NV12, \ - AV_PIX_FMT_YUV420P, \ -+ AV_PIX_FMT_NV12, \ - AV_PIX_FMT_NONE}, \ - .hw_configs = (const AVCodecHWConfigInternal *const []) { HW_CONFIG_INTERNAL(DRM_PRIME), \ - HW_CONFIG_INTERNAL(NV12), \ +diff --git a/libavutil/hwcontext_drm.c b/libavutil/hwcontext_drm.c +index 2d1962c9c0..9210b6c9f5 100644 +--- a/libavutil/hwcontext_drm.c ++++ b/libavutil/hwcontext_drm.c +@@ -117,6 +117,8 @@ static const struct { + { AV_PIX_FMT_GRAY16LE, DRM_FORMAT_R16, }, + { AV_PIX_FMT_GRAY16BE, DRM_FORMAT_R16 | DRM_FORMAT_BIG_ENDIAN }, + #endif ++ { AV_PIX_FMT_NV24, DRM_FORMAT_NV24, }, ++ { AV_PIX_FMT_YUV444P, DRM_FORMAT_YUV444, }, + { AV_PIX_FMT_BGR8, DRM_FORMAT_BGR233, }, + { AV_PIX_FMT_RGB555LE, DRM_FORMAT_XRGB1555, }, + { AV_PIX_FMT_RGB555BE, DRM_FORMAT_XRGB1555 | DRM_FORMAT_BIG_ENDIAN }, -- -2.40.0 +2.41.0 -From 7612f91257a22339bfde5e3258b4b8c2671bb876 Mon Sep 17 00:00:00 2001 +From fe7abf1ad8ec7522d86c87c1b55164122199a327 Mon Sep 17 00:00:00 2001 From: boogie <boogiepop@gmx.com> -Date: Mon, 1 May 2023 20:03:53 +0200 -Subject: [PATCH 23/24] Workaround for Mpp bug, where color primaries, trc and - colorspace is giving wrong UNSPECIFIED values +Date: Fri, 28 Jul 2023 22:08:47 +0200 +Subject: [PATCH 12/13] add AV_PIX_FMT_NV15 definition as a placeholder to + enable supported DRM frames --- - libavcodec/rkmppdec.c | 6 ++++++ - 1 file changed, 6 insertions(+) + libavcodec/rkmpp.c | 2 +- + libavutil/hwcontext_drm.c | 1 + + libavutil/pixfmt.h | 2 ++ + 3 files changed, 4 insertions(+), 1 deletion(-) -diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c -index 4f9ecb0155..60f1506804 100644 ---- a/libavcodec/rkmppdec.c -+++ b/libavcodec/rkmppdec.c -@@ -703,6 +703,12 @@ 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); +diff --git a/libavcodec/rkmpp.c b/libavcodec/rkmpp.c +index b76dc1a868..dfb76e1d91 100644 +--- a/libavcodec/rkmpp.c ++++ b/libavcodec/rkmpp.c +@@ -27,7 +27,7 @@ static rkformat rkformats[13] = { + { .av = AV_PIX_FMT_YUV422P, .mpp = MPP_FMT_YUV422P, .drm = DRM_FORMAT_YUV422, .rga = RK_FORMAT_YCbCr_422_P}, + { .av = AV_PIX_FMT_NV12, .mpp = MPP_FMT_YUV420SP, .drm = DRM_FORMAT_NV12, .rga = RK_FORMAT_YCbCr_420_SP}, + { .av = AV_PIX_FMT_NV16, .mpp = MPP_FMT_YUV422SP, .drm = DRM_FORMAT_NV16, .rga = RK_FORMAT_YCbCr_422_SP}, +- { .av = AV_PIX_FMT_NONE, .mpp = MPP_FMT_YUV420SP_10BIT, .drm = DRM_FORMAT_NV15, .rga = RK_FORMAT_YCbCr_420_SP_10B}, ++ { .av = AV_PIX_FMT_NV15, .mpp = MPP_FMT_YUV420SP_10BIT, .drm = DRM_FORMAT_NV15, .rga = RK_FORMAT_YCbCr_420_SP_10B}, + { .av = AV_PIX_FMT_BGR24, .mpp = MPP_FMT_BGR888, .drm = DRM_FORMAT_BGR888, .rga = RK_FORMAT_BGR_888}, + { .av = AV_PIX_FMT_BGR0, .mpp = MPP_FMT_BGRA8888, .drm = DRM_FORMAT_XRGB8888, .rga = RK_FORMAT_BGRX_8888}, + { .av = AV_PIX_FMT_BGRA, .mpp = MPP_FMT_BGRA8888, .drm = DRM_FORMAT_ARGB8888, .rga = RK_FORMAT_BGRA_8888}, +diff --git a/libavutil/hwcontext_drm.c b/libavutil/hwcontext_drm.c +index 9210b6c9f5..32bf958c5d 100644 +--- a/libavutil/hwcontext_drm.c ++++ b/libavutil/hwcontext_drm.c +@@ -138,6 +138,7 @@ static const struct { + { AV_PIX_FMT_ABGR, DRM_FORMAT_RGBA8888, }, + { AV_PIX_FMT_RGBA, DRM_FORMAT_ABGR8888, }, + { AV_PIX_FMT_BGRA, DRM_FORMAT_ARGB8888, }, ++ { AV_PIX_FMT_NV15, DRM_FORMAT_NV15, }, + }; -+ // when mpp can not determine the color space, it returns reserved (0) value -+ // firefox does not understand this and instead expect unspecified (2) values -+ frame->color_primaries = frame->color_primaries == AVCOL_PRI_RESERVED0 ? AVCOL_PRI_UNSPECIFIED : frame->color_primaries; -+ frame->color_trc = frame->color_trc == AVCOL_TRC_RESERVED0 ? AVCOL_TRC_UNSPECIFIED : frame->color_trc; -+ frame->colorspace = frame->colorspace == AVCOL_SPC_RGB ? AVCOL_SPC_UNSPECIFIED: frame->color_trc; + static void drm_device_free(AVHWDeviceContext *hwdev) +diff --git a/libavutil/pixfmt.h b/libavutil/pixfmt.h +index 37c2c79e01..d2348b016b 100644 +--- a/libavutil/pixfmt.h ++++ b/libavutil/pixfmt.h +@@ -420,6 +420,8 @@ enum AVPixelFormat { + AV_PIX_FMT_RGBAF32BE, ///< IEEE-754 single precision packed RGBA 32:32:32:32, 128bpp, RGBARGBA..., big-endian + AV_PIX_FMT_RGBAF32LE, ///< IEEE-754 single precision packed RGBA 32:32:32:32, 128bpp, RGBARGBA..., little-endian + ++ AV_PIX_FMT_NV15, ///< Rockchip Specific 10bit NV12 + - 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); + AV_PIX_FMT_NB ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions + }; + -- -2.40.0 +2.41.0 -From d8ecadf7de6ec350502b2613dfc34c815969b518 Mon Sep 17 00:00:00 2001 +From ac1a698091e8457472391cbf279bcd228e4b8fb9 Mon Sep 17 00:00:00 2001 From: boogie <boogiepop@gmx.com> -Date: Tue, 2 May 2023 02:07:20 +0200 -Subject: [PATCH 24/24] Log more understandable errors +Date: Mon, 31 Jul 2023 01:32:54 +0200 +Subject: [PATCH 13/13] give pixel descriptor to prevent crashes. descriptor + might not be %100 correct --- - libavcodec/rkmppdec.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) + libavutil/pixdesc.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) -diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c -index 60f1506804..c1d357344b 100644 ---- a/libavcodec/rkmppdec.c -+++ b/libavcodec/rkmppdec.c -@@ -679,7 +679,7 @@ static int rkmpp_get_frame(AVCodecContext *avctx, AVFrame *frame, int timeout) - - if(!decoder->buffer_callback){ - ret = AVERROR_UNKNOWN; -- av_log(avctx, AV_LOG_ERROR, "Decoder has no valid buffer_callback\n"); -+ av_log(avctx, AV_LOG_ERROR, "Decoder can't set output for MPP format:%d and AVFormat:%d.\n", decoder->mpp_format, avctx->pix_fmt); - goto fail; - } +diff --git a/libavutil/pixdesc.c b/libavutil/pixdesc.c +index 62a2ae08d9..c5e8c7bd9a 100644 +--- a/libavutil/pixdesc.c ++++ b/libavutil/pixdesc.c +@@ -2717,6 +2717,18 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_FLOAT | + AV_PIX_FMT_FLAG_ALPHA, + }, ++ [AV_PIX_FMT_NV15] = { ++ .name = "nv15", ++ .nb_components = 3, ++ .log2_chroma_w = 1, ++ .log2_chroma_h = 1, ++ .comp = { ++ { 0, 1, 0, 0, 10 }, /* Y */ ++ { 1, 2, 0, 0, 10 }, /* U */ ++ { 1, 2, 1, 0, 10 }, /* V */ ++ }, ++ .flags = AV_PIX_FMT_FLAG_PLANAR, ++ }, + }; + static const char * const color_range_names[] = { -- -2.40.0 +2.41.0 |