diff mbox series

[FFmpeg-devel,3/4,v2] avcodec: add LCEVC decoding support via LCEVCdec

Message ID 20240721225350.298-3-jamrial@gmail.com
State New
Headers show
Series [FFmpeg-devel,1/4,v2] avutil/frame: add an LCEVC enhancement data payload side data type | expand

Checks

Context Check Description
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

James Almer July 21, 2024, 10:53 p.m. UTC
Signed-off-by: James Almer <jamrial@gmail.com>
---
 configure                 |   3 +
 doc/general_contents.texi |  13 ++
 libavcodec/Makefile       |   1 +
 libavcodec/lcevcdec.c     | 276 ++++++++++++++++++++++++++++++++++++++
 libavcodec/lcevcdec.h     |  44 ++++++
 5 files changed, 337 insertions(+)
 create mode 100644 libavcodec/lcevcdec.c
 create mode 100644 libavcodec/lcevcdec.h

Comments

Frank Plowman July 22, 2024, 11:16 a.m. UTC | #1
On 21/07/2024 23:53, James Almer wrote:
> Signed-off-by: James Almer <jamrial@gmail.com>
> ---
>  configure                 |   3 +
>  doc/general_contents.texi |  13 ++
>  libavcodec/Makefile       |   1 +
>  libavcodec/lcevcdec.c     | 276 ++++++++++++++++++++++++++++++++++++++
>  libavcodec/lcevcdec.h     |  44 ++++++
>  5 files changed, 337 insertions(+)
>  create mode 100644 libavcodec/lcevcdec.c
>  create mode 100644 libavcodec/lcevcdec.h
> 
> diff --git a/configure b/configure
> index f6f5c29fea..d1f32684a6 100755
> --- a/configure
> +++ b/configure
> @@ -225,6 +225,7 @@ External library support:
>    --enable-libcdio         enable audio CD grabbing with libcdio [no]
>    --enable-libcodec2       enable codec2 en/decoding using libcodec2 [no]
>    --enable-libdav1d        enable AV1 decoding via libdav1d [no]
> +  --enable-liblcevc_dec    enable LCEVC decoding via liblcevc_dec [no]
>    --enable-libdavs2        enable AVS2 decoding via libdavs2 [no]
>    --enable-libdc1394       enable IIDC-1394 grabbing using libdc1394
>                             and libraw1394 [no]
> @@ -1914,6 +1915,7 @@ EXTERNAL_LIBRARY_LIST="
>      libcelt
>      libcodec2
>      libdav1d
> +    liblcevc_dec
>      libdc1394
>      libflite
>      libfontconfig
> @@ -6854,6 +6856,7 @@ enabled libcelt           && require libcelt celt/celt.h celt_decode -lcelt0 &&
>  enabled libcaca           && require_pkg_config libcaca caca caca.h caca_create_canvas
>  enabled libcodec2         && require libcodec2 codec2/codec2.h codec2_create -lcodec2
>  enabled libdav1d          && require_pkg_config libdav1d "dav1d >= 0.5.0" "dav1d/dav1d.h" dav1d_version
> +enabled liblcevc_dec      && require_pkg_config liblcevc_dec "lcevc_dec >= 2.0.0" "LCEVC/lcevc_dec.h" LCEVC_CreateDecoder
>  enabled libdavs2          && require_pkg_config libdavs2 "davs2 >= 1.6.0" davs2.h davs2_decoder_open
>  enabled libdc1394         && require_pkg_config libdc1394 libdc1394-2 dc1394/dc1394.h dc1394_new
>  enabled libdrm            && check_pkg_config libdrm libdrm xf86drm.h drmGetVersion
> diff --git a/doc/general_contents.texi b/doc/general_contents.texi
> index e7cf4f8239..ecaf3979ce 100644
> --- a/doc/general_contents.texi
> +++ b/doc/general_contents.texi
> @@ -245,6 +245,19 @@ Go to @url{https://github.com/google/liblc3/} and follow the instructions for
>  installing the library.
>  Then pass @code{--enable-liblc3} to configure to enable it.
>  
> +@section LCEVCdec
> +
> +FFmpeg can make use of the liblcevc_dec library for LCEVC enhacement layer
> +decoding on supported bitstreams.
> +
> +Go to @url{https://github.com/v-novaltd/LCEVCdec} and follow the instructions
> +for installing the library. Then pass @code{--enable-libvpx} to configure to
                                                      ^
                                         Should be --enable-liblcevc_dec

> +enable it.
> +
> +@float NOTE
> +LCEVCdec is under the BSD-3-Clause-Clear License.
> +@end float
> +
>  @section OpenH264
>  
>  FFmpeg can make use of the OpenH264 library for H.264 decoding and encoding.
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index 771e2b597e..71bc3c8075 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -121,6 +121,7 @@ OBJS-$(CONFIG_INTRAX8)                 += intrax8.o intrax8dsp.o msmpeg4_vc1_dat
>  OBJS-$(CONFIG_IVIDSP)                  += ivi_dsp.o
>  OBJS-$(CONFIG_JNI)                     += ffjni.o jni.o
>  OBJS-$(CONFIG_JPEGTABLES)              += jpegtables.o
> +OBJS-$(CONFIG_LIBLCEVC_DEC)            += lcevcdec.o
>  OBJS-$(CONFIG_LCMS2)                   += fflcms2.o
>  OBJS-$(CONFIG_LLAUDDSP)                += lossless_audiodsp.o
>  OBJS-$(CONFIG_LLVIDDSP)                += lossless_videodsp.o
> diff --git a/libavcodec/lcevcdec.c b/libavcodec/lcevcdec.c
> new file mode 100644
> index 0000000000..4edb0b72dc
> --- /dev/null
> +++ b/libavcodec/lcevcdec.c
> @@ -0,0 +1,276 @@
> +/*
> + * 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 "libavutil/avassert.h"
> +#include "libavutil/frame.h"
> +#include "libavutil/imgutils.h"
> +#include "libavutil/log.h"
> +#include "libavutil/mem.h"
> +#include "decode.h"
> +#include "lcevcdec.h"
> +
> +static LCEVC_ColorFormat map_format(int format)
> +{
> +    switch (format) {
> +    case AV_PIX_FMT_YUV420P:
> +        return LCEVC_I420_8;
> +    case AV_PIX_FMT_YUV420P10:
> +        return LCEVC_I420_10_LE;
> +    case AV_PIX_FMT_NV12:
> +        return LCEVC_NV12_8;
> +    case AV_PIX_FMT_NV21:
> +        return LCEVC_NV21_8;
> +    case AV_PIX_FMT_GRAY8:
> +        return LCEVC_GRAY_8;
> +    }
> +
> +    return LCEVC_ColorFormat_Unknown;
> +}
> +
> +static int alloc_base_frame(void *logctx, LCEVC_DecoderHandle decoder,
> +                            const AVFrame *frame, LCEVC_PictureHandle *picture)
> +{
> +    LCEVC_PictureDesc desc;
> +    LCEVC_ColorFormat fmt = map_format(frame->format);
> +    LCEVC_PictureLockHandle lock;
> +    uint8_t *data[4] = { NULL };
> +    int linesizes[4] = { 0 };
> +    uint32_t planes;
> +    LCEVC_ReturnCode res;
> +
> +    res = LCEVC_DefaultPictureDesc(&desc, fmt, frame->width, frame->height);
> +    if (res != LCEVC_Success)
> +		return AVERROR_EXTERNAL;
> +
> +    desc.cropTop    = frame->crop_top;
> +    desc.cropBottom = frame->crop_bottom;
> +    desc.cropLeft   = frame->crop_left;
> +    desc.cropRight  = frame->crop_right;
> +    desc.sampleAspectRatioNum  = frame->sample_aspect_ratio.num;
> +    desc.sampleAspectRatioDen  = frame->sample_aspect_ratio.den;
> +
> +    /* Allocate LCEVC Picture */
> +    res = LCEVC_AllocPicture(decoder, &desc, picture);
> +    if (res != LCEVC_Success)
> +        return AVERROR_EXTERNAL;
> +
> +    res = LCEVC_LockPicture(decoder, *picture, LCEVC_Access_Write, &lock);
> +    if (res != LCEVC_Success)
> +        return AVERROR_EXTERNAL;
> +
> +    res = LCEVC_GetPicturePlaneCount(decoder, *picture, &planes);
> +    if (res != LCEVC_Success)
> +        return AVERROR_EXTERNAL;
> +
> +    for (unsigned i = 0; i < planes; i++) {
> +        LCEVC_PicturePlaneDesc plane;
> +
> +        res = LCEVC_GetPictureLockPlaneDesc(decoder, lock, i, &plane);
> +        if (res != LCEVC_Success)
> +            return AVERROR_EXTERNAL;
> +
> +        data[i] = plane.firstSample;
> +        linesizes[i] = plane.rowByteStride;
> +    }
> +
> +    av_image_copy2(data, linesizes, frame->data, frame->linesize,
> +                   frame->format, frame->width, frame->height);
> +
> +    res = LCEVC_UnlockPicture(decoder, lock);
> +    if (res != LCEVC_Success)
> +        return AVERROR_EXTERNAL;
> +
> +    return 0;
> +}
> +
> +static int alloc_enhanced_frame(void *logctx, LCEVC_DecoderHandle decoder,
> +                                const AVFrame *frame, LCEVC_PictureHandle *picture)
> +{
> +    LCEVC_PictureDesc desc ;
> +    LCEVC_ColorFormat fmt = map_format(frame->format);
> +    LCEVC_PicturePlaneDesc planes[4] = { 0 };
> +    int width = frame->width * 2 / FFMAX(frame->sample_aspect_ratio.den, 1);
> +    int height = frame->height * 2 / FFMAX(frame->sample_aspect_ratio.num, 1);
> +    LCEVC_ReturnCode res;
> +
> +    res = LCEVC_DefaultPictureDesc(&desc, fmt, width, height);
> +    if (res != LCEVC_Success)
> +        return AVERROR_EXTERNAL;
> +
> +    /* Set plane description */
> +    for (int i = 0; i < 4; i++) {
> +        planes[i].firstSample = frame->data[i];
> +        planes[i].rowByteStride = frame->linesize[i];
> +    }
> +
> +    /* Allocate LCEVC Picture */
> +    res = LCEVC_AllocPictureExternal(decoder, &desc, NULL, planes, picture);
> +    if (res != LCEVC_Success)
> +        return AVERROR_EXTERNAL;
> +
> +    return 0;
> +}
> +
> +int ff_lcevc_send_frame(void *logctx, FFLCEVCContext *lcevc, const AVFrame *in)
> +{
> +    const AVFrameSideData *sd = av_frame_get_side_data(in, AV_FRAME_DATA_LCEVC);
> +    LCEVC_PictureHandle picture;
> +    LCEVC_ReturnCode res;
> +    int ret = 0;
> +
> +    if (!sd)
> +        return 0;
> +
> +    res = LCEVC_SendDecoderEnhancementData(lcevc->decoder, in->pts, 0, sd->data, sd->size);
> +    if (res != LCEVC_Success)
> +        return AVERROR_EXTERNAL;
> +
> +    ret = alloc_base_frame(logctx, lcevc->decoder, in, &picture);
> +    if (ret < 0)
> +        return ret;
> +
> +    res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, 0, picture, -1, NULL);
> +    if (res != LCEVC_Success)
> +        return AVERROR_EXTERNAL;
> +
> +    memset(&picture, 0, sizeof(picture));
> +    ret = alloc_enhanced_frame(logctx, lcevc->decoder, in, &picture);
> +    if (ret < 0)
> +        return ret;
> +
> +    res = LCEVC_SendDecoderPicture(lcevc->decoder, picture);
> +    if (res != LCEVC_Success)
> +        return AVERROR_EXTERNAL;
> +
> +    return 0;
> +}
> +
> +static int generate_output(void *logctx, FFLCEVCContext *lcevc, AVFrame *out)
> +{
> +    LCEVC_PictureDesc desc;
> +    LCEVC_DecodeInformation info;
> +    LCEVC_PictureHandle picture;
> +    LCEVC_ReturnCode res;
> +
> +    res = LCEVC_ReceiveDecoderPicture(lcevc->decoder, &picture, &info);
> +    if (res != LCEVC_Success)
> +        return AVERROR_EXTERNAL;
> +
> +    res = LCEVC_GetPictureDesc(lcevc->decoder, picture, &desc);
> +    if (res != LCEVC_Success)
> +        return AVERROR_EXTERNAL;
> +
> +    out->crop_top = desc.cropTop;
> +    out->crop_bottom = desc.cropBottom;
> +    out->crop_left = desc.cropLeft;
> +    out->crop_right = desc.cropRight;
> +    out->sample_aspect_ratio.num = desc.sampleAspectRatioNum;
> +    out->sample_aspect_ratio.den = desc.sampleAspectRatioDen;
> +    out->width = desc.width + out->crop_left + out->crop_right;
> +    out->height = desc.height + out->crop_top + out->crop_bottom;
> +
> +    return 0;
> +}
> +
> +int ff_lcevc_receive_frame(void *logctx, FFLCEVCContext *lcevc, AVFrame *out)
> +{
> +    LCEVC_PictureHandle picture;
> +    LCEVC_ReturnCode res;
> +    int ret;
> +
> +    ret = generate_output(logctx, lcevc, out);
> +    if (ret < 0)
> +        return ret;
> +
> +    res = LCEVC_ReceiveDecoderBase (lcevc->decoder, &picture);
> +    if (res != LCEVC_Success)
> +        return AVERROR_EXTERNAL;
> +
> +    res = LCEVC_FreePicture(lcevc->decoder, picture);
> +    if (res != LCEVC_Success)
> +        return AVERROR_EXTERNAL;
> +
> +    return 0;
> +}
> +
> +int ff_lcevc_process(void *logctx, AVFrame *frame)
> +{
> +    FrameDecodeData  *fdd = (FrameDecodeData*)frame->private_ref->data;
> +    AVBufferRef      *ref = (AVBufferRef*)fdd->post_process_opaque;
> +    FFLCEVCContext *lcevc = (FFLCEVCContext*)ref->data;
> +    int ret;
> +
> +    ret = ff_lcevc_send_frame(logctx, lcevc, frame);
> +    if (ret < 0)
> +        return ret;
> +
> +    ff_lcevc_receive_frame(logctx, lcevc, frame);
> +    if (ret < 0)
> +        return ret;
> +
> +    return 0;
> +}
> +
> +static void event_callback(LCEVC_DecoderHandle dec, LCEVC_Event event,
> +    LCEVC_PictureHandle pic, const LCEVC_DecodeInformation *info,
> +    const uint8_t *data, uint32_t size, void *logctx)
> +{
> +    switch (event) {
> +    case LCEVC_Log:
> +        av_log(logctx, AV_LOG_INFO, "%s\n", data);
> +        break;
> +    default:
> +        break;
> +    }
> +}
> +
> +int ff_lcevc_init(FFLCEVCContext *lcevc, void *logctx)
> +{
> +    LCEVC_AccelContextHandle dummy = { 0 };
> +
> +    int32_t events[] = { LCEVC_Log };
> +
> +    if (LCEVC_CreateDecoder(&lcevc->decoder, dummy) != LCEVC_Success) {
> +        av_log(logctx, AV_LOG_ERROR, "Failed to create LCEVC decoder\n");
> +        return AVERROR_EXTERNAL;
> +    }
> +
> +    LCEVC_ConfigureDecoderInt(lcevc->decoder, "log_level", 4);
> +    LCEVC_ConfigureDecoderIntArray(lcevc->decoder, "events", FF_ARRAY_ELEMS(events), events);
> +    LCEVC_SetDecoderEventCallback(lcevc->decoder, event_callback, logctx);
> +
> +    if (LCEVC_InitializeDecoder(lcevc->decoder) != LCEVC_Success) {
> +        av_log(logctx, AV_LOG_ERROR, "Failed to initialize LCEVC decoder\n");
> +        return AVERROR_EXTERNAL;
> +    }
> +
> +    return 0;
> +}
> +
> +void ff_lcevc_free(void *opaque, uint8_t *data)
> +{
> +    FFLCEVCContext *lcevc = opaque;
> +    LCEVC_DestroyDecoder(lcevc->decoder);
> +    av_free(data);
> +}
> +
> +void ff_lcevc_unref(void *opaque)
> +{
> +    AVBufferRef *ref = opaque;
> +    av_buffer_unref(&ref);
> +}
> diff --git a/libavcodec/lcevcdec.h b/libavcodec/lcevcdec.h
> new file mode 100644
> index 0000000000..fe105371d3
> --- /dev/null
> +++ b/libavcodec/lcevcdec.h
> @@ -0,0 +1,44 @@
> +/*
> + * 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
> + */
> +
> +#ifndef AVCODEC_LCEVCDEC_H
> +#define AVCODEC_LCEVCDEC_H
> +
> +#include "config_components.h"
> +
> +#include <stdint.h>
> +#if CONFIG_LIBLCEVC_DEC
> +#include <LCEVC/lcevc_dec.h>
> +#else
> +typedef uintptr_t LCEVC_DecoderHandle;
> +#endif
> +
> +typedef struct FFLCEVCContext {
> +    LCEVC_DecoderHandle decoder;
> +} FFLCEVCContext;
> +
> +struct AVFrame;
> +
> +int ff_lcevc_process(void *logctx, struct AVFrame *frame);
> +int ff_lcevc_send_frame(void *logctx, FFLCEVCContext *lcevc, const AVFrame *in);
> +int ff_lcevc_receive_frame(void *logctx, FFLCEVCContext *lcevc, AVFrame *out);
> +int ff_lcevc_init(FFLCEVCContext *lcevc, void *logctx);
> +void ff_lcevc_unref(void *opaque);
> +void ff_lcevc_free(void *opaque, uint8_t *data);
> +
> +#endif /* AVCODEC_LCEVCDEC_H */
diff mbox series

