@@ -407,7 +407,7 @@ OBJS-$(CONFIG_H263_V4L2M2M_ENCODER) += v4l2_m2m_enc.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 \
- h264_refs.o \
+ h264_refs.o lcevcdec.o \
h264_slice.o h264data.o h274.o
OBJS-$(CONFIG_H264_AMF_ENCODER) += amfenc_h264.o
OBJS-$(CONFIG_H264_CUVID_DECODER) += cuviddec.o
@@ -418,6 +418,11 @@ typedef struct RcOverride{
* Do not apply film grain, export it instead.
*/
#define AV_CODEC_EXPORT_DATA_FILM_GRAIN (1 << 3)
+/**
+ * Decoding only.
+ * Do not apply picture enhancement layers, export them instead.
+ */
+#define AV_CODEC_EXPORT_DATA_ENHANCEMENTS (1 << 3)
/**
* The decoder will keep a reference to the frame and may reuse it later.
@@ -103,6 +103,7 @@ static void h264_copy_picture_params(H264Picture *dst, const H264Picture *src)
dst->mb_height = src->mb_height;
dst->mb_stride = src->mb_stride;
dst->needs_fg = src->needs_fg;
+ dst->needs_lcevc = src->needs_lcevc;
}
int ff_h264_ref_picture(H264Picture *dst, const H264Picture *src)
@@ -191,6 +191,13 @@ static int alloc_picture(H264Context *h, H264Picture *pic)
av_assert0(!pic->f->data[0]);
+#if CONFIG_LIBLCEVC_DEC
+ if (pic->needs_lcevc) {
+ pic->f->width = FFMAX(h->avctx->width, h->avctx->coded_width) * 2 / FFMAX(h->avctx->sample_aspect_ratio.den, 1);
+ pic->f->height = FFMAX(h->avctx->height, h->avctx->coded_height) * 2 / FFMAX(h->avctx->sample_aspect_ratio.num, 1);
+ }
+#endif
+
pic->tf.f = pic->f;
ret = ff_thread_get_ext_buffer(h->avctx, &pic->tf,
pic->reference ? AV_GET_BUFFER_FLAG_REF : 0);
@@ -206,6 +213,13 @@ static int alloc_picture(H264Context *h, H264Picture *pic)
goto fail;
}
+#if CONFIG_LIBLCEVC_DEC
+ if (pic->needs_lcevc) {
+ pic->f->width = FFMAX(h->avctx->width, h->avctx->coded_width);
+ pic->f->height = FFMAX(h->avctx->height, h->avctx->coded_height);
+ }
+#endif
+
ret = ff_hwaccel_frame_priv_alloc(h->avctx, &pic->hwaccel_picture_private);
if (ret < 0)
goto fail;
@@ -459,6 +473,8 @@ int ff_h264_update_thread_context(AVCodecContext *dst,
h->recovery_frame = h1->recovery_frame;
h->non_gray = h1->non_gray;
+ av_buffer_replace(&h->lcevc, h1->lcevc);
+
return err;
}
@@ -519,6 +535,9 @@ static int h264_frame_start(H264Context *h)
pic->needs_fg = h->sei.common.film_grain_characteristics.present && !h->avctx->hwaccel &&
!(h->avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN);
+ pic->needs_lcevc = h->sei.common.lcevc.info && !h->avctx->hwaccel &&
+ !(h->avctx->export_side_data & AV_CODEC_EXPORT_DATA_ENHANCEMENTS);
+
if ((ret = alloc_picture(h, pic)) < 0)
return ret;
@@ -57,6 +57,10 @@
#include "thread.h"
#include "threadframe.h"
+#if CONFIG_LIBLCEVC_DEC
+#include "lcevcdec.h"
+#endif
+
const uint16_t ff_h264_mb_sizes[4] = { 256, 384, 512, 768 };
int avpriv_h264_has_num_reorder_frames(AVCodecContext *avctx)
@@ -378,6 +382,8 @@ static av_cold int h264_decode_end(AVCodecContext *avctx)
h264_free_pic(h, &h->cur_pic);
h264_free_pic(h, &h->last_pic_for_ec);
+ av_buffer_unref(&h->lcevc);
+
return 0;
}
@@ -405,6 +411,9 @@ FF_ENABLE_DEPRECATION_WARNINGS
#endif
if (!avctx->internal->is_copy) {
+#if CONFIG_LIBLCEVC_DEC
+ FFLCEVCContext *lcevc;
+#endif
if (avctx->extradata_size > 0 && avctx->extradata) {
ret = ff_h264_decode_extradata(avctx->extradata, avctx->extradata_size,
&h->ps, &h->is_avc, &h->nal_length_size,
@@ -419,6 +428,21 @@ FF_ENABLE_DEPRECATION_WARNINGS
ret = 0;
}
}
+#if CONFIG_LIBLCEVC_DEC
+ lcevc = av_mallocz(sizeof(FFLCEVCContext));
+ ret = ff_lcevc_init(lcevc, avctx);
+ if (ret < 0) {
+ int explode = avctx->err_recognition & AV_EF_EXPLODE;
+ av_log(avctx, explode ? AV_LOG_ERROR: AV_LOG_WARNING,
+ "Error initializing LCEVC\n");
+ if (explode) {
+ av_free(lcevc);
+ return ret;
+ }
+ ret = 0;
+ }
+ h->lcevc = av_buffer_create(lcevc, sizeof(FFLCEVCContext), ff_lcevc_free, lcevc, 0);
+#endif
}
if (h->ps.sps && h->ps.sps->bitstream_restriction_flag &&
@@ -668,9 +692,23 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size)
h->setup_finished = 1;
}
- if (h->avctx->hwaccel &&
- (ret = FF_HW_CALL(h->avctx, start_frame, buf, buf_size)) < 0)
- goto end;
+ if (h->avctx->hwaccel) {
+ ret = FF_HW_CALL(h->avctx, start_frame, buf, buf_size);
+ if (ret < 0)
+ goto end;
+ }
+#if CONFIG_LIBLCEVC_DEC
+ else if (h->cur_pic_ptr->needs_lcevc) {
+ FrameDecodeData *fdd = (FrameDecodeData*)h->cur_pic_ptr->f->private_ref->data;
+ fdd->post_process_opaque = av_buffer_ref(h->lcevc);
+ if (!fdd->post_process_opaque) {
+ ret = -1;
+ goto end;
+ }
+ fdd->post_process_opaque_free = ff_lcevc_unref;
+ fdd->post_process = ff_lcevc_process;
+ }
+#endif
}
max_slice_ctx = avctx->hwaccel ? 1 : h->nb_slice_ctx;
@@ -905,6 +943,10 @@ static int output_frame(H264Context *h, AVFrame *dst, H264Picture *srcp)
if (!(h->avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN))
av_frame_remove_side_data(dst, AV_FRAME_DATA_FILM_GRAIN_PARAMS);
+#if CONFIG_LIBLCEVC_DEC
+ if (!(h->avctx->export_side_data & AV_CODEC_EXPORT_DATA_ENHANCEMENTS))
+ av_frame_remove_side_data(dst, AV_FRAME_DATA_LCEVC);
+#endif
return 0;
fail:
@@ -154,6 +154,7 @@ typedef struct H264Picture {
int invalid_gap;
int sei_recovery_frame_cnt;
int needs_fg; ///< whether picture needs film grain synthesis (see `f_grain`)
+ int needs_lcevc; ///< whether picture needs LCEVC enhancement
const PPS *pps;
@@ -580,6 +581,8 @@ typedef struct H264Context {
int non_gray; ///< Did we encounter a intra frame after a gray gap frame
int noref_gray;
int skip_gray;
+
+ AVBufferRef *lcevc; // FFLCEVCContext
} H264Context;
extern const uint16_t ff_h264_mb_sizes[4];
Signed-off-by: James Almer <jamrial@gmail.com> --- libavcodec/Makefile | 2 +- libavcodec/avcodec.h | 5 ++++ libavcodec/h264_picture.c | 1 + libavcodec/h264_slice.c | 19 ++++++++++++++++ libavcodec/h264dec.c | 48 ++++++++++++++++++++++++++++++++++++--- libavcodec/h264dec.h | 3 +++ 6 files changed, 74 insertions(+), 4 deletions(-)