@@ -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
@@ -6859,6 +6861,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
@@ -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-liblcevc-dec} 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.
@@ -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
new file mode 100644
@@ -0,0 +1,289 @@
+/*
+ * 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 1;
+
+ 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;
+
+ if (!lcevc->initialized) {
+ ret = ff_lcevc_init(lcevc, logctx);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = ff_lcevc_send_frame(logctx, lcevc, frame);
+ if (ret)
+ return ret < 0 ? ret : 0;
+
+ 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->initialized)
+ return 0;
+
+ 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");
+ LCEVC_DestroyDecoder(lcevc->decoder);
+ return AVERROR_EXTERNAL;
+ }
+
+ lcevc->initialized = 1;
+
+ return 0;
+}
+
+void ff_lcevc_free(void *opaque, uint8_t *data)
+{
+ FFLCEVCContext *lcevc = opaque;
+ if (lcevc->initialized)
+ LCEVC_DestroyDecoder(lcevc->decoder);
+ lcevc->initialized = 0;
+ av_free(data);
+}
+
+void ff_lcevc_unref(void *opaque)
+{
+ AVBufferRef *ref = opaque;
+ av_buffer_unref(&ref);
+}
new file mode 100644
@@ -0,0 +1,45 @@
+/*
+ * 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;
+ int initialized;
+} 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 */
Signed-off-by: James Almer <jamrial@gmail.com> --- configure | 3 + doc/general_contents.texi | 13 ++ libavcodec/Makefile | 1 + libavcodec/lcevcdec.c | 289 ++++++++++++++++++++++++++++++++++++++ libavcodec/lcevcdec.h | 45 ++++++ 5 files changed, 351 insertions(+) create mode 100644 libavcodec/lcevcdec.c create mode 100644 libavcodec/lcevcdec.h