Patch

diff --git a/configure b/configure
index f6f5c29fea..d1f32684a6 100755
--- a/configure
+++ b/configure
@@ -225,6 +225,7 @@  External library support:
   --enable-libcdio         enable audio CD grabbing with libcdio [no]
   --enable-libcodec2       enable codec2 en/decoding using libcodec2 [no]
   --enable-libdav1d        enable AV1 decoding via libdav1d [no]
+  --enable-liblcevc_dec    enable LCEVC decoding via liblcevc_dec [no]
   --enable-libdavs2        enable AVS2 decoding via libdavs2 [no]
   --enable-libdc1394       enable IIDC-1394 grabbing using libdc1394
                            and libraw1394 [no]
@@ -1914,6 +1915,7 @@  EXTERNAL_LIBRARY_LIST="
     libcelt
     libcodec2
     libdav1d
+    liblcevc_dec
     libdc1394
     libflite
     libfontconfig
@@ -6854,6 +6856,7 @@  enabled libcelt           && require libcelt celt/celt.h celt_decode -lcelt0 &&
 enabled libcaca           && require_pkg_config libcaca caca caca.h caca_create_canvas
 enabled libcodec2         && require libcodec2 codec2/codec2.h codec2_create -lcodec2
 enabled libdav1d          && require_pkg_config libdav1d "dav1d >= 0.5.0" "dav1d/dav1d.h" dav1d_version
