Obtain aom_image metadata on decode

- Added aom_img_get_metadata() function so user can obtain metadata
associated with an aom_image.
- Added aom_img_num_metadata() function so user can get the number of
metadata blocks associated with an aom_image.
- Added image metadata array to AV1Decoder so it can be obtained during
decoding process.
- Implemented read_metadata_itut_t35() to parse ITU-T T.35 metadata from
stream to metadata array.
- Added necessary tests for these new functions.
- Only ITU-T T.35 metadata decoding is implemented in this CL.

BUG=aomedia:2507

Change-Id: I4e3a54c2859cd968ef6e9f1e01a92a557e6e4d1d
diff --git a/aom/aom_image.h b/aom/aom_image.h
index 863277e..0cf2e9e 100644
--- a/aom/aom_image.h
+++ b/aom/aom_image.h
@@ -30,7 +30,7 @@
  * types, removing or reassigning enums, adding/removing/rearranging
  * fields to structures
  */
-#define AOM_IMAGE_ABI_VERSION (6) /**<\hideinitializer*/
+#define AOM_IMAGE_ABI_VERSION (7) /**<\hideinitializer*/
 
 #define AOM_IMG_FMT_PLANAR 0x100  /**< Image is a planar format. */
 #define AOM_IMG_FMT_UV_FLIP 0x200 /**< V plane precedes U in memory. */
@@ -351,6 +351,32 @@
 int aom_img_add_metadata(aom_image_t *img, uint32_t type, const uint8_t *data,
                          size_t sz);
 
