Commit ccb8cc4f authored by Tom Finegan's avatar Tom Finegan

Experiment compatibility fix: OBU_SIZING and OBU_NO_IVF.

Make OBU_SIZING and OBU_NO_IVF work when combined. Correct the
support for OBUs with LEB128 size fields in obudec.c.

In addition: explicitly disallow pipe input of Annex B OBU without
framing (this implementation requires seeking backwards to function).

Change-Id: I331371f51cae7752a9b1fc091174fe32816ea027
parent 839b8cc3
......@@ -83,7 +83,7 @@ size_t aom_uleb_size_in_bytes(uint64_t value);
// Returns 0 on success, -1 on decode failure.
// On success, 'value' stores the decoded LEB128 value and 'length' stores
// the number of bytes decoded
// the number of bytes decoded.
int aom_uleb_decode(const uint8_t *buffer, size_t available, uint64_t *value,
size_t *length);
......
......@@ -665,6 +665,7 @@ static int main_loop(int argc, const char **argv_) {
return EXIT_FAILURE;
}
#endif
input.aom_input_ctx->filename = fn;
input.aom_input_ctx->file = infile;
if (file_is_ivf(input.aom_input_ctx))
input.aom_input_ctx->file_type = FILE_TYPE_IVF;
......
......@@ -19,11 +19,67 @@
#include "av1/common/common.h"
#define OBU_HEADER_SIZE_BYTES 1
#if CONFIG_SCALABILITY
#define OBU_HEADER_EXTENSION_SIZE_BYTES 1
#if CONFIG_OBU_SIZING
// Unsigned LEB128 OBU length field has maximum size of 8 bytes.
#define OBU_MAX_LENGTH_FIELD_SIZE 8
#define OBU_MAX_HEADER_SIZE \
(OBU_HEADER_SIZE_BYTES + OBU_HEADER_EXTENSION_SIZE_BYTES + \
OBU_MAX_LENGTH_FIELD_SIZE)
#else
#define OBU_MAX_LENGTH_FIELD_SIZE PRE_OBU_SIZE_BYTES
#define OBU_MAX_HEADER_SIZE \
(OBU_HEADER_SIZE_BYTES + OBU_HEADER_EXTENSION_SIZE_BYTES + PRE_OBU_SIZE_BYTES)
#endif
#if CONFIG_OBU_NO_IVF
int read_obu_type(uint8_t obu_header, OBU_TYPE *obu_type) {
if (!obu_type) return -1;
const int obu_type_value = (obu_header >> 3) & 0xF;
switch (obu_type_value) {
case OBU_SEQUENCE_HEADER: *obu_type = OBU_SEQUENCE_HEADER; break;
case OBU_TEMPORAL_DELIMITER: *obu_type = OBU_TEMPORAL_DELIMITER; break;
case OBU_FRAME_HEADER: *obu_type = OBU_FRAME_HEADER; break;
case OBU_TILE_GROUP: *obu_type = OBU_TILE_GROUP; break;
case OBU_METADATA: *obu_type = OBU_METADATA; break;
case OBU_PADDING: *obu_type = OBU_PADDING; break;
default: return -1;
}
return 0;
}
// Reads OBU size from infile and returns 0 upon success. Returns obu_size via
// output pointer obu_size. Returns -1 when reading or parsing fails. Always
// returns FILE pointer to position at time of call. Returns 0 and sets obu_size
// to 0 when end of file is reached.
int read_obu_size(FILE *infile, uint64_t *obu_size, size_t *length_field_size) {
if (!infile || !obu_size) return 1;
uint8_t read_buffer[OBU_MAX_LENGTH_FIELD_SIZE] = { 0 };
size_t bytes_read = fread(read_buffer, 1, OBU_MAX_LENGTH_FIELD_SIZE, infile);
*obu_size = 0;
if (bytes_read == 0) {
return 0;
}
const int seek_pos = (int)bytes_read;
if (seek_pos != 0 && fseek(infile, -seek_pos, SEEK_CUR) != 0) return 1;
#if CONFIG_OBU_SIZING
if (aom_uleb_decode(read_buffer, bytes_read, obu_size, length_field_size) !=
0) {
return 1;
}
#else
if (length_field_size) *length_field_size = PRE_OBU_SIZE_BYTES;
*obu_size = mem_get_le32(read_buffer);
#endif
return 0;
}
int obu_read_temporal_unit(FILE *infile, uint8_t **buffer, size_t *bytes_read,
#if CONFIG_SCALABILITY
size_t *buffer_size, int last_layer_id) {
......@@ -31,8 +87,6 @@ int obu_read_temporal_unit(FILE *infile, uint8_t **buffer, size_t *bytes_read,
size_t *buffer_size) {
#endif
size_t ret;
const size_t obu_length_header_size =
PRE_OBU_SIZE_BYTES + OBU_HEADER_SIZE_BYTES;
uint64_t obu_size = 0;
uint8_t *data = NULL;
......@@ -43,109 +97,116 @@ int obu_read_temporal_unit(FILE *infile, uint8_t **buffer, size_t *bytes_read,
*buffer_size = 0;
*bytes_read = 0;
while (1) {
// augment the buffer to just contain the next size field
// and the first byte of the header
*buffer = realloc(*buffer, (*buffer_size) + obu_length_header_size);
data = *buffer + (*buffer_size);
*buffer_size += obu_length_header_size;
ret = fread(data, 1, obu_length_header_size, infile);
if (ret == 0) {
// fprintf(stderr, "Found end of stream, ending temporal unit\n");
size_t length_field_size = 0;
ret = read_obu_size(infile, &obu_size, &length_field_size);
if (ret != 0) {
warn("Failed to read OBU size.\n");
return 1;
}
if (ret == 0 && obu_size == 0) {
fprintf(stderr, "Found end of stream, ending temporal unit\n");
break;
}
if (ret != obu_length_header_size) {
warn("Failed to read OBU Header\n");
obu_size += length_field_size;
// Expand the buffer to contain the full OBU and its length.
const uint8_t *old_buffer = *buffer;
*buffer = (uint8_t *)realloc(*buffer, *buffer_size + obu_size);
if (!*buffer) {
free((void *)old_buffer);
warn("OBU buffer alloc failed.\n");
return 1;
}
*bytes_read += obu_length_header_size;
if (((data[PRE_OBU_SIZE_BYTES] >> 3) & 0xF) == OBU_TEMPORAL_DELIMITER) {
data = *buffer + (*buffer_size);
*buffer_size += obu_size;
ret = fread(data, 1, obu_size, infile);
if (ret != obu_size) {
warn("Failed to read OBU.\n");
return 1;
}
*bytes_read += obu_size;
OBU_TYPE obu_type;
if (read_obu_type(data[length_field_size], &obu_type) != 0) {
warn("Invalid OBU type.\n");
return 1;
}
if (obu_type == OBU_TEMPORAL_DELIMITER) {
// Stop when a temporal delimiter is found
// fprintf(stderr, "Found temporal delimiter, ending temporal unit\n");
// prevent decoder to start decoding another frame from this buffer
*bytes_read -= obu_length_header_size;
*bytes_read -= obu_size;
break;
}
#if CONFIG_SCALABILITY
// break if obu_extension_flag is found and enhancement_id change
if ((data[PRE_OBU_SIZE_BYTES] & 0x1)) {
uint8_t obu_extension_header;
const int total_obu_header_size =
(int)obu_length_header_size + OBU_HEADER_EXTENSION_SIZE_BYTES;
int curr_layer_id;
ret = fread(&obu_extension_header, 1, OBU_HEADER_EXTENSION_SIZE_BYTES,
infile);
if (ret != OBU_HEADER_EXTENSION_SIZE_BYTES) {
warn("Failed to read OBU Header Extension\n");
return 1;
}
curr_layer_id = (obu_extension_header >> 3) & 0x3;
if (data[length_field_size] & 0x1) {
const uint8_t obu_extension_header =
data[length_field_size + OBU_HEADER_SIZE_BYTES];
const int curr_layer_id = (obu_extension_header >> 3) & 0x3;
if (curr_layer_id && (curr_layer_id > last_layer_id)) {
// new enhancement layer
*bytes_read -= obu_length_header_size;
fseek(infile, -total_obu_header_size, SEEK_CUR);
*bytes_read -= obu_size;
const int i_obu_size = (int)obu_size;
fseek(infile, -i_obu_size, SEEK_CUR);
break;
} else {
fseek(infile, -OBU_HEADER_EXTENSION_SIZE_BYTES, SEEK_CUR);
}
}
#endif
// otherwise, read the OBU payload into memory
#if CONFIG_OBU_SIZING
aom_uleb_decode(data, PRE_OBU_SIZE_BYTES, &obu_size, NULL);
#else
obu_size = mem_get_le32(data);
#endif // CONFIG_OBU_SIZING
// fprintf(stderr, "Found OBU of type %d and size %d\n",
// ((data[PRE_OBU_SIZE_BYTES] >> 3) & 0xF), obu_size);
obu_size--; // removing the byte of the header already read
if (obu_size) {
*buffer = realloc(*buffer, (*buffer_size) + obu_size);
data = *buffer + (*buffer_size);
*buffer_size += obu_size;
ret = fread(data, 1, obu_size, infile);
if (ret != obu_size) {
warn("Failed to read OBU Payload\n");
return 1;
}
*bytes_read += obu_size;
}
}
return 0;
}
int file_is_obu(struct AvxInputContext *input_ctx) {
uint8_t obutd[PRE_OBU_SIZE_BYTES + OBU_HEADER_SIZE_BYTES];
uint64_t size;
uint8_t obutd[OBU_MAX_HEADER_SIZE] = { 0 };
uint64_t size = 0;
// Parsing of Annex B OBU streams via pipe without framing not supported. This
// implementation requires seeking backwards in the input stream. Tell caller
// that this input cannot be processed.
if (!input_ctx->filename || strcmp(input_ctx->filename, "-") == 0) return 0;
// Reading the first OBU TD to enable TU end detection at TD start.
const size_t obu_length_header_size =
PRE_OBU_SIZE_BYTES + OBU_HEADER_SIZE_BYTES;
const size_t ret = fread(obutd, 1, obu_length_header_size, input_ctx->file);
if (ret != obu_length_header_size) {
warn("Failed to read OBU Header\n");
const size_t ret = fread(obutd, 1, OBU_MAX_HEADER_SIZE, input_ctx->file);
if (ret != OBU_MAX_HEADER_SIZE) {
warn("Failed to read OBU Header, not enough data to process header.\n");
return 0;
}
#if CONFIG_OBU_SIZING
aom_uleb_decode(obutd, PRE_OBU_SIZE_BYTES, &size, NULL);
if (aom_uleb_decode(obutd, OBU_MAX_HEADER_SIZE, &size, NULL) != 0) {
warn("OBU size parse failed.\n");
return 0;
}
const size_t obu_header_offset = aom_uleb_size_in_bytes(size);
#else
const size_t obu_header_offset = PRE_OBU_SIZE_BYTES;
size = mem_get_le32(obutd);
#endif // CONFIG_OBU_SIZING
fseek(input_ctx->file, obu_header_offset + OBU_HEADER_SIZE_BYTES, SEEK_SET);
if (size != 1) {
warn("Expected first OBU size to be 1, got %d", size);
warn("Expected first OBU size to be 1, got %d\n", size);
return 0;
}
if (((obutd[PRE_OBU_SIZE_BYTES] >> 3) & 0xF) != OBU_TEMPORAL_DELIMITER) {
warn("Expected OBU TD at file start, got %d\n", obutd[PRE_OBU_SIZE_BYTES]);
OBU_TYPE obu_type;
if (read_obu_type(obutd[obu_header_offset], &obu_type) != 0) {
warn("Invalid OBU type found while probing for OBU_TEMPORAL_DELIMITER.\n");
return 0;
}
if (obu_type != OBU_TEMPORAL_DELIMITER) {
warn("Expected OBU TD at file start, got %d\n", obutd[obu_header_offset]);
return 0;
}
// fprintf(stderr, "Starting to parse OBU stream\n");
// fprintf(stderr, "Starting to parse OBU stream\n");
return 1;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment