// Reads unsigned LEB128 integer and returns 0 upon successful read and decode. // Stores raw bytes in 'value_buffer', length of the number in 'value_length', // and decoded value in 'value'. If 'buffered' is true, it is buffered in the // detect buffer first. static int obudec_read_leb128(struct AvxInputContext *input_ctx,
uint8_t *value_buffer, size_t *value_length,
uint64_t *value, bool buffered) {
if (!input_ctx || !value_buffer || !value_length || !value) return -1;
size_t len;
for (len = 0; len < OBU_MAX_LENGTH_FIELD_SIZE; ++len) { const size_t num_read =
buffer_input(input_ctx, 1, &value_buffer[len], buffered);
if (num_read == 0) {
if (len == 0 && input_eof(input_ctx)) {
*value_length = 0; return0;
} // Ran out of data before completing read of value. return -1;
}
if ((value_buffer[len] >> 7) == 0) {
++len;
*value_length = len; break;
}
}
// Reads OBU header from 'input_ctx'. The 'buffer_capacity' passed in must be // large enough to store an OBU header with extension (2 bytes). Raw OBU data is // written to 'obu_data', parsed OBU header values are written to 'obu_header', // and total bytes read from file are written to 'bytes_read'. Returns 0 for // success, and non-zero on failure. When end of file is reached, the return // value is 0 and the 'bytes_read' value is set to 0. If 'buffered' is true, it // is buffered in the detect buffer first. static int obudec_read_obu_header(struct AvxInputContext *input_ctx,
size_t buffer_capacity, int is_annexb,
uint8_t *obu_data, ObuHeader *obu_header,
size_t *bytes_read, bool buffered) {
if (!input_ctx || buffer_capacity < (OBU_HEADER_SIZE + OBU_EXTENSION_SIZE) ||
!obu_data || !obu_header || !bytes_read) { return -1;
}
*bytes_read = buffer_input(input_ctx, 1, obu_data, buffered);
if (input_eof(input_ctx) && *bytes_read == 0) { return0;
} else if (*bytes_read != 1) {
fprintf(stderr, "obudec: Failure reading OBU header.\n"); return -1;
}
const int has_extension = (obu_data[0] >> 2) & 0x1;
if (has_extension) {
if (buffer_input(input_ctx, 1, &obu_data[1], buffered) != 1) {
fprintf(stderr, "obudec: Failure reading OBU extension."); return -1;
}
++*bytes_read;
}
// Reads OBU payload from 'input_ctx' and returns 0 for success when all payload // bytes are read from the file. Payload data is written to 'obu_data', and // actual bytes read added to 'bytes_read'. If 'buffered' is true, it is // buffered in the detect buffer first. static int obudec_read_obu_payload(struct AvxInputContext *input_ctx,
size_t payload_length, uint8_t *obu_data,
size_t *bytes_read, bool buffered) {
if (!input_ctx || payload_length == 0 || !obu_data || !bytes_read) return -1;
if (buffer_input(input_ctx, payload_length, obu_data, buffered) !=
payload_length) {
fprintf(stderr, "obudec: Failure reading OBU payload.\n"); return -1;
}
if (is_annexb) { // read the size of first temporal unit
if (obudec_read_leb128(avx_ctx, &detect_buf[0], &length_of_unit_size,
&unit_size, /*buffered=*/true) != 0) {
fprintf(stderr, "obudec: Failure reading temporal unit header\n");
rewind_detect(avx_ctx); return0;
}
// read the size of first frame unit
if (obudec_read_leb128(avx_ctx, &detect_buf[length_of_unit_size],
&annexb_header_length, &unit_size, /*buffered=*/true) != 0) {
fprintf(stderr, "obudec: Failure reading frame unit header\n");
rewind_detect(avx_ctx); return0;
}
annexb_header_length += length_of_unit_size;
}
if (obu_header.has_size_field) {
if (obu_header.type == OBU_TEMPORAL_DELIMITER && payload_length != 0) {
fprintf(
stderr, "obudec: Invalid OBU_TEMPORAL_DELIMITER payload length (non-zero).");
rewind_detect(avx_ctx); return0;
}
} else if (!is_annexb) {
fprintf(stderr, "obudec: OBU size fields required, cannot decode input.\n");
rewind_detect(avx_ctx); return0;
}
// Appears that input is valid Section 5 AV1 stream.
obu_ctx->buffer = (uint8_t *)malloc(OBU_BUFFER_SIZE);
if (!obu_ctx->buffer) {
fprintf(stderr, "Out of memory.\n");
rewind_detect(avx_ctx); return0;
}
obu_ctx->buffer_capacity = OBU_BUFFER_SIZE;
memcpy(obu_ctx->buffer, &detect_buf[0], bytes_read);
obu_ctx->bytes_buffered = bytes_read; // If the first OBU is a SEQUENCE_HEADER, then it will have a payload. // We need to read this in so that our buffer only contains complete OBUs.
if (payload_length > 0) {
if (payload_length > (obu_ctx->buffer_capacity - bytes_read)) {
fprintf(stderr, "obudec: First OBU's payload is too large\n");
rewind_detect(avx_ctx);
obudec_free(obu_ctx); return0;
}
size_t payload_bytes = 0; const int status = obudec_read_obu_payload(
avx_ctx, payload_length, &obu_ctx->buffer[bytes_read], &payload_bytes, /*buffered=*/false);
if (status < 0) {
rewind_detect(avx_ctx);
obudec_free(obu_ctx); return0;
}
obu_ctx->bytes_buffered += payload_bytes;
} return1;
}
int obudec_read_temporal_unit(struct ObuDecInputContext *obu_ctx,
uint8_t **buffer, size_t *bytes_read,
size_t *buffer_size) {
FILE *f = obu_ctx->avx_ctx->file;
if (!f) return -1;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.