You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-11-23 21:54:53 +02:00
avformat/vvc: Fix crash on allocation failure, avoid allocations
This is the VVC version of 8b5d155301.
(Hint: This ensures that the order of NALU arrays is OPI-VPS-SPS-PPS-
Prefix-SEI-Suffix-SEI, regardless of the order in the original
extradata. I hope this is right.)
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
This commit is contained in:
@@ -32,6 +32,16 @@
|
|||||||
#include "avio_internal.h"
|
#include "avio_internal.h"
|
||||||
#include "vvc.h"
|
#include "vvc.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
OPI_INDEX,
|
||||||
|
VPS_INDEX,
|
||||||
|
SPS_INDEX,
|
||||||
|
PPS_INDEX,
|
||||||
|
SEI_PREFIX_INDEX,
|
||||||
|
SEI_SUFFIX_INDEX,
|
||||||
|
NB_ARRAYS
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct VVCCNALUnitArray {
|
typedef struct VVCCNALUnitArray {
|
||||||
uint8_t array_completeness;
|
uint8_t array_completeness;
|
||||||
uint8_t NAL_unit_type;
|
uint8_t NAL_unit_type;
|
||||||
@@ -67,7 +77,7 @@ typedef struct VVCDecoderConfigurationRecord {
|
|||||||
uint16_t max_picture_height;
|
uint16_t max_picture_height;
|
||||||
uint16_t avg_frame_rate;
|
uint16_t avg_frame_rate;
|
||||||
uint8_t num_of_arrays;
|
uint8_t num_of_arrays;
|
||||||
VVCCNALUnitArray *array;
|
VVCCNALUnitArray arrays[NB_ARRAYS];
|
||||||
} VVCDecoderConfigurationRecord;
|
} VVCDecoderConfigurationRecord;
|
||||||
|
|
||||||
static void vvcc_update_ptl(VVCDecoderConfigurationRecord *vvcc,
|
static void vvcc_update_ptl(VVCDecoderConfigurationRecord *vvcc,
|
||||||
@@ -432,32 +442,11 @@ static void nal_unit_parse_header(GetBitContext *gb, uint8_t *nal_type)
|
|||||||
|
|
||||||
static int vvcc_array_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size,
|
static int vvcc_array_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size,
|
||||||
uint8_t nal_type, int ps_array_completeness,
|
uint8_t nal_type, int ps_array_completeness,
|
||||||
VVCDecoderConfigurationRecord *vvcc)
|
VVCCNALUnitArray *array)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
uint8_t index;
|
|
||||||
uint16_t num_nalus;
|
uint16_t num_nalus;
|
||||||
VVCCNALUnitArray *array;
|
|
||||||
|
|
||||||
for (index = 0; index < vvcc->num_of_arrays; index++)
|
|
||||||
if (vvcc->array[index].NAL_unit_type == nal_type)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (index >= vvcc->num_of_arrays) {
|
|
||||||
uint8_t i;
|
|
||||||
|
|
||||||
ret =
|
|
||||||
av_reallocp_array(&vvcc->array, index + 1,
|
|
||||||
sizeof(VVCCNALUnitArray));
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
for (i = vvcc->num_of_arrays; i <= index; i++)
|
|
||||||
memset(&vvcc->array[i], 0, sizeof(VVCCNALUnitArray));
|
|
||||||
vvcc->num_of_arrays = index + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
array = &vvcc->array[index];
|
|
||||||
num_nalus = array->num_nalus;
|
num_nalus = array->num_nalus;
|
||||||
|
|
||||||
ret = av_reallocp_array(&array->nal_unit, num_nalus + 1, sizeof(uint8_t *));
|
ret = av_reallocp_array(&array->nal_unit, num_nalus + 1, sizeof(uint8_t *));
|
||||||
@@ -504,7 +493,8 @@ static int vvcc_array_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size,
|
|||||||
|
|
||||||
static int vvcc_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size,
|
static int vvcc_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size,
|
||||||
int ps_array_completeness,
|
int ps_array_completeness,
|
||||||
VVCDecoderConfigurationRecord *vvcc)
|
VVCDecoderConfigurationRecord *vvcc,
|
||||||
|
unsigned array_idx)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
GetBitContext gbc;
|
GetBitContext gbc;
|
||||||
@@ -529,18 +519,15 @@ static int vvcc_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size,
|
|||||||
* vvcc. Perhaps the SEI playload type should be checked
|
* vvcc. Perhaps the SEI playload type should be checked
|
||||||
* and non-declarative SEI messages discarded?
|
* and non-declarative SEI messages discarded?
|
||||||
*/
|
*/
|
||||||
switch (nal_type) {
|
ret = vvcc_array_add_nal_unit(nal_buf, nal_size, nal_type,
|
||||||
case VVC_OPI_NUT:
|
ps_array_completeness,
|
||||||
case VVC_VPS_NUT:
|
&vvcc->arrays[array_idx]);
|
||||||
case VVC_SPS_NUT:
|
if (ret < 0)
|
||||||
case VVC_PPS_NUT:
|
goto end;
|
||||||
case VVC_PREFIX_SEI_NUT:
|
if (vvcc->arrays[array_idx].num_nalus == 1)
|
||||||
case VVC_SUFFIX_SEI_NUT:
|
vvcc->num_of_arrays++;
|
||||||
ret = vvcc_array_add_nal_unit(nal_buf, nal_size, nal_type,
|
|
||||||
ps_array_completeness, vvcc);
|
if (nal_type == VVC_VPS_NUT)
|
||||||
if (ret < 0)
|
|
||||||
goto end;
|
|
||||||
else if (nal_type == VVC_VPS_NUT)
|
|
||||||
ret = vvcc_parse_vps(&gbc, vvcc);
|
ret = vvcc_parse_vps(&gbc, vvcc);
|
||||||
else if (nal_type == VVC_SPS_NUT)
|
else if (nal_type == VVC_SPS_NUT)
|
||||||
ret = vvcc_parse_sps(&gbc, vvcc);
|
ret = vvcc_parse_sps(&gbc, vvcc);
|
||||||
@@ -551,11 +538,6 @@ static int vvcc_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size,
|
|||||||
}
|
}
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto end;
|
goto end;
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ret = AVERROR_INVALIDDATA;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
end:
|
end:
|
||||||
av_free(rbsp_buf);
|
av_free(rbsp_buf);
|
||||||
@@ -572,22 +554,21 @@ static void vvcc_init(VVCDecoderConfigurationRecord *vvcc)
|
|||||||
|
|
||||||
static void vvcc_close(VVCDecoderConfigurationRecord *vvcc)
|
static void vvcc_close(VVCDecoderConfigurationRecord *vvcc)
|
||||||
{
|
{
|
||||||
uint8_t i;
|
for (unsigned i = 0; i < FF_ARRAY_ELEMS(vvcc->arrays); i++) {
|
||||||
|
VVCCNALUnitArray *const array = &vvcc->arrays[i];
|
||||||
|
|
||||||
for (i = 0; i < vvcc->num_of_arrays; i++) {
|
array->num_nalus = 0;
|
||||||
vvcc->array[i].num_nalus = 0;
|
av_freep(&array->nal_unit);
|
||||||
av_freep(&vvcc->array[i].nal_unit);
|
av_freep(&array->nal_unit_length);
|
||||||
av_freep(&vvcc->array[i].nal_unit_length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vvcc->num_of_arrays = 0;
|
vvcc->num_of_arrays = 0;
|
||||||
av_freep(&vvcc->array);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vvcc_write(AVIOContext *pb, VVCDecoderConfigurationRecord *vvcc)
|
static int vvcc_write(AVIOContext *pb, VVCDecoderConfigurationRecord *vvcc)
|
||||||
{
|
{
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
uint16_t j, vps_count = 0, sps_count = 0, pps_count = 0;
|
uint16_t vps_count = 0, sps_count = 0, pps_count = 0;
|
||||||
/*
|
/*
|
||||||
* It's unclear how to properly compute these fields, so
|
* It's unclear how to properly compute these fields, so
|
||||||
* let's always set them to values meaning 'unspecified'.
|
* let's always set them to values meaning 'unspecified'.
|
||||||
@@ -672,40 +653,33 @@ static int vvcc_write(AVIOContext *pb, VVCDecoderConfigurationRecord *vvcc)
|
|||||||
av_log(NULL, AV_LOG_TRACE,
|
av_log(NULL, AV_LOG_TRACE,
|
||||||
"num_of_arrays: %" PRIu8 "\n",
|
"num_of_arrays: %" PRIu8 "\n",
|
||||||
vvcc->num_of_arrays);
|
vvcc->num_of_arrays);
|
||||||
for (i = 0; i < vvcc->num_of_arrays; i++) {
|
for (unsigned i = 0; i < FF_ARRAY_ELEMS(vvcc->arrays); i++) {
|
||||||
|
const VVCCNALUnitArray *const array = &vvcc->arrays[i];
|
||||||
|
|
||||||
|
if (array->num_nalus == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
av_log(NULL, AV_LOG_TRACE,
|
av_log(NULL, AV_LOG_TRACE,
|
||||||
"array_completeness[%" PRIu8 "]: %" PRIu8 "\n", i,
|
"array_completeness[%u]: %" PRIu8 "\n", i,
|
||||||
vvcc->array[i].array_completeness);
|
array->array_completeness);
|
||||||
av_log(NULL, AV_LOG_TRACE,
|
av_log(NULL, AV_LOG_TRACE,
|
||||||
"NAL_unit_type[%" PRIu8 "]: %" PRIu8 "\n", i,
|
"NAL_unit_type[%u]: %" PRIu8 "\n", i,
|
||||||
vvcc->array[i].NAL_unit_type);
|
array->NAL_unit_type);
|
||||||
av_log(NULL, AV_LOG_TRACE,
|
av_log(NULL, AV_LOG_TRACE,
|
||||||
"num_nalus[%" PRIu8 "]: %" PRIu16 "\n", i,
|
"num_nalus[%u]: %" PRIu16 "\n", i,
|
||||||
vvcc->array[i].num_nalus);
|
array->num_nalus);
|
||||||
for (j = 0; j < vvcc->array[i].num_nalus; j++)
|
for (unsigned j = 0; j < array->num_nalus; j++)
|
||||||
av_log(NULL, AV_LOG_TRACE,
|
av_log(NULL, AV_LOG_TRACE,
|
||||||
"nal_unit_length[%" PRIu8 "][%" PRIu16 "]: %"
|
"nal_unit_length[%u][%u]: %"
|
||||||
PRIu16 "\n", i, j, vvcc->array[i].nal_unit_length[j]);
|
PRIu16 "\n", i, j, array->nal_unit_length[j]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need at least one of each: VPS and SPS.
|
* We need at least one of each: VPS and SPS.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < vvcc->num_of_arrays; i++)
|
vps_count = vvcc->arrays[VPS_INDEX].num_nalus;
|
||||||
switch (vvcc->array[i].NAL_unit_type) {
|
sps_count = vvcc->arrays[SPS_INDEX].num_nalus;
|
||||||
case VVC_VPS_NUT:
|
pps_count = vvcc->arrays[PPS_INDEX].num_nalus;
|
||||||
vps_count += vvcc->array[i].num_nalus;
|
|
||||||
break;
|
|
||||||
case VVC_SPS_NUT:
|
|
||||||
sps_count += vvcc->array[i].num_nalus;
|
|
||||||
break;
|
|
||||||
case VVC_PPS_NUT:
|
|
||||||
pps_count += vvcc->array[i].num_nalus;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vps_count > VVC_MAX_VPS_COUNT)
|
if (vps_count > VVC_MAX_VPS_COUNT)
|
||||||
return AVERROR_INVALIDDATA;
|
return AVERROR_INVALIDDATA;
|
||||||
if (!sps_count || sps_count > VVC_MAX_SPS_COUNT)
|
if (!sps_count || sps_count > VVC_MAX_SPS_COUNT)
|
||||||
@@ -804,25 +778,29 @@ static int vvcc_write(AVIOContext *pb, VVCDecoderConfigurationRecord *vvcc)
|
|||||||
/* unsigned int(8) num_of_arrays; */
|
/* unsigned int(8) num_of_arrays; */
|
||||||
avio_w8(pb, vvcc->num_of_arrays);
|
avio_w8(pb, vvcc->num_of_arrays);
|
||||||
|
|
||||||
for (i = 0; i < vvcc->num_of_arrays; i++) {
|
for (unsigned i = 0; i < FF_ARRAY_ELEMS(vvcc->arrays); i++) {
|
||||||
|
const VVCCNALUnitArray *const array = &vvcc->arrays[i];
|
||||||
|
|
||||||
|
if (!array->num_nalus)
|
||||||
|
continue;
|
||||||
/*
|
/*
|
||||||
* bit(1) array_completeness;
|
* bit(1) array_completeness;
|
||||||
* unsigned int(2) reserved = 0;
|
* unsigned int(2) reserved = 0;
|
||||||
* unsigned int(5) NAL_unit_type;
|
* unsigned int(5) NAL_unit_type;
|
||||||
*/
|
*/
|
||||||
avio_w8(pb, vvcc->array[i].array_completeness << 7 |
|
avio_w8(pb, array->array_completeness << 7 |
|
||||||
vvcc->array[i].NAL_unit_type & 0x1f);
|
array->NAL_unit_type & 0x1f);
|
||||||
/* unsigned int(16) num_nalus; */
|
/* unsigned int(16) num_nalus; */
|
||||||
if (vvcc->array[i].NAL_unit_type != VVC_DCI_NUT &&
|
if (array->NAL_unit_type != VVC_DCI_NUT &&
|
||||||
vvcc->array[i].NAL_unit_type != VVC_OPI_NUT)
|
array->NAL_unit_type != VVC_OPI_NUT)
|
||||||
avio_wb16(pb, vvcc->array[i].num_nalus);
|
avio_wb16(pb, array->num_nalus);
|
||||||
for (j = 0; j < vvcc->array[i].num_nalus; j++) {
|
for (int j = 0; j < array->num_nalus; j++) {
|
||||||
/* unsigned int(16) nal_unit_length; */
|
/* unsigned int(16) nal_unit_length; */
|
||||||
avio_wb16(pb, vvcc->array[i].nal_unit_length[j]);
|
avio_wb16(pb, array->nal_unit_length[j]);
|
||||||
|
|
||||||
/* bit(8*nal_unit_length) nal_unit; */
|
/* bit(8*nal_unit_length) nal_unit; */
|
||||||
avio_write(pb, vvcc->array[i].nal_unit[j],
|
avio_write(pb, array->nal_unit[j],
|
||||||
vvcc->array[i].nal_unit_length[j]);
|
array->nal_unit_length[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -932,19 +910,18 @@ int ff_isom_write_vvcc(AVIOContext *pb, const uint8_t *data,
|
|||||||
|
|
||||||
buf += 4;
|
buf += 4;
|
||||||
|
|
||||||
switch (type) {
|
for (unsigned i = 0; i < FF_ARRAY_ELEMS(vvcc.arrays); i++) {
|
||||||
case VVC_OPI_NUT:
|
static const uint8_t array_idx_to_type[] =
|
||||||
case VVC_VPS_NUT:
|
{ VVC_OPI_NUT, VVC_VPS_NUT, VVC_SPS_NUT,
|
||||||
case VVC_SPS_NUT:
|
VVC_PPS_NUT, VVC_PREFIX_SEI_NUT, VVC_SUFFIX_SEI_NUT };
|
||||||
case VVC_PPS_NUT:
|
|
||||||
case VVC_PREFIX_SEI_NUT:
|
if (type == array_idx_to_type[i]) {
|
||||||
case VVC_SUFFIX_SEI_NUT:
|
ret = vvcc_add_nal_unit(buf, len, ps_array_completeness,
|
||||||
ret = vvcc_add_nal_unit(buf, len, ps_array_completeness, &vvcc);
|
&vvcc, i);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto end;
|
goto end;
|
||||||
break;
|
break;
|
||||||
default:
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buf += len;
|
buf += len;
|
||||||
|
|||||||
Reference in New Issue
Block a user