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:
parent
c1f81c13a1
commit
b1eb15c1cf
@ -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 },
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user