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