Add 'is_layer_specific_obu' param to av1_write_obu_header
Refactor to later allow making some metadata OBUs layer-specific.
Bug: 377851082
Change-Id: Ice49b9fa4ee3053d0eb93d6bec821dbac1bd153e
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index e936afc..813a988 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -3507,7 +3507,8 @@
obu_header_size = av1_write_obu_header(
&ppi->level_params, &cpi->frame_header_count,
OBU_TEMPORAL_DELIMITER,
- ppi->seq_params.has_nonzero_operating_point_idc, 0, ctx->cx_data);
+ ppi->seq_params.has_nonzero_operating_point_idc,
+ /*is_layer_specific_obu=*/false, 0, ctx->cx_data);
if (obu_header_size != 1) {
aom_internal_error(&ppi->error, AOM_CODEC_ERROR, NULL);
}
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index 7826a9c..70728dd 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -3379,7 +3379,8 @@
uint32_t av1_write_obu_header(AV1LevelParams *const level_params,
int *frame_header_count, OBU_TYPE obu_type,
bool has_nonzero_operating_point_idc,
- int obu_extension, uint8_t *const dst) {
+ bool is_layer_specific_obu, int obu_extension,
+ uint8_t *const dst) {
assert(IMPLIES(!has_nonzero_operating_point_idc, obu_extension == 0));
if (level_params->keep_level_stats &&
@@ -3388,29 +3389,22 @@
uint32_t size = 0;
- // The AV1 spec Version 1.0.0 with Errata 1 has the following requirements on
- // the OBU extension header:
+ // The AV1 spec draft version (as of git commit 5e04f)
+ // has the following requirements on the OBU extension header:
//
// 6.4.1. General sequence header OBU semantics:
+ // If operating_point_idc[ op ] is not equal to 0 for any value of op from 0
+ // to operating_points_cnt_minus_1, it is a requirement of bitstream
+ // conformance that obu_extension_flag is equal to 1 for all layer-specific
+ // OBUs in the coded video sequence.
+ // (...)
// It is a requirement of bitstream conformance that if OperatingPointIdc
// is equal to 0, then obu_extension_flag is equal to 0 for all OBUs that
// follow this sequence header until the next sequence header.
//
- // 7.5. Ordering of OBUs:
- // If a coded video sequence contains at least one enhancement layer (OBUs
- // with spatial_id greater than 0 or temporal_id greater than 0) then all
- // frame headers and tile group OBUs associated with base (spatial_id
- // equals 0 and temporal_id equals 0) and enhancement layer (spatial_id
- // greater than 0 or temporal_id greater than 0) data must include the OBU
- // extension header.
- //
// Set obu_extension_flag to satisfy these requirements.
- int obu_extension_flag = 0;
- if (has_nonzero_operating_point_idc) {
- obu_extension_flag =
- (obu_type == OBU_FRAME_HEADER || obu_type == OBU_TILE_GROUP ||
- obu_type == OBU_FRAME || obu_type == OBU_REDUNDANT_FRAME_HEADER);
- }
+ const int obu_extension_flag =
+ has_nonzero_operating_point_idc && is_layer_specific_obu;
const int obu_has_size_field = 1;
dst[0] = ((int)obu_type << 3) | (obu_extension_flag << 2) |
@@ -3622,7 +3616,7 @@
lst_obu->tg_hdr_size = av1_write_obu_header(
level_params, &cpi->frame_header_count, obu_type,
cpi->common.seq_params->has_nonzero_operating_point_idc,
- obu_extension_header, *data);
+ /*is_layer_specific_obu=*/true, obu_extension_header, *data);
*data += lst_obu->tg_hdr_size;
const uint32_t frame_header_size =
@@ -3822,7 +3816,8 @@
*curr_tg_hdr_size = av1_write_obu_header(
&cpi->ppi->level_params, &cpi->frame_header_count, obu_type,
cm->seq_params->has_nonzero_operating_point_idc,
- pack_bs_params->obu_extn_header, pack_bs_params->tile_data_curr);
+ /*is_layer_specific_obu=*/true, pack_bs_params->obu_extn_header,
+ pack_bs_params->tile_data_curr);
pack_bs_params->obu_header_size = *curr_tg_hdr_size;
if (cpi->num_tg == 1)
@@ -3924,7 +3919,8 @@
&cpi->ppi->level_params, &cpi->frame_header_count,
OBU_REDUNDANT_FRAME_HEADER,
cpi->common.seq_params->has_nonzero_operating_point_idc,
- obu_extn_header, &curr_tg_start[fh_info->obu_header_byte_offset]);
+ /*is_layer_specific_obu=*/true, obu_extn_header,
+ &curr_tg_start[fh_info->obu_header_byte_offset]);
*curr_tg_data_size += fh_info->total_length;
*total_size += (uint32_t)fh_info->total_length;
@@ -4236,9 +4232,13 @@
aom_internal_error(cm->error, AOM_CODEC_ERROR,
"av1_write_metadata_array: output buffer full");
}
+ // According to the AV1 spec draft version (as of git commit 5e04f)
+ // Section 6.7.1, some metadata types can be layer specific, but we
+ // currently only support non-layer specific metadata.
obu_header_size = av1_write_obu_header(
&cpi->ppi->level_params, &cpi->frame_header_count, OBU_METADATA,
- cm->seq_params->has_nonzero_operating_point_idc, 0, dst);
+ cm->seq_params->has_nonzero_operating_point_idc,
+ /*is_layer_specific_obu=*/false, 0, dst);
assert(obu_header_size <= 2);
obu_payload_size =
av1_write_metadata_obu(current_metadata, dst + obu_header_size,
@@ -4305,7 +4305,8 @@
}
obu_header_size = av1_write_obu_header(
level_params, &cpi->frame_header_count, OBU_SEQUENCE_HEADER,
- cm->seq_params->has_nonzero_operating_point_idc, 0, data);
+ cm->seq_params->has_nonzero_operating_point_idc,
+ /*is_layer_specific_obu=*/false, 0, data);
assert(obu_header_size <= 2);
obu_payload_size = av1_write_sequence_header_obu(
cm->seq_params, data + obu_header_size, data_size - obu_header_size);
@@ -4345,8 +4346,8 @@
}
obu_header_size = av1_write_obu_header(
level_params, &cpi->frame_header_count, OBU_FRAME_HEADER,
- cm->seq_params->has_nonzero_operating_point_idc, obu_extension_header,
- data);
+ cm->seq_params->has_nonzero_operating_point_idc,
+ /*is_layer_specific_obu=*/true, obu_extension_header, data);
// TODO: bug 42302568 - Pass data_size - obu_header_size to
// write_frame_header_obu().
obu_payload_size = write_frame_header_obu(cpi, &cpi->td.mb.e_mbd, &saved_wb,
diff --git a/av1/encoder/bitstream.h b/av1/encoder/bitstream.h
index 66f21e8..a19977c 100644
--- a/av1/encoder/bitstream.h
+++ b/av1/encoder/bitstream.h
@@ -92,13 +92,14 @@
uint32_t av1_write_sequence_header_obu(const SequenceHeader *seq_params,
uint8_t *const dst, size_t dst_size);
-// Writes the OBU header byte, and the OBU header extension byte when
-// has_nonzero_operating_point_idc is true and the OBU is part of a frame.
+// Writes the OBU header byte, and the OBU header extension byte when both
+// has_nonzero_operating_point_idc and is_layer_specific_obu are true.
// Returns number of bytes written to 'dst'.
uint32_t av1_write_obu_header(AV1LevelParams *const level_params,
int *frame_header_count, OBU_TYPE obu_type,
bool has_nonzero_operating_point_idc,
- int obu_extension, uint8_t *const dst);
+ bool is_layer_specific_obu, int obu_extension,
+ uint8_t *const dst);
// Encodes obu_payload_size as a leb128 integer and writes it to the dest
// buffer. The output must fill the buffer exactly. Returns AOM_CODEC_OK on
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 1067288..44c92e5 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -5413,7 +5413,8 @@
if (av1_write_obu_header(&ppi->level_params, &ppi->cpi->frame_header_count,
OBU_SEQUENCE_HEADER,
- ppi->seq_params.has_nonzero_operating_point_idc, 0,
+ ppi->seq_params.has_nonzero_operating_point_idc,
+ /*is_layer_specific_obu=*/false, 0,
&header_buf[0]) != obu_header_size) {
return NULL;
}