@@ -2968,7 +2968,7 @@ h263i_decoder_select="h263_decoder"
h263p_decoder_select="h263_decoder"
h263p_encoder_select="h263_encoder"
h264_decoder_select="cabac golomb h264chroma h264dsp h264parse h264pred h264qpel h264_sei videodsp"
-h264_decoder_suggest="error_resilience"
+h264_decoder_suggest="error_resilience liblcevc_dec"
hap_decoder_select="snappy texturedsp"
hap_encoder_deps="libsnappy"
hap_encoder_select="texturedspenc"
@@ -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 << 4)
/**
* 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,11 @@ static int alloc_picture(H264Context *h, H264Picture *pic)
av_assert0(!pic->f->data[0]);
+ 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);
+ }
+
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 +211,11 @@ static int alloc_picture(H264Context *h, H264Picture *pic)
goto fail;
}
+ 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);
+ }
+
ret = ff_hwaccel_frame_priv_alloc(h->avctx, &pic->hwaccel_picture_private);
if (ret < 0)
goto fail;
@@ -459,6 +469,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 +531,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 = CONFIG_LIBLCEVC_DEC && 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;
@@ -38,6 +38,7 @@
#include "libavutil/video_enc_params.h"
#include "codec_internal.h"
+#include "decode.h"
#include "internal.h"
#include "error_resilience.h"
#include "avcodec.h"
@@ -49,6 +50,7 @@
#include "golomb.h"
#include "hwaccel_internal.h"
#include "hwconfig.h"
+#include "lcevcdec.h"
#include "mpegutils.h"
#include "profiles.h"
#include "rectangle.h"
@@ -377,6 +379,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;
}
@@ -404,6 +408,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,
@@ -418,6 +425,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 &&
@@ -667,9 +689,20 @@ 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;
+ } else if (CONFIG_LIBLCEVC_DEC && 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;
+ }
}
max_slice_ctx = avctx->hwaccel ? 1 : h->nb_slice_ctx;
@@ -904,6 +937,8 @@ 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 (!(h->avctx->export_side_data & AV_CODEC_EXPORT_DATA_ENHANCEMENTS))
+ av_frame_remove_side_data(dst, AV_FRAME_DATA_LCEVC);
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> --- configure | 2 +- libavcodec/avcodec.h | 5 +++++ libavcodec/h264_picture.c | 1 + libavcodec/h264_slice.c | 15 ++++++++++++++ libavcodec/h264dec.c | 41 ++++++++++++++++++++++++++++++++++++--- libavcodec/h264dec.h | 3 +++ 6 files changed, 63 insertions(+), 4 deletions(-)