+/*!\brief Return a metadata payload stored within the image metadata array.
+ *
+ * Gets the metadata (aom_metadata_t) at the indicated index in the image
+ * metadata array. Caller of this function owns the memory.
+ *
+ * \param[in] img          Pointer to image descriptor to get metadata from
+ * \param[in] index        Metadata index to get from metadata array
+ *
+ * \return Returns a pointer to a newly allocated copy of the selected metadata,
+ * if img and/or index is invalid, it returns NULL.
+ */
+aom_metadata_t *aom_img_get_metadata(aom_image_t *img, size_t index);
+
+/*!\brief Return the number of metadata blocks within the image.
+ *
+ * Gets the number of metadata blocks contained within the provided image
+ * metadata array.
+ *
+ * \param[in] img          Pointer to image descriptor to get metadata number
+ * from.
+ *
+ * \return Returns the size of the metadata array. If img or metadata is NULL,
+ * it returns 0.
+ */
+size_t aom_img_num_metadata(aom_image_t *img);
+
 /*!\brief Remove metadata from image.
  *
  * Removes all metadata in image metadata list and sets metadata list pointer
diff --git a/aom/exports_com b/aom/exports_com
index a192cf9..68dbfe0 100644
--- a/aom/exports_com
+++ b/aom/exports_com
@@ -15,10 +15,12 @@
 text aom_img_alloc_with_border
 text aom_img_flip
 text aom_img_free
+text aom_img_get_metadata
 text aom_img_metadata_array_free
 text aom_img_metadata_array_alloc
 text aom_img_metadata_free
 text aom_img_metadata_alloc
+text aom_img_num_metadata
 text aom_img_plane_height
 text aom_img_plane_width
 text aom_img_remove_metadata
diff --git a/aom/src/aom_image.c b/aom/src/aom_image.c
index 5e2edb4..5fd2297 100644
--- a/aom/src/aom_image.c
+++ b/aom/src/aom_image.c
@@ -379,3 +379,20 @@
     img->metadata = NULL;
   }
 }
+
+aom_metadata_t *aom_img_get_metadata(aom_image_t *img, size_t index) {
+  if (!img) return NULL;
+  aom_metadata_t *metadata = NULL;
+  aom_metadata_array_t *array = img->metadata;
+  if (array && array->sz > 0 && index < array->sz) {
+    metadata = aom_img_metadata_alloc(array->metadata_array[index]->type,
+                                      array->metadata_array[index]->payload,
+                                      array->metadata_array[index]->sz);
+  }
+  return metadata;
+}
+
+size_t aom_img_num_metadata(aom_image_t *img) {
+  if (!img || !img->metadata) return 0;
+  return img->metadata->sz;
+}
diff --git a/av1/av1_dx_iface.c b/av1/av1_dx_iface.c
index 6b06ad4..91432d7 100644
--- a/av1/av1_dx_iface.c
+++ b/av1/av1_dx_iface.c
@@ -802,6 +802,18 @@
           if (ctx->need_resync) return NULL;
           yuvconfig2image(&ctx->img, sd, frame_worker_data->user_priv);
 
+          if (pbi->metadata != NULL) {
+            int array_size = (int)pbi->metadata->sz;
+            for (int i = 0; i < array_size; ++i) {
+              aom_img_add_metadata(&ctx->img,
+                                   pbi->metadata->metadata_array[i]->type,
+                                   pbi->metadata->metadata_array[i]->payload,
+                                   pbi->metadata->metadata_array[i]->sz);
+            }
+            aom_img_metadata_array_free(pbi->metadata);
+            pbi->metadata = NULL;
+          }
+
           if (!pbi->ext_tile_debug && cm->large_scale_tile) {
             *index += 1;  // Advance the iterator to point to the next image
 
diff --git a/av1/decoder/decoder.h b/av1/decoder/decoder.h
index 61206dd..be13918 100644
--- a/av1/decoder/decoder.h
+++ b/av1/decoder/decoder.h
@@ -243,6 +243,7 @@
 #endif
 
   AV1DecRowMTInfo frame_row_mt_info;
+  aom_metadata_array_t *metadata;
 } AV1Decoder;
 
 // Returns 0 on success. Sets pbi->common.error.error_code to a nonzero error
diff --git a/av1/decoder/obu.c b/av1/decoder/obu.c
index 3619264..2bdedc0 100644
--- a/av1/decoder/obu.c
+++ b/av1/decoder/obu.c
@@ -548,32 +548,33 @@
   return tile_list_payload_size;
 }
 
-// Reads the country code as specified in Recommendation ITU-T T.35. On
-// success, returns the number of bytes read from 'data'. On failure, calls
+// On success, returns the number of bytes read from 'data'. On failure, calls
 // aom_internal_error() and does not return.
-//
-// Note: This function does not read itu_t_t35_payload_bytes because the exact
-// syntax of itu_t_t35_payload_bytes is not defined in the spec.
-static size_t read_metadata_itut_t35(AV1_COMMON *const cm, const uint8_t *data,
+static size_t read_metadata_itut_t35(AV1Decoder *const pbi, const uint8_t *data,
                                      size_t sz) {
-  size_t i = 0;
-  // itu_t_t35_country_code f(8)
-  if (i >= sz) {
+  if (sz <= 0) {
+    AV1_COMMON *const cm = &pbi->common;
     aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
                        "itu_t_t35_country_code is missing");
   }
-  const int itu_t_t35_country_code = data[i];
-  ++i;
-  if (itu_t_t35_country_code == 0xFF) {
-    // itu_t_t35_country_code_extension_byte f(8)
-    if (i >= sz) {
-      aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
-                         "itu_t_t35_country_code_extension_byte is missing");
+
+  if (!pbi->metadata) {
+    pbi->metadata = aom_img_metadata_array_alloc(1);
+  } else {
+    aom_metadata_array_t *metadata =
+        aom_img_metadata_array_alloc(pbi->metadata->sz + 1);
+    for (size_t i = 0; i < pbi->metadata->sz; ++i) {
+      metadata->metadata_array[i] =
+          aom_img_metadata_alloc(pbi->metadata->metadata_array[i]->type,
+                                 pbi->metadata->metadata_array[i]->payload,
+                                 pbi->metadata->metadata_array[i]->sz);
     }
-    ++i;
+    aom_img_metadata_array_free(pbi->metadata);
+    pbi->metadata = metadata;
   }
-  // itu_t_t35_payload_bytes
-  return i;
+  pbi->metadata->metadata_array[pbi->metadata->sz - 1] =
+      aom_img_metadata_alloc(OBU_METADATA_TYPE_ITUT_T35, data, sz - 1);
+  return sz - 1;
 }
 
 static void read_metadata_hdr_cll(struct aom_read_bit_buffer *rb) {
@@ -709,7 +710,7 @@
   if (metadata_type == OBU_METADATA_TYPE_ITUT_T35) {
     size_t bytes_read =
         type_length +
-        read_metadata_itut_t35(cm, data + type_length, sz - type_length);
+        read_metadata_itut_t35(pbi, data + type_length, sz - type_length);
     // Ignore itu_t_t35_payload_bytes and check trailing bits. Section 6.7.2
     // of the spec says:
     //   itu_t_t35_payload_bytes shall be bytes containing data registered as
diff --git a/test/metadata_test.cc b/test/metadata_test.cc
index bd8a1dd..0c55cbc 100644
--- a/test/metadata_test.cc
+++ b/test/metadata_test.cc
@@ -48,6 +48,9 @@
       ASSERT_EQ(aom_img_add_metadata(current_frame, OBU_METADATA_TYPE_ITUT_T35,
                                      kExampleData, kExampleDataSize),
                 0);
+      ASSERT_EQ(aom_img_add_metadata(current_frame, OBU_METADATA_TYPE_ITUT_T35,
+                                     kExampleData, kExampleDataSize),
+                0);
     }
   }
 
@@ -71,6 +74,16 @@
       EXPECT_TRUE(found_metadata);
     }
   }
+
+  virtual void DecompressedFrameHook(const aom_image_t &img,
+                                     aom_codec_pts_t /*pts*/) {
+    ASSERT_TRUE(img.metadata != nullptr);
+    EXPECT_EQ(img.metadata->sz, 2u);
+    EXPECT_EQ(memcmp(kExampleData, img.metadata->metadata_array[0]->payload,
+                     kExampleDataSize),
+              0);
+    aom_img_metadata_array_free(img.metadata);
+  }
 };
 
 TEST_P(MetadataEncodeTest, TestMetadataEncoding) {
@@ -181,3 +194,45 @@
   aom_remove_metadata_from_frame_buffer(&yvBuf);
   aom_remove_metadata_from_frame_buffer(NULL);
 }
