1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2025-02-14 22:22:59 +02:00

avcodec/exr: add multipart support

This commit is contained in:
Paul B Mahol 2021-02-16 02:52:42 +01:00
parent c1f81c13a1
commit b1eb15c1cf

View File

@ -143,6 +143,8 @@ typedef struct EXRContext {
EXRTileAttribute tile_attr; /* header data attribute of tile */
int is_tile; /* 0 if scanline, 1 if tile */
int is_multipart;
int current_part;
int is_luma;/* 1 if there is an Y plane */
@ -153,10 +155,12 @@ typedef struct EXRContext {
EXRChannel *channels;
int nb_channels;
int current_channel_offset;
uint32_t chunk_count;
EXRThreadData *thread_data;
const char *layer;
int selected_part;
enum AVColorTransferCharacteristic apply_trc_type;
float gamma;
@ -1015,6 +1019,8 @@ static int decode_block(AVCodecContext *avctx, void *tdata,
return AVERROR_INVALIDDATA;
src = buf + line_offset + 20;
if (s->is_multipart)
src += 4;
tile_x = AV_RL32(src - 20);
tile_y = AV_RL32(src - 16);
@ -1050,6 +1056,8 @@ static int decode_block(AVCodecContext *avctx, void *tdata,
return AVERROR_INVALIDDATA;
src = buf + line_offset + 8;
if (s->is_multipart)
src += 4;
line = AV_RL32(src - 8);
if (line < s->ymin || line > s->ymax)
@ -1266,6 +1274,21 @@ static int decode_block(AVCodecContext *avctx, void *tdata,
return 0;
}
static void skip_header_chunk(EXRContext *s)
{
while (bytestream2_get_bytes_left(&s->gb) > 0) {
if (!bytestream2_peek_byte(&s->gb))
break;
// Process unknown variables
for (int i = 0; i < 2; i++) // value_name and value_type
while (bytestream2_get_byte(&s->gb) != 0);
// Skip variable length
bytestream2_skip(&s->gb, bytestream2_get_le32(&s->gb));
}
}
/**
* Check if the variable name corresponds to its data type.
*
@ -1334,7 +1357,9 @@ static int decode_header(EXRContext *s, AVFrame *frame)
s->tile_attr.xSize = -1;
s->tile_attr.ySize = -1;
s->is_tile = 0;
s->is_multipart = 0;
s->is_luma = 0;
s->current_part = 0;
if (bytestream2_get_bytes_left(&s->gb) < 10) {
av_log(s->avctx, AV_LOG_ERROR, "Header too short to parse.\n");
@ -1359,18 +1384,50 @@ static int decode_header(EXRContext *s, AVFrame *frame)
if (flags & 0x02)
s->is_tile = 1;
if (flags & 0x10)
s->is_multipart = 1;
if (flags & 0x08) {
avpriv_report_missing_feature(s->avctx, "deep data");
return AVERROR_PATCHWELCOME;
}
if (flags & 0x10) {
avpriv_report_missing_feature(s->avctx, "multipart");
return AVERROR_PATCHWELCOME;
}
// Parse the header
while (bytestream2_get_bytes_left(&s->gb) > 0 && *s->gb.buffer) {
while (bytestream2_get_bytes_left(&s->gb) > 0) {
int var_size;
while (s->is_multipart && s->current_part < s->selected_part &&
bytestream2_get_bytes_left(&s->gb) > 0) {
if (bytestream2_peek_byte(&s->gb)) {
skip_header_chunk(s);
} else {
bytestream2_skip(&s->gb, 1);
if (!bytestream2_peek_byte(&s->gb))
break;
}
bytestream2_skip(&s->gb, 1);
s->current_part++;
}
if (!bytestream2_peek_byte(&s->gb)) {
if (!s->is_multipart)
break;
bytestream2_skip(&s->gb, 1);
if (s->current_part == s->selected_part) {
while (bytestream2_get_bytes_left(&s->gb) > 0) {
if (bytestream2_peek_byte(&s->gb)) {
skip_header_chunk(s);
} else {
bytestream2_skip(&s->gb, 1);
if (!bytestream2_peek_byte(&s->gb))
break;
}
}
}
if (!bytestream2_peek_byte(&s->gb))
break;
s->current_part++;
}
if ((var_size = check_header_variable(s, "channels",
"chlist", 38)) >= 0) {
GetByteContext ch_gb;
@ -1593,9 +1650,11 @@ static int decode_header(EXRContext *s, AVFrame *frame)
if (s->compression == EXR_UNKN)
s->compression = bytestream2_get_byte(&s->gb);
else
else {
bytestream2_skip(&s->gb, 1);
av_log(s->avctx, AV_LOG_WARNING,
"Found more than one compression attribute.\n");
}
continue;
} else if ((var_size = check_header_variable(s, "tiles",
@ -1646,6 +1705,22 @@ static int decode_header(EXRContext *s, AVFrame *frame)
s->avctx->framerate.num = bytestream2_get_le32(&s->gb);
s->avctx->framerate.den = bytestream2_get_le32(&s->gb);
continue;
} else if ((var_size = check_header_variable(s, "chunkCount",
"int", 23)) >= 0) {
s->chunk_count = bytestream2_get_le32(&s->gb);
continue;
} else if ((var_size = check_header_variable(s, "type",
"string", 16)) >= 0) {
uint8_t key[256] = { 0 };
bytestream2_get_buffer(&s->gb, key, FFMIN(sizeof(key) - 1, var_size));
if (strncmp("scanlineimage", key, var_size) &&
strncmp("tiledimage", key, var_size))
return AVERROR_PATCHWELCOME;
continue;
}
@ -1941,6 +2016,8 @@ static av_cold int decode_end(AVCodecContext *avctx)
static const AVOption options[] = {
{ "layer", "Set the decoding layer", OFFSET(layer),
AV_OPT_TYPE_STRING, { .str = "" }, 0, 0, VD },
{ "part", "Set the decoding part", OFFSET(selected_part),
AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VD },
{ "gamma", "Set the float gamma value when decoding", OFFSET(gamma),
AV_OPT_TYPE_FLOAT, { .dbl = 1.0f }, 0.001, FLT_MAX, VD },