adding support for trailing bits write/read
Change-Id: I012e7af7370fa9de7acbcd03a271b16f2b8b5ae8
diff --git a/aom_dsp/bitwriter.h b/aom_dsp/bitwriter.h
index d6972a1..1f84df6 100644
--- a/aom_dsp/bitwriter.h
+++ b/aom_dsp/bitwriter.h
@@ -52,8 +52,8 @@
aom_daala_start_encode(bc, buffer);
}
-static INLINE void aom_stop_encode(aom_writer *bc) {
- aom_daala_stop_encode(bc);
+static INLINE int aom_stop_encode(aom_writer *bc) {
+ return aom_daala_stop_encode(bc);
}
static INLINE void aom_write(aom_writer *br, int bit, int probability) {
diff --git a/aom_dsp/bitwriter_buffer.c b/aom_dsp/bitwriter_buffer.c
index 75260a8..cad52cb 100644
--- a/aom_dsp/bitwriter_buffer.c
+++ b/aom_dsp/bitwriter_buffer.c
@@ -15,6 +15,12 @@
#include "./aom_config.h"
#include "./bitwriter_buffer.h"
+#if CONFIG_TRAILING_BITS
+int aom_wb_is_byte_aligned(const struct aom_write_bit_buffer *wb) {
+ return (wb->bit_offset % CHAR_BIT == 0);
+}
+#endif
+
uint32_t aom_wb_bytes_written(const struct aom_write_bit_buffer *wb) {
return wb->bit_offset / CHAR_BIT + (wb->bit_offset % CHAR_BIT > 0);
}
diff --git a/aom_dsp/bitwriter_buffer.h b/aom_dsp/bitwriter_buffer.h
index 85a7883..f273d76 100644
--- a/aom_dsp/bitwriter_buffer.h
+++ b/aom_dsp/bitwriter_buffer.h
@@ -23,6 +23,10 @@
uint32_t bit_offset;
};
+#if CONFIG_TRAILING_BITS
+int aom_wb_is_byte_aligned(const struct aom_write_bit_buffer *wb);
+#endif
+
uint32_t aom_wb_bytes_written(const struct aom_write_bit_buffer *wb);
void aom_wb_write_bit(struct aom_write_bit_buffer *wb, int bit);
diff --git a/aom_dsp/daalaboolwriter.c b/aom_dsp/daalaboolwriter.c
index 59af2a2..b24ffbf 100644
--- a/aom_dsp/daalaboolwriter.c
+++ b/aom_dsp/daalaboolwriter.c
@@ -18,11 +18,14 @@
od_ec_enc_init(&br->ec, 62025);
}
-void aom_daala_stop_encode(daala_writer *br) {
+int aom_daala_stop_encode(daala_writer *br) {
+ int nb_bits;
uint32_t daala_bytes;
unsigned char *daala_data;
daala_data = od_ec_enc_done(&br->ec, &daala_bytes);
+ nb_bits = od_ec_enc_tell(&br->ec);
memcpy(br->buffer, daala_data, daala_bytes);
br->pos = daala_bytes;
od_ec_enc_clear(&br->ec);
+ return nb_bits;
}
diff --git a/aom_dsp/daalaboolwriter.h b/aom_dsp/daalaboolwriter.h
index e10885b..f9c596c 100644
--- a/aom_dsp/daalaboolwriter.h
+++ b/aom_dsp/daalaboolwriter.h
@@ -34,7 +34,7 @@
typedef struct daala_writer daala_writer;
void aom_daala_start_encode(daala_writer *w, uint8_t *buffer);
-void aom_daala_stop_encode(daala_writer *w);
+int aom_daala_stop_encode(daala_writer *w);
static INLINE void aom_daala_write(daala_writer *w, int bit, int prob) {
int p = (0x7FFFFF - (prob << 15) + prob) >> 8;
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index 62523c4..3a9d57e 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -3329,8 +3329,14 @@
}
}
-int av1_decode_frame_headers_and_setup(AV1Decoder *pbi, const uint8_t *data,
+int av1_decode_frame_headers_and_setup(AV1Decoder *pbi,
+#if CONFIG_TRAILING_BITS
+ struct aom_read_bit_buffer *rb,
+#endif
+ const uint8_t *data,
+#if !CONFIG_TRAILING_BITS
const uint8_t *data_end,
+#endif
const uint8_t **p_data_end) {
AV1_COMMON *const cm = &pbi->common;
const int num_planes = av1_num_planes(cm);
@@ -3349,9 +3355,15 @@
}
xd->global_motion = cm->global_motion;
+#if !CONFIG_TRAILING_BITS
struct aom_read_bit_buffer rb;
+#endif
read_uncompressed_header(pbi,
+#if CONFIG_TRAILING_BITS
+ rb);
+#else
av1_init_read_bit_buffer(pbi, &rb, data, data_end));
+#endif
// If cm->single_tile_decoding = 0, the independent decoding of a single tile
// or a section of a frame is not allowed.
@@ -3361,7 +3373,11 @@
pbi->dec_tile_col = -1;
}
+#if CONFIG_TRAILING_BITS
+ pbi->uncomp_hdr_size = aom_rb_bytes_read(rb);
+#else
pbi->uncomp_hdr_size = aom_rb_bytes_read(&rb);
+#endif
YV12_BUFFER_CONFIG *new_fb = get_frame_new_buffer(cm);
xd->cur_buf = new_fb;
if (av1_allow_intrabc(cm)) {
@@ -3371,8 +3387,12 @@
}
if (cm->show_existing_frame) {
- // showing a frame directly
+ // showing a frame directly
+#if CONFIG_TRAILING_BITS
+ *p_data_end = data + aom_rb_bytes_read(rb);
+#else
*p_data_end = data + aom_rb_bytes_read(&rb);
+#endif
#if CONFIG_FWD_KF
if (cm->reset_decoder_state) {
// Use the default frame context values.
diff --git a/av1/decoder/decodeframe.h b/av1/decoder/decodeframe.h
index 4759426..7520251 100644
--- a/av1/decoder/decodeframe.h
+++ b/av1/decoder/decodeframe.h
@@ -30,8 +30,13 @@
void av1_decode_frame(struct AV1Decoder *pbi, const uint8_t *data,
const uint8_t *data_end, const uint8_t **p_data_end);
int av1_decode_frame_headers_and_setup(struct AV1Decoder *pbi,
+#if CONFIG_TRAILING_BITS
+ struct aom_read_bit_buffer *rb,
+#endif
const uint8_t *data,
+#if !CONFIG_TRAILING_BITS
const uint8_t *data_end,
+#endif
const uint8_t **p_data_end);
void av1_decode_tg_tiles_and_wrapup(struct AV1Decoder *pbi, const uint8_t *data,
diff --git a/av1/decoder/obu.c b/av1/decoder/obu.c
index 6667b9a..565be02 100644
--- a/av1/decoder/obu.c
+++ b/av1/decoder/obu.c
@@ -127,6 +127,23 @@
return AOM_CODEC_OK;
}
+#if CONFIG_TRAILING_BITS
+// Checks that the remaining bits start with a 1 and ends with 0s.
+// May consume an additional byte, if already byte aligned before the check.
+static int check_trailing_bits(AV1Decoder *pbi,
+ struct aom_read_bit_buffer *rb) {
+ AV1_COMMON *const cm = &pbi->common;
+ // bit_offset is set to 0 (mod 8) when the reader is already byte aligned
+ int bits_before_alignment = 8 - rb->bit_offset % 8;
+ int trailing = aom_rb_read_literal(rb, bits_before_alignment);
+ if (trailing != (1 << (bits_before_alignment - 1))) {
+ cm->error.error_code = AOM_CODEC_CORRUPT_FRAME;
+ return 1;
+ }
+ return 0;
+}
+#endif
+
static uint32_t read_temporal_delimiter_obu() { return 0; }
static uint32_t read_sequence_header_obu(AV1Decoder *pbi,
@@ -162,10 +179,24 @@
return ((rb->bit_offset - saved_bit_offset + 7) >> 3);
}
-static uint32_t read_frame_header_obu(AV1Decoder *pbi, const uint8_t *data,
+static uint32_t read_frame_header_obu(AV1Decoder *pbi,
+#if CONFIG_TRAILING_BITS
+ struct aom_read_bit_buffer *rb,
+#endif
+ const uint8_t *data,
+#if !CONFIG_TRAILING_BITS
const uint8_t *data_end,
+#endif
const uint8_t **p_data_end) {
- av1_decode_frame_headers_and_setup(pbi, data, data_end, p_data_end);
+ av1_decode_frame_headers_and_setup(pbi,
+#if CONFIG_TRAILING_BITS
+ rb,
+#endif
+ data,
+#if !CONFIG_TRAILING_BITS
+ data_end,
+#endif
+ p_data_end);
return (uint32_t)(pbi->uncomp_hdr_size);
}
@@ -428,8 +459,18 @@
#endif // CONFIG_OBU_FRAME
// Only decode first frame header received
if (!frame_header_received) {
- frame_header_size =
- read_frame_header_obu(pbi, data, data_end, p_data_end);
+#if CONFIG_TRAILING_BITS
+ av1_init_read_bit_buffer(pbi, &rb, data, data_end);
+#endif
+ frame_header_size = read_frame_header_obu(pbi,
+#if CONFIG_TRAILING_BITS
+ &rb,
+#endif
+ data,
+#if !CONFIG_TRAILING_BITS
+ data_end,
+#endif
+ p_data_end);
frame_header_received = 1;
}
decoded_payload_size = frame_header_size;
@@ -469,6 +510,18 @@
break;
}
+#if CONFIG_TRAILING_BITS
+ // Cannot check bit pattern at the end of frame, redundant frame headers,
+ // tile group, metadata, padding or unrecognized OBUs
+ // because the current code consumes or skips all bytes
+ if (payload_size > 0 &&
+ (obu_header.type == OBU_SEQUENCE_HEADER ||
+ obu_header.type == OBU_FRAME_HEADER) &&
+ check_trailing_bits(pbi, &rb)) {
+ return;
+ }
+#endif
+
// Check that the signalled OBU size matches the actual amount of data read
if (decoded_payload_size != payload_size) {
cm->error.error_code = AOM_CODEC_CORRUPT_FRAME;
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index 42aa3ef..6d2786c 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -3529,6 +3529,17 @@
return length_field_size;
}
+#if CONFIG_TRAILING_BITS
+static void add_trailing_bits(struct aom_write_bit_buffer *wb) {
+ if (aom_wb_is_byte_aligned(wb)) {
+ aom_wb_write_literal(wb, 0x80, 8);
+ } else {
+ // assumes that the other bits are already 0s
+ aom_wb_write_bit(wb, 1);
+ }
+}
+#endif
+
static uint32_t write_sequence_header_obu(AV1_COMP *cpi, uint8_t *const dst
#if CONFIG_SCALABILITY
,
@@ -3563,6 +3574,10 @@
aom_wb_write_bit(&wb, cm->film_grain_params_present);
#endif
+#if CONFIG_TRAILING_BITS
+ add_trailing_bits(&wb);
+#endif
+
size = aom_wb_bytes_written(&wb);
return size;
}
@@ -3582,6 +3597,10 @@
return total_size;
}
+#if CONFIG_TRAILING_BITS
+ add_trailing_bits(&wb);
+#endif
+
uncompressed_hdr_size = aom_wb_bytes_written(&wb);
total_size = uncompressed_hdr_size;
return total_size;
@@ -3799,6 +3818,9 @@
const int is_last_col = (tile_col == tile_cols - 1);
const int is_last_tile = is_last_col && is_last_row;
int is_last_tile_in_tg = 0;
+#if CONFIG_TRAILING_BITS
+ int nb_bits = 0;
+#endif
if (new_tg) {
data = dst + total_size;
@@ -3857,10 +3879,31 @@
aom_start_encode(&mode_bc, dst + total_size);
write_modes(cpi, &tile_info, &mode_bc, &tok, tok_end);
+#if CONFIG_TRAILING_BITS
+ nb_bits = aom_stop_encode(&mode_bc);
+#else
aom_stop_encode(&mode_bc);
+#endif
tile_size = mode_bc.pos;
assert(tile_size > 0);
+#if CONFIG_TRAILING_BITS
+ // similar to add_trailing_bits, but specific to end of last tile
+ if (is_last_tile) {
+ if (nb_bits % 8 == 0) {
+ // the arithmetic encoder ended on a byte boundary
+ // adding a 0b10000000 byte
+ *(dst + total_size + tile_size) = 0x80;
+ tile_size += 1;
+ } else {
+ // arithmetic encoder left several 0 bits
+ // changing the first 0 bit to 1
+ int bit_offset = 7 - nb_bits % 8;
+ *(dst + total_size + tile_size) |= 1 << bit_offset;
+ }
+ }
+#endif
+
curr_tg_data_size += (tile_size + (is_last_tile_in_tg ? 0 : 4));
buf->size = tile_size;
if (tile_size > *max_tile_size) {
diff --git a/build/cmake/aom_config_defaults.cmake b/build/cmake/aom_config_defaults.cmake
index 1327432..83fb26a 100644
--- a/build/cmake/aom_config_defaults.cmake
+++ b/build/cmake/aom_config_defaults.cmake
@@ -119,4 +119,5 @@
set(CONFIG_SKIP_SGR 1 CACHE NUMBER "AV1 experiment flag.")
set(CONFIG_SPATIAL_SEGMENTATION 1 CACHE NUMBER "AV1 experiment flag.")
set(CONFIG_TILE_INFO_FIRST 0 CACHE NUMBER "AV1 experiment flag.")
+set(CONFIG_TRAILING_BITS 0 CACHE NUMBER "AV1 experiment flag.")
set(CONFIG_FILEOPTIONS 1 CACHE NUMBER "AV1 config option flag.")