+
+TEST(MetadataTest, GetMetadataFromImage) {
+  aom_image_t image;
+  image.metadata = NULL;
+
+  ASSERT_EQ(aom_img_add_metadata(&image, OBU_METADATA_TYPE_ITUT_T35,
+                                 kExampleData, kExampleDataSize),
+            0);
+
+  EXPECT_TRUE(aom_img_get_metadata(NULL, 0) == NULL);
+  EXPECT_TRUE(aom_img_get_metadata(&image, 10u) == NULL);
+
+  aom_metadata_t *metadata = aom_img_get_metadata(&image, 0);
+  EXPECT_TRUE(metadata != NULL);
+  aom_img_metadata_free(metadata);
+  aom_img_metadata_array_free(image.metadata);
+}
+
+TEST(MetadataTest, ReadMetadatasFromImage) {
+  aom_image_t image;
+  image.metadata = NULL;
+
+  ASSERT_EQ(aom_img_add_metadata(&image, OBU_METADATA_TYPE_ITUT_T35,
+                                 kExampleData, kExampleDataSize),
+            0);
+  ASSERT_EQ(aom_img_add_metadata(&image, OBU_METADATA_TYPE_HDR_CLL,
+                                 kExampleData, kExampleDataSize),
+            0);
+  ASSERT_EQ(aom_img_add_metadata(&image, OBU_METADATA_TYPE_HDR_MDCV,
+                                 kExampleData, kExampleDataSize),
+            0);
+
+  size_t number_metadata = aom_img_num_metadata(&image);
+  EXPECT_EQ(number_metadata, 3u);
+  for (size_t i = 0; i < number_metadata; ++i) {
+    aom_metadata_t *metadata = aom_img_get_metadata(&image, i);
+    ASSERT_TRUE(metadata != NULL);
+    EXPECT_EQ(memcmp(kExampleData, metadata->payload, kExampleDataSize), 0);
+    aom_img_metadata_free(metadata);
+  }
+  aom_img_metadata_array_free(image.metadata);
+}