mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2026-06-04 06:30:49 +00:00
405 lines
14 KiB
C
405 lines
14 KiB
C
/*
|
|
* 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/buffer.h"
|
|
#include "libavutil/frame.h"
|
|
#include "libavutil/hdr_dynamic_metadata.h"
|
|
#include "libavutil/internal.h"
|
|
#include "libavutil/mem.h"
|
|
|
|
#include "avcodec.h"
|
|
#include "atsc_a53.h"
|
|
#include "bytestream.h"
|
|
#include "decode.h"
|
|
#include "dynamic_hdr_vivid.h"
|
|
#include "dovi_rpu.h"
|
|
#include "itut35.h"
|
|
#include "version.h"
|
|
|
|
int ff_itut_t35_parse_buffer(FFITUTT35 *const itut_t35, const uint8_t *buf,
|
|
size_t buf_size, int flags) {
|
|
GetByteContext gb;
|
|
int provider_code, country_code;
|
|
unsigned int provider_oriented_code = 0;
|
|
|
|
bytestream2_init(&gb, buf, buf_size);
|
|
|
|
if (flags & FF_ITUT_T35_FLAG_COUNTRY_CODE)
|
|
country_code = itut_t35->country_code;
|
|
else {
|
|
country_code = bytestream2_get_byte(&gb);
|
|
if (country_code == 0xFF) {
|
|
if (bytestream2_get_bytes_left(&gb) < 1)
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
bytestream2_skipu(&gb, 1); // itu_t_t35_country_code_extension_byte
|
|
}
|
|
}
|
|
|
|
switch (country_code) {
|
|
case ITU_T_T35_COUNTRY_CODE_US:
|
|
if (bytestream2_get_bytes_left(&gb) < 2)
|
|
return AVERROR_INVALIDDATA;
|
|
provider_code = bytestream2_get_be16u(&gb);
|
|
|
|
switch (provider_code) {
|
|
case ITU_T_T35_PROVIDER_CODE_ATSC:
|
|
if (bytestream2_get_bytes_left(&gb) < 4)
|
|
return AVERROR_INVALIDDATA;
|
|
provider_oriented_code = bytestream2_get_be32u(&gb);
|
|
switch (provider_oriented_code) {
|
|
case MKBETAG('D', 'T', 'G', '1'): // afd_data
|
|
if (bytestream2_get_bytes_left(&gb) < 2)
|
|
return AVERROR_INVALIDDATA;
|
|
if (!(bytestream2_get_byteu(&gb) & 0x40)) // active_format_flag
|
|
return 0; //ignore
|
|
break;
|
|
case MKBETAG('G', 'A', '9', '4'): // closed captions
|
|
break;
|
|
default: // ignore unsupported identifiers
|
|
return 0;
|
|
}
|
|
break;
|
|
case ITU_T_T35_PROVIDER_CODE_AOM:
|
|
if (bytestream2_get_bytes_left(&gb) < 1)
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
provider_oriented_code = bytestream2_get_byteu(&gb);
|
|
if (provider_oriented_code != 0x0001)
|
|
return 0; // ignore
|
|
break;
|
|
case ITU_T_T35_PROVIDER_CODE_SAMSUNG:
|
|
if (bytestream2_get_bytes_left(&gb) < 3)
|
|
return AVERROR_INVALIDDATA;
|
|
provider_oriented_code = bytestream2_get_be16u(&gb);
|
|
int application_identifier = bytestream2_get_byteu(&gb);
|
|
|
|
if (provider_oriented_code != 1 || application_identifier != 4)
|
|
return 0; // ignore
|
|
break;
|
|
case ITU_T_T35_PROVIDER_CODE_DOLBY:
|
|
if (bytestream2_get_bytes_left(&gb) < 4)
|
|
return AVERROR_INVALIDDATA;
|
|
provider_oriented_code = bytestream2_get_be32u(&gb);
|
|
if (provider_oriented_code != 0x800)
|
|
return 0; // ignore
|
|
break;
|
|
case ITU_T_T35_PROVIDER_CODE_SMPTE:
|
|
if (bytestream2_get_bytes_left(&gb) < 2)
|
|
return AVERROR_INVALIDDATA;
|
|
provider_oriented_code = bytestream2_get_be16u(&gb);
|
|
if (provider_oriented_code != 1)
|
|
return 0; // ignore
|
|
break;
|
|
default: // ignore unsupported provider codes
|
|
return 0;
|
|
}
|
|
break;
|
|
case ITU_T_T35_COUNTRY_CODE_UK:
|
|
if (bytestream2_get_bytes_left(&gb) < 3)
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
bytestream2_skipu(&gb, 1); // t35_uk_country_code_second_octet
|
|
provider_code = bytestream2_get_be16u(&gb);
|
|
|
|
switch (provider_code) {
|
|
case ITU_T_T35_PROVIDER_CODE_VNOVA:
|
|
break;
|
|
default: // ignore unsupported provider codes
|
|
return 0;
|
|
}
|
|
break;
|
|
case ITU_T_T35_COUNTRY_CODE_CN:
|
|
if (bytestream2_get_bytes_left(&gb) < 2)
|
|
return AVERROR_INVALIDDATA;
|
|
provider_code = bytestream2_get_be16u(&gb);
|
|
|
|
switch (provider_code) {
|
|
case ITU_T_T35_PROVIDER_CODE_HDR_VIVID:
|
|
if (bytestream2_get_bytes_left(&gb) < 2)
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
provider_oriented_code = bytestream2_get_be16u(&gb);
|
|
if (provider_oriented_code != 0x0005)
|
|
return 0; //ignore
|
|
break;
|
|
default: // ignore unsupported provider codes
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
default: // ignore unsupported country codes
|
|
return 0;
|
|
}
|
|
|
|
if (!bytestream2_get_bytes_left(&gb))
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
itut_t35->payload = gb.buffer;
|
|
itut_t35->payload_size = bytestream2_get_bytes_left(&gb);
|
|
|
|
itut_t35->country_code = country_code;
|
|
itut_t35->provider_code = provider_code;
|
|
itut_t35->provider_oriented_code = provider_oriented_code;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int ff_itut_t35_parse_payload_to_struct(FFITUTT35 *const itut_t35, FFITUTT35Aux *const aux,
|
|
FFITUTT35Meta *metadata, int err_recognition)
|
|
{
|
|
int ret;
|
|
|
|
switch (itut_t35->country_code) {
|
|
case ITU_T_T35_COUNTRY_CODE_US:
|
|
switch (itut_t35->provider_code) {
|
|
case ITU_T_T35_PROVIDER_CODE_AOM:
|
|
ff_aom_uninit_film_grain_params(&metadata->aom_film_grain);
|
|
ret = ff_aom_parse_film_grain_sets(&metadata->aom_film_grain,
|
|
itut_t35->payload, itut_t35->payload_size);
|
|
if (ret < 0)
|
|
return ret;
|
|
break;
|
|
case ITU_T_T35_PROVIDER_CODE_ATSC:
|
|
switch (itut_t35->provider_oriented_code) {
|
|
case MKBETAG('D', 'T', 'G', '1'): // afd_data
|
|
av_buffer_unref(&metadata->afd);
|
|
metadata->afd = av_buffer_alloc(1);
|
|
if (!metadata->afd)
|
|
return AVERROR(ENOMEM);
|
|
|
|
*metadata->afd->data = *itut_t35->payload & 0xf;
|
|
|
|
break;
|
|
case MKBETAG('G', 'A', '9', '4'): // closed captions
|
|
ret = ff_parse_a53_cc(&metadata->a53_cc, itut_t35->payload, itut_t35->payload_size);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
break;
|
|
default: // ignore unsupported identifiers
|
|
break;
|
|
}
|
|
break;
|
|
case ITU_T_T35_PROVIDER_CODE_SAMSUNG: {
|
|
size_t size;
|
|
AVDynamicHDRPlus *hdr_plus = av_dynamic_hdr_plus_alloc(&size);
|
|
if (!hdr_plus)
|
|
return AVERROR(ENOMEM);
|
|
|
|
ret = av_dynamic_hdr_plus_from_t35(hdr_plus, itut_t35->payload,
|
|
itut_t35->payload_size);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
av_buffer_unref(&metadata->hdr_plus);
|
|
metadata->hdr_plus = av_buffer_create((uint8_t *)hdr_plus, size, NULL, NULL, 0);
|
|
if (!metadata->hdr_plus) {
|
|
av_free(hdr_plus);
|
|
return AVERROR(ENOMEM);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case ITU_T_T35_PROVIDER_CODE_DOLBY: {
|
|
AVDOVIMetadata *dovi;
|
|
|
|
if (!aux || !aux->dovi)
|
|
return 0; // ignore
|
|
|
|
ret = ff_dovi_rpu_parse(aux->dovi, itut_t35->payload, itut_t35->payload_size,
|
|
err_recognition);
|
|
if (ret < 0)
|
|
return 0; // ignore
|
|
|
|
ret = ff_dovi_get_metadata(aux->dovi, &dovi);
|
|
if (ret <= 0)
|
|
return ret;
|
|
|
|
av_buffer_unref(&metadata->dovi);
|
|
metadata->dovi = av_buffer_create((uint8_t *)dovi, ret, NULL, NULL, 0);
|
|
if (!metadata->dovi) {
|
|
av_free(dovi);
|
|
return AVERROR(ENOMEM);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case ITU_T_T35_PROVIDER_CODE_SMPTE: {
|
|
size_t size;
|
|
AVDynamicHDRSmpte2094App5 *hdr_smpte2094_app5 = av_dynamic_hdr_smpte2094_app5_alloc(&size);
|
|
if (!hdr_smpte2094_app5)
|
|
return AVERROR(ENOMEM);
|
|
|
|
ret = av_dynamic_hdr_smpte2094_app5_from_t35(hdr_smpte2094_app5, itut_t35->payload,
|
|
itut_t35->payload_size);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
av_buffer_unref(&metadata->hdr_smpte2094_app5);
|
|
metadata->hdr_smpte2094_app5 = av_buffer_create((uint8_t *)hdr_smpte2094_app5, size, NULL, NULL, 0);
|
|
if (!metadata->hdr_smpte2094_app5) {
|
|
av_free(hdr_smpte2094_app5);
|
|
return AVERROR(ENOMEM);
|
|
}
|
|
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case ITU_T_T35_COUNTRY_CODE_UK:
|
|
switch (itut_t35->provider_code) {
|
|
case ITU_T_T35_PROVIDER_CODE_VNOVA:
|
|
av_buffer_unref(&metadata->lcevc);
|
|
metadata->lcevc = av_buffer_alloc(itut_t35->payload_size);
|
|
if (!metadata->lcevc)
|
|
return AVERROR(ENOMEM);
|
|
|
|
memcpy(metadata->lcevc->data, itut_t35->payload, itut_t35->payload_size);
|
|
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case ITU_T_T35_COUNTRY_CODE_CN:
|
|
switch (itut_t35->provider_code) {
|
|
case ITU_T_T35_PROVIDER_CODE_HDR_VIVID: {
|
|
size_t size;
|
|
AVDynamicHDRVivid *hdr_vivid = av_dynamic_hdr_vivid_alloc(&size);
|
|
if (!hdr_vivid)
|
|
return AVERROR(ENOMEM);
|
|
|
|
ret = ff_parse_itu_t_t35_to_dynamic_hdr_vivid(hdr_vivid, itut_t35->payload,
|
|
itut_t35->payload_size);
|
|
if (ret < 0) {
|
|
av_free(hdr_vivid);
|
|
return ret;
|
|
}
|
|
|
|
av_buffer_unref(&metadata->hdr_vivid);
|
|
metadata->hdr_vivid = av_buffer_create((uint8_t *)hdr_vivid, size, NULL, NULL, 0);
|
|
if (!metadata->hdr_vivid) {
|
|
av_free(hdr_vivid);
|
|
return AVERROR(ENOMEM);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
// ignore unsupported provider codes
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ff_itut_t35_parse_payload_to_frame(FFITUTT35 *const itut_t35, FFITUTT35Aux *const aux,
|
|
AVCodecContext *const avctx, AVFrame *const frame)
|
|
{
|
|
FFITUTT35Meta metadata = { 0 };
|
|
int ret;
|
|
|
|
ret = ff_itut_t35_parse_payload_to_struct(itut_t35, aux, &metadata, avctx->err_recognition);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
if (metadata.afd) {
|
|
if (!av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_AFD, metadata.afd))
|
|
av_buffer_unref(&metadata.afd);
|
|
metadata.afd = NULL;
|
|
}
|
|
|
|
if (metadata.a53_cc) {
|
|
ret = ff_frame_new_side_data_from_buf(avctx, frame, AV_FRAME_DATA_A53_CC, &metadata.a53_cc);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
#if FF_API_CODEC_PROPS
|
|
FF_DISABLE_DEPRECATION_WARNINGS
|
|
avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS;
|
|
FF_ENABLE_DEPRECATION_WARNINGS
|
|
#endif
|
|
}
|
|
|
|
if (metadata.aom_film_grain.enable) {
|
|
ret = ff_aom_attach_film_grain_sets(&metadata.aom_film_grain, frame);
|
|
if (ret < 0)
|
|
return ret;
|
|
}
|
|
|
|
if (metadata.hdr_plus) {
|
|
ret = ff_frame_new_side_data_from_buf(avctx, frame, AV_FRAME_DATA_DYNAMIC_HDR_PLUS,
|
|
&metadata.hdr_plus);
|
|
if (ret < 0)
|
|
return ret;
|
|
}
|
|
|
|
if (metadata.dovi) {
|
|
AVFrameSideData *sd = av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_DOVI_METADATA,
|
|
metadata.dovi);
|
|
if (!sd) {
|
|
av_buffer_unref(&metadata.dovi);
|
|
return AVERROR(ENOMEM);
|
|
}
|
|
metadata.dovi = NULL;
|
|
}
|
|
|
|
if (metadata.hdr_smpte2094_app5) {
|
|
ret = ff_frame_new_side_data_from_buf(avctx, frame, AV_FRAME_DATA_DYNAMIC_HDR_SMPTE_2094_APP5,
|
|
&metadata.hdr_smpte2094_app5);
|
|
if (ret < 0)
|
|
return ret;
|
|
}
|
|
|
|
if (metadata.lcevc) {
|
|
ret = ff_frame_new_side_data_from_buf(avctx, frame, AV_FRAME_DATA_LCEVC,
|
|
&metadata.lcevc);
|
|
if (ret < 0)
|
|
return ret;
|
|
}
|
|
|
|
if (metadata.hdr_vivid) {
|
|
ret = ff_frame_new_side_data_from_buf(avctx, frame, AV_FRAME_DATA_DYNAMIC_HDR_VIVID,
|
|
&metadata.hdr_vivid);
|
|
if (ret < 0)
|
|
return ret;
|
|
}
|
|
|
|
ff_itut_t35_unref(&metadata);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void ff_itut_t35_unref(FFITUTT35Meta *metadata)
|
|
{
|
|
ff_aom_uninit_film_grain_params(&metadata->aom_film_grain);
|
|
av_buffer_unref(&metadata->afd);
|
|
av_buffer_unref(&metadata->a53_cc);
|
|
av_buffer_unref(&metadata->hdr_plus);
|
|
av_buffer_unref(&metadata->hdr_smpte2094_app5);
|
|
av_buffer_unref(&metadata->lcevc);
|
|
av_buffer_unref(&metadata->dovi);
|
|
av_buffer_unref(&metadata->hdr_vivid);
|
|
}
|