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"