Adds metadata container for aom_image
- Adds aom_metadata struct to contain the different types of metadata
payloads an image can carry along with its alloc and free functions.
- Adds aom_metadata_array struct to aom_image to contain the different
metadata payloads an aom_image could contain.
- Adds the code needed to move metadata around libaom in lookahead.c and
to pass it from yuv12_buffer to aom_image and viceversa.
- Adds tests to check alloc/dealloc metadata functions.
The expectation is for user to use aom_add_metadata_to_img() function
to add a metadata payload to an aom_image_t to prevent him from doing
direct metadata pointer assignation. The function makes sure the memory
belongs to libaom by doing a memcpy of the input. User should free his
own memory.
BUG=aomedia:2507
Change-Id: I2e2b4f5dcd3c61d8715b11949802b23191390beb
diff --git a/aom/aom_image.h b/aom/aom_image.h
index 5f615d7..d07d485 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 (5) /**<\hideinitializer*/
+#define AOM_IMAGE_ABI_VERSION (6) /**<\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. */
@@ -137,6 +137,16 @@
AOM_CSP_RESERVED = 3 /**< Reserved value */
} aom_chroma_sample_position_t; /**< alias for enum aom_transfer_function */
+/*!\brief Array of aom_metadata structs for an image. */
+typedef struct aom_metadata_array aom_metadata_array_t;
+
+/*!\brief Metadata payload. */
+typedef struct aom_metadata {
+ uint8_t type; /**< Metadata type */
+ uint8_t *payload; /**< Metadata payload data */
+ size_t sz; /**< Metadata payload size */
+} aom_metadata_t;
+
/**\brief Image Descriptor */
typedef struct aom_image {
aom_img_fmt_t fmt; /**< Image Format */
@@ -188,6 +198,9 @@
int img_data_owner; /**< private */
int self_allocd; /**< private */
+ aom_metadata_array_t
+ *metadata; /**< Metadata payloads associated with the image. */
+
void *fb_priv; /**< Frame buffer data associated with the image. */
} aom_image_t; /**< alias for struct aom_image */
@@ -324,6 +337,52 @@
*/
int aom_img_plane_height(const aom_image_t *img, int plane);
+/*!\brief Add metadata to image.
+ *
+ * Adds metadata to aom_image_t.
+ * Function makes a copy of the provided data parameter.
+ *
+ * \param[in] img Image descriptor
+ * \param[in] type Metadata type
+ * \param[in] data Metadata contents
+ * \param[in] sz Metadata contents size
+ */
+int aom_img_add_metadata(aom_image_t *img, uint8_t type, uint8_t *data,
+ size_t sz);
+
+/*!\brief Remove metadata from image.
+ *
+ * Removes all metadata in image metadata list and sets metadata list pointer
+ * to NULL.
+ * Returns the number of deleted metadata structs.
+ *
+ * \param[in] img Image descriptor
+ */
+size_t aom_img_remove_metadata(aom_image_t *img);
+
+/*!\brief Allocate memory for aom_metadata struct.
+ *
+ * Allocates memory for aom_metadata struct and sets its type. Optionally
+ * allocates storage for the metadata payload and copies the payload data
+ * into the aom_metadata struct:
+ * - When sz is > 0 and data is NULL, allocates metadata payload buffer of sz.
+ * - When sz is > 0 and data is non-NULL, a metadata payload buffer of sz
+ * is allocated and sz bytes are copied from data into the payload buffer.
+ *
+ * \param[in] type Metadata type
+ * \param[in] data Metadata data pointer
+ * \param[in] sz Metadata size
+ */
+aom_metadata_t *aom_img_metadata_alloc(uint8_t type, uint8_t *data, size_t sz);
+
+/*!\brief Free metadata struct.
+ *
+ * Free metadata struct and its buffer.
+ *
+ * \param[in] metadata Metadata struct pointer
+ */
+int aom_img_metadata_free(aom_metadata_t *metadata);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/aom/exports_com b/aom/exports_com
index cf99bc5..a192cf9 100644
--- a/aom/exports_com
+++ b/aom/exports_com
@@ -10,12 +10,18 @@
text aom_codec_version_extra_str
text aom_codec_version_str
text aom_free
+text aom_img_add_metadata
text aom_img_alloc
text aom_img_alloc_with_border
text aom_img_flip
text aom_img_free
+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_plane_height
text aom_img_plane_width
+text aom_img_remove_metadata
text aom_img_set_rect
text aom_img_wrap
text aom_malloc
diff --git a/aom/exports_test b/aom/exports_test
index 01b864b..452a532 100644
--- a/aom/exports_test
+++ b/aom/exports_test
@@ -1,2 +1,4 @@
+text aom_copy_metadata_to_frame_buffer
text aom_dsp_rtcd
+text aom_remove_metadata_from_frame_buffer
text aom_scale_rtcd
diff --git a/aom/internal/aom_image_internal.h b/aom/internal/aom_image_internal.h
index ba9cb64..2629d65 100644
--- a/aom/internal/aom_image_internal.h
+++ b/aom/internal/aom_image_internal.h
@@ -23,6 +23,32 @@
extern "C" {
#endif
+/*!\brief Array of aom_metadata structs for an image. */
+struct aom_metadata_array {
+ size_t sz; /* Number of metadata structs in the list */
+ aom_metadata_t **metadata_array; /* Array of metadata structs */
+};
+
+/*!\brief Alloc memory for aom_metadata_array struct.
+ *
+ * Allocate memory for aom_metadata_array struct.
+ * If sz is 0 the aom_metadata_array structs internal buffer list will be NULL,
+ * but the aom_metadata_array struct itself will still be allocated.
+ * Returns a pointer to the allocated struct or NULL on failure.
+ *
+ * \param[in] sz Size of internal metadata list buffer
+ */
+aom_metadata_array_t *aom_img_metadata_array_alloc(size_t sz);
+
+/*!\brief Free metadata array struct.
+ *
+ * Free metadata array struct and all metadata structs inside.
+ * Returns the number of deleted metadata structs.
+ *
+ * \param[in] arr Metadata array struct pointer
+ */
+size_t aom_img_metadata_array_free(aom_metadata_array_t *arr);
+
typedef void *(*aom_alloc_img_data_cb_fn_t)(void *priv, size_t size);
/*!\brief Open a descriptor, allocating storage for the underlying image by
diff --git a/aom/src/aom_image.c b/aom/src/aom_image.c
index f703504..9f7ed99 100644
--- a/aom/src/aom_image.c
+++ b/aom/src/aom_image.c
@@ -267,6 +267,7 @@
void aom_img_free(aom_image_t *img) {
if (img) {
+ aom_img_remove_metadata(img);
if (img->img_data && img->img_data_owner) aom_free(img->img_data);
if (img->self_allocd) free(img);
@@ -286,3 +287,99 @@
else
return img->d_h;
}
+
+aom_metadata_t *aom_img_metadata_alloc(uint8_t type, uint8_t *data, size_t sz) {
+ aom_metadata_t *metadata =
+ (aom_metadata_t *)calloc(1, sizeof(aom_metadata_t));
+ if (!metadata) return NULL;
+ metadata->type = type;
+ if (sz > 0) {
+ metadata->payload = (uint8_t *)calloc(sz, sizeof(uint8_t));
+ if (!metadata->payload) {
+ free(metadata);
+ return NULL;
+ }
+ if (data) {
+ memcpy(metadata->payload, data, sz);
+ metadata->sz = sz;
+ }
+ }
+ return metadata;
+}
+
+int aom_img_metadata_free(aom_metadata_t *metadata) {
+ if (!metadata) return -1;
+ if (metadata->payload) free(metadata->payload);
+ free(metadata);
+ return 0;
+}
+
+aom_metadata_array_t *aom_img_metadata_array_alloc(size_t sz) {
+ aom_metadata_array_t *arr =
+ (aom_metadata_array_t *)calloc(1, sizeof(aom_metadata_array_t));
+ if (!arr) return NULL;
+ if (sz > 0) {
+ arr->metadata_array =
+ (aom_metadata_t **)calloc(sz, sizeof(aom_metadata_t *));
+ if (!arr->metadata_array) {
+ aom_img_metadata_array_free(arr);
+ return NULL;
+ }
+ arr->sz = sz;
+ }
+ return arr;
+}
+
+size_t aom_img_metadata_array_free(aom_metadata_array_t *arr) {
+ size_t deleted_metadatas = 0;
+ if (!arr) return deleted_metadatas;
+ if (arr->metadata_array) {
+ for (size_t i = 0; i < arr->sz; i++) {
+ if (aom_img_metadata_free(arr->metadata_array[i]) == 0) {
+ deleted_metadatas++;
+ }
+ }
+ free(arr->metadata_array);
+ }
+ free(arr);
+ return deleted_metadatas;
+}
+
+int aom_img_add_metadata(aom_image_t *img, uint8_t type, uint8_t *data,
+ size_t sz) {
+ if (!img) return -1;
+ if (!img->metadata) {
+ img->metadata = aom_img_metadata_array_alloc(0);
+ if (!img->metadata) return -1;
+ }
+ aom_metadata_t *metadata = aom_img_metadata_alloc(type, data, sz);
+ if (!metadata) goto fail;
+ if (!img->metadata->metadata_array) {
+ img->metadata->metadata_array =
+ (aom_metadata_t **)calloc(1, sizeof(metadata));
+ if (!img->metadata->metadata_array || img->metadata->sz != 0) {
+ aom_img_metadata_free(metadata);
+ goto fail;
+ }
+ } else {
+ img->metadata->metadata_array =
+ (aom_metadata_t **)realloc(img->metadata->metadata_array,
+ (img->metadata->sz + 1) * sizeof(metadata));
+ }
+ img->metadata->metadata_array[img->metadata->sz] = metadata;
+ img->metadata->sz++;
+ return 0;
+fail:
+ aom_img_metadata_array_free(img->metadata);
+ img->metadata = NULL;
+ return -1;
+}
+
+size_t aom_img_remove_metadata(aom_image_t *img) {
+ if (img && img->metadata) {
+ size_t sz = aom_img_metadata_array_free(img->metadata);
+ img->metadata = NULL;
+ return sz;
+ }
+ return 0;
+}
diff --git a/aom_scale/generic/yv12config.c b/aom_scale/generic/yv12config.c
index 6406b18..8de3531 100644
--- a/aom_scale/generic/yv12config.c
+++ b/aom_scale/generic/yv12config.c
@@ -31,7 +31,7 @@
aom_free(ybf->buffer_alloc);
}
if (ybf->y_buffer_8bit) aom_free(ybf->y_buffer_8bit);
-
+ aom_remove_metadata_from_frame_buffer(ybf);
/* buffer_alloc isn't accessed by most functions. Rather y_buffer,
u_buffer and v_buffer point to buffer_alloc and are used. Clear out
all of this so that a freed pointer isn't inadvertently used */
@@ -287,3 +287,32 @@
}
return AOM_CODEC_MEM_ERROR;
}
+
+size_t aom_remove_metadata_from_frame_buffer(YV12_BUFFER_CONFIG *ybf) {
+ if (ybf && ybf->metadata) {
+ size_t sz = aom_img_metadata_array_free(ybf->metadata);
+ ybf->metadata = NULL;
+ return sz;
+ }
+ return 0;
+}
+
+int aom_copy_metadata_to_frame_buffer(YV12_BUFFER_CONFIG *ybf,
+ aom_metadata_array_t *arr) {
+ if (!ybf || !arr || !arr->metadata_array) return -1;
+ aom_remove_metadata_from_frame_buffer(ybf);
+ ybf->metadata = aom_img_metadata_array_alloc(arr->sz);
+ if (!ybf->metadata) return 0;
+ for (size_t i = 0; i < ybf->metadata->sz; i++) {
+ ybf->metadata->metadata_array[i] = aom_img_metadata_alloc(
+ arr->metadata_array[i]->type, arr->metadata_array[i]->payload,
+ arr->metadata_array[i]->sz);
+ if (ybf->metadata->metadata_array[i] == NULL) {
+ aom_img_metadata_array_free(ybf->metadata);
+ ybf->metadata = NULL;
+ return -1;
+ }
+ }
+ ybf->metadata->sz = arr->sz;
+ return 0;
+}
diff --git a/aom_scale/yv12config.h b/aom_scale/yv12config.h
index 04a1c04..43856f0 100644
--- a/aom_scale/yv12config.h
+++ b/aom_scale/yv12config.h
@@ -21,6 +21,7 @@
#include "aom/aom_codec.h"
#include "aom/aom_frame_buffer.h"
#include "aom/aom_integer.h"
+#include "aom/internal/aom_image_internal.h"
#define AOMINNERBORDERINPIXELS 160
#define AOM_INTERP_EXTEND 4
@@ -105,6 +106,7 @@
int corrupted;
int flags;
+ aom_metadata_array_t *metadata;
} YV12_BUFFER_CONFIG;
#define YV12_FLAG_HIGHBITDEPTH 8
@@ -135,6 +137,30 @@
int aom_free_frame_buffer(YV12_BUFFER_CONFIG *ybf);
+/*!\brief Removes metadata from YUV_BUFFER_CONFIG struct.
+ *
+ * Frees metadata in frame buffer.
+ * Frame buffer metadata pointer will be set to NULL.
+ * Returns the number of deleted metadata structs.
+ *
+ * \param[in] ybf Frame buffer struct pointer
+ */
+size_t aom_remove_metadata_from_frame_buffer(YV12_BUFFER_CONFIG *ybf);
+
+/*!\brief Copy metadata to YUV_BUFFER_CONFIG struct.
+ *
+ * Copies metadata in frame buffer.
+ * Frame buffer will clear any previous metadata and will reallocate the
+ * metadata array to the new metadata size. Then, it will copy the new metadata
+ * array into it.
+ * Returns 0 on success or -1 on failure.
+ *
+ * \param[in] ybf Frame buffer struct pointer
+ * \param[in] arr Metadata array struct pointer
+ */
+int aom_copy_metadata_to_frame_buffer(YV12_BUFFER_CONFIG *ybf,
+ aom_metadata_array_t *arr);
+
#ifdef __cplusplus
}
#endif
diff --git a/av1/av1_iface_common.h b/av1/av1_iface_common.h
index 81ec619..f87fd1b 100644
--- a/av1/av1_iface_common.h
+++ b/av1/av1_iface_common.h
@@ -74,6 +74,7 @@
img->img_data_owner = 0;
img->self_allocd = 0;
img->sz = yv12->frame_size;
+ img->metadata = yv12->metadata;
}
static aom_codec_err_t image2yuvconfig(const aom_image_t *img,
@@ -133,6 +134,7 @@
yv12->border = (border < 0) ? 0 : border;
yv12->subsampling_x = img->x_chroma_shift;
yv12->subsampling_y = img->y_chroma_shift;
+ yv12->metadata = img->metadata;
return AOM_CODEC_OK;
}
diff --git a/av1/encoder/lookahead.c b/av1/encoder/lookahead.c
index b6ae9e2..818b3c3 100644
--- a/av1/encoder/lookahead.c
+++ b/av1/encoder/lookahead.c
@@ -180,6 +180,8 @@
buf->ts_start = ts_start;
buf->ts_end = ts_end;
buf->flags = flags;
+ aom_remove_metadata_from_frame_buffer(&buf->img);
+ aom_copy_metadata_to_frame_buffer(&buf->img, src->metadata);
return 0;
}
diff --git a/test/metadata_memory_handling_test.cc b/test/metadata_memory_handling_test.cc
new file mode 100644
index 0000000..fdd4f92
--- /dev/null
+++ b/test/metadata_memory_handling_test.cc
@@ -0,0 +1,110 @@
+#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
+
+#include "aom/aom_codec.h"
+#include "aom/internal/aom_image_internal.h"
+#include "aom_scale/yv12config.h"
+
+TEST(MetadataMemoryHandlingTest, MetadataAllocation) {
+ aom_metadata_t *metadata;
+ uint8_t data[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ metadata = aom_img_metadata_alloc(OBU_METADATA_TYPE_ITUT_T35, data, 10);
+ ASSERT_TRUE(metadata != NULL);
+
+ int status = aom_img_metadata_free(metadata);
+ EXPECT_EQ(status, 0);
+}
+
+TEST(MetadataMemoryHandlingTest, MetadataArrayAllocation) {
+ aom_metadata_array_t *metadata_array;
+ uint8_t data[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ metadata_array = aom_img_metadata_array_alloc(2);
+ ASSERT_TRUE(metadata_array != NULL);
+
+ metadata_array->metadata_array[0] =
+ aom_img_metadata_alloc(OBU_METADATA_TYPE_ITUT_T35, data, 10);
+ metadata_array->metadata_array[1] =
+ aom_img_metadata_alloc(OBU_METADATA_TYPE_ITUT_T35, data, 10);
+
+ int status = aom_img_metadata_array_free(metadata_array);
+ EXPECT_EQ(status, 2);
+}
+
+TEST(MetadataMemoryHandlingTest, AddMetadataToImage) {
+ aom_image_t image;
+ image.metadata = NULL;
+
+ uint8_t data[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ int status =
+ aom_img_add_metadata(&image, OBU_METADATA_TYPE_ITUT_T35, data, 10);
+ ASSERT_EQ(status, 0);
+
+ status = aom_img_metadata_array_free(image.metadata);
+ EXPECT_EQ(status, 1);
+
+ status = aom_img_add_metadata(NULL, OBU_METADATA_TYPE_ITUT_T35, data, 10);
+ EXPECT_EQ(status, -1);
+}
+
+TEST(MetadataMemoryHandlingTest, RemoveMetadataFromImage) {
+ aom_image_t image;
+ image.metadata = NULL;
+
+ uint8_t data[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ int status =
+ aom_img_add_metadata(&image, OBU_METADATA_TYPE_ITUT_T35, data, 10);
+ ASSERT_EQ(status, 0);
+
+ status = aom_img_remove_metadata(&image);
+ EXPECT_EQ(status, 1);
+
+ status = aom_img_remove_metadata(NULL);
+ EXPECT_EQ(status, 0);
+}
+
+TEST(MetadataMemoryHandlingTest, CopyMetadataToFrameBUffer) {
+ YV12_BUFFER_CONFIG yvBuf;
+ yvBuf.metadata = NULL;
+ aom_metadata_array_t *metadata_array;
+ aom_metadata_array_t *metadata_array_2;
+ uint8_t data[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ metadata_array = aom_img_metadata_array_alloc(1);
+ ASSERT_TRUE(metadata_array != NULL);
+
+ metadata_array->metadata_array[0] =
+ aom_img_metadata_alloc(OBU_METADATA_TYPE_ITUT_T35, data, 10);
+
+ // Metadata_array
+ int status = aom_copy_metadata_to_frame_buffer(&yvBuf, metadata_array);
+ EXPECT_EQ(status, 0);
+
+ status = aom_copy_metadata_to_frame_buffer(NULL, metadata_array);
+ EXPECT_EQ(status, -1);
+
+ status = aom_img_metadata_array_free(metadata_array);
+ EXPECT_EQ(status, 1);
+
+ // Metadata_array_2
+ metadata_array_2 = aom_img_metadata_array_alloc(0);
+ ASSERT_TRUE(metadata_array_2 != NULL);
+
+ status = aom_copy_metadata_to_frame_buffer(&yvBuf, metadata_array_2);
+ EXPECT_EQ(status, -1);
+
+ status = aom_img_metadata_array_free(metadata_array_2);
+ EXPECT_EQ(status, 0);
+
+ // YV12_BUFFER_CONFIG
+ status = aom_copy_metadata_to_frame_buffer(&yvBuf, NULL);
+ EXPECT_EQ(status, -1);
+
+ status = aom_remove_metadata_from_frame_buffer(NULL);
+ EXPECT_EQ(status, 0);
+
+ status = aom_remove_metadata_from_frame_buffer(&yvBuf);
+ EXPECT_EQ(status, 1);
+}
diff --git a/test/test.cmake b/test/test.cmake
index 4e3540f..8c721b5 100644
--- a/test/test.cmake
+++ b/test/test.cmake
@@ -34,6 +34,7 @@
"${AOM_ROOT}/test/decode_test_driver.h"
"${AOM_ROOT}/test/function_equivalence_test.h"
"${AOM_ROOT}/test/log2_test.cc"
+ "${AOM_ROOT}/test/metadata_memory_handling_test.cc"
"${AOM_ROOT}/test/md5_helper.h"
"${AOM_ROOT}/test/register_state_check.h"
"${AOM_ROOT}/test/test_vectors.cc"