avcodec/av1dec: parse and export Metadata OBUs
This includes Mastering Display, Content light level, and some ITU-T T35 metadata like closed captions and HDR10+. Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
parent
7a8560cb22
commit
d6d5765051
@ -21,13 +21,16 @@
|
||||
#include "config_components.h"
|
||||
|
||||
#include "libavutil/film_grain_params.h"
|
||||
#include "libavutil/mastering_display_metadata.h"
|
||||
#include "libavutil/pixdesc.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "avcodec.h"
|
||||
#include "av1dec.h"
|
||||
#include "atsc_a53.h"
|
||||
#include "bytestream.h"
|
||||
#include "codec_internal.h"
|
||||
#include "decode.h"
|
||||
#include "dynamic_hdr10_plus.h"
|
||||
#include "hwconfig.h"
|
||||
#include "profiles.h"
|
||||
#include "thread.h"
|
||||
@ -645,6 +648,7 @@ fail:
|
||||
static av_cold int av1_decode_free(AVCodecContext *avctx)
|
||||
{
|
||||
AV1DecContext *s = avctx->priv_data;
|
||||
AV1RawMetadataITUTT35 itut_t35;
|
||||
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(s->ref); i++) {
|
||||
av1_frame_unref(avctx, &s->ref[i]);
|
||||
@ -655,8 +659,14 @@ static av_cold int av1_decode_free(AVCodecContext *avctx)
|
||||
|
||||
av_buffer_unref(&s->seq_ref);
|
||||
av_buffer_unref(&s->header_ref);
|
||||
av_buffer_unref(&s->cll_ref);
|
||||
av_buffer_unref(&s->mdcv_ref);
|
||||
av_freep(&s->tile_group_info);
|
||||
|
||||
while (s->itut_t35_fifo && av_fifo_read(s->itut_t35_fifo, &itut_t35, 1) >= 0)
|
||||
av_buffer_unref(&itut_t35.payload_ref);
|
||||
av_fifo_freep2(&s->itut_t35_fifo);
|
||||
|
||||
ff_cbs_fragment_free(&s->current_obu);
|
||||
ff_cbs_close(&s->cbc);
|
||||
|
||||
@ -771,6 +781,11 @@ static av_cold int av1_decode_init(AVCodecContext *avctx)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
s->itut_t35_fifo = av_fifo_alloc2(1, sizeof(AV1RawMetadataITUTT35),
|
||||
AV_FIFO_FLAG_AUTO_GROW);
|
||||
if (!s->itut_t35_fifo)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
av_opt_set_int(s->cbc->priv_data, "operating_point", s->operating_point, 0);
|
||||
|
||||
if (avctx->extradata && avctx->extradata_size) {
|
||||
@ -852,6 +867,107 @@ fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int export_itut_t35(AVCodecContext *avctx, AVFrame *frame,
|
||||
const AV1RawMetadataITUTT35 *itut_t35)
|
||||
{
|
||||
GetByteContext gb;
|
||||
int ret, provider_code;
|
||||
|
||||
bytestream2_init(&gb, itut_t35->payload, itut_t35->payload_size);
|
||||
|
||||
provider_code = bytestream2_get_be16(&gb);
|
||||
switch (provider_code) {
|
||||
case 0x31: { // atsc_provider_code
|
||||
uint32_t user_identifier = bytestream2_get_be32(&gb);
|
||||
switch (user_identifier) {
|
||||
case MKBETAG('G', 'A', '9', '4'): { // closed captions
|
||||
AVBufferRef *buf = NULL;
|
||||
|
||||
ret = ff_parse_a53_cc(&buf, gb.buffer, bytestream2_get_bytes_left(&gb));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (!ret)
|
||||
break;
|
||||
|
||||
if (!av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_A53_CC, buf))
|
||||
av_buffer_unref(&buf);
|
||||
|
||||
avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS;
|
||||
break;
|
||||
}
|
||||
default: // ignore unsupported identifiers
|
||||
break;
|
||||
}
|
||||
}
|
||||
case 0x3C: { // smpte_provider_code
|
||||
AVDynamicHDRPlus *hdrplus;
|
||||
int provider_oriented_code = bytestream2_get_be16(&gb);
|
||||
int application_identifier = bytestream2_get_byte(&gb);
|
||||
|
||||
if (itut_t35->itu_t_t35_country_code != 0xB5 ||
|
||||
provider_oriented_code != 1 || application_identifier != 4)
|
||||
break;
|
||||
|
||||
hdrplus = av_dynamic_hdr_plus_create_side_data(frame);
|
||||
if (!hdrplus)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
ret = ff_parse_itu_t_t35_to_dynamic_hdr10_plus(hdrplus, gb.buffer,
|
||||
bytestream2_get_bytes_left(&gb));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
default: // ignore unsupported provider codes
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int export_metadata(AVCodecContext *avctx, AVFrame *frame)
|
||||
{
|
||||
AV1DecContext *s = avctx->priv_data;
|
||||
AV1RawMetadataITUTT35 itut_t35;
|
||||
int ret = 0;
|
||||
|
||||
if (s->mdcv) {
|
||||
AVMasteringDisplayMetadata *mastering = av_mastering_display_metadata_create_side_data(frame);
|
||||
if (!mastering)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
mastering->display_primaries[i][0] = av_make_q(s->mdcv->primary_chromaticity_x[i], 1 << 16);
|
||||
mastering->display_primaries[i][1] = av_make_q(s->mdcv->primary_chromaticity_y[i], 1 << 16);
|
||||
}
|
||||
mastering->white_point[0] = av_make_q(s->mdcv->white_point_chromaticity_x, 1 << 16);
|
||||
mastering->white_point[1] = av_make_q(s->mdcv->white_point_chromaticity_y, 1 << 16);
|
||||
|
||||
mastering->max_luminance = av_make_q(s->mdcv->luminance_max, 1 << 8);
|
||||
mastering->min_luminance = av_make_q(s->mdcv->luminance_min, 1 << 14);
|
||||
|
||||
mastering->has_primaries = 1;
|
||||
mastering->has_luminance = 1;
|
||||
}
|
||||
|
||||
if (s->cll) {
|
||||
AVContentLightMetadata *light = av_content_light_metadata_create_side_data(frame);
|
||||
if (!light)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
light->MaxCLL = s->cll->max_cll;
|
||||
light->MaxFALL = s->cll->max_fall;
|
||||
}
|
||||
|
||||
while (av_fifo_read(s->itut_t35_fifo, &itut_t35, 1) >= 0) {
|
||||
if (ret >= 0)
|
||||
ret = export_itut_t35(avctx, frame, &itut_t35);
|
||||
av_buffer_unref(&itut_t35.payload_ref);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int export_film_grain(AVCodecContext *avctx, AVFrame *frame)
|
||||
{
|
||||
AV1DecContext *s = avctx->priv_data;
|
||||
@ -928,6 +1044,12 @@ static int set_output_frame(AVCodecContext *avctx, AVFrame *frame,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = export_metadata(avctx, frame);
|
||||
if (ret < 0) {
|
||||
av_frame_unref(frame);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN) {
|
||||
ret = export_film_grain(avctx, frame);
|
||||
if (ret < 0) {
|
||||
@ -1173,7 +1295,47 @@ static int av1_decode_frame(AVCodecContext *avctx, AVFrame *frame,
|
||||
case AV1_OBU_TILE_LIST:
|
||||
case AV1_OBU_TEMPORAL_DELIMITER:
|
||||
case AV1_OBU_PADDING:
|
||||
break;
|
||||
case AV1_OBU_METADATA:
|
||||
switch (obu->obu.metadata.metadata_type) {
|
||||
case AV1_METADATA_TYPE_HDR_CLL:
|
||||
av_buffer_unref(&s->cll_ref);
|
||||
s->cll_ref = av_buffer_ref(unit->content_ref);
|
||||
if (!s->cll_ref) {
|
||||
s->cll = NULL;
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto end;
|
||||
}
|
||||
s->cll = &obu->obu.metadata.metadata.hdr_cll;
|
||||
break;
|
||||
case AV1_METADATA_TYPE_HDR_MDCV:
|
||||
av_buffer_unref(&s->mdcv_ref);
|
||||
s->mdcv_ref = av_buffer_ref(unit->content_ref);
|
||||
if (!s->mdcv_ref) {
|
||||
s->mdcv = NULL;
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto end;
|
||||
}
|
||||
s->mdcv = &obu->obu.metadata.metadata.hdr_mdcv;
|
||||
break;
|
||||
case AV1_METADATA_TYPE_ITUT_T35: {
|
||||
AV1RawMetadataITUTT35 itut_t35;
|
||||
memcpy(&itut_t35, &obu->obu.metadata.metadata.itut_t35, sizeof(itut_t35));
|
||||
itut_t35.payload_ref = av_buffer_ref(obu->obu.metadata.metadata.itut_t35.payload_ref);
|
||||
if (!itut_t35.payload_ref) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto end;
|
||||
}
|
||||
ret = av_fifo_write(s->itut_t35_fifo, &itut_t35, 1);
|
||||
if (ret < 0) {
|
||||
av_buffer_unref(&itut_t35.payload_ref);
|
||||
goto end;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
av_log(avctx, AV_LOG_DEBUG,
|
||||
@ -1218,6 +1380,7 @@ end:
|
||||
static void av1_decode_flush(AVCodecContext *avctx)
|
||||
{
|
||||
AV1DecContext *s = avctx->priv_data;
|
||||
AV1RawMetadataITUTT35 itut_t35;
|
||||
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(s->ref); i++)
|
||||
av1_frame_unref(avctx, &s->ref[i]);
|
||||
@ -1226,6 +1389,10 @@ static void av1_decode_flush(AVCodecContext *avctx)
|
||||
s->operating_point_idc = 0;
|
||||
s->raw_frame_header = NULL;
|
||||
s->raw_seq = NULL;
|
||||
s->cll = NULL;
|
||||
s->mdcv = NULL;
|
||||
while (av_fifo_read(s->itut_t35_fifo, &itut_t35, 1) >= 0)
|
||||
av_buffer_unref(&itut_t35.payload_ref);
|
||||
|
||||
ff_cbs_flush(s->cbc);
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "libavutil/fifo.h"
|
||||
#include "libavutil/buffer.h"
|
||||
#include "libavutil/frame.h"
|
||||
#include "libavutil/pixfmt.h"
|
||||
@ -73,6 +74,13 @@ typedef struct AV1DecContext {
|
||||
AVBufferRef *header_ref;
|
||||
AV1RawFrameHeader *raw_frame_header;
|
||||
TileGroupInfo *tile_group_info;
|
||||
|
||||
AVBufferRef *cll_ref;
|
||||
AV1RawMetadataHDRCLL *cll;
|
||||
AVBufferRef *mdcv_ref;
|
||||
AV1RawMetadataHDRMDCV *mdcv;
|
||||
AVFifo *itut_t35_fifo;
|
||||
|
||||
uint16_t tile_num;
|
||||
uint16_t tg_start;
|
||||
uint16_t tg_end;
|
||||
|
Loading…
Reference in New Issue
Block a user