[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
diff --git a/aom/aom_decoder.h b/aom/aom_decoder.h index 3c67fb3..3973c50 100644 --- a/aom/aom_decoder.h +++ b/aom/aom_decoder.h
@@ -85,6 +85,7 @@ 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
diff --git a/aom/aom_encoder.h b/aom/aom_encoder.h index e93d081..d54d89f 100644 --- a/aom/aom_encoder.h +++ b/aom/aom_encoder.h
@@ -663,6 +663,14 @@ */ 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
diff --git a/aom/aomdx.h b/aom/aomdx.h index 2beba60..b3a5fb1 100644 --- a/aom/aomdx.h +++ b/aom/aomdx.h
@@ -146,6 +146,9 @@ */ 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 @@ #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 */
diff --git a/aomdec.c b/aomdec.c index b765335..9fd8f0a 100644 --- a/aomdec.c +++ b/aomdec.c
@@ -111,13 +111,17 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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));
diff --git a/aomenc.c b/aomenc.c index b601080..6afa006 100644 --- a/aomenc.c +++ b/aomenc.c
@@ -380,6 +380,8 @@ 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 @@ &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 @@ 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 @@ 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");
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c index fd94390..f93e21c 100644 --- a/av1/av1_cx_iface.c +++ b/av1/av1_cx_iface.c
@@ -655,6 +655,8 @@ 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 @@ 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 @@ 1, // sframe_mode 0, // large_scale_tile 0, // monochrome + 0, // save_as_annexb 0, // tile_width_count 0, // tile_height_count { 0 }, // tile_widths
diff --git a/av1/av1_dx_iface.c b/av1/av1_dx_iface.c index bcf7078..f3ae661 100644 --- a/av1/av1_dx_iface.c +++ b/av1/av1_dx_iface.c
@@ -59,6 +59,7 @@ 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 @@ 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 @@ 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 @@ // 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 @@ 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 @@ 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 @@ 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 @@ { 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
diff --git a/av1/common/onyxc_int.h b/av1/common/onyxc_int.h index 2623445..b491724 100644 --- a/av1/common/onyxc_int.h +++ b/av1/common/onyxc_int.h
@@ -516,6 +516,9 @@ 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;
diff --git a/av1/decoder/obu.c b/av1/decoder/obu.c index 4a3828b..40434bf 100644 --- a/av1/decoder/obu.c +++ b/av1/decoder/obu.c
@@ -76,7 +76,7 @@ // 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 @@ 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 @@ } 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 @@ } 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) {
diff --git a/av1/decoder/obu.h b/av1/decoder/obu.h index 9fe5795..2295c69 100644 --- a/av1/decoder/obu.h +++ b/av1/decoder/obu.h
@@ -35,7 +35,8 @@ 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,
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c index ac1ae9b..7849ae3 100644 --- a/av1/encoder/encoder.c +++ b/av1/encoder/encoder.c
@@ -5935,6 +5935,63 @@ 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
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h index df7c434..fde3298 100644 --- a/av1/encoder/encoder.h +++ b/av1/encoder/encoder.h
@@ -288,6 +288,7 @@ 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_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);
diff --git a/examples/scalable_decoder.c b/examples/scalable_decoder.c index 3586df6..6b41c85 100644 --- a/examples/scalable_decoder.c +++ b/examples/scalable_decoder.c
@@ -102,7 +102,7 @@ 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;
diff --git a/obudec.c b/obudec.c index 4d035c1..1ce7d24 100644 --- a/obudec.c +++ b/obudec.c
@@ -35,6 +35,10 @@ 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 @@ // 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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; }
diff --git a/obudec.h b/obudec.h index 158202e..c413f20 100644 --- a/obudec.h +++ b/obudec.h
@@ -22,9 +22,11 @@ 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);