+enabled liblcevc_dec      && require_pkg_config liblcevc_dec "lcevc_dec >= 2.0.0" "LCEVC/lcevc_dec.h" LCEVC_CreateDecoder
 enabled libdavs2          && require_pkg_config libdavs2 "davs2 >= 1.6.0" davs2.h davs2_decoder_open
 enabled libdc1394         && require_pkg_config libdc1394 libdc1394-2 dc1394/dc1394.h dc1394_new
 enabled libdrm            && check_pkg_config libdrm libdrm xf86drm.h drmGetVersion
diff --git a/doc/general_contents.texi b/doc/general_contents.texi
index e7cf4f8239..ecaf3979ce 100644
--- a/doc/general_contents.texi
+++ b/doc/general_contents.texi
@@ -245,6 +245,19 @@  Go to @url{https://github.com/google/liblc3/} and follow the instructions for
 installing the library.
 Then pass @code{--enable-liblc3} to configure to enable it.
 
+@section LCEVCdec
+
+FFmpeg can make use of the liblcevc_dec library for LCEVC enhacement layer
+decoding on supported bitstreams.
+
+Go to @url{https://github.com/v-novaltd/LCEVCdec} and follow the instructions
+for installing the library. Then pass @code{--enable-libvpx} to configure to
+enable it.
+
+@float NOTE
+LCEVCdec is under the BSD-3-Clause-Clear License.
+@end float
+
 @section OpenH264
 
 FFmpeg can make use of the OpenH264 library for H.264 decoding and encoding.
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 771e2b597e..71bc3c8075 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -121,6 +121,7 @@  OBJS-$(CONFIG_INTRAX8)                 += intrax8.o intrax8dsp.o msmpeg4_vc1_dat
 OBJS-$(CONFIG_IVIDSP)                  += ivi_dsp.o
 OBJS-$(CONFIG_JNI)                     += ffjni.o jni.o
 OBJS-$(CONFIG_JPEGTABLES)              += jpegtables.o
+OBJS-$(CONFIG_LIBLCEVC_DEC)            += lcevcdec.o
 OBJS-$(CONFIG_LCMS2)                   += fflcms2.o
 OBJS-$(CONFIG_LLAUDDSP)                += lossless_audiodsp.o
 OBJS-$(CONFIG_LLVIDDSP)                += lossless_videodsp.o
diff --git a/libavcodec/lcevcdec.c b/libavcodec/lcevcdec.c
new file mode 100644
index 0000000000..4edb0b72dc
--- /dev/null
+++ b/libavcodec/lcevcdec.c
@@ -0,0 +1,276 @@ 
+/*
+ * 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 "libavutil/avassert.h"
+#include "libavutil/frame.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/log.h"
+#include "libavutil/mem.h"
+#include "decode.h"
+#include "lcevcdec.h"
+
+static LCEVC_ColorFormat map_format(int format)
+{
+    switch (format) {
+    case AV_PIX_FMT_YUV420P:
+        return LCEVC_I420_8;
+    case AV_PIX_FMT_YUV420P10:
+        return LCEVC_I420_10_LE;
+    case AV_PIX_FMT_NV12:
+        return LCEVC_NV12_8;
+    case AV_PIX_FMT_NV21:
+        return LCEVC_NV21_8;
+    case AV_PIX_FMT_GRAY8:
+        return LCEVC_GRAY_8;
+    }
+
+    return LCEVC_ColorFormat_Unknown;
+}
+
+static int alloc_base_frame(void *logctx, LCEVC_DecoderHandle decoder,
+                            const AVFrame *frame, LCEVC_PictureHandle *picture)
+{
+    LCEVC_PictureDesc desc;
+    LCEVC_ColorFormat fmt = map_format(frame->format);
+    LCEVC_PictureLockHandle lock;
+    uint8_t *data[4] = { NULL };
+    int linesizes[4] = { 0 };
+    uint32_t planes;
+    LCEVC_ReturnCode res;
+
+    res = LCEVC_DefaultPictureDesc(&desc, fmt, frame->width, frame->height);
+    if (res != LCEVC_Success)
+		return AVERROR_EXTERNAL;
+
+    desc.cropTop    = frame->crop_top;
+    desc.cropBottom = frame->crop_bottom;
+    desc.cropLeft   = frame->crop_left;
+    desc.cropRight  = frame->crop_right;
+    desc.sampleAspectRatioNum  = frame->sample_aspect_ratio.num;
+    desc.sampleAspectRatioDen  = frame->sample_aspect_ratio.den;
+
+    /* Allocate LCEVC Picture */
+    res = LCEVC_AllocPicture(decoder, &desc, picture);
+    if (res != LCEVC_Success)
+        return AVERROR_EXTERNAL;
+
+    res = LCEVC_LockPicture(decoder, *picture, LCEVC_Access_Write, &lock);
+    if (res != LCEVC_Success)
+        return AVERROR_EXTERNAL;
+
+    res = LCEVC_GetPicturePlaneCount(decoder, *picture, &planes);
+    if (res != LCEVC_Success)
+        return AVERROR_EXTERNAL;
+
+    for (unsigned i = 0; i < planes; i++) {
+        LCEVC_PicturePlaneDesc plane;
+
+        res = LCEVC_GetPictureLockPlaneDesc(decoder, lock, i, &plane);
+        if (res != LCEVC_Success)
+            return AVERROR_EXTERNAL;
+
+        data[i] = plane.firstSample;
+        linesizes[i] = plane.rowByteStride;
+    }
+
+    av_image_copy2(data, linesizes, frame->data, frame->linesize,
+                   frame->format, frame->width, frame->height);
+
+    res = LCEVC_UnlockPicture(decoder, lock);
+    if (res != LCEVC_Success)
+        return AVERROR_EXTERNAL;
+
+    return 0;
+}
+
+static int alloc_enhanced_frame(void *logctx, LCEVC_DecoderHandle decoder,
+                                const AVFrame *frame, LCEVC_PictureHandle *picture)
+{
+    LCEVC_PictureDesc desc ;
+    LCEVC_ColorFormat fmt = map_format(frame->format);
+    LCEVC_PicturePlaneDesc planes[4] = { 0 };
+    int width = frame->width * 2 / FFMAX(frame->sample_aspect_ratio.den, 1);
+    int height = frame->height * 2 / FFMAX(frame->sample_aspect_ratio.num, 1);
+    LCEVC_ReturnCode res;
+
+    res = LCEVC_DefaultPictureDesc(&desc, fmt, width, height);
+    if (res != LCEVC_Success)
+        return AVERROR_EXTERNAL;
+
+    /* Set plane description */
+    for (int i = 0; i < 4; i++) {
+        planes[i].firstSample = frame->data[i];
+        planes[i].rowByteStride = frame->linesize[i];
+    }
+
+    /* Allocate LCEVC Picture */
+    res = LCEVC_AllocPictureExternal(decoder, &desc, NULL, planes, picture);
+    if (res != LCEVC_Success)
+        return AVERROR_EXTERNAL;
+
+    return 0;
+}
+
+int ff_lcevc_send_frame(void *logctx, FFLCEVCContext *lcevc, const AVFrame *in)
+{
+    const AVFrameSideData *sd = av_frame_get_side_data(in, AV_FRAME_DATA_LCEVC);
+    LCEVC_PictureHandle picture;
+    LCEVC_ReturnCode res;
+    int ret = 0;
+
+    if (!sd)
+        return 0;
+
+    res = LCEVC_SendDecoderEnhancementData(lcevc->decoder, in->pts, 0, sd->data, sd->size);
+    if (res != LCEVC_Success)
+        return AVERROR_EXTERNAL;
+
+    ret = alloc_base_frame(logctx, lcevc->decoder, in, &picture);
+    if (ret < 0)
+        return ret;
+
+    res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, 0, picture, -1, NULL);
+    if (res != LCEVC_Success)
+        return AVERROR_EXTERNAL;
+
+    memset(&picture, 0, sizeof(picture));
+    ret = alloc_enhanced_frame(logctx, lcevc->decoder, in, &picture);
+    if (ret < 0)
+        return ret;
+
+    res = LCEVC_SendDecoderPicture(lcevc->decoder, picture);
+    if (res != LCEVC_Success)
+        return AVERROR_EXTERNAL;
+
+    return 0;
+}
+
+static int generate_output(void *logctx, FFLCEVCContext *lcevc, AVFrame *out)
+{
+    LCEVC_PictureDesc desc;
+    LCEVC_DecodeInformation info;
+    LCEVC_PictureHandle picture;
+    LCEVC_ReturnCode res;
+
+    res = LCEVC_ReceiveDecoderPicture(lcevc->decoder, &picture, &info);
+    if (res != LCEVC_Success)
+        return AVERROR_EXTERNAL;
+
+    res = LCEVC_GetPictureDesc(lcevc->decoder, picture, &desc);
+    if (res != LCEVC_Success)
+        return AVERROR_EXTERNAL;
+
+    out->crop_top = desc.cropTop;
+    out->crop_bottom = desc.cropBottom;
+    out->crop_left = desc.cropLeft;
+    out->crop_right = desc.cropRight;
+    out->sample_aspect_ratio.num = desc.sampleAspectRatioNum;
+    out->sample_aspect_ratio.den = desc.sampleAspectRatioDen;
+    out->width = desc.width + out->crop_left + out->crop_right;
+    out->height = desc.height + out->crop_top + out->crop_bottom;
+
+    return 0;
+}
+
+int ff_lcevc_receive_frame(void *logctx, FFLCEVCContext *lcevc, AVFrame *out)
+{
+    LCEVC_PictureHandle picture;
+    LCEVC_ReturnCode res;
+    int ret;
+
+    ret = generate_output(logctx, lcevc, out);
+    if (ret < 0)
+        return ret;
+
+    res = LCEVC_ReceiveDecoderBase (lcevc->decoder, &picture);
+    if (res != LCEVC_Success)
+        return AVERROR_EXTERNAL;
+
+    res = LCEVC_FreePicture(lcevc->decoder, picture);
+    if (res != LCEVC_Success)
+        return AVERROR_EXTERNAL;
+
+    return 0;
+}
+
+int ff_lcevc_process(void *logctx, AVFrame *frame)
+{
+    FrameDecodeData  *fdd = (FrameDecodeData*)frame->private_ref->data;
+    AVBufferRef      *ref = (AVBufferRef*)fdd->post_process_opaque;
+    FFLCEVCContext *lcevc = (FFLCEVCContext*)ref->data;
+    int ret;
+
+    ret = ff_lcevc_send_frame(logctx, lcevc, frame);
+    if (ret < 0)
+        return ret;
+
+    ff_lcevc_receive_frame(logctx, lcevc, frame);
+    if (ret < 0)
+        return ret;
+
+    return 0;
+}
+
+static void event_callback(LCEVC_DecoderHandle dec, LCEVC_Event event,
+    LCEVC_PictureHandle pic, const LCEVC_DecodeInformation *info,
+    const uint8_t *data, uint32_t size, void *logctx)
+{
+    switch (event) {
+    case LCEVC_Log:
+        av_log(logctx, AV_LOG_INFO, "%s\n", data);
+        break;
+    default:
+        break;
+    }
+}
+
+int ff_lcevc_init(FFLCEVCContext *lcevc, void *logctx)
+{
+    LCEVC_AccelContextHandle dummy = { 0 };
+
+    int32_t events[] = { LCEVC_Log };
+
+    if (LCEVC_CreateDecoder(&lcevc->decoder, dummy) != LCEVC_Success) {
+        av_log(logctx, AV_LOG_ERROR, "Failed to create LCEVC decoder\n");
+        return AVERROR_EXTERNAL;
+    }
+
+    LCEVC_ConfigureDecoderInt(lcevc->decoder, "log_level", 4);
+    LCEVC_ConfigureDecoderIntArray(lcevc->decoder, "events", FF_ARRAY_ELEMS(events), events);
+    LCEVC_SetDecoderEventCallback(lcevc->decoder, event_callback, logctx);
+
+    if (LCEVC_InitializeDecoder(lcevc->decoder) != LCEVC_Success) {
+        av_log(logctx, AV_LOG_ERROR, "Failed to initialize LCEVC decoder\n");
+        return AVERROR_EXTERNAL;
+    }
+
+    return 0;
+}
+
+void ff_lcevc_free(void *opaque, uint8_t *data)
+{
+    FFLCEVCContext *lcevc = opaque;
+    LCEVC_DestroyDecoder(lcevc->decoder);
+    av_free(data);
+}
+
+void ff_lcevc_unref(void *opaque)
+{
+    AVBufferRef *ref = opaque;
+    av_buffer_unref(&ref);
+}
diff --git a/libavcodec/lcevcdec.h b/libavcodec/lcevcdec.h
new file mode 100644
index 0000000000..fe105371d3
--- /dev/null
+++ b/libavcodec/lcevcdec.h
@@ -0,0 +1,44 @@ 
+/*
+ * 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
+ */
+
+#ifndef AVCODEC_LCEVCDEC_H
+#define AVCODEC_LCEVCDEC_H
+
+#include "config_components.h"
+
+#include <stdint.h>
+#if CONFIG_LIBLCEVC_DEC
+#include <LCEVC/lcevc_dec.h>
+#else
+typedef uintptr_t LCEVC_DecoderHandle;
+#endif
+
+typedef struct FFLCEVCContext {
+    LCEVC_DecoderHandle decoder;
+} FFLCEVCContext;
+
+struct AVFrame;
+
+int ff_lcevc_process(void *logctx, struct AVFrame *frame);
+int ff_lcevc_send_frame(void *logctx, FFLCEVCContext *lcevc, const AVFrame *in);
+int ff_lcevc_receive_frame(void *logctx, FFLCEVCContext *lcevc, AVFrame *out);
+int ff_lcevc_init(FFLCEVCContext *lcevc, void *logctx);
+void ff_lcevc_unref(void *opaque);
+void ff_lcevc_free(void *opaque, uint8_t *data);
+
+#endif /* AVCODEC_LCEVCDEC_H */