ffmpeg/libavcodec/itut35.c
James Almer 151fe3a5ac avcodec/itut35: unref existing buffers before allocating new ones
Finishes fixing memleaks.

Signed-off-by: James Almer <jamrial@gmail.com>
2026-06-02 23:24:19 -03:00

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);
}