Commit 29c46fb4 authored by Soo-Chul Han's avatar Soo-Chul Han Committed by Yaowu Xu

[NORMATIVE-DECODING] option of annex-b/non-annex-b bitstreams

libaom modified to encode/decode AV1 as annex-b or non-annex-b

Encoder option --annexb=0 or 1  (default 0)
Decoder option --annexb

BUG=aomedia:1590
BUG=aomedia:1591

Change-Id: I0f092b45fbf30e689c7fe3c6540d22f497946880
parent 31bcc769
......@@ -85,6 +85,7 @@ typedef struct aom_codec_stream_info {
unsigned int h; /**< Height (or 0 for unknown/default) */
unsigned int is_kf; /**< Current frame is a keyframe */
unsigned int enhancement_layers_cnt; /**< Enhancement layers */
unsigned int is_annexb; /**< Is Bitstream in Annex-B format */
} aom_codec_stream_info_t;
/* REQUIRED FUNCTIONS
......
......@@ -663,6 +663,14 @@ typedef struct aom_codec_enc_cfg {
*/
unsigned int monochrome;
/*!\brief Bitstream syntax mode
*
* This value indicates the bitstream syntax mode.
* A value of 0 indicates bitstream is saved as Section 5 bitstream. A value
* of 1 indicates the bitstream is saved in Annex-B format
*/
unsigned int save_as_annexb;
/*!\brief Number of explicit tile widths specified
*
* This value indicates the number of tile widths specified
......
......@@ -146,6 +146,9 @@ enum aom_dec_control_id {
*/
AV1_SET_TILE_MODE,
/** control function to indicate whether bitstream is in Annex-B format. */
AV1D_SET_IS_ANNEXB,
/** control function to set an aom_inspect_cb callback that is invoked each
* time a frame is decoded. When compiled without --enable-inspection, this
* returns AOM_CODEC_INCAPABLE.
......@@ -187,6 +190,8 @@ AOM_CTRL_USE_TYPE(AV1_SET_DECODE_TILE_COL, int)
#define AOM_CTRL_AV1_SET_DECODE_TILE_COL
AOM_CTRL_USE_TYPE(AV1_SET_TILE_MODE, unsigned int)
#define AOM_CTRL_AV1_SET_TILE_MODE
AOM_CTRL_USE_TYPE(AV1D_SET_IS_ANNEXB, unsigned int)
#define AOM_CTRL_AV1D_SET_IS_ANNEXB
AOM_CTRL_USE_TYPE(AV1_SET_INSPECTION_CALLBACK, aom_inspect_init *)
#define AOM_CTRL_AV1_SET_INSPECTION_CALLBACK
/*!\endcond */
......
......@@ -111,13 +111,17 @@ static const arg_def_t tiler = ARG_DEF(NULL, "tile-row", 1,
static const arg_def_t tilec = ARG_DEF(NULL, "tile-column", 1,
"Column index of tile to decode "
"(-1 for all columns)");
static const arg_def_t isannexb =
ARG_DEF(NULL, "annexb", 0, "Bitstream is in Annex-B format");
static const arg_def_t *all_args[] = {
&help, &codecarg, &use_yv12, &use_i420, &flipuvarg,
&rawvideo, &noblitarg, &progressarg, &limitarg, &skiparg,
&postprocarg, &summaryarg, &outputfile, &threadsarg, &verbosearg,
&scalearg, &fb_arg, &md5arg, &framestatsarg, &continuearg,
&outbitdeptharg, &tilem, &tiler, &tilec, NULL
&help, &codecarg, &use_yv12, &use_i420,
&flipuvarg, &rawvideo, &noblitarg, &progressarg,
&limitarg, &skiparg, &postprocarg, &summaryarg,
&outputfile, &threadsarg, &verbosearg, &scalearg,
&fb_arg, &md5arg, &framestatsarg, &continuearg,
&outbitdeptharg, &tilem, &tiler, &tilec,
&isannexb, NULL
};
#if CONFIG_LIBYUV
......@@ -500,6 +504,7 @@ static int main_loop(int argc, const char **argv_) {
aom_codec_dec_cfg_t cfg = { 0, 0, 0, CONFIG_LOWBITDEPTH, { 1 } };
unsigned int output_bit_depth = 0;
unsigned int tile_mode = 0;
unsigned int is_annexb = 0;
int tile_row = -1;
int tile_col = -1;
int frames_corrupted = 0;
......@@ -527,7 +532,7 @@ static int main_loop(int argc, const char **argv_) {
memset(&webm_ctx, 0, sizeof(webm_ctx));
input.webm_ctx = &webm_ctx;
#endif
struct ObuDecInputContext obu_ctx = { NULL, NULL, 0, 0 };
struct ObuDecInputContext obu_ctx = { NULL, NULL, 0, 0, 0 };
obu_ctx.avx_ctx = &aom_input_ctx;
input.obu_ctx = &obu_ctx;
input.aom_input_ctx = &aom_input_ctx;
......@@ -604,6 +609,9 @@ static int main_loop(int argc, const char **argv_) {
output_bit_depth = arg_parse_uint(&arg);
} else if (arg_match(&arg, &tilem, argi)) {
tile_mode = arg_parse_int(&arg);
} else if (arg_match(&arg, &isannexb, argi)) {
is_annexb = 1;
input.obu_ctx->is_annexb = 1;
} else if (arg_match(&arg, &tiler, argi)) {
tile_row = arg_parse_int(&arg);
} else if (arg_match(&arg, &tilec, argi)) {
......@@ -718,6 +726,11 @@ static int main_loop(int argc, const char **argv_) {
goto fail;
}
if (aom_codec_control(&decoder, AV1D_SET_IS_ANNEXB, is_annexb)) {
fprintf(stderr, "Failed to set is_annexb: %s\n", aom_codec_error(&decoder));
goto fail;
}
if (aom_codec_control(&decoder, AV1_SET_DECODE_TILE_ROW, tile_row)) {
fprintf(stderr, "Failed to set decode_tile_row: %s\n",
aom_codec_error(&decoder));
......
......@@ -380,6 +380,8 @@ static const arg_def_t sframe_dist =
ARG_DEF(NULL, "sframe-dist", 1, "S-Frame interval (frames)");
static const arg_def_t sframe_mode =
ARG_DEF(NULL, "sframe-mode", 1, "S-Frame insertion mode (1..2)");
static const arg_def_t save_as_annexb =
ARG_DEF(NULL, "annexb", 1, "Save as Annex-B");
static const arg_def_t noise_sens =
ARG_DEF(NULL, "noise-sensitivity", 1, "Noise sensitivity (frames to blur)");
static const arg_def_t sharpness =
......@@ -653,6 +655,7 @@ static const arg_def_t *av1_args[] = { &cpu_used_av1,
&inbitdeptharg,
&sframe_dist,
&sframe_mode,
&save_as_annexb,
NULL };
static const int av1_arg_ctrl_map[] = { AOME_SET_CPUUSED,
AOME_SET_DEVSF,
......@@ -1225,6 +1228,8 @@ static int parse_stream_params(struct AvxEncoderConfig *global,
config->cfg.sframe_dist = arg_parse_uint(&arg);
} else if (arg_match(&arg, &sframe_mode, argi)) {
config->cfg.sframe_mode = arg_parse_uint(&arg);
} else if (arg_match(&arg, &save_as_annexb, argi)) {
config->cfg.save_as_annexb = arg_parse_uint(&arg);
} else if (arg_match(&arg, &tile_width, argi)) {
config->cfg.tile_width_count =
arg_parse_list(&arg, config->cfg.tile_widths, MAX_TILE_WIDTHS);
......@@ -1538,6 +1543,10 @@ static void initialize_encoder(struct stream_state *stream,
stream->config.cfg.large_scale_tile);
ctx_exit_on_error(&stream->decoder, "Failed to set decode_tile_mode");
aom_codec_control(&stream->decoder, AV1D_SET_IS_ANNEXB,
stream->config.cfg.save_as_annexb);
ctx_exit_on_error(&stream->decoder, "Failed to set is_annexb");
aom_codec_control(&stream->decoder, AV1_SET_DECODE_TILE_ROW, -1);
ctx_exit_on_error(&stream->decoder, "Failed to set decode_tile_row");
......
......@@ -655,6 +655,8 @@ static aom_codec_err_t set_encoder_config(
oxcf->aq_mode = extra_cfg->aq_mode;
oxcf->deltaq_mode = extra_cfg->deltaq_mode;
oxcf->save_as_annexb = cfg->save_as_annexb;
oxcf->frame_periodic_boost = extra_cfg->frame_periodic_boost;
oxcf->motion_vector_unit_test = extra_cfg->motion_vector_unit_test;
return AOM_CODEC_OK;
......@@ -1313,6 +1315,15 @@ static aom_codec_err_t encoder_encode(aom_codec_alg_priv_t *ctx,
obu_header_size + obu_payload_size + length_field_size;
}
if (ctx->oxcf.save_as_annexb) {
size_t curr_frame_size = pkt.data.frame.sz;
if (av1_convert_sect5obus_to_annexb(ctx->pending_cx_data,
&curr_frame_size) != AOM_CODEC_OK) {
return AOM_CODEC_ERROR;
}
pkt.data.frame.sz = curr_frame_size;
}
pkt.data.frame.pts = ticks_to_timebase_units(timebase, dst_time_stamp);
pkt.data.frame.flags = get_frame_pkt_flags(cpi, lib_flags);
pkt.data.frame.duration = (uint32_t)ticks_to_timebase_units(
......@@ -1703,6 +1714,7 @@ static aom_codec_enc_cfg_map_t encoder_usage_cfg_map[] = {
1, // sframe_mode
0, // large_scale_tile
0, // monochrome
0, // save_as_annexb
0, // tile_width_count
0, // tile_height_count
{ 0 }, // tile_widths
......
......@@ -59,6 +59,7 @@ struct aom_codec_alg_priv {
int decode_tile_row;
int decode_tile_col;
unsigned int tile_mode;
unsigned int is_annexb;
AVxWorker *frame_workers;
int num_frame_workers;
......@@ -181,15 +182,25 @@ static aom_codec_err_t decoder_peek_si_internal(const uint8_t *data,
intra_only_flag = 1;
si->is_kf = 1;
struct aom_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL };
size_t length_field_size = 0;
if (si->is_annexb) {
length_field_size = get_obu_length_field_size(data, data_sz - 1);
}
struct aom_read_bit_buffer rb = { data + length_field_size, data + data_sz, 0,
NULL, NULL };
const uint8_t obu_header = (uint8_t)aom_rb_read_literal(&rb, 8);
OBU_TYPE obu_type;
if (get_obu_type(obu_header, &obu_type) != 0)
return AOM_CODEC_UNSUP_BITSTREAM;
// One byte has been consumed by the OBU header.
rb.bit_buffer += get_obu_length_field_size(data + 1, data_sz - 1) * 8;
if (!si->is_annexb) {
// One byte has been consumed by the OBU header.
// TODO(shan): Assuming 1-byte obu_header (need to account in case extension
// exists)
rb.bit_buffer += get_obu_length_field_size(data + 1, data_sz - 1) + 2;
}
// This check is disabled because existing behavior is depended upon by
// decoder tests (see decode_test_driver.cc), scalability_decoder (see
......@@ -365,6 +376,7 @@ static aom_codec_err_t init_decoder(aom_codec_alg_priv_t *ctx) {
frame_worker_data->pbi->max_threads = ctx->cfg.threads;
frame_worker_data->pbi->inv_tile_order = ctx->invert_tile_order;
frame_worker_data->pbi->common.large_scale_tile = ctx->tile_mode;
frame_worker_data->pbi->common.is_annexb = ctx->is_annexb;
frame_worker_data->pbi->dec_tile_row = ctx->decode_tile_row;
frame_worker_data->pbi->dec_tile_col = ctx->decode_tile_col;
worker->hook = (AVxWorkerHook)frame_worker_hook;
......@@ -402,6 +414,7 @@ static aom_codec_err_t decode_one(aom_codec_alg_priv_t *ctx,
// of the heap.
if (!ctx->si.h) {
int is_intra_only = 0;
ctx->si.is_annexb = ctx->is_annexb;
const aom_codec_err_t res =
decoder_peek_si_internal(*data, data_sz, &ctx->si, &is_intra_only);
if (res != AOM_CODEC_OK) return res;
......@@ -425,6 +438,8 @@ static aom_codec_err_t decode_one(aom_codec_alg_priv_t *ctx,
frame_worker_data->pbi->dec_tile_row = ctx->decode_tile_row;
frame_worker_data->pbi->dec_tile_col = ctx->decode_tile_col;
frame_worker_data->pbi->common.is_annexb = ctx->is_annexb;
worker->had_error = 0;
winterface->execute(worker);
......@@ -461,6 +476,7 @@ static aom_codec_err_t decoder_decode(aom_codec_alg_priv_t *ctx,
res = init_decoder(ctx);
if (res != AOM_CODEC_OK) return res;
}
// Decode in serial mode.
if (frame_count > 0) {
int i;
......@@ -904,6 +920,12 @@ static aom_codec_err_t ctrl_set_tile_mode(aom_codec_alg_priv_t *ctx,
return AOM_CODEC_OK;
}
static aom_codec_err_t ctrl_set_is_annexb(aom_codec_alg_priv_t *ctx,
va_list args) {
ctx->is_annexb = va_arg(args, unsigned int);
return AOM_CODEC_OK;
}
static aom_codec_err_t ctrl_set_inspection_callback(aom_codec_alg_priv_t *ctx,
va_list args) {
#if !CONFIG_INSPECTION
......@@ -934,6 +956,7 @@ static aom_codec_ctrl_fn_map_t decoder_ctrl_maps[] = {
{ AV1_SET_DECODE_TILE_ROW, ctrl_set_decode_tile_row },
{ AV1_SET_DECODE_TILE_COL, ctrl_set_decode_tile_col },
{ AV1_SET_TILE_MODE, ctrl_set_tile_mode },
{ AV1D_SET_IS_ANNEXB, ctrl_set_is_annexb },
{ AV1_SET_INSPECTION_CALLBACK, ctrl_set_inspection_callback },
// Getters
......
......@@ -516,6 +516,9 @@ typedef struct AV1Common {
int tpl_mvs_mem_size;
// TODO(jingning): This can be combined with sign_bias later.
int8_t ref_frame_side[REF_FRAMES];
int is_annexb;
int frame_refs_short_signaling;
int temporal_layer_id;
int enhancement_layer_id;
......
......@@ -76,7 +76,7 @@ static int valid_obu_type(int obu_type) {
// Parses OBU header and stores values in 'header'.
static aom_codec_err_t read_obu_header(struct aom_read_bit_buffer *rb,
ObuHeader *header) {
int is_annexb, ObuHeader *header) {
if (!rb || !header) return AOM_CODEC_INVALID_PARAM;
header->size = 1;
......@@ -90,8 +90,9 @@ static aom_codec_err_t read_obu_header(struct aom_read_bit_buffer *rb,
header->has_extension = aom_rb_read_bit(rb);
header->has_length_field = aom_rb_read_bit(rb);
if (!header->has_length_field) {
// libaom does not support streams with this bit set to 0.
if (!header->has_length_field && !is_annexb) {
// section 5 obu streams must have length field set.
return AOM_CODEC_UNSUP_BITSTREAM;
}
......@@ -109,14 +110,15 @@ static aom_codec_err_t read_obu_header(struct aom_read_bit_buffer *rb,
}
aom_codec_err_t aom_read_obu_header(uint8_t *buffer, size_t buffer_length,
size_t *consumed, ObuHeader *header) {
size_t *consumed, ObuHeader *header,
int is_annexb) {
if (buffer_length < 1 || !consumed || !header) return AOM_CODEC_INVALID_PARAM;
// TODO(tomfinegan): Set the error handler here and throughout this file, and
// confirm parsing work done via aom_read_bit_buffer is successful.
struct aom_read_bit_buffer rb = { buffer, buffer + buffer_length, 0, NULL,
NULL };
aom_codec_err_t parse_result = read_obu_header(&rb, header);
aom_codec_err_t parse_result = read_obu_header(&rb, is_annexb, header);
if (parse_result == AOM_CODEC_OK) *consumed = header->size;
return parse_result;
}
......@@ -382,25 +384,39 @@ void av1_decode_frame_from_obus(struct AV1Decoder *pbi, const uint8_t *data,
}
size_t length_field_size = 0;
size_t obu_size = 0;
if (cm->is_annexb) {
if (read_obu_size(data, bytes_available, &obu_size, &length_field_size) !=
AOM_CODEC_OK) {
cm->error.error_code = AOM_CODEC_CORRUPT_FRAME;
return;
}
}
if (data_end < data + length_field_size) {
cm->error.error_code = AOM_CODEC_CORRUPT_FRAME;
return;
}
av1_init_read_bit_buffer(pbi, &rb, data + length_field_size, data_end);
const aom_codec_err_t status = read_obu_header(&rb, &obu_header);
const aom_codec_err_t status =
read_obu_header(&rb, cm->is_annexb, &obu_header);
if (status != AOM_CODEC_OK) {
cm->error.error_code = status;
return;
}
if (read_obu_size(data + obu_header.size, bytes_available - obu_header.size,
&payload_size, &length_field_size) != AOM_CODEC_OK) {
cm->error.error_code = AOM_CODEC_CORRUPT_FRAME;
return;
if (!cm->is_annexb) {
if (read_obu_size(data + obu_header.size,
bytes_available - obu_header.size, &payload_size,
&length_field_size) != AOM_CODEC_OK) {
cm->error.error_code = AOM_CODEC_CORRUPT_FRAME;
return;
}
av1_init_read_bit_buffer(
pbi, &rb, data + length_field_size + obu_header.size, data_end);
} else {
payload_size = obu_size - obu_header.size;
}
av1_init_read_bit_buffer(
pbi, &rb, data + length_field_size + obu_header.size, data_end);
data += length_field_size + obu_header.size;
if (data_end < data) {
......
......@@ -35,7 +35,8 @@ typedef struct {
int get_obu_type(uint8_t obu_header_byte, OBU_TYPE *obu_type);
aom_codec_err_t aom_read_obu_header(uint8_t *buffer, size_t buffer_length,
size_t *consumed, ObuHeader *header);
size_t *consumed, ObuHeader *header,
int is_annexb);
void av1_decode_frame_from_obus(struct AV1Decoder *pbi, const uint8_t *data,
const uint8_t *data_end,
......
......@@ -5935,6 +5935,63 @@ int av1_set_internal_size(AV1_COMP *cpi, AOM_SCALING horiz_mode,
int av1_get_quantizer(AV1_COMP *cpi) { return cpi->common.base_qindex; }
int av1_convert_sect5obus_to_annexb(uint8_t *buffer, size_t *frame_size) {
size_t output_size = 0;
size_t total_bytes_read = 0;
size_t remaining_size = *frame_size;
uint8_t *buff_ptr = buffer;
// go through each OBUs
while (total_bytes_read < *frame_size) {
uint8_t saved_obu_header[2];
uint64_t obu_payload_size;
size_t length_of_payload_size;
size_t length_of_obu_size;
uint32_t obu_header_size = (buff_ptr[0] >> 2) & 0x1 ? 2 : 1;
size_t obu_bytes_read = obu_header_size; // bytes read for current obu
// save the obu header (1 or 2 bytes)
memmove(saved_obu_header, buff_ptr, obu_header_size);
// clear the obu_has_size_field
saved_obu_header[0] = saved_obu_header[0] & (~0x2);
// get the payload_size and length of payload_size
if (aom_uleb_decode(buff_ptr + obu_header_size, remaining_size,
&obu_payload_size, &length_of_payload_size) != 0) {
return AOM_CODEC_ERROR;
}
obu_bytes_read += length_of_payload_size;
// calculate the length of size of the obu header plus payload
length_of_obu_size =
aom_uleb_size_in_bytes((uint64_t)(obu_header_size + obu_payload_size));
// move the rest of data to new location
memmove(buff_ptr + length_of_obu_size + obu_header_size,
buff_ptr + obu_bytes_read, remaining_size - obu_bytes_read);
obu_bytes_read += obu_payload_size;
// write the new obu size
const uint64_t obu_size = obu_header_size + obu_payload_size;
size_t coded_obu_size;
if (aom_uleb_encode(obu_size, sizeof(obu_size), buff_ptr,
&coded_obu_size) != 0) {
return AOM_CODEC_ERROR;
}
// write the saved (modified) obu_header following obu size
memmove(buff_ptr + length_of_obu_size, saved_obu_header, obu_header_size);
total_bytes_read += obu_bytes_read;
remaining_size -= obu_bytes_read;
buff_ptr += length_of_obu_size + obu_size;
output_size += length_of_obu_size + obu_size;
}
*frame_size = output_size;
return AOM_CODEC_OK;
}
void av1_apply_encoding_flags(AV1_COMP *cpi, aom_enc_frame_flags_t flags) {
// TODO(yunqingwang): For what references to use, external encoding flags
// should be consistent with internal reference frame selection. Need to
......
......@@ -288,6 +288,7 @@ typedef struct AV1EncoderConfig {
int enable_warped_motion;
int allow_warped_motion;
int enable_superres;
unsigned int save_as_annexb;
} AV1EncoderConfig;
static INLINE int is_lossless_requested(const AV1EncoderConfig *cfg) {
......@@ -619,6 +620,8 @@ int av1_set_internal_size(AV1_COMP *cpi, AOM_SCALING horiz_mode,
int av1_get_quantizer(struct AV1_COMP *cpi);
int av1_convert_sect5obus_to_annexb(uint8_t *buffer, size_t *input_size);
static INLINE int frame_is_kf_gf_arf(const AV1_COMP *cpi) {
return frame_is_intra_only(&cpi->common) || cpi->refresh_alt_ref_frame ||
(cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref);
......
......@@ -102,7 +102,7 @@ int main(int argc, char **argv) {
size_t buffer_size = 0;
int next_layer_id = 0;
struct AvxInputContext aom_input_ctx;
struct ObuDecInputContext obu_ctx = { &aom_input_ctx, NULL, 0, 0 };
struct ObuDecInputContext obu_ctx = { &aom_input_ctx, NULL, 0, 0, 0 };
aom_codec_stream_info_t si;
uint8_t tmpbuf[32];
unsigned int i;
......
......@@ -35,6 +35,10 @@ static int obudec_read_leb128(FILE *f, uint8_t *value_buffer,
if (!f || !value_buffer || !value_length || !value) return -1;
for (int len = 0; len < OBU_MAX_LENGTH_FIELD_SIZE; ++len) {
const size_t num_read = fread(&value_buffer[len], 1, 1, f);
if (num_read == 0 && feof(f)) {
*value_length = 0;
return 0;
}
if (num_read != 1) {
// Ran out of data before completing read of value.
return -1;
......@@ -82,8 +86,8 @@ static int obudec_read_obu_size(FILE *infile, uint64_t *obu_size,
// 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.
static int obudec_read_obu_header(FILE *f, size_t buffer_capacity,
uint8_t *obu_data, ObuHeader *obu_header,
size_t *bytes_read) {
int is_annexb, uint8_t *obu_data,
ObuHeader *obu_header, size_t *bytes_read) {
if (!f || buffer_capacity < (OBU_HEADER_SIZE + OBU_EXTENSION_SIZE) ||
!obu_data || !obu_header || !bytes_read) {
return -1;
......@@ -107,8 +111,8 @@ static int obudec_read_obu_header(FILE *f, size_t buffer_capacity,
}
size_t obu_bytes_parsed = 0;
const aom_codec_err_t parse_result =
aom_read_obu_header(obu_data, *bytes_read, &obu_bytes_parsed, obu_header);
const aom_codec_err_t parse_result = aom_read_obu_header(
obu_data, *bytes_read, &obu_bytes_parsed, obu_header, is_annexb);
if (parse_result != AOM_CODEC_OK || *bytes_read != obu_bytes_parsed) {
fprintf(stderr, "obudec: Error parsing OBU header.\n");
return -1;
......@@ -133,7 +137,7 @@ static int obudec_read_obu_payload(FILE *f, uint64_t payload_length,
return 0;
}
static int obudec_read_one_obu(FILE *f, size_t buffer_capacity,
static int obudec_read_one_obu(FILE *f, size_t buffer_capacity, int is_annexb,
uint8_t *obu_data, uint64_t *obu_length,
ObuHeader *obu_header) {
const size_t kMinimumBufferSize = OBU_DETECTION_SIZE;
......@@ -142,8 +146,22 @@ static int obudec_read_one_obu(FILE *f, size_t buffer_capacity,
return -1;
}
uint64_t obu_payload_length = 0;
size_t leb128_length = 0;
uint64_t obu_size = 0;
if (is_annexb) {
if (obudec_read_leb128(f, &obu_data[0], &leb128_length, &obu_size) != 0) {
fprintf(stderr, "obudec: Failure reading OBU size length.\n");
return -1;
} else if (leb128_length == 0) {
*obu_length = 0;
return 0;
}
}
size_t bytes_read = 0;
if (obudec_read_obu_header(f, buffer_capacity, obu_data, obu_header,
if (obudec_read_obu_header(f, buffer_capacity, is_annexb,
obu_data + leb128_length, obu_header,
&bytes_read) != 0) {
return -1;
} else if (bytes_read == 0) {
......@@ -151,13 +169,18 @@ static int obudec_read_one_obu(FILE *f, size_t buffer_capacity,
return 0;
}
uint64_t obu_payload_length = 0;
size_t leb128_length = 0;
if (obudec_read_leb128(f, &obu_data[bytes_read], &leb128_length,
&obu_payload_length) != 0) {
fprintf(stderr, "obudec: Failure reading OBU payload length.\n");
return -1;
if (!is_annexb) {
if (obudec_read_leb128(f, &obu_data[bytes_read], &leb128_length,
&obu_payload_length) != 0) {
fprintf(stderr, "obudec: Failure reading OBU payload length.\n");
return -1;
}
}
if (is_annexb) {
obu_payload_length = obu_size - bytes_read;
}
bytes_read += leb128_length;
if (UINT64_MAX - bytes_read < obu_payload_length) return -1;
......@@ -181,14 +204,14 @@ int file_is_obu(struct ObuDecInputContext *obu_ctx) {
struct AvxInputContext *avx_ctx = obu_ctx->avx_ctx;
uint8_t detect_buf[OBU_DETECTION_SIZE] = { 0 };
const int is_annexb = obu_ctx->is_annexb;
FILE *f = avx_ctx->file;
uint64_t obu_length = 0;
ObuHeader obu_header;
memset(&obu_header, 0, sizeof(obu_header));
if (obudec_read_one_obu(f, OBU_DETECTION_SIZE, &detect_buf[0], &obu_length,
&obu_header) != 0) {
if (obudec_read_one_obu(f, OBU_DETECTION_SIZE, is_annexb, &detect_buf[0],
&obu_length, &obu_header) != 0) {
fprintf(stderr, "obudec: Failure reading first OBU.\n");
rewind(f);
return 0;
......@@ -213,10 +236,10 @@ int file_is_obu(struct ObuDecInputContext *obu_ctx) {
rewind(f);
return 0;
}
} else {
} else if (!is_annexb) {
fprintf(stderr, "obudec: OBU size fields required, cannot decode input.\n");
rewind(f);
return 0;
return (0);
}
// Appears that input is valid Section 5 AV1 stream.
......@@ -246,6 +269,7 @@ int obudec_read_temporal_unit(struct ObuDecInputContext *obu_ctx,
return 1;
}
const int is_annexb = obu_ctx->is_annexb;
while (1) {
ObuHeader obu_header;
memset(&obu_header, 0, sizeof(obu_header));
......@@ -254,7 +278,8 @@ int obudec_read_temporal_unit(struct ObuDecInputContext *obu_ctx,
uint8_t *data = obu_ctx->buffer + obu_ctx->bytes_buffered;
const size_t capacity = obu_ctx->buffer_capacity - obu_ctx->bytes_buffered;
if (obudec_read_one_obu(f, capacity, data, &obu_size, &obu_header) != 0) {
if (obudec_read_one_obu(f, capacity, is_annexb, data, &obu_size,
&obu_header) != 0) {
fprintf(stderr, "obudec: read_one_obu failed in TU loop\n");
return -1;
}
......
......@@ -22,9 +22,11 @@ struct ObuDecInputContext {
uint8_t *buffer;
size_t buffer_capacity;
size_t bytes_buffered;
int is_annexb;
};
// Returns 1 when file data starts with what appears to be a Temporal Delimiter
// Returns 1 when file data starts (if Annex B stream, after reading the
// size of the OBU) with what appears to be a Temporal Delimiter
// OBU as defined by Section 5 of the AV1 bitstream specification.
int file_is_obu(struct ObuDecInputContext *obu_ctx);
......
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