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;
   }