From 68f31525258137aeadeb084395970ae2222b3ca5 Mon Sep 17 00:00:00 2001 From: Pierre-Anthony Lemieux Date: Fri, 10 Dec 2021 07:54:36 -0800 Subject: [PATCH] Address FFmpeg/devel review comments * Rename variables and functions * Fix rational initialization * Fix memory leaks when heap allocation fails * Replaced `unsigned long` with `uint_t` * Make `asset_locator_map` a stack object * `imf_close()` is now called automatically * Miscellaneous code path optimizations * Code style improved --- .clang-format | 3 +- imf-prepare-patches.sh | 67 ++--- imf-unit-tests.sh | 6 +- libavformat/imf.h | 139 +++++---- libavformat/imf_cpl.c | 388 ++++++++++++++---------- libavformat/imfdec.c | 650 +++++++++++++++++++++++----------------- libavformat/tests/imf.c | 148 +++++---- 7 files changed, 795 insertions(+), 606 deletions(-) diff --git a/.clang-format b/.clang-format index bf6b4e8cbe..1c41889729 100644 --- a/.clang-format +++ b/.clang-format @@ -4,7 +4,7 @@ AlignAfterOpenBracket: false AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: false AlignOperands: false -AlignTrailingComments: false +AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false @@ -22,6 +22,7 @@ BraceWrapping: AfterFunction: true BreakBeforeTernaryOperators: false BreakConstructorInitializersBeforeComma: true +BreakStringLiterals: true ColumnLimit: 0 CommentPragmas: '^ IWYU pragma:' ContinuationIndentWidth: 4 diff --git a/imf-prepare-patches.sh b/imf-prepare-patches.sh index 3f7fe4a7f3..3a1fbc8db4 100755 --- a/imf-prepare-patches.sh +++ b/imf-prepare-patches.sh @@ -2,7 +2,7 @@ set -e -PATCH_VERSION="5" +PATCH_VERSION="9" PATCH_NAME="avformat/imf" @@ -11,14 +11,12 @@ PATCH_BRANCH="rd/patches" PATCHES_DIR="build/patches" -PATCHES_IMF_HEADERS="libavformat/imf.h" -PATCHES_IMF_DEC="libavformat/imfdec.c" -PATCHES_IMF_CPL="libavformat/imf_cpl.c" -PATCHES_IMF_TESTS="libavformat/tests/imf.c" -PATCHES_MXF="libavformat/mxf.h libavformat/mxfdec.c" +PATCHES_SRC="libavformat/imf.h libavformat/imf_cpl.c libavformat/imfdec.c" PATCHES_MISC="MAINTAINERS configure doc/demuxers.texi libavformat/Makefile libavformat/allformats.c" +PATCHES_MAKEFILE="libavformat/Makefile" +PATCHES_TESTS="libavformat/tests/imf.c" -PATCHES_ALL="$PATCHES_IMF_HEADERS $PATCHES_IMF_DEC $PATCHES_IMF_CPL $PATCHES_IMF_TESTS $PATCHES_MXF $PATCHES_MISC" +PATCHES_ALL="$PATCHES_SRC $PATCHES_MAKEFILE $PATCHES_MISC $PATCHES_TESTS" git fetch --all @@ -30,9 +28,8 @@ git rebase $BASE_BRANCH git reset $BASE_BRANCH -AUGMENTED=" * POSSIBILITY OF SUCH DAMAGE.\n\ - *\n\ - * This file is part of FFmpeg.\n\ +# update copyright header +GPLCC=" * This file is part of FFmpeg.\n\ *\n\ * FFmpeg is free software; you can redistribute it and\/or\n\ * modify it under the terms of the GNU Lesser General Public\n\ @@ -46,14 +43,24 @@ AUGMENTED=" * POSSIBILITY OF SUCH DAMAGE.\n\ *\n\ * You should have received a copy of the GNU Lesser General Public\n\ * License along with FFmpeg; if not, write to the Free Software\n\ - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA" + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n\ + *\\/\n\ +\n\ +\\/*" + +sed -i "s/^ \* This file is part of FFmpeg\./$GPLCC/" $PATCHES_SRC $PATCHES_TESTS -sed -i "/^ \* This file is part of FFmpeg\./,+1 d" $PATCHES_IMF_HEADERS $PATCHES_IMF_DEC $PATCHES_IMF_CPL $PATCHES_IMF_TESTS -sed -i "s/^ \* POSSIBILITY OF SUCH DAMAGE\./$AUGMENTED/" $PATCHES_IMF_HEADERS $PATCHES_IMF_DEC $PATCHES_IMF_CPL $PATCHES_IMF_TESTS +# remove MXF documentation +sed -i "/^@section mxf/,+12d" doc/demuxers.texi -git add -- $PATCHES_ALL +# remove clang formatting commands +sed -i "/^\\/\\/ clang-format/d" $PATCHES_SRC $PATCHES_TESTS -git commit -m "${PATCH_NAME}: Headers" -- $PATCHES_IMF_HEADERS +# remove tests from Makefile +sed -i "/^TESTPROGS-\$(CONFIG_IMF_DEMUXER)/d" $PATCHES_MAKEFILE + +git add -- $PATCHES_SRC $PATCHES_MISC $PATCHES_MAKEFILE +git commit -m "${PATCH_NAME}: Demuxer" -- $PATCHES_SRC $PATCHES_MISC $PATCHES_MAKEFILE git notes add -m "The IMF demuxer accepts as input an IMF CPL. The assets referenced by the CPL can be contained in multiple deliveries, each defined by an ASSETMAP file: @@ -73,32 +80,16 @@ The location of the Track Files referenced by the Composition Playlist is stored in one or more XML documents called Asset Maps. More details at https://www.imfug.com/explainer. The IMF standard was first introduced in 2013 and is managed by the SMPTE. -Header and build files. - CHANGE NOTES: -- fixed patchwork warnings -- updated patch notes -- added LGPL license -- removed imf_internal.h -- Improve error handling, including removing exit() -- Fix code style -- Allow custom I/O for all files (following DASH and HLS template) -- replace realloc with av_realloc_f to fix leaks" - -# git commit -m "[IMF demuxer] MCA improvements to MXF decoder" -- $PATCHES_MXF -# git notes add -m "Add support for SMPTE ST 377-4 (Multichannel Audio Labeling -- MCA) \ -# to the MXF decoder. MCA allows arbitrary audio channel configurations \ -# in MXF files." - -git commit -m "${PATCH_NAME}: CPL processor" -- $PATCHES_IMF_CPL -git notes add -m "Implements IMF Composition Playlist (CPL) parsing." - -git commit -m "${PATCH_NAME}: Demuxer implementation" -- $PATCHES_IMF_DEC -git notes add -m "Implements the IMF demuxer." +- fix leaks when head allocation fails +" -git commit -m "${PATCH_NAME}: Tests and build files" -- $PATCHES_IMF_TESTS $PATCHES_MISC -git notes add -m "Tests and build files for the IMF demuxer." +# add tests back to the Makefile +sed -i "/^TESTPROGS-\$(CONFIG_SRTP)/a TESTPROGS-\$(CONFIG_IMF_DEMUXER) += imf" $PATCHES_MAKEFILE +git add -- $PATCHES_TESTS $PATCHES_MAKEFILE +git commit -m "${PATCH_NAME}: Tests" -- $PATCHES_TESTS $PATCHES_MAKEFILE +git notes add -m "Tests for the IMF demuxer." mkdir -p $PATCHES_DIR diff --git a/imf-unit-tests.sh b/imf-unit-tests.sh index e75998cb22..f65575fbcc 100755 --- a/imf-unit-tests.sh +++ b/imf-unit-tests.sh @@ -1,7 +1,11 @@ #!/bin/sh valgrind --leak-check=full ./ffmpeg -y -i http://ffmpeg-imf-samples-public.s3.us-west-1.amazonaws.com/callout_51_l_r_c_lfe_ls_rs.mxf -f wav /dev/null -valgrind --leak-check=full ./ffmpeg -y -i http://ffmpeg-imf-samples-public.s3-website-us-west-1.amazonaws.com/countdown/CPL_f5095caa-f204-4e1c-8a84-7af48c7ae16b.xml -f mp4 /dev/null + +valgrind --leak-check=full ./ffmpeg -y \ + -assetmaps http://ffmpeg-imf-samples-public.s3.us-west-1.amazonaws.com/countdown-qc/ASSETMAP.xml,http://ffmpeg-imf-samples-public.s3.us-west-1.amazonaws.com/countdown/ASSETMAP.xml \ + -i http://ffmpeg-imf-samples-public.s3-website-us-west-1.amazonaws.com/countdown/CPL_f5095caa-f204-4e1c-8a84-7af48c7ae16b.xml \ + -f mp4 /dev/null make libavformat/tests/imf valgrind --leak-check=full libavformat/tests/imf \ No newline at end of file diff --git a/libavformat/imf.h b/libavformat/imf.h index dbebdca4a9..27b9615c77 100644 --- a/libavformat/imf.h +++ b/libavformat/imf.h @@ -26,8 +26,9 @@ */ /** - * Public header file for the processing of Interoperable Master Format (IMF) packages. - * + * Public header file for the processing of Interoperable Master Format (IMF) + * packages. + * * @author Pierre-Anthony Lemieux * @author Valentin Noel * @file @@ -42,142 +43,148 @@ #include "libavutil/rational.h" #include -#define IMF_UUID_FORMAT "urn:uuid:%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" +#define FF_UUID_FORMAT \ + "urn:uuid:%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-" \ + "%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" /** * UUID as defined in IETF RFC 422 */ -typedef uint8_t UUID[16]; +typedef uint8_t FFUUID[16]; /** * IMF Composition Playlist Base Resource */ -typedef struct IMFBaseResource { - AVRational edit_rate; /**< BaseResourceType/EditRate */ - unsigned long entry_point; /**< BaseResourceType/EntryPoint */ - unsigned long duration; /**< BaseResourceType/Duration */ - unsigned long repeat_count; /**< BaseResourceType/RepeatCount */ -} IMFBaseResource; +typedef struct FFIMFBaseResource { + AVRational edit_rate; /**< BaseResourceType/EditRate */ + uint32_t entry_point; /**< BaseResourceType/EntryPoint */ + uint32_t duration; /**< BaseResourceType/Duration */ + uint32_t repeat_count; /**< BaseResourceType/RepeatCount */ +} FFIMFBaseResource; /** * IMF Composition Playlist Track File Resource */ -typedef struct IMFTrackFileResource { - IMFBaseResource base; - UUID track_file_uuid; /**< TrackFileResourceType/TrackFileId */ -} IMFTrackFileResource; +typedef struct FFIMFTrackFileResource { + FFIMFBaseResource base; + FFUUID track_file_uuid; /**< TrackFileResourceType/TrackFileId */ +} FFIMFTrackFileResource; /** * IMF Marker */ -typedef struct IMFMarker { +typedef struct FFIMFMarker { xmlChar *label_utf8; /**< Marker/Label */ xmlChar *scope_utf8; /**< Marker/Label/\@scope */ - unsigned long offset; /**< Marker/Offset */ -} IMFMarker; + uint32_t offset; /**< Marker/Offset */ +} FFIMFMarker; /** * IMF Composition Playlist Marker Resource */ -typedef struct IMFMarkerResource { - IMFBaseResource base; - unsigned long marker_count; /**< Number of Marker elements */ - IMFMarker *markers; /**< Marker elements */ -} IMFMarkerResource; +typedef struct FFIMFMarkerResource { + FFIMFBaseResource base; + uint32_t marker_count; /**< Number of Marker elements */ + FFIMFMarker *markers; /**< Marker elements */ +} FFIMFMarkerResource; /** * IMF Composition Playlist Virtual Track */ -typedef struct IMFBaseVirtualTrack { - UUID id_uuid; /**< TrackId associated with the Virtual Track */ -} IMFBaseVirtualTrack; +typedef struct FFIMFBaseVirtualTrack { + FFUUID id_uuid; /**< TrackId associated with the Virtual Track */ +} FFIMFBaseVirtualTrack; /** * IMF Composition Playlist Virtual Track that consists of Track File Resources */ -typedef struct IMFTrackFileVirtualTrack { - IMFBaseVirtualTrack base; - unsigned long resource_count; /**< Number of Resource elements present in the Virtual Track */ - IMFTrackFileResource *resources; /**< Resource elements of the Virtual Track */ -} IMFTrackFileVirtualTrack; +typedef struct FFIMFTrackFileVirtualTrack { + FFIMFBaseVirtualTrack base; + uint32_t resource_count; /**< Number of Resource elements present in the Virtual Track */ + FFIMFTrackFileResource *resources; /**< Resource elements of the Virtual Track */ + uint32_t resources_alloc_sz; /**< Size of the resources buffer */ +} FFIMFTrackFileVirtualTrack; /** * IMF Composition Playlist Virtual Track that consists of Marker Resources */ -typedef struct IMFMarkerVirtualTrack { - IMFBaseVirtualTrack base; - unsigned long resource_count; /**< Number of Resource elements present in the Virtual Track */ - IMFMarkerResource *resources; /**< Resource elements of the Virtual Track */ -} IMFMarkerVirtualTrack; +typedef struct FFIMFMarkerVirtualTrack { + FFIMFBaseVirtualTrack base; + uint32_t resource_count; /**< Number of Resource elements present in the Virtual Track */ + FFIMFMarkerResource *resources; /**< Resource elements of the Virtual Track */ +} FFIMFMarkerVirtualTrack; /** * IMF Composition Playlist */ -typedef struct IMFCPL { - UUID id_uuid; /**< CompositionPlaylist/Id element */ - xmlChar *content_title_utf8; /**< CompositionPlaylist/ContentTitle element */ - AVRational edit_rate; /**< CompositionPlaylist/EditRate element */ - IMFMarkerVirtualTrack *main_markers_track; /**< Main Marker Virtual Track */ - IMFTrackFileVirtualTrack *main_image_2d_track; /**< Main Image Virtual Track */ - unsigned long main_audio_track_count; /**< Number of Main Audio Virtual Tracks */ - IMFTrackFileVirtualTrack *main_audio_tracks; /**< Main Audio Virtual Tracks */ -} IMFCPL; +typedef struct FFIMFCPL { + FFUUID id_uuid; /**< CompositionPlaylist/Id element */ + xmlChar *content_title_utf8; /**< CompositionPlaylist/ContentTitle element */ + AVRational edit_rate; /**< CompositionPlaylist/EditRate element */ + FFIMFMarkerVirtualTrack *main_markers_track; /**< Main Marker Virtual Track */ + FFIMFTrackFileVirtualTrack *main_image_2d_track; /**< Main Image Virtual Track */ + uint32_t main_audio_track_count; /**< Number of Main Audio Virtual Tracks */ + FFIMFTrackFileVirtualTrack *main_audio_tracks; /**< Main Audio Virtual Tracks */ +} FFIMFCPL; /** - * Parse an IMF CompositionPlaylist element into the IMFCPL data structure. + * Parse an IMF CompositionPlaylist element into the FFIMFCPL data structure. * @param[in] doc An XML document from which the CPL is read. - * @param[out] cpl Pointer to a memory area (allocated by the client), where the function writes a pointer to the newly constructed - * IMFCPL structure (or NULL if the CPL could not be parsed). The client is responsible for freeing the IMFCPL structure using - * imf_cpl_free(). + * @param[out] cpl Pointer to a memory area (allocated by the client), where the + * function writes a pointer to the newly constructed FFIMFCPL structure (or + * NULL if the CPL could not be parsed). The client is responsible for freeing + * the FFIMFCPL structure using ff_imf_cpl_free(). * @return A non-zero value in case of an error. */ -int parse_imf_cpl_from_xml_dom(xmlDocPtr doc, IMFCPL **cpl); +int ff_parse_imf_cpl_from_xml_dom(xmlDocPtr doc, FFIMFCPL **cpl); /** - * Parse an IMF Composition Playlist document into the IMFCPL data structure. + * Parse an IMF Composition Playlist document into the FFIMFCPL data structure. * @param[in] in The context from which the CPL is read. - * @param[out] cpl Pointer to a memory area (allocated by the client), where the function writes a pointer to the newly constructed - * IMFCPL structure (or NULL if the CPL could not be parsed). The client is responsible for freeing the IMFCPL structure using - * imf_cpl_free(). + * @param[out] cpl Pointer to a memory area (allocated by the client), where the + * function writes a pointer to the newly constructed FFIMFCPL structure (or + * NULL if the CPL could not be parsed). The client is responsible for freeing + * the FFIMFCPL structure using ff_imf_cpl_free(). * @return A non-zero value in case of an error. */ -int parse_imf_cpl(AVIOContext *in, IMFCPL **cpl); +int ff_parse_imf_cpl(AVIOContext *in, FFIMFCPL **cpl); /** - * Allocates and initializes an IMFCPL data structure. - * @return A pointer to the newly constructed IMFCPL structure (or NULL if the structure could not be constructed). The client is - * responsible for freeing the IMFCPL structure using imf_cpl_free(). + * Allocates and initializes an FFIMFCPL data structure. + * @return A pointer to the newly constructed FFIMFCPL structure (or NULL if the + * structure could not be constructed). The client is responsible for freeing + * the FFIMFCPL structure using ff_imf_cpl_free(). */ -IMFCPL *imf_cpl_alloc(void); +FFIMFCPL *ff_imf_cpl_alloc(void); /** - * Deletes an IMFCPL data structure previously instantiated with imf_cpl_alloc(). - * @param[in] cpl The IMFCPL structure to delete. + * Deletes an FFIMFCPL data structure previously instantiated with ff_imf_cpl_alloc(). + * @param[in] cpl The FFIMFCPL structure to delete. */ -void imf_cpl_free(IMFCPL *cpl); +void ff_imf_cpl_free(FFIMFCPL *cpl); /** - * Reads an unsigned long from an XML element + * Reads an unsigned 32-bit integer from an XML element * @return 0 on success, < 0 AVERROR code on error. */ -int imf_xml_read_ulong(xmlNodePtr element, unsigned long *number); +int ff_xml_read_uint32(xmlNodePtr element, uint32_t *number); /** * Reads an AVRational from an XML element * @return 0 on success, < 0 AVERROR code on error. */ -int imf_xml_read_rational(xmlNodePtr element, AVRational *rational); +int ff_xml_read_rational(xmlNodePtr element, AVRational *rational); /** * Reads a UUID from an XML element * @return 0 on success, < 0 AVERROR code on error. */ -int imf_xml_read_UUID(xmlNodePtr element, uint8_t uuid[16]); +int ff_xml_read_uuid(xmlNodePtr element, uint8_t uuid[16]); /** * Returns the first child element with the specified local name * @return A pointer to the child element, or NULL if no such child element exists. */ -xmlNodePtr imf_xml_get_child_element_by_name(xmlNodePtr parent, const char *name_utf8); +xmlNodePtr ff_xml_get_child_element_by_name(xmlNodePtr parent, const char *name_utf8); #endif diff --git a/libavformat/imf_cpl.c b/libavformat/imf_cpl.c index 765d1daaee..fbf34c7874 100644 --- a/libavformat/imf_cpl.c +++ b/libavformat/imf_cpl.c @@ -39,7 +39,7 @@ #include "libavutil/error.h" #include -xmlNodePtr imf_xml_get_child_element_by_name(xmlNodePtr parent, const char *name_utf8) +xmlNodePtr ff_xml_get_child_element_by_name(xmlNodePtr parent, const char *name_utf8) { xmlNodePtr cur_element; @@ -52,7 +52,7 @@ xmlNodePtr imf_xml_get_child_element_by_name(xmlNodePtr parent, const char *name return NULL; } -int imf_xml_read_UUID(xmlNodePtr element, uint8_t uuid[16]) +int ff_xml_read_uuid(xmlNodePtr element, uint8_t uuid[16]) { xmlChar *element_text = NULL; int scanf_ret; @@ -60,7 +60,7 @@ int imf_xml_read_UUID(xmlNodePtr element, uint8_t uuid[16]) element_text = xmlNodeListGetString(element->doc, element->xmlChildrenNode, 1); scanf_ret = sscanf(element_text, - IMF_UUID_FORMAT, + FF_UUID_FORMAT, &uuid[0], &uuid[1], &uuid[2], @@ -86,7 +86,7 @@ int imf_xml_read_UUID(xmlNodePtr element, uint8_t uuid[16]) return ret; } -int imf_xml_read_rational(xmlNodePtr element, AVRational *rational) +int ff_xml_read_rational(xmlNodePtr element, AVRational *rational) { xmlChar *element_text = NULL; int ret = 0; @@ -101,14 +101,14 @@ int imf_xml_read_rational(xmlNodePtr element, AVRational *rational) return ret; } -int imf_xml_read_ulong(xmlNodePtr element, unsigned long *number) +int ff_xml_read_uint32(xmlNodePtr element, uint32_t *number) { xmlChar *element_text = NULL; int ret = 0; element_text = xmlNodeListGetString(element->doc, element->xmlChildrenNode, 1); - if (sscanf(element_text, "%lu", number) != 1) { - av_log(NULL, AV_LOG_ERROR, "Invalid unsigned long"); + if (sscanf(element_text, "%" PRIu32, number) != 1) { + av_log(NULL, AV_LOG_ERROR, "Invalid unsigned 32-bit integer"); ret = AVERROR_INVALIDDATA; } xmlFree(element_text); @@ -116,105 +116,108 @@ int imf_xml_read_ulong(xmlNodePtr element, unsigned long *number) return ret; } -static void imf_base_virtual_track_init(IMFBaseVirtualTrack *track) +static void imf_base_virtual_track_init(FFIMFBaseVirtualTrack *track) { memset(track->id_uuid, 0, sizeof(track->id_uuid)); } -static void imf_marker_virtual_track_init(IMFMarkerVirtualTrack *track) +static void imf_marker_virtual_track_init(FFIMFMarkerVirtualTrack *track) { - imf_base_virtual_track_init((IMFBaseVirtualTrack *)track); + imf_base_virtual_track_init((FFIMFBaseVirtualTrack *)track); track->resource_count = 0; track->resources = NULL; } -static void imf_trackfile_virtual_track_init(IMFTrackFileVirtualTrack *track) +static void imf_trackfile_virtual_track_init(FFIMFTrackFileVirtualTrack *track) { - imf_base_virtual_track_init((IMFBaseVirtualTrack *)track); + imf_base_virtual_track_init((FFIMFBaseVirtualTrack *)track); track->resource_count = 0; + track->resources_alloc_sz = 0; track->resources = NULL; } -static void imf_base_resource_init(IMFBaseResource *rsrc) +static void imf_base_resource_init(FFIMFBaseResource *rsrc) { rsrc->duration = 0; - rsrc->edit_rate = av_make_q(0, 0); + rsrc->edit_rate = av_make_q(0, 1); rsrc->entry_point = 0; rsrc->repeat_count = 1; } -static void imf_marker_resource_init(IMFMarkerResource *rsrc) +static void imf_marker_resource_init(FFIMFMarkerResource *rsrc) { - imf_base_resource_init((IMFBaseResource *)rsrc); + imf_base_resource_init((FFIMFBaseResource *)rsrc); rsrc->marker_count = 0; rsrc->markers = NULL; } -static void imf_marker_init(IMFMarker *marker) +static void imf_marker_init(FFIMFMarker *marker) { marker->label_utf8 = NULL; marker->offset = 0; marker->scope_utf8 = NULL; } -static void imf_trackfile_resource_init(IMFTrackFileResource *rsrc) +static void imf_trackfile_resource_init(FFIMFTrackFileResource *rsrc) { - imf_base_resource_init((IMFBaseResource *)rsrc); + imf_base_resource_init((FFIMFBaseResource *)rsrc); memset(rsrc->track_file_uuid, 0, sizeof(rsrc->track_file_uuid)); } -static int fill_content_title(xmlNodePtr cpl_element, IMFCPL *cpl) +static int fill_content_title(xmlNodePtr cpl_element, FFIMFCPL *cpl) { xmlNodePtr element = NULL; - if (!(element = imf_xml_get_child_element_by_name(cpl_element, "ContentTitle"))) { + if (!(element = ff_xml_get_child_element_by_name(cpl_element, "ContentTitle"))) { av_log(NULL, AV_LOG_ERROR, "ContentTitle element not found in the IMF CPL\n"); return AVERROR_INVALIDDATA; } - cpl->content_title_utf8 = xmlNodeListGetString(cpl_element->doc, element->xmlChildrenNode, 1); + cpl->content_title_utf8 = xmlNodeListGetString(cpl_element->doc, + element->xmlChildrenNode, + 1); return 0; } -static int fill_edit_rate(xmlNodePtr cpl_element, IMFCPL *cpl) +static int fill_edit_rate(xmlNodePtr cpl_element, FFIMFCPL *cpl) { xmlNodePtr element = NULL; - if (!(element = imf_xml_get_child_element_by_name(cpl_element, "EditRate"))) { + if (!(element = ff_xml_get_child_element_by_name(cpl_element, "EditRate"))) { av_log(NULL, AV_LOG_ERROR, "EditRate element not found in the IMF CPL\n"); return AVERROR_INVALIDDATA; } - return imf_xml_read_rational(element, &cpl->edit_rate); + return ff_xml_read_rational(element, &cpl->edit_rate); } -static int fill_id(xmlNodePtr cpl_element, IMFCPL *cpl) +static int fill_id(xmlNodePtr cpl_element, FFIMFCPL *cpl) { xmlNodePtr element = NULL; - if (!(element = imf_xml_get_child_element_by_name(cpl_element, "Id"))) { + if (!(element = ff_xml_get_child_element_by_name(cpl_element, "Id"))) { av_log(NULL, AV_LOG_ERROR, "Id element not found in the IMF CPL\n"); return AVERROR_INVALIDDATA; } - return imf_xml_read_UUID(element, cpl->id_uuid); + return ff_xml_read_uuid(element, cpl->id_uuid); } -static int fill_marker(xmlNodePtr marker_elem, IMFMarker *marker) +static int fill_marker(xmlNodePtr marker_elem, FFIMFMarker *marker) { xmlNodePtr element = NULL; int ret = 0; /* read Offset */ - if (!(element = imf_xml_get_child_element_by_name(marker_elem, "Offset"))) { + if (!(element = ff_xml_get_child_element_by_name(marker_elem, "Offset"))) { av_log(NULL, AV_LOG_ERROR, "Offset element not found in a Marker\n"); return AVERROR_INVALIDDATA; } - if ((ret = imf_xml_read_ulong(element, &marker->offset))) + if ((ret = ff_xml_read_uint32(element, &marker->offset))) return ret; /* read Label and Scope */ - if (!(element = imf_xml_get_child_element_by_name(marker_elem, "Label"))) { + if (!(element = ff_xml_get_child_element_by_name(marker_elem, "Label"))) { av_log(NULL, AV_LOG_ERROR, "Label element not found in a Marker\n"); return AVERROR_INVALIDDATA; } @@ -224,71 +227,76 @@ static int fill_marker(xmlNodePtr marker_elem, IMFMarker *marker) } if (!(marker->scope_utf8 = xmlGetNoNsProp(element, "scope"))) { marker->scope_utf8 = xmlCharStrdup("http://www.smpte-ra.org/schemas/2067-3/2013#standard-markers"); + if (!marker->scope_utf8) { + xmlFree(marker->label_utf8); + return AVERROR(ENOMEM); + } } return ret; } -static int fill_base_resource(xmlNodePtr resource_elem, IMFBaseResource *resource, IMFCPL *cpl) +static int fill_base_resource(xmlNodePtr resource_elem, FFIMFBaseResource *resource, FFIMFCPL *cpl) { xmlNodePtr element = NULL; int ret = 0; /* read EditRate */ - if (!(element = imf_xml_get_child_element_by_name(resource_elem, "EditRate"))) { + if (!(element = ff_xml_get_child_element_by_name(resource_elem, "EditRate"))) { resource->edit_rate = cpl->edit_rate; - } else if (ret = imf_xml_read_rational(element, &resource->edit_rate)) { + } else if (ret = ff_xml_read_rational(element, &resource->edit_rate)) { av_log(NULL, AV_LOG_ERROR, "Invalid EditRate element found in a Resource\n"); return ret; } /* read EntryPoint */ - if (element = imf_xml_get_child_element_by_name(resource_elem, "EntryPoint")) { - if (ret = imf_xml_read_ulong(element, &resource->entry_point)) { + if (element = ff_xml_get_child_element_by_name(resource_elem, "EntryPoint")) { + if (ret = ff_xml_read_uint32(element, &resource->entry_point)) { av_log(NULL, AV_LOG_ERROR, "Invalid EntryPoint element found in a Resource\n"); return ret; } - } else + } else { resource->entry_point = 0; + } /* read IntrinsicDuration */ - if (!(element = imf_xml_get_child_element_by_name(resource_elem, "IntrinsicDuration"))) { + if (!(element = ff_xml_get_child_element_by_name(resource_elem, "IntrinsicDuration"))) { av_log(NULL, AV_LOG_ERROR, "IntrinsicDuration element missing from Resource\n"); return AVERROR_INVALIDDATA; } - if (ret = imf_xml_read_ulong(element, &resource->duration)) { + if (ret = ff_xml_read_uint32(element, &resource->duration)) { av_log(NULL, AV_LOG_ERROR, "Invalid IntrinsicDuration element found in a Resource\n"); return ret; } resource->duration -= resource->entry_point; /* read SourceDuration */ - if (element = imf_xml_get_child_element_by_name(resource_elem, "SourceDuration")) { - if (ret = imf_xml_read_ulong(element, &resource->duration)) { + if (element = ff_xml_get_child_element_by_name(resource_elem, "SourceDuration")) + if (ret = ff_xml_read_uint32(element, &resource->duration)) { av_log(NULL, AV_LOG_ERROR, "SourceDuration element missing from Resource\n"); return ret; } - } /* read RepeatCount */ - if (element = imf_xml_get_child_element_by_name(resource_elem, "RepeatCount")) { - ret = imf_xml_read_ulong(element, &resource->repeat_count); - } + if (element = ff_xml_get_child_element_by_name(resource_elem, "RepeatCount")) + ret = ff_xml_read_uint32(element, &resource->repeat_count); return ret; } -static int fill_trackfile_resource(xmlNodePtr tf_resource_elem, IMFTrackFileResource *tf_resource, IMFCPL *cpl) +static int fill_trackfile_resource(xmlNodePtr tf_resource_elem, + FFIMFTrackFileResource *tf_resource, + FFIMFCPL *cpl) { xmlNodePtr element = NULL; int ret = 0; - if (ret = fill_base_resource(tf_resource_elem, (IMFBaseResource *)tf_resource, cpl)) + if (ret = fill_base_resource(tf_resource_elem, (FFIMFBaseResource *)tf_resource, cpl)) return ret; /* read TrackFileId */ - if (element = imf_xml_get_child_element_by_name(tf_resource_elem, "TrackFileId")) { - if (ret = imf_xml_read_UUID(element, tf_resource->track_file_uuid)) { + if (element = ff_xml_get_child_element_by_name(tf_resource_elem, "TrackFileId")) { + if (ret = ff_xml_read_uuid(element, tf_resource->track_file_uuid)) { av_log(NULL, AV_LOG_ERROR, "Invalid TrackFileId element found in Resource\n"); return ret; } @@ -300,25 +308,32 @@ static int fill_trackfile_resource(xmlNodePtr tf_resource_elem, IMFTrackFileReso return ret; } -static int fill_marker_resource(xmlNodePtr marker_resource_elem, IMFMarkerResource *marker_resource, IMFCPL *cpl) +static int fill_marker_resource(xmlNodePtr marker_resource_elem, + FFIMFMarkerResource *marker_resource, + FFIMFCPL *cpl) { xmlNodePtr element = NULL; + void *tmp; int ret = 0; - if (ret = fill_base_resource(marker_resource_elem, (IMFBaseResource *)marker_resource, cpl)) + if (ret = fill_base_resource(marker_resource_elem, (FFIMFBaseResource *)marker_resource, cpl)) return ret; /* read markers */ element = xmlFirstElementChild(marker_resource_elem); while (element) { if (xmlStrcmp(element->name, "Marker") == 0) { - marker_resource->markers = av_realloc_f(marker_resource->markers, ++marker_resource->marker_count, sizeof(IMFMarker)); - if (!marker_resource->markers) { - av_log(NULL, AV_LOG_PANIC, "Cannot allocate Marker\n"); + tmp = av_realloc(marker_resource->markers, + (marker_resource->marker_count + 1) * sizeof(FFIMFMarker)); + if (!tmp) return AVERROR(ENOMEM); - } - imf_marker_init(&marker_resource->markers[marker_resource->marker_count - 1]); - fill_marker(element, &marker_resource->markers[marker_resource->marker_count - 1]); + marker_resource->markers = tmp; + imf_marker_init(&marker_resource->markers[marker_resource->marker_count]); + ret = fill_marker(element, + &marker_resource->markers[marker_resource->marker_count]); + marker_resource->marker_count++; + if (ret) + return ret; } element = xmlNextElementSibling(element); } @@ -326,32 +341,35 @@ static int fill_marker_resource(xmlNodePtr marker_resource_elem, IMFMarkerResour return ret; } -static int push_marker_sequence(xmlNodePtr marker_sequence_elem, IMFCPL *cpl) +static int push_marker_sequence(xmlNodePtr marker_sequence_elem, FFIMFCPL *cpl) { int ret = 0; uint8_t uuid[16]; xmlNodePtr resource_list_elem = NULL; xmlNodePtr resource_elem = NULL; xmlNodePtr track_id_elem = NULL; + unsigned long resource_elem_count; + void *tmp; /* read TrackID element */ - if (!(track_id_elem = imf_xml_get_child_element_by_name(marker_sequence_elem, "TrackId"))) { + if (!(track_id_elem = ff_xml_get_child_element_by_name(marker_sequence_elem, "TrackId"))) { av_log(NULL, AV_LOG_ERROR, "TrackId element missing from Sequence\n"); return AVERROR_INVALIDDATA; } - if (ret = imf_xml_read_UUID(track_id_elem, uuid)) { + if (ret = ff_xml_read_uuid(track_id_elem, uuid)) { av_log(NULL, AV_LOG_ERROR, "Invalid TrackId element found in Sequence\n"); return AVERROR_INVALIDDATA; } - av_log(NULL, AV_LOG_DEBUG, "Processing IMF CPL Marker Sequence for Virtual Track " IMF_UUID_FORMAT "\n", UID_ARG(uuid)); + av_log(NULL, + AV_LOG_DEBUG, + "Processing IMF CPL Marker Sequence for Virtual Track " FF_UUID_FORMAT "\n", + UID_ARG(uuid)); /* create main marker virtual track if it does not exist */ if (!cpl->main_markers_track) { - cpl->main_markers_track = av_malloc(sizeof(IMFMarkerVirtualTrack)); - if (!cpl->main_markers_track) { - av_log(NULL, AV_LOG_PANIC, "Cannot allocate Marker Virtual Track\n"); + cpl->main_markers_track = av_malloc(sizeof(FFIMFMarkerVirtualTrack)); + if (!cpl->main_markers_track) return AVERROR(ENOMEM); - } imf_marker_virtual_track_init(cpl->main_markers_track); memcpy(cpl->main_markers_track->base.id_uuid, uuid, sizeof(uuid)); } else if (memcmp(cpl->main_markers_track->base.id_uuid, uuid, sizeof(uuid)) != 0) { @@ -360,18 +378,28 @@ static int push_marker_sequence(xmlNodePtr marker_sequence_elem, IMFCPL *cpl) } /* process resources */ - resource_list_elem = imf_xml_get_child_element_by_name(marker_sequence_elem, "ResourceList"); + resource_list_elem = ff_xml_get_child_element_by_name(marker_sequence_elem, "ResourceList"); if (!resource_list_elem) return 0; + resource_elem_count = xmlChildElementCount(resource_list_elem); + tmp = av_realloc(cpl->main_markers_track->resources, + (cpl->main_markers_track->resource_count + resource_elem_count) + * sizeof(FFIMFMarkerResource)); + if (!tmp) { + av_log(NULL, AV_LOG_ERROR, "Cannot allocate Marker Resources\n"); + return AVERROR(ENOMEM); + } + cpl->main_markers_track->resources = tmp; + resource_elem = xmlFirstElementChild(resource_list_elem); while (resource_elem) { - cpl->main_markers_track->resources = av_realloc_f(cpl->main_markers_track->resources, ++cpl->main_markers_track->resource_count, sizeof(IMFMarkerResource)); - if (!cpl->main_markers_track->resources) { - av_log(NULL, AV_LOG_PANIC, "Cannot allocate Resource\n"); - return AVERROR(ENOMEM); - } - imf_marker_resource_init(&cpl->main_markers_track->resources[cpl->main_markers_track->resource_count - 1]); - if (ret = fill_marker_resource(resource_elem, &cpl->main_markers_track->resources[cpl->main_markers_track->resource_count - 1], cpl)) + imf_marker_resource_init( + &cpl->main_markers_track->resources[cpl->main_markers_track->resource_count]); + ret = fill_marker_resource(resource_elem, + &cpl->main_markers_track->resources[cpl->main_markers_track->resource_count], + cpl); + cpl->main_markers_track->resource_count++; + if (ret) return ret; resource_elem = xmlNextElementSibling(resource_elem); } @@ -392,28 +420,33 @@ static int has_stereo_resources(xmlNodePtr element) return 0; } -static int push_main_audio_sequence(xmlNodePtr audio_sequence_elem, IMFCPL *cpl) +static int push_main_audio_sequence(xmlNodePtr audio_sequence_elem, FFIMFCPL *cpl) { int ret = 0; uint8_t uuid[16]; xmlNodePtr resource_list_elem = NULL; xmlNodePtr resource_elem = NULL; xmlNodePtr track_id_elem = NULL; - IMFTrackFileVirtualTrack *vt = NULL; + unsigned long resource_elem_count; + FFIMFTrackFileVirtualTrack *vt = NULL; + void *tmp; /* read TrackID element */ - if (!(track_id_elem = imf_xml_get_child_element_by_name(audio_sequence_elem, "TrackId"))) { + if (!(track_id_elem = ff_xml_get_child_element_by_name(audio_sequence_elem, "TrackId"))) { av_log(NULL, AV_LOG_ERROR, "TrackId element missing from audio sequence\n"); return AVERROR_INVALIDDATA; } - if (ret = imf_xml_read_UUID(track_id_elem, uuid)) { + if (ret = ff_xml_read_uuid(track_id_elem, uuid)) { av_log(NULL, AV_LOG_ERROR, "Invalid TrackId element found in audio sequence\n"); return ret; } - av_log(NULL, AV_LOG_DEBUG, "Processing IMF CPL Audio Sequence for Virtual Track " IMF_UUID_FORMAT "\n", UID_ARG(uuid)); + av_log(NULL, + AV_LOG_DEBUG, + "Processing IMF CPL Audio Sequence for Virtual Track " FF_UUID_FORMAT "\n", + UID_ARG(uuid)); /* get the main audio virtual track corresponding to the sequence */ - for (int i = 0; i < cpl->main_audio_track_count; i++) + for (uint32_t i = 0; i < cpl->main_audio_track_count; i++) if (memcmp(cpl->main_audio_tracks[i].base.id_uuid, uuid, sizeof(uuid)) == 0) { vt = &cpl->main_audio_tracks[i]; break; @@ -421,42 +454,57 @@ static int push_main_audio_sequence(xmlNodePtr audio_sequence_elem, IMFCPL *cpl) /* create a main audio virtual track if none exists for the sequence */ if (!vt) { - cpl->main_audio_tracks = av_realloc_f(cpl->main_audio_tracks, ++cpl->main_audio_track_count, sizeof(IMFTrackFileVirtualTrack)); - if (!cpl->main_audio_tracks) { - av_log(NULL, AV_LOG_PANIC, "Cannot allocate MainAudio virtual track\n"); + tmp = av_realloc(cpl->main_audio_tracks, + (cpl->main_audio_track_count + 1) * sizeof(FFIMFTrackFileVirtualTrack)); + if (!tmp) return AVERROR(ENOMEM); - } - vt = &cpl->main_audio_tracks[cpl->main_audio_track_count - 1]; + cpl->main_audio_tracks = tmp; + vt = &cpl->main_audio_tracks[cpl->main_audio_track_count]; imf_trackfile_virtual_track_init(vt); + cpl->main_audio_track_count++; memcpy(vt->base.id_uuid, uuid, sizeof(uuid)); } /* process resources */ - resource_list_elem = imf_xml_get_child_element_by_name(audio_sequence_elem, "ResourceList"); + resource_list_elem = ff_xml_get_child_element_by_name(audio_sequence_elem, "ResourceList"); if (!resource_list_elem) return 0; + resource_elem_count = xmlChildElementCount(resource_list_elem); + tmp = av_fast_realloc(vt->resources, + &vt->resources_alloc_sz, + (vt->resource_count + resource_elem_count) * sizeof(FFIMFTrackFileResource)); + if (!tmp) { + av_log(NULL, AV_LOG_ERROR, "Cannot allocate Main Audio Resources\n"); + return AVERROR(ENOMEM); + } + vt->resources = tmp; + resource_elem = xmlFirstElementChild(resource_list_elem); while (resource_elem) { - vt->resources = av_realloc_f(vt->resources, ++vt->resource_count, sizeof(IMFTrackFileResource)); - if (!vt->resources) { - av_log(NULL, AV_LOG_PANIC, "Cannot allocate Resource\n"); - return AVERROR(ENOMEM); + imf_trackfile_resource_init(&vt->resources[vt->resource_count]); + ret = fill_trackfile_resource(resource_elem, + &vt->resources[vt->resource_count], + cpl); + vt->resource_count++; + if (ret) { + av_log(NULL, AV_LOG_ERROR, "Invalid Resource\n"); + continue; } - imf_trackfile_resource_init(&vt->resources[vt->resource_count - 1]); - fill_trackfile_resource(resource_elem, &vt->resources[vt->resource_count - 1], cpl); resource_elem = xmlNextElementSibling(resource_elem); } return ret; } -static int push_main_image_2d_sequence(xmlNodePtr image_sequence_elem, IMFCPL *cpl) +static int push_main_image_2d_sequence(xmlNodePtr image_sequence_elem, FFIMFCPL *cpl) { int ret = 0; uint8_t uuid[16]; xmlNodePtr resource_list_elem = NULL; xmlNodePtr resource_elem = NULL; xmlNodePtr track_id_elem = NULL; + void *tmp; + unsigned long resource_elem_count; /* skip stereoscopic resources */ if (has_stereo_resources(image_sequence_elem)) { @@ -465,49 +513,64 @@ static int push_main_image_2d_sequence(xmlNodePtr image_sequence_elem, IMFCPL *c } /* read TrackId element*/ - if (!(track_id_elem = imf_xml_get_child_element_by_name(image_sequence_elem, "TrackId"))) { + if (!(track_id_elem = ff_xml_get_child_element_by_name(image_sequence_elem, "TrackId"))) { av_log(NULL, AV_LOG_ERROR, "TrackId element missing from audio sequence\n"); return AVERROR_INVALIDDATA; } - if (ret = imf_xml_read_UUID(track_id_elem, uuid)) { + if (ret = ff_xml_read_uuid(track_id_elem, uuid)) { av_log(NULL, AV_LOG_ERROR, "Invalid TrackId element found in audio sequence\n"); return ret; } /* create main image virtual track if one does not exist */ if (!cpl->main_image_2d_track) { - cpl->main_image_2d_track = av_malloc(sizeof(IMFTrackFileVirtualTrack)); - if (!cpl->main_image_2d_track) { - av_log(NULL, AV_LOG_PANIC, "Cannot allocate MainImage virtual track\n"); + cpl->main_image_2d_track = av_malloc(sizeof(FFIMFTrackFileVirtualTrack)); + if (!cpl->main_image_2d_track) return AVERROR(ENOMEM); - } imf_trackfile_virtual_track_init(cpl->main_image_2d_track); memcpy(cpl->main_image_2d_track->base.id_uuid, uuid, sizeof(uuid)); } else if (memcmp(cpl->main_image_2d_track->base.id_uuid, uuid, sizeof(uuid)) != 0) { av_log(NULL, AV_LOG_ERROR, "Multiple MainImage virtual tracks found\n"); return AVERROR_INVALIDDATA; } - av_log(NULL, AV_LOG_DEBUG, "Processing IMF CPL Main Image Sequence for Virtual Track " IMF_UUID_FORMAT "\n", UID_ARG(uuid)); + av_log(NULL, + AV_LOG_DEBUG, + "Processing IMF CPL Main Image Sequence for Virtual Track " FF_UUID_FORMAT "\n", + UID_ARG(uuid)); /* process resources */ - if (!(resource_list_elem = imf_xml_get_child_element_by_name(image_sequence_elem, "ResourceList"))) + resource_list_elem = ff_xml_get_child_element_by_name(image_sequence_elem, "ResourceList"); + if (!resource_list_elem) return 0; + resource_elem_count = xmlChildElementCount(resource_list_elem); + tmp = av_fast_realloc(cpl->main_image_2d_track->resources, + &cpl->main_image_2d_track->resources_alloc_sz, + (cpl->main_image_2d_track->resource_count + resource_elem_count) * sizeof(FFIMFTrackFileResource)); + if (!tmp) { + av_log(NULL, AV_LOG_ERROR, "Cannot allocate Main Image Resources\n"); + return AVERROR(ENOMEM); + } + cpl->main_image_2d_track->resources = tmp; + resource_elem = xmlFirstElementChild(resource_list_elem); while (resource_elem) { - cpl->main_image_2d_track->resources = av_realloc_f(cpl->main_image_2d_track->resources, ++cpl->main_image_2d_track->resource_count, sizeof(IMFTrackFileResource)); - if (!cpl->main_image_2d_track->resources) { - av_log(NULL, AV_LOG_PANIC, "Cannot allocate Resource\n"); - return AVERROR(ENOMEM); + imf_trackfile_resource_init( + &cpl->main_image_2d_track->resources[cpl->main_image_2d_track->resource_count]); + ret = fill_trackfile_resource(resource_elem, + &cpl->main_image_2d_track->resources[cpl->main_image_2d_track->resource_count], + cpl); + cpl->main_image_2d_track->resource_count++; + if (ret) { + av_log(NULL, AV_LOG_ERROR, "Invalid Resource\n"); + continue; } - imf_trackfile_resource_init(&cpl->main_image_2d_track->resources[cpl->main_image_2d_track->resource_count - 1]); - fill_trackfile_resource(resource_elem, &cpl->main_image_2d_track->resources[cpl->main_image_2d_track->resource_count - 1], cpl); resource_elem = xmlNextElementSibling(resource_elem); } return 0; } -static int fill_virtual_tracks(xmlNodePtr cpl_element, IMFCPL *cpl) +static int fill_virtual_tracks(xmlNodePtr cpl_element, FFIMFCPL *cpl) { int ret = 0; xmlNodePtr segment_list_elem = NULL; @@ -515,7 +578,7 @@ static int fill_virtual_tracks(xmlNodePtr cpl_element, IMFCPL *cpl) xmlNodePtr sequence_list_elem = NULL; xmlNodePtr sequence_elem = NULL; - if (!(segment_list_elem = imf_xml_get_child_element_by_name(cpl_element, "SegmentList"))) { + if (!(segment_list_elem = ff_xml_get_child_element_by_name(cpl_element, "SegmentList"))) { av_log(NULL, AV_LOG_ERROR, "SegmentList element missing\n"); return AVERROR_INVALIDDATA; } @@ -524,19 +587,22 @@ static int fill_virtual_tracks(xmlNodePtr cpl_element, IMFCPL *cpl) segment_elem = xmlFirstElementChild(segment_list_elem); while (segment_elem) { av_log(NULL, AV_LOG_DEBUG, "Processing IMF CPL Segment\n"); - sequence_list_elem = imf_xml_get_child_element_by_name(segment_elem, "SequenceList"); + sequence_list_elem = ff_xml_get_child_element_by_name(segment_elem, "SequenceList"); if (!segment_list_elem) continue; sequence_elem = xmlFirstElementChild(sequence_list_elem); while (sequence_elem) { - if (xmlStrcmp(sequence_elem->name, "MarkerSequence") == 0) { + if (xmlStrcmp(sequence_elem->name, "MarkerSequence") == 0) ret = push_marker_sequence(sequence_elem, cpl); - } else if (xmlStrcmp(sequence_elem->name, "MainImageSequence") == 0) { + else if (xmlStrcmp(sequence_elem->name, "MainImageSequence") == 0) ret = push_main_image_2d_sequence(sequence_elem, cpl); - } else if (xmlStrcmp(sequence_elem->name, "MainAudioSequence") == 0) { + else if (xmlStrcmp(sequence_elem->name, "MainAudioSequence") == 0) ret = push_main_audio_sequence(sequence_elem, cpl); - } else - av_log(NULL, AV_LOG_INFO, "The following Sequence is not supported and is ignored: %s\n", sequence_elem->name); + else + av_log(NULL, + AV_LOG_INFO, + "The following Sequence is not supported and is ignored: %s\n", + sequence_elem->name); if (ret == AVERROR(ENOMEM)) /* abort parsing only if memory error occurred */ return ret; @@ -548,14 +614,13 @@ static int fill_virtual_tracks(xmlNodePtr cpl_element, IMFCPL *cpl) return ret; } -int parse_imf_cpl_from_xml_dom(xmlDocPtr doc, IMFCPL **cpl) +int ff_parse_imf_cpl_from_xml_dom(xmlDocPtr doc, FFIMFCPL **cpl) { int ret = 0; xmlNodePtr cpl_element = NULL; - *cpl = imf_cpl_alloc(); + *cpl = ff_imf_cpl_alloc(); if (!*cpl) { - av_log(NULL, AV_LOG_FATAL, "Cannot allocate CPL\n"); ret = AVERROR(ENOMEM); goto cleanup; } @@ -576,13 +641,13 @@ int parse_imf_cpl_from_xml_dom(xmlDocPtr doc, IMFCPL **cpl) cleanup: if (*cpl && ret) { - imf_cpl_free(*cpl); + ff_imf_cpl_free(*cpl); *cpl = NULL; } return ret; } -static void imf_marker_free(IMFMarker *marker) +static void imf_marker_free(FFIMFMarker *marker) { if (!marker) return; @@ -590,73 +655,72 @@ static void imf_marker_free(IMFMarker *marker) xmlFree(marker->scope_utf8); } -static void imf_marker_resource_free(IMFMarkerResource *rsrc) +static void imf_marker_resource_free(FFIMFMarkerResource *rsrc) { if (!rsrc) return; - for (unsigned long i = 0; i < rsrc->marker_count; i++) + for (uint32_t i = 0; i < rsrc->marker_count; i++) imf_marker_free(&rsrc->markers[i]); - av_free(rsrc->markers); + av_freep(&rsrc->markers); } -static void imf_marker_virtual_track_free(IMFMarkerVirtualTrack *vt) +static void imf_marker_virtual_track_free(FFIMFMarkerVirtualTrack *vt) { if (!vt) return; - for (unsigned long i = 0; i < vt->resource_count; i++) + for (uint32_t i = 0; i < vt->resource_count; i++) imf_marker_resource_free(&vt->resources[i]); - av_free(vt->resources); + av_freep(&vt->resources); } -static void imf_trackfile_virtual_track_free(IMFTrackFileVirtualTrack *vt) +static void imf_trackfile_virtual_track_free(FFIMFTrackFileVirtualTrack *vt) { if (!vt) return; - av_free(vt->resources); + av_freep(&vt->resources); } -static void imf_cpl_init(IMFCPL *cpl) +static void imf_cpl_init(FFIMFCPL *cpl) { memset(cpl->id_uuid, 0, sizeof(cpl->id_uuid)); cpl->content_title_utf8 = NULL; - cpl->edit_rate = av_make_q(0, 0); + cpl->edit_rate = av_make_q(0, 1); cpl->main_markers_track = NULL; cpl->main_image_2d_track = NULL; cpl->main_audio_track_count = 0; cpl->main_audio_tracks = NULL; } -IMFCPL *imf_cpl_alloc(void) +FFIMFCPL *ff_imf_cpl_alloc(void) { - IMFCPL *cpl; + FFIMFCPL *cpl; - cpl = av_malloc(sizeof(IMFCPL)); + cpl = av_malloc(sizeof(FFIMFCPL)); if (!cpl) return NULL; imf_cpl_init(cpl); return cpl; } -void imf_cpl_free(IMFCPL *cpl) +void ff_imf_cpl_free(FFIMFCPL *cpl) { - if (cpl) { - xmlFree(cpl->content_title_utf8); - imf_marker_virtual_track_free(cpl->main_markers_track); - if (cpl->main_markers_track) - av_free(cpl->main_markers_track); - imf_trackfile_virtual_track_free(cpl->main_image_2d_track); - if (cpl->main_image_2d_track) - av_free(cpl->main_image_2d_track); - for (unsigned long i = 0; i < cpl->main_audio_track_count; i++) - imf_trackfile_virtual_track_free(&cpl->main_audio_tracks[i]); - if (cpl->main_audio_tracks) - av_free(cpl->main_audio_tracks); - } - av_free(cpl); - cpl = NULL; -} - -int parse_imf_cpl(AVIOContext *in, IMFCPL **cpl) + if (!cpl) + return; + xmlFree(cpl->content_title_utf8); + imf_marker_virtual_track_free(cpl->main_markers_track); + if (cpl->main_markers_track) + av_freep(&cpl->main_markers_track); + imf_trackfile_virtual_track_free(cpl->main_image_2d_track); + if (cpl->main_image_2d_track) + av_freep(&cpl->main_image_2d_track); + for (uint32_t i = 0; i < cpl->main_audio_track_count; i++) + imf_trackfile_virtual_track_free(&cpl->main_audio_tracks[i]); + if (cpl->main_audio_tracks) + av_freep(&cpl->main_audio_tracks); + av_freep(&cpl); +} + +int ff_parse_imf_cpl(AVIOContext *in, FFIMFCPL **cpl) { AVBPrint buf; xmlDoc *doc = NULL; @@ -666,7 +730,8 @@ int parse_imf_cpl(AVIOContext *in, IMFCPL **cpl) filesize = avio_size(in); filesize = filesize > 0 ? filesize : 8192; av_bprint_init(&buf, filesize + 1, AV_BPRINT_SIZE_UNLIMITED); - if ((ret = avio_read_to_bprint(in, &buf, UINT_MAX - 1)) < 0 || !avio_feof(in) || (filesize = buf.len) == 0) { + ret = avio_read_to_bprint(in, &buf, UINT_MAX - 1); + if (ret < 0 || !avio_feof(in) || (filesize = buf.len) == 0) { if (ret == 0) { av_log(NULL, AV_LOG_ERROR, "Cannot read IMF CPL\n"); return AVERROR_INVALIDDATA; @@ -675,17 +740,24 @@ int parse_imf_cpl(AVIOContext *in, IMFCPL **cpl) LIBXML_TEST_VERSION doc = xmlReadMemory(buf.str, filesize, NULL, NULL, 0); if (!doc) { - av_log(NULL, AV_LOG_ERROR, "XML parsing failed when reading the IMF CPL\n"); + av_log(NULL, + AV_LOG_ERROR, + "XML parsing failed when reading the IMF CPL\n"); ret = AVERROR_INVALIDDATA; } - if (ret = parse_imf_cpl_from_xml_dom(doc, cpl)) { + if (ret = ff_parse_imf_cpl_from_xml_dom(doc, cpl)) { av_log(NULL, AV_LOG_ERROR, "Cannot parse IMF CPL\n"); } else { - av_log(NULL, AV_LOG_INFO, "IMF CPL ContentTitle: %s\n", (*cpl)->content_title_utf8); - av_log(NULL, AV_LOG_INFO, "IMF CPL Id: " IMF_UUID_FORMAT "\n", UID_ARG((*cpl)->id_uuid)); + av_log(NULL, + AV_LOG_INFO, + "IMF CPL ContentTitle: %s\n", + (*cpl)->content_title_utf8); + av_log(NULL, + AV_LOG_INFO, + "IMF CPL Id: " FF_UUID_FORMAT "\n", + UID_ARG((*cpl)->id_uuid)); } xmlFreeDoc(doc); - xmlCleanupParser(); } av_bprint_finalize(&buf, NULL); diff --git a/libavformat/imfdec.c b/libavformat/imfdec.c index 87ddff6eb9..502152c4e8 100644 --- a/libavformat/imfdec.c +++ b/libavformat/imfdec.c @@ -57,14 +57,14 @@ #define MAX_BPRINT_READ_SIZE (UINT_MAX - 1) #define DEFAULT_ASSETMAP_SIZE 8 * 1024 -#define IMF_AVRATIONAL_FORMAT "%d/%d" -#define IMF_AVRATIONAL_ARG(rational) rational.num, rational.den +#define AVRATIONAL_FORMAT "%d/%d" +#define AVRATIONAL_ARG(rational) rational.num, rational.den /** * IMF Asset locator */ typedef struct IMFAssetLocator { - UUID uuid; + FFUUID uuid; char *absolute_uri; } IMFAssetLocator; @@ -73,13 +73,13 @@ typedef struct IMFAssetLocator { * Results from the parsing of one or more ASSETMAP XML files */ typedef struct IMFAssetLocatorMap { - uint8_t asset_count; - IMFAssetLocator **assets; + uint32_t asset_count; + IMFAssetLocator *assets; } IMFAssetLocatorMap; typedef struct IMFVirtualTrackResourcePlaybackCtx { IMFAssetLocator *locator; - IMFTrackFileResource *resource; + FFIMFTrackFileResource *resource; AVFormatContext *ctx; } IMFVirtualTrackResourcePlaybackCtx; @@ -90,7 +90,8 @@ typedef struct IMFVirtualTrackPlaybackCtx { AVRational current_timestamp; AVRational duration; // Resources - unsigned int resource_count; + uint32_t resource_count; + uint32_t resources_alloc_sz; IMFVirtualTrackResourcePlaybackCtx *resources; // Decoding cursors uint32_t current_resource_index; @@ -103,43 +104,37 @@ typedef struct IMFContext { char *asset_map_paths; AVIOInterruptCB *interrupt_callback; AVDictionary *avio_opts; - IMFCPL *cpl; - IMFAssetLocatorMap *asset_locator_map; - unsigned int track_count; + FFIMFCPL *cpl; + IMFAssetLocatorMap asset_locator_map; + uint32_t track_count; IMFVirtualTrackPlaybackCtx **tracks; } IMFContext; static int imf_uri_is_url(const char *string) { - char *substr = strstr(string, "://"); - return substr != NULL; + return strstr(string, "://") != NULL; } static int imf_uri_is_unix_abs_path(const char *string) { - char *substr = strstr(string, "/"); - int index = (int)(substr - string); - return index == 0; + return string[0] == '/'; } static int imf_uri_is_dos_abs_path(const char *string) { - // Absolute path case: `C:\path\to\somwhere` - char *substr = strstr(string, ":\\"); - int index = (int)(substr - string); - if (index == 1) + /* Absolute path case: `C:\path\to\somwhere` */ + if (string[1] == ':' && string[2] == '\\') return 1; - // Absolute path case: `C:/path/to/somwhere` - substr = strstr(string, ":/"); - index = (int)(substr - string); - if (index == 1) + /* Absolute path case: `C:/path/to/somwhere` */ + if (string[1] == ':' && string[2] == '/') return 1; - // Network path case: `\\path\to\somwhere` - substr = strstr(string, "\\\\"); - index = (int)(substr - string); - return index == 0; + /* Network path case: `\\path\to\somwhere` */ + if (string[0] == '\\' && string[1] == '\\') + return 1; + + return 0; } /** @@ -150,13 +145,18 @@ static int imf_uri_is_dos_abs_path(const char *string) * @param base_url the url of the asset map XML file, if any (can be NULL). * @return a negative value in case of error, 0 otherwise. */ -static int parse_imf_asset_map_from_xml_dom(AVFormatContext *s, xmlDocPtr doc, IMFAssetLocatorMap *asset_map, const char *base_url) +static int parse_imf_asset_map_from_xml_dom(AVFormatContext *s, + xmlDocPtr doc, + IMFAssetLocatorMap *asset_map, + const char *base_url) { xmlNodePtr asset_map_element = NULL; xmlNodePtr node = NULL; + xmlNodePtr asset_element = NULL; char *uri; int ret = 0; IMFAssetLocator *asset = NULL; + void *tmp; asset_map_element = xmlDocGetRootElement(doc); @@ -166,112 +166,88 @@ static int parse_imf_asset_map_from_xml_dom(AVFormatContext *s, xmlDocPtr doc, I } if (asset_map_element->type != XML_ELEMENT_NODE || av_strcasecmp(asset_map_element->name, "AssetMap")) { - av_log(s, AV_LOG_ERROR, "Unable to parse asset map XML - wrong root node name[%s] type[%d]\n", asset_map_element->name, (int)asset_map_element->type); + av_log(s, + AV_LOG_ERROR, + "Unable to parse asset map XML - wrong root node name[%s] type[%d]\n", + asset_map_element->name, + (int)asset_map_element->type); return AVERROR_INVALIDDATA; } - // parse asset locators - - if (!(node = imf_xml_get_child_element_by_name(asset_map_element, "AssetList"))) { + /* parse asset locators */ + if (!(node = ff_xml_get_child_element_by_name(asset_map_element, "AssetList"))) { av_log(s, AV_LOG_ERROR, "Unable to parse asset map XML - missing AssetList node\n"); return AVERROR_INVALIDDATA; } + tmp = av_realloc(asset_map->assets, + (xmlChildElementCount(node) + asset_map->asset_count) + * sizeof(IMFAssetLocator)); + if (!tmp) { + av_log(NULL, AV_LOG_ERROR, "Cannot allocate IMF asset locators\n"); + return AVERROR(ENOMEM); + } + asset_map->assets = tmp; - node = xmlFirstElementChild(node); - while (node) { - if (av_strcasecmp(node->name, "Asset") != 0) + asset_element = xmlFirstElementChild(node); + while (asset_element) { + if (av_strcasecmp(asset_element->name, "Asset") != 0) continue; - asset = av_malloc(sizeof(IMFAssetLocator)); - if (!asset) - return AVERROR(ENOMEM); + asset = &(asset_map->assets[asset_map->asset_count]); - if (imf_xml_read_UUID(imf_xml_get_child_element_by_name(node, "Id"), asset->uuid)) { + if (ff_xml_read_uuid(ff_xml_get_child_element_by_name(asset_element, "Id"), asset->uuid)) { av_log(s, AV_LOG_ERROR, "Could not parse UUID from asset in asset map.\n"); - ret = AVERROR_INVALIDDATA; - goto clean_up_asset; + return AVERROR_INVALIDDATA; } - av_log(s, AV_LOG_DEBUG, "Found asset id: " IMF_UUID_FORMAT "\n", UID_ARG(asset->uuid)); + av_log(s, AV_LOG_DEBUG, "Found asset id: " FF_UUID_FORMAT "\n", UID_ARG(asset->uuid)); - if (!(node = imf_xml_get_child_element_by_name(node, "ChunkList"))) { + if (!(node = ff_xml_get_child_element_by_name(asset_element, "ChunkList"))) { av_log(s, AV_LOG_ERROR, "Unable to parse asset map XML - missing ChunkList node\n"); - ret = AVERROR_INVALIDDATA; - goto clean_up_asset; + return AVERROR_INVALIDDATA; } - if (!(node = imf_xml_get_child_element_by_name(node, "Chunk"))) { + if (!(node = ff_xml_get_child_element_by_name(node, "Chunk"))) { av_log(s, AV_LOG_ERROR, "Unable to parse asset map XML - missing Chunk node\n"); - ret = AVERROR_INVALIDDATA; - goto clean_up_asset; + return AVERROR_INVALIDDATA; } - uri = xmlNodeGetContent(imf_xml_get_child_element_by_name(node, "Path")); + uri = xmlNodeGetContent(ff_xml_get_child_element_by_name(node, "Path")); if (!imf_uri_is_url(uri) && !imf_uri_is_unix_abs_path(uri) && !imf_uri_is_dos_abs_path(uri)) asset->absolute_uri = av_append_path_component(base_url, uri); else asset->absolute_uri = av_strdup(uri); xmlFree(uri); if (!asset->absolute_uri) { - av_log(NULL, AV_LOG_PANIC, "Cannot allocate asset locator absolute URI\n"); - ret = AVERROR(ENOMEM); - goto clean_up_asset; + return AVERROR(ENOMEM); } av_log(s, AV_LOG_DEBUG, "Found asset absolute URI: %s\n", asset->absolute_uri); - node = xmlNextElementSibling(node->parent->parent); - - asset_map->assets = av_realloc_f(asset_map->assets, asset_map->asset_count + 1, sizeof(IMFAssetLocator)); - if (!asset_map->assets) { - av_log(NULL, AV_LOG_PANIC, "Cannot allocate IMF asset locators\n"); - ret = AVERROR(ENOMEM); - goto clean_up_asset; - } - asset_map->assets[asset_map->asset_count++] = asset; - continue; - - clean_up_asset: - av_freep(&asset); - return ret; + asset_map->asset_count++; + asset_element = xmlNextElementSibling(asset_element); } return ret; } /** - * Allocate a IMFAssetLocatorMap pointer and return it. - * @return the allocated IMFAssetLocatorMap pointer. + * Initializes an IMFAssetLocatorMap structure. */ -static IMFAssetLocatorMap *imf_asset_locator_map_alloc(void) +static void imf_asset_locator_map_init(IMFAssetLocatorMap *asset_map) { - IMFAssetLocatorMap *asset_map; - - asset_map = av_malloc(sizeof(IMFAssetLocatorMap)); - if (!asset_map) - return NULL; - asset_map->assets = NULL; asset_map->asset_count = 0; - return asset_map; } /** * Free a IMFAssetLocatorMap pointer. */ -static void imf_asset_locator_map_free(IMFAssetLocatorMap *asset_map) +static void imf_asset_locator_map_deinit(IMFAssetLocatorMap *asset_map) { - if (asset_map == NULL) { - return; - } - - for (int i = 0; i < asset_map->asset_count; ++i) { - av_free(asset_map->assets[i]->absolute_uri); - av_free(asset_map->assets[i]); - } - + for (uint32_t i = 0; i < asset_map->asset_count; ++i) + av_freep(&asset_map->assets[i].absolute_uri); av_freep(&asset_map->assets); - av_freep(&asset_map); } static int parse_assetmap(AVFormatContext *s, const char *url, AVIOContext *in) @@ -303,41 +279,38 @@ static int parse_assetmap(AVFormatContext *s, const char *url, AVIOContext *in) av_bprint_init(&buf, filesize + 1, AV_BPRINT_SIZE_UNLIMITED); - if ((ret = avio_read_to_bprint(in, &buf, MAX_BPRINT_READ_SIZE)) < 0 || !avio_feof(in) || (filesize = buf.len) == 0) { + ret = avio_read_to_bprint(in, &buf, MAX_BPRINT_READ_SIZE); + if (ret < 0 || !avio_feof(in) || (filesize = buf.len) == 0) { av_log(s, AV_LOG_ERROR, "Unable to read to asset map '%s'\n", url); if (ret == 0) ret = AVERROR_INVALIDDATA; - } else { - LIBXML_TEST_VERSION + goto clean_up; + } - tmp_str = strdup(url); - if (!tmp_str) { - av_log(s, AV_LOG_PANIC, "Unable to duplicate string\n"); - ret = AVERROR(ENOMEM); - goto clean_up; - } - base_url = av_dirname(tmp_str); - if (c->asset_locator_map == NULL) { - c->asset_locator_map = imf_asset_locator_map_alloc(); - if (!c->asset_locator_map) { - av_log(s, AV_LOG_PANIC, "Unable to allocate asset map locator\n"); - ret = AVERROR(ENOMEM); - goto clean_up; - } - } + LIBXML_TEST_VERSION - doc = xmlReadMemory(buf.str, filesize, url, NULL, 0); + tmp_str = av_strdup(url); + if (!tmp_str) { + ret = AVERROR(ENOMEM); + goto clean_up; + } + base_url = av_dirname(tmp_str); - if (!(ret = parse_imf_asset_map_from_xml_dom(s, doc, c->asset_locator_map, base_url))) { - av_log(s, AV_LOG_DEBUG, "Found %d assets from %s\n", c->asset_locator_map->asset_count, url); - } + doc = xmlReadMemory(buf.str, filesize, url, NULL, 0); - xmlFreeDoc(doc); - } + ret = parse_imf_asset_map_from_xml_dom(s, doc, &c->asset_locator_map, base_url); + if (!ret) + av_log(s, + AV_LOG_DEBUG, + "Found %d assets from %s\n", + c->asset_locator_map.asset_count, + url); + + xmlFreeDoc(doc); clean_up: if (tmp_str) - free(tmp_str); + av_freep(&tmp_str); if (close_in) avio_close(in); av_bprint_finalize(&buf, NULL); @@ -345,19 +318,16 @@ static int parse_assetmap(AVFormatContext *s, const char *url, AVIOContext *in) return ret; } -static IMFAssetLocator *find_asset_map_locator(IMFAssetLocatorMap *asset_map, UUID uuid) +static IMFAssetLocator *find_asset_map_locator(IMFAssetLocatorMap *asset_map, FFUUID uuid) { - IMFAssetLocator *asset_locator; - for (int i = 0; i < asset_map->asset_count; ++i) { - asset_locator = asset_map->assets[i]; - if (memcmp(asset_map->assets[i]->uuid, uuid, 16) == 0) { - return asset_locator; - } - } + for (uint32_t i = 0; i < asset_map->asset_count; ++i) + if (memcmp(asset_map->assets[i].uuid, uuid, 16) == 0) + return &(asset_map->assets[i]); return NULL; } -static int open_track_resource_context(AVFormatContext *s, IMFVirtualTrackResourcePlaybackCtx *track_resource) +static int open_track_resource_context(AVFormatContext *s, + IMFVirtualTrackResourcePlaybackCtx *track_resource) { IMFContext *c = s->priv_data; int ret = 0; @@ -366,51 +336,79 @@ static int open_track_resource_context(AVFormatContext *s, IMFVirtualTrackResour if (!track_resource->ctx) { track_resource->ctx = avformat_alloc_context(); - if (!track_resource->ctx) { - av_log(NULL, AV_LOG_PANIC, "Cannot allocate Track Resource Context\n"); + if (!track_resource->ctx) return AVERROR(ENOMEM); - } } if (track_resource->ctx->iformat) { - av_log(s, AV_LOG_DEBUG, "Input context already opened for %s.\n", track_resource->locator->absolute_uri); - return ret; + av_log(s, + AV_LOG_DEBUG, + "Input context already opened for %s.\n", + track_resource->locator->absolute_uri); + return 0; } track_resource->ctx->io_open = s->io_open; track_resource->ctx->io_close = s->io_close; track_resource->ctx->flags |= s->flags & ~AVFMT_FLAG_CUSTOM_IO; - if ((ret = ff_copy_whiteblacklists(track_resource->ctx, s)) < 0) { + if ((ret = ff_copy_whiteblacklists(track_resource->ctx, s)) < 0) goto cleanup; - } av_dict_copy(&opts, c->avio_opts, 0); - ret = avformat_open_input(&track_resource->ctx, track_resource->locator->absolute_uri, NULL, &opts); + ret = avformat_open_input(&track_resource->ctx, + track_resource->locator->absolute_uri, + NULL, + &opts); av_dict_free(&opts); if (ret < 0) { - av_log(s, AV_LOG_ERROR, "Could not open %s input context: %s\n", track_resource->locator->absolute_uri, av_err2str(ret)); - goto cleanup; + av_log(s, + AV_LOG_ERROR, + "Could not open %s input context: %s\n", + track_resource->locator->absolute_uri, + av_err2str(ret)); + return ret; } ret = avformat_find_stream_info(track_resource->ctx, NULL); if (ret < 0) { - av_log(s, AV_LOG_ERROR, "Could not find %s stream information: %s\n", track_resource->locator->absolute_uri, av_err2str(ret)); + av_log(s, + AV_LOG_ERROR, + "Could not find %s stream information: %s\n", + track_resource->locator->absolute_uri, + av_err2str(ret)); goto cleanup; } - // Compare the source timebase to the resource edit rate, considering the first stream of the source file - if (av_cmp_q(track_resource->ctx->streams[0]->time_base, av_inv_q(track_resource->resource->base.edit_rate))) { - av_log(s, AV_LOG_WARNING, "Incoherent source stream timebase %d/%d regarding resource edit rate: %d/%d", track_resource->ctx->streams[0]->time_base.num, track_resource->ctx->streams[0]->time_base.den, track_resource->resource->base.edit_rate.den, track_resource->resource->base.edit_rate.num); - } + /* Compare the source timebase to the resource edit rate, considering the first stream of the source file */ + if (av_cmp_q(track_resource->ctx->streams[0]->time_base, av_inv_q(track_resource->resource->base.edit_rate))) + av_log(s, + AV_LOG_WARNING, + "Incoherent source stream timebase %d/%d regarding resource edit rate: %d/%d", + track_resource->ctx->streams[0]->time_base.num, + track_resource->ctx->streams[0]->time_base.den, + track_resource->resource->base.edit_rate.den, + track_resource->resource->base.edit_rate.num); - entry_point = (int64_t)track_resource->resource->base.entry_point * track_resource->resource->base.edit_rate.den * AV_TIME_BASE / track_resource->resource->base.edit_rate.num; + entry_point = (int64_t)track_resource->resource->base.entry_point + * track_resource->resource->base.edit_rate.den + * AV_TIME_BASE + / track_resource->resource->base.edit_rate.num; if (entry_point) { - av_log(s, AV_LOG_DEBUG, "Seek at resource %s entry point: %ld\n", track_resource->locator->absolute_uri, track_resource->resource->base.entry_point); + av_log(s, + AV_LOG_DEBUG, + "Seek at resource %s entry point: %" PRIu32 "\n", + track_resource->locator->absolute_uri, + track_resource->resource->base.entry_point); ret = avformat_seek_file(track_resource->ctx, -1, entry_point, entry_point, entry_point, 0); if (ret < 0) { - av_log(s, AV_LOG_ERROR, "Could not seek at %" PRId64 "on %s: %s\n", entry_point, track_resource->locator->absolute_uri, av_err2str(ret)); + av_log(s, + AV_LOG_ERROR, + "Could not seek at %" PRId64 "on %s: %s\n", + entry_point, + track_resource->locator->absolute_uri, + av_err2str(ret)); goto cleanup; } } @@ -418,91 +416,111 @@ static int open_track_resource_context(AVFormatContext *s, IMFVirtualTrackResour return ret; cleanup: avformat_free_context(track_resource->ctx); + track_resource->ctx = NULL; return ret; } -static int open_track_file_resource(AVFormatContext *s, IMFTrackFileResource *track_file_resource, IMFVirtualTrackPlaybackCtx *track) +static int open_track_file_resource(AVFormatContext *s, + FFIMFTrackFileResource *track_file_resource, + IMFVirtualTrackPlaybackCtx *track) { IMFContext *c = s->priv_data; IMFAssetLocator *asset_locator; - IMFVirtualTrackResourcePlaybackCtx track_resource; + IMFVirtualTrackResourcePlaybackCtx vt_ctx; + void *tmp; int ret; - if (!(asset_locator = find_asset_map_locator(c->asset_locator_map, track_file_resource->track_file_uuid))) { - av_log(s, AV_LOG_ERROR, "Could not find asset locator for UUID: " IMF_UUID_FORMAT "\n", UID_ARG(track_file_resource->track_file_uuid)); + asset_locator = find_asset_map_locator(&c->asset_locator_map, track_file_resource->track_file_uuid); + if (!asset_locator) { + av_log(s, + AV_LOG_ERROR, + "Could not find asset locator for UUID: " FF_UUID_FORMAT "\n", + UID_ARG(track_file_resource->track_file_uuid)); return AVERROR_INVALIDDATA; } - av_log(s, AV_LOG_DEBUG, "Found locator for " IMF_UUID_FORMAT ": %s\n", UID_ARG(asset_locator->uuid), asset_locator->absolute_uri); + av_log(s, + AV_LOG_DEBUG, + "Found locator for " FF_UUID_FORMAT ": %s\n", + UID_ARG(asset_locator->uuid), + asset_locator->absolute_uri); + tmp = av_fast_realloc(track->resources, + &track->resources_alloc_sz, + (track->resource_count + track_file_resource->base.repeat_count) + * sizeof(IMFVirtualTrackResourcePlaybackCtx)); + if (!tmp) + return AVERROR(ENOMEM); + track->resources = tmp; - for (int repetition = 0; repetition < track_file_resource->base.repeat_count; ++repetition) { - track->resources = av_realloc_f(track->resources, track->resource_count + 1, sizeof(IMFVirtualTrackResourcePlaybackCtx)); - if (!track->resources) { - av_log(NULL, AV_LOG_PANIC, "Cannot allocate Virtual Track playback context\n"); - return AVERROR(ENOMEM); - } - track_resource.locator = asset_locator; - track_resource.resource = track_file_resource; - track_resource.ctx = NULL; - if ((ret = open_track_resource_context(s, &track_resource)) != 0) { + for (uint32_t i = 0; i < track_file_resource->base.repeat_count; ++i) { + vt_ctx.locator = asset_locator; + vt_ctx.resource = track_file_resource; + vt_ctx.ctx = NULL; + if ((ret = open_track_resource_context(s, &vt_ctx)) != 0) return ret; - } - track->resources[track->resource_count++] = track_resource; - track->duration = av_add_q(track->duration, av_make_q((int)track_file_resource->base.duration * track_file_resource->base.edit_rate.den, track_file_resource->base.edit_rate.num)); + track->resources[track->resource_count++] = vt_ctx; + track->duration = av_add_q(track->duration, + av_make_q((int)track_file_resource->base.duration * track_file_resource->base.edit_rate.den, + track_file_resource->base.edit_rate.num)); } return ret; } -static int open_virtual_track(AVFormatContext *s, IMFTrackFileVirtualTrack *virtual_track, int32_t track_index) +static void imf_virtual_track_playback_context_deinit(IMFVirtualTrackPlaybackCtx *track) +{ + for (uint32_t i = 0; i < track->resource_count; ++i) + if (track->resources[i].ctx && track->resources[i].ctx->iformat) + avformat_close_input(&track->resources[i].ctx); + + av_freep(&track->resources); +} + +static int open_virtual_track(AVFormatContext *s, + FFIMFTrackFileVirtualTrack *virtual_track, + int32_t track_index) { IMFContext *c = s->priv_data; - IMFVirtualTrackPlaybackCtx *track; + IMFVirtualTrackPlaybackCtx *track = NULL; + void *tmp; int ret = 0; - track = av_mallocz(sizeof(IMFVirtualTrackPlaybackCtx)); - if (!track) { - av_log(NULL, AV_LOG_PANIC, "Cannot allocate IMF Virtual Track Playback context\n"); + if (!(track = av_mallocz(sizeof(IMFVirtualTrackPlaybackCtx)))) return AVERROR(ENOMEM); - } track->index = track_index; - track->duration = av_make_q(0, INT32_MAX); + track->duration = av_make_q(0, 1); - for (int i = 0; i < virtual_track->resource_count; i++) { - av_log(s, AV_LOG_DEBUG, "Open stream from file " IMF_UUID_FORMAT ", stream %d\n", UID_ARG(virtual_track->resources[i].track_file_uuid), i); + for (uint32_t i = 0; i < virtual_track->resource_count; i++) { + av_log(s, + AV_LOG_DEBUG, + "Open stream from file " FF_UUID_FORMAT ", stream %d\n", + UID_ARG(virtual_track->resources[i].track_file_uuid), + i); if ((ret = open_track_file_resource(s, &virtual_track->resources[i], track)) != 0) { - av_log(s, AV_LOG_ERROR, "Could not open image track resource " IMF_UUID_FORMAT "\n", UID_ARG(virtual_track->resources[i].track_file_uuid)); - return ret; + av_log(s, + AV_LOG_ERROR, + "Could not open image track resource " FF_UUID_FORMAT "\n", + UID_ARG(virtual_track->resources[i].track_file_uuid)); + goto clean_up; } } track->current_timestamp = av_make_q(0, track->duration.den); - c->tracks = av_realloc_f(c->tracks, c->track_count + 1, sizeof(IMFVirtualTrackPlaybackCtx)); - if (!c->tracks) { - av_log(NULL, AV_LOG_PANIC, "Cannot allocate Virtual Track playback context\n"); - return AVERROR(ENOMEM); + tmp = av_realloc(c->tracks, (c->track_count + 1) * sizeof(IMFVirtualTrackPlaybackCtx *)); + if (!tmp) { + ret = AVERROR(ENOMEM); + goto clean_up; } + c->tracks = tmp; c->tracks[c->track_count++] = track; - return ret; -} - -static void imf_virtual_track_playback_context_free(IMFVirtualTrackPlaybackCtx *track) -{ - if (!track) { - return; - } - - for (int i = 0; i < track->resource_count; ++i) { - - if (track->resources[i].ctx && track->resources[i].ctx->iformat) { - avformat_close_input(&(track->resources[i].ctx)); - track->resources[i].ctx = NULL; - } - } + return 0; - av_freep(&(track->resources)); +clean_up: + imf_virtual_track_playback_context_deinit(track); + av_free(track); + return ret; } static int set_context_streams_from_tracks(AVFormatContext *s) @@ -514,21 +532,29 @@ static int set_context_streams_from_tracks(AVFormatContext *s) int ret = 0; - for (int i = 0; i < c->track_count; ++i) { - // Open the first resource of the track to get stream information + for (uint32_t i = 0; i < c->track_count; ++i) { + /* Open the first resource of the track to get stream information */ first_resource_stream = c->tracks[i]->resources[0].ctx->streams[0]; - av_log(s, AV_LOG_DEBUG, "Open the first resource of track %d\n", c->tracks[i]->index); - // Copy stream information + /* Copy stream information */ asset_stream = avformat_new_stream(s, NULL); + if (!asset_stream) { + av_log(s, AV_LOG_ERROR, "Could not create stream\n"); + break; + } asset_stream->id = i; - if ((ret = avcodec_parameters_copy(asset_stream->codecpar, first_resource_stream->codecpar)) < 0) { + ret = avcodec_parameters_copy(asset_stream->codecpar, first_resource_stream->codecpar); + if (ret < 0) { av_log(s, AV_LOG_ERROR, "Could not copy stream parameters\n"); break; } - avpriv_set_pts_info(asset_stream, first_resource_stream->pts_wrap_bits, first_resource_stream->time_base.num, first_resource_stream->time_base.den); - asset_stream->duration = (int64_t)av_q2d(av_mul_q(c->tracks[i]->duration, av_inv_q(asset_stream->time_base))); + avpriv_set_pts_info(asset_stream, + first_resource_stream->pts_wrap_bits, + first_resource_stream->time_base.num, + first_resource_stream->time_base.den); + asset_stream->duration = (int64_t)av_q2d(av_mul_q(c->tracks[i]->duration, + av_inv_q(asset_stream->time_base))); } return ret; @@ -561,70 +587,83 @@ static int open_cpl_tracks(AVFormatContext *s) int32_t track_index = 0; int ret; - if (c->cpl->main_image_2d_track) { + if (c->cpl->main_image_2d_track) if ((ret = open_virtual_track(s, c->cpl->main_image_2d_track, track_index++)) != 0) { - av_log(s, AV_LOG_ERROR, "Could not open image track " IMF_UUID_FORMAT "\n", UID_ARG(c->cpl->main_image_2d_track->base.id_uuid)); + av_log(s, + AV_LOG_ERROR, + "Could not open image track " FF_UUID_FORMAT "\n", + UID_ARG(c->cpl->main_image_2d_track->base.id_uuid)); return ret; } - } - for (int audio_track_index = 0; audio_track_index < c->cpl->main_audio_track_count; ++audio_track_index) { - if ((ret = open_virtual_track(s, &c->cpl->main_audio_tracks[audio_track_index], track_index++)) != 0) { - av_log(s, AV_LOG_ERROR, "Could not open audio track " IMF_UUID_FORMAT "\n", UID_ARG(c->cpl->main_audio_tracks[audio_track_index].base.id_uuid)); + for (uint32_t i = 0; i < c->cpl->main_audio_track_count; ++i) + if ((ret = open_virtual_track(s, &c->cpl->main_audio_tracks[i], track_index++)) != 0) { + av_log(s, + AV_LOG_ERROR, + "Could not open audio track " FF_UUID_FORMAT "\n", + UID_ARG(c->cpl->main_audio_tracks[i].base.id_uuid)); return ret; } - } return set_context_streams_from_tracks(s); } -static int imf_close(AVFormatContext *s); - static int imf_read_header(AVFormatContext *s) { IMFContext *c = s->priv_data; char *asset_map_path; - int ret; + char *tmp_str; + int ret = 0; c->interrupt_callback = &s->interrupt_callback; - c->base_url = av_dirname(av_strdup(s->url)); + tmp_str = av_strdup(s->url); + if (!tmp_str) { + ret = AVERROR(ENOMEM); + return ret; + } + c->base_url = av_dirname(tmp_str); if ((ret = save_avio_options(s)) < 0) - goto fail; + return ret; av_log(s, AV_LOG_DEBUG, "start parsing IMF CPL: %s\n", s->url); - if ((ret = parse_imf_cpl(s->pb, &c->cpl)) < 0) - goto fail; + if ((ret = ff_parse_imf_cpl(s->pb, &c->cpl)) < 0) + return ret; - av_log(s, AV_LOG_DEBUG, "parsed IMF CPL: " IMF_UUID_FORMAT "\n", UID_ARG(c->cpl->id_uuid)); + av_log(s, + AV_LOG_DEBUG, + "parsed IMF CPL: " FF_UUID_FORMAT "\n", + UID_ARG(c->cpl->id_uuid)); if (!c->asset_map_paths) { c->asset_map_paths = av_append_path_component(c->base_url, "ASSETMAP.xml"); + if (!c->asset_map_paths) { + ret = AVERROR(ENOMEM); + return ret; + } + av_log(s, AV_LOG_DEBUG, "No asset maps provided, using the default ASSETMAP.xml\n"); } - // Parse each asset map XML file - asset_map_path = strtok(c->asset_map_paths, ","); + /* Parse each asset map XML file */ + imf_asset_locator_map_init(&c->asset_locator_map); + asset_map_path = av_strtok(c->asset_map_paths, ",", &tmp_str); while (asset_map_path != NULL) { av_log(s, AV_LOG_DEBUG, "start parsing IMF Asset Map: %s\n", asset_map_path); - if ((ret = parse_assetmap(s, asset_map_path, NULL)) < 0) - goto fail; + if (ret = parse_assetmap(s, asset_map_path, NULL)) + return ret; - asset_map_path = strtok(NULL, ","); + asset_map_path = av_strtok(NULL, ",", &tmp_str); } av_log(s, AV_LOG_DEBUG, "parsed IMF Asset Maps\n"); - if ((ret = open_cpl_tracks(s)) != 0) { - goto fail; - } + if (ret = open_cpl_tracks(s)) + return ret; av_log(s, AV_LOG_DEBUG, "parsed IMF package\n"); - return ret; -fail: - imf_close(s); - return ret; + return 0; } static IMFVirtualTrackPlaybackCtx *get_next_track_with_minimum_timestamp(AVFormatContext *s) @@ -633,53 +672,75 @@ static IMFVirtualTrackPlaybackCtx *get_next_track_with_minimum_timestamp(AVForma IMFVirtualTrackPlaybackCtx *track; AVRational minimum_timestamp = av_make_q(INT32_MAX, 1); - for (int i = 0; i < c->track_count; ++i) { + for (uint32_t i = 0; i < c->track_count; ++i) { av_log( s, AV_LOG_DEBUG, - "Compare track %d timestamp " IMF_AVRATIONAL_FORMAT " to minimum " IMF_AVRATIONAL_FORMAT " (over duration: " IMF_AVRATIONAL_FORMAT ")\n", + "Compare track %d timestamp " AVRATIONAL_FORMAT + " to minimum " AVRATIONAL_FORMAT + " (over duration: " AVRATIONAL_FORMAT + ")\n", i, - IMF_AVRATIONAL_ARG(c->tracks[i]->current_timestamp), - IMF_AVRATIONAL_ARG(minimum_timestamp), - IMF_AVRATIONAL_ARG(c->tracks[i]->duration)); + AVRATIONAL_ARG(c->tracks[i]->current_timestamp), + AVRATIONAL_ARG(minimum_timestamp), + AVRATIONAL_ARG(c->tracks[i]->duration)); if (av_cmp_q(c->tracks[i]->current_timestamp, minimum_timestamp) < 0) { track = c->tracks[i]; minimum_timestamp = track->current_timestamp; } } - av_log(s, AV_LOG_DEBUG, "Found next track to read: %d (timestamp: %lf / %lf)\n", track->index, av_q2d(track->current_timestamp), av_q2d(minimum_timestamp)); + av_log(s, + AV_LOG_DEBUG, + "Found next track to read: %d (timestamp: %lf / %lf)\n", + track->index, + av_q2d(track->current_timestamp), + av_q2d(minimum_timestamp)); return track; } -static IMFVirtualTrackResourcePlaybackCtx *get_resource_context_for_timestamp(AVFormatContext *s, IMFVirtualTrackPlaybackCtx *track) +static IMFVirtualTrackResourcePlaybackCtx *get_resource_context_for_timestamp(AVFormatContext *s, + IMFVirtualTrackPlaybackCtx *track) { AVRational edit_unit_duration = av_inv_q(track->resources[0].resource->base.edit_rate); AVRational cumulated_duration = av_make_q(0, edit_unit_duration.den); - av_log(s, AV_LOG_DEBUG, "Looking for track %d resource for timestamp = %lf / %lf\n", track->index, av_q2d(track->current_timestamp), av_q2d(track->duration)); - for (int i = 0; i < track->resource_count; ++i) { - cumulated_duration = av_add_q(cumulated_duration, av_make_q((int)track->resources[i].resource->base.duration * edit_unit_duration.num, edit_unit_duration.den)); + av_log(s, + AV_LOG_DEBUG, + "Looking for track %d resource for timestamp = %lf / %lf\n", + track->index, + av_q2d(track->current_timestamp), + av_q2d(track->duration)); + for (uint32_t i = 0; i < track->resource_count; ++i) { + cumulated_duration = av_add_q(cumulated_duration, + av_make_q((int)track->resources[i].resource->base.duration * edit_unit_duration.num, + edit_unit_duration.den)); if (av_cmp_q(av_add_q(track->current_timestamp, edit_unit_duration), cumulated_duration) <= 0) { av_log(s, AV_LOG_DEBUG, - "Found resource %d in track %d to read for timestamp %lf (on cumulated=%lf): entry=%ld, duration=%lu, editrate=" IMF_AVRATIONAL_FORMAT " | edit_unit_duration=%lf\n", + "Found resource %d in track %d to read for timestamp %lf " + "(on cumulated=%lf): entry=%" PRIu32 + ", duration=%" PRIu32 + ", editrate=" AVRATIONAL_FORMAT + " | edit_unit_duration=%lf\n", i, track->index, av_q2d(track->current_timestamp), av_q2d(cumulated_duration), track->resources[i].resource->base.entry_point, track->resources[i].resource->base.duration, - IMF_AVRATIONAL_ARG(track->resources[i].resource->base.edit_rate), + AVRATIONAL_ARG(track->resources[i].resource->base.edit_rate), av_q2d(edit_unit_duration)); if (track->current_resource_index != i) { - av_log(s, AV_LOG_DEBUG, "Switch resource on track %d: re-open context\n", track->index); + av_log(s, + AV_LOG_DEBUG, + "Switch resource on track %d: re-open context\n", + track->index); avformat_close_input(&(track->resources[track->current_resource_index].ctx)); - if (open_track_resource_context(s, &(track->resources[i])) != 0) { + if (open_track_resource_context(s, &(track->resources[i])) != 0) return NULL; - } track->current_resource_index = i; } return &(track->resources[track->current_resource_index]); @@ -688,28 +749,28 @@ static IMFVirtualTrackResourcePlaybackCtx *get_resource_context_for_timestamp(AV return NULL; } -static int ff_imf_read_packet(AVFormatContext *s, AVPacket *pkt) +static int imf_read_packet(AVFormatContext *s, AVPacket *pkt) { IMFContext *c = s->priv_data; - IMFVirtualTrackResourcePlaybackCtx *resource_to_read = NULL; AVRational edit_unit_duration; int ret = 0; + IMFVirtualTrackPlaybackCtx *track; + FFStream *track_stream; - IMFVirtualTrackPlaybackCtx *track_to_read = get_next_track_with_minimum_timestamp(s); - FFStream *track_to_read_stream_internal; + track = get_next_track_with_minimum_timestamp(s); - if (av_cmp_q(track_to_read->current_timestamp, track_to_read->duration) == 0) { + if (av_cmp_q(track->current_timestamp, track->duration) == 0) return AVERROR_EOF; - } - resource_to_read = get_resource_context_for_timestamp(s, track_to_read); + resource_to_read = get_resource_context_for_timestamp(s, track); if (!resource_to_read) { - edit_unit_duration = av_inv_q(track_to_read->resources[track_to_read->current_resource_index].resource->base.edit_rate); - if (av_cmp_q(av_add_q(track_to_read->current_timestamp, edit_unit_duration), track_to_read->duration) > 0) { + edit_unit_duration = av_inv_q(track->resources[track->current_resource_index].resource->base.edit_rate); + if (av_cmp_q(av_add_q(track->current_timestamp, edit_unit_duration), + track->duration) + > 0) return AVERROR_EOF; - } av_log(s, AV_LOG_ERROR, "Could not find IMF track resource to read\n"); return AVERROR_STREAM_NOT_FOUND; @@ -717,25 +778,42 @@ static int ff_imf_read_packet(AVFormatContext *s, AVPacket *pkt) while (!ff_check_interrupt(c->interrupt_callback) && !ret) { ret = av_read_frame(resource_to_read->ctx, pkt); - av_log(s, AV_LOG_DEBUG, "Got packet: pts=%" PRId64 ", dts=%" PRId64 ", duration=%" PRId64 ", stream_index=%d, pos=%" PRId64 "\n", pkt->pts, pkt->dts, pkt->duration, pkt->stream_index, pkt->pos); - track_to_read_stream_internal = ffstream(s->streams[track_to_read->index]); + av_log(s, + AV_LOG_DEBUG, + "Got packet: pts=%" PRId64 + ", dts=%" PRId64 + ", duration=%" PRId64 + ", stream_index=%d, pos=%" PRId64 + "\n", + pkt->pts, + pkt->dts, + pkt->duration, + pkt->stream_index, + pkt->pos); + track_stream = ffstream(s->streams[track->index]); if (ret >= 0) { - // Update packet info from track - if (pkt->dts < track_to_read_stream_internal->cur_dts && track_to_read->last_pts > 0) { - pkt->dts = track_to_read_stream_internal->cur_dts; - } + /* Update packet info from track */ + if (pkt->dts < track_stream->cur_dts && track->last_pts > 0) + pkt->dts = track_stream->cur_dts; - pkt->pts = track_to_read->last_pts; - pkt->dts = pkt->dts - (int64_t)track_to_read->resources[track_to_read->current_resource_index].resource->base.entry_point; - pkt->stream_index = track_to_read->index; + pkt->pts = track->last_pts; + pkt->dts = pkt->dts + - (int64_t)track->resources[track->current_resource_index].resource->base.entry_point; + pkt->stream_index = track->index; - // Update track cursors - track_to_read->current_timestamp = av_add_q(track_to_read->current_timestamp, av_make_q((int)pkt->duration * resource_to_read->ctx->streams[0]->time_base.num, resource_to_read->ctx->streams[0]->time_base.den)); - track_to_read->last_pts += pkt->duration; + /* Update track cursors */ + track->current_timestamp = av_add_q(track->current_timestamp, + av_make_q((int)pkt->duration * resource_to_read->ctx->streams[0]->time_base.num, + resource_to_read->ctx->streams[0]->time_base.den)); + track->last_pts += pkt->duration; return 0; } else if (ret != AVERROR_EOF) { - av_log(s, AV_LOG_ERROR, "Could not get packet from track %d: %s\n", track_to_read->index, av_err2str(ret)); + av_log(s, + AV_LOG_ERROR, + "Could not get packet from track %d: %s\n", + track->index, + av_err2str(ret)); return ret; } } @@ -750,38 +828,50 @@ static int imf_close(AVFormatContext *s) av_log(s, AV_LOG_DEBUG, "Close IMF package\n"); av_dict_free(&c->avio_opts); av_freep(&c->base_url); - imf_asset_locator_map_free(c->asset_locator_map); - imf_cpl_free(c->cpl); + imf_asset_locator_map_deinit(&c->asset_locator_map); + ff_imf_cpl_free(c->cpl); - for (int i = 0; i < c->track_count; ++i) { - imf_virtual_track_playback_context_free(c->tracks[i]); - av_freep(&(c->tracks[i])); + for (uint32_t i = 0; i < c->track_count; ++i) { + imf_virtual_track_playback_context_deinit(c->tracks[i]); + av_freep(&c->tracks[i]); } - av_freep(&(c->tracks)); + av_freep(&c->tracks); return 0; } +// clang-format off static const AVOption imf_options[] = { - {"assetmaps", "IMF CPL-related asset map comma-separated absolute paths. If not specified, the CPL sibling `ASSETMAP.xml` file is used.", offsetof(IMFContext, asset_map_paths), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, AV_OPT_FLAG_DECODING_PARAM}, - {NULL}}; + { + .name = "assetmaps", + .help = "Comma-separated paths to ASSETMAP files." + "If not specified, the `ASSETMAP.xml` file in the same directory as the CPL is used.", + .offset = offsetof(IMFContext, asset_map_paths), + .type = AV_OPT_TYPE_STRING, + .default_val = {.str = NULL}, + .flags = AV_OPT_FLAG_DECODING_PARAM, + }, + {NULL}, +}; static const AVClass imf_class = { .class_name = "imf", - .item_name = av_default_item_name, - .option = imf_options, - .version = LIBAVUTIL_VERSION_INT, + .item_name = av_default_item_name, + .option = imf_options, + .version = LIBAVUTIL_VERSION_INT, }; const AVInputFormat ff_imf_demuxer = { - .name = "imf", - .long_name = NULL_IF_CONFIG_SMALL("IMF (Interoperable Master Format)"), - .priv_class = &imf_class, + .name = "imf", + .long_name = NULL_IF_CONFIG_SMALL("IMF (Interoperable Master Format)"), + .flags_internal = FF_FMT_INIT_CLEANUP, + .priv_class = &imf_class, .priv_data_size = sizeof(IMFContext), - .read_header = imf_read_header, - .read_packet = ff_imf_read_packet, - .read_close = imf_close, - .extensions = "xml", - .mime_type = "application/xml,text/xml", + .read_header = imf_read_header, + .read_packet = imf_read_packet, + .read_close = imf_close, + .extensions = "xml", + .mime_type = "application/xml,text/xml", }; +// clang-format on \ No newline at end of file diff --git a/libavformat/tests/imf.c b/libavformat/tests/imf.c index cc98da7042..efb5c5abc6 100644 --- a/libavformat/tests/imf.c +++ b/libavformat/tests/imf.c @@ -270,7 +270,7 @@ const char *asset_map_doc = static int test_cpl_parsing(void) { xmlDocPtr doc; - IMFCPL *cpl; + FFIMFCPL *cpl; int ret; doc = xmlReadMemory(cpl_doc, strlen(cpl_doc), NULL, NULL, 0); @@ -279,7 +279,7 @@ static int test_cpl_parsing(void) return 1; } - ret = parse_imf_cpl_from_xml_dom(doc, &cpl); + ret = ff_parse_imf_cpl_from_xml_dom(doc, &cpl); xmlFreeDoc(doc); if (ret) { printf("CPL parsing failed.\n"); @@ -287,36 +287,36 @@ static int test_cpl_parsing(void) } printf("%s\n", cpl->content_title_utf8); - printf(IMF_UUID_FORMAT "\n", UID_ARG(cpl->id_uuid)); + printf(FF_UUID_FORMAT "\n", UID_ARG(cpl->id_uuid)); printf("%i %i\n", cpl->edit_rate.num, cpl->edit_rate.den); - printf("Marker resource count: %lu\n", cpl->main_markers_track->resource_count); - for (unsigned long i = 0; i < cpl->main_markers_track->resource_count; i++) { - printf("Marker resource %lu\n", i); - for (unsigned long j = 0; j < cpl->main_markers_track->resources[i].marker_count; j++) { - printf(" Marker %lu\n", j); + printf("Marker resource count: %" PRIu32 "\n", cpl->main_markers_track->resource_count); + for (uint32_t i = 0; i < cpl->main_markers_track->resource_count; i++) { + printf("Marker resource %" PRIu32 "\n", i); + for (uint32_t j = 0; j < cpl->main_markers_track->resources[i].marker_count; j++) { + printf(" Marker %" PRIu32 "\n", j); printf(" Label %s\n", cpl->main_markers_track->resources[i].markers[j].label_utf8); - printf(" Offset %lu\n", cpl->main_markers_track->resources[i].markers[j].offset); + printf(" Offset %" PRIu32 "\n", cpl->main_markers_track->resources[i].markers[j].offset); } } - printf("Main image resource count: %lu\n", cpl->main_image_2d_track->resource_count); - for (unsigned long i = 0; i < cpl->main_image_2d_track->resource_count; i++) { - printf("Track file resource %lu\n", i); - printf(" " IMF_UUID_FORMAT "\n", UID_ARG(cpl->main_image_2d_track->resources[i].track_file_uuid)); + printf("Main image resource count: %" PRIu32 "\n", cpl->main_image_2d_track->resource_count); + for (uint32_t i = 0; i < cpl->main_image_2d_track->resource_count; i++) { + printf("Track file resource %" PRIu32 "\n", i); + printf(" " FF_UUID_FORMAT "\n", UID_ARG(cpl->main_image_2d_track->resources[i].track_file_uuid)); } - printf("Main audio track count: %lu\n", cpl->main_audio_track_count); - for (unsigned long i = 0; i < cpl->main_audio_track_count; i++) { - printf(" Main audio virtual track %lu\n", i); - printf(" Main audio resource count: %lu\n", cpl->main_audio_tracks[i].resource_count); - for (unsigned long j = 0; j < cpl->main_audio_tracks[i].resource_count; j++) { - printf(" Track file resource %lu\n", j); - printf(" " IMF_UUID_FORMAT "\n", UID_ARG(cpl->main_audio_tracks[i].resources[j].track_file_uuid)); + printf("Main audio track count: %" PRIu32 "\n", cpl->main_audio_track_count); + for (uint32_t i = 0; i < cpl->main_audio_track_count; i++) { + printf(" Main audio virtual track %" PRIu32 "\n", i); + printf(" Main audio resource count: %" PRIu32 "\n", cpl->main_audio_tracks[i].resource_count); + for (uint32_t j = 0; j < cpl->main_audio_tracks[i].resource_count; j++) { + printf(" Track file resource %" PRIu32 "\n", j); + printf(" " FF_UUID_FORMAT "\n", UID_ARG(cpl->main_audio_tracks[i].resources[j].track_file_uuid)); } } - imf_cpl_free(cpl); + ff_imf_cpl_free(cpl); return 0; } @@ -324,7 +324,7 @@ static int test_cpl_parsing(void) static int test_bad_cpl_parsing(void) { xmlDocPtr doc; - IMFCPL *cpl; + FFIMFCPL *cpl; int ret; doc = xmlReadMemory(cpl_bad_doc, strlen(cpl_bad_doc), NULL, NULL, 0); @@ -333,7 +333,7 @@ static int test_bad_cpl_parsing(void) return ret; } - ret = parse_imf_cpl_from_xml_dom(doc, &cpl); + ret = ff_parse_imf_cpl_from_xml_dom(doc, &cpl); xmlFreeDoc(doc); if (ret) { printf("CPL parsing failed.\n"); @@ -343,20 +343,26 @@ static int test_bad_cpl_parsing(void) return 0; } -static int check_asset_locator_attributes(IMFAssetLocator *asset, IMFAssetLocator expected_asset) +static int check_asset_locator_attributes(IMFAssetLocator *asset, IMFAssetLocator *expected_asset) { - printf("\tCompare " IMF_UUID_FORMAT " to " IMF_UUID_FORMAT ".\n", UID_ARG(asset->uuid), UID_ARG(expected_asset.uuid)); - for (int i = 0; i < 16; ++i) { - if (asset->uuid[i] != expected_asset.uuid[i]) { - printf("Invalid asset locator UUID: found " IMF_UUID_FORMAT " instead of " IMF_UUID_FORMAT " expected.\n", UID_ARG(asset->uuid), UID_ARG(expected_asset.uuid)); + printf("\tCompare " FF_UUID_FORMAT " to " FF_UUID_FORMAT ".\n", + UID_ARG(asset->uuid), + UID_ARG(expected_asset->uuid)); + for (uint32_t i = 0; i < 16; ++i) { + if (asset->uuid[i] != expected_asset->uuid[i]) { + printf("Invalid asset locator UUID: found " FF_UUID_FORMAT " instead of " FF_UUID_FORMAT " expected.\n", + UID_ARG(asset->uuid), + UID_ARG(expected_asset->uuid)); return 1; } } - printf("\tCompare %s to %s.\n", asset->absolute_uri, expected_asset.absolute_uri); - if (strcmp(asset->absolute_uri, expected_asset.absolute_uri) != 0) { - printf("Invalid asset locator URI: found %s instead of %s expected.\n", asset->absolute_uri, expected_asset.absolute_uri); + printf("\tCompare %s to %s.\n", asset->absolute_uri, expected_asset->absolute_uri); + if (strcmp(asset->absolute_uri, expected_asset->absolute_uri) != 0) { + printf("Invalid asset locator URI: found %s instead of %s expected.\n", + asset->absolute_uri, + expected_asset->absolute_uri); return 1; } @@ -364,16 +370,21 @@ static int check_asset_locator_attributes(IMFAssetLocator *asset, IMFAssetLocato } static IMFAssetLocator ASSET_MAP_EXPECTED_LOCATORS[5] = { - [0] = {.uuid = {0xb5, 0xd6, 0x74, 0xb8, 0xc6, 0xce, 0x4b, 0xce, 0x3b, 0xdf, 0xbe, 0x04, 0x5d, 0xfd, 0xb2, 0xd0}, .absolute_uri = (char *)"IMF_TEST_ASSET_MAP_video.mxf"}, - [1] = {.uuid = {0xec, 0x34, 0x67, 0xec, 0xab, 0x2a, 0x4f, 0x49, 0xc8, 0xcb, 0x89, 0xca, 0xa3, 0x76, 0x1f, 0x4a}, .absolute_uri = (char *)"IMF_TEST_ASSET_MAP_video_1.mxf"}, - [2] = {.uuid = {0x5c, 0xf5, 0xb5, 0xa7, 0x8b, 0xb3, 0x4f, 0x08, 0xea, 0xa6, 0x35, 0x33, 0xd4, 0xb7, 0x7f, 0xa6}, .absolute_uri = (char *)"IMF_TEST_ASSET_MAP_audio.mxf"}, - [3] = {.uuid = {0x55, 0x97, 0x77, 0xd6, 0xec, 0x29, 0x43, 0x75, 0xf9, 0x0d, 0x30, 0x0b, 0x0b, 0xf7, 0x36, 0x86}, .absolute_uri = (char *)"CPL_IMF_TEST_ASSET_MAP.xml"}, - [4] = {.uuid = {0xdd, 0x04, 0x52, 0x8d, 0x9b, 0x80, 0x45, 0x2a, 0x7a, 0x13, 0x80, 0x5b, 0x08, 0x27, 0x8b, 0x3d}, .absolute_uri = (char *)"PKL_IMF_TEST_ASSET_MAP.xml"}, + {.uuid = {0xb5, 0xd6, 0x74, 0xb8, 0xc6, 0xce, 0x4b, 0xce, 0x3b, 0xdf, 0xbe, 0x04, 0x5d, 0xfd, 0xb2, 0xd0}, + .absolute_uri = (char *)"IMF_TEST_ASSET_MAP_video.mxf"}, + {.uuid = {0xec, 0x34, 0x67, 0xec, 0xab, 0x2a, 0x4f, 0x49, 0xc8, 0xcb, 0x89, 0xca, 0xa3, 0x76, 0x1f, 0x4a}, + .absolute_uri = (char *)"IMF_TEST_ASSET_MAP_video_1.mxf"}, + {.uuid = {0x5c, 0xf5, 0xb5, 0xa7, 0x8b, 0xb3, 0x4f, 0x08, 0xea, 0xa6, 0x35, 0x33, 0xd4, 0xb7, 0x7f, 0xa6}, + .absolute_uri = (char *)"IMF_TEST_ASSET_MAP_audio.mxf"}, + {.uuid = {0x55, 0x97, 0x77, 0xd6, 0xec, 0x29, 0x43, 0x75, 0xf9, 0x0d, 0x30, 0x0b, 0x0b, 0xf7, 0x36, 0x86}, + .absolute_uri = (char *)"CPL_IMF_TEST_ASSET_MAP.xml"}, + {.uuid = {0xdd, 0x04, 0x52, 0x8d, 0x9b, 0x80, 0x45, 0x2a, 0x7a, 0x13, 0x80, 0x5b, 0x08, 0x27, 0x8b, 0x3d}, + .absolute_uri = (char *)"PKL_IMF_TEST_ASSET_MAP.xml"}, }; static int test_asset_map_parsing(void) { - IMFAssetLocatorMap *asset_locator_map; + IMFAssetLocatorMap asset_locator_map; xmlDoc *doc; int ret; @@ -384,32 +395,33 @@ static int test_asset_map_parsing(void) } printf("Allocate asset map\n"); - asset_locator_map = imf_asset_locator_map_alloc(); + imf_asset_locator_map_init(&asset_locator_map); printf("Parse asset map XML document\n"); - ret = parse_imf_asset_map_from_xml_dom(NULL, doc, asset_locator_map, doc->name); + ret = parse_imf_asset_map_from_xml_dom(NULL, doc, &asset_locator_map, doc->name); if (ret) { printf("Asset map parsing failed.\n"); goto cleanup; } - printf("Compare assets count: %d to 5\n", asset_locator_map->asset_count); - if (asset_locator_map->asset_count != 5) { - printf("Asset map parsing failed: found %d assets instead of 5 expected.\n", asset_locator_map->asset_count); + printf("Compare assets count: %d to 5\n", asset_locator_map.asset_count); + if (asset_locator_map.asset_count != 5) { + printf("Asset map parsing failed: found %d assets instead of 5 expected.\n", + asset_locator_map.asset_count); ret = 1; goto cleanup; } - for (int i = 0; i < asset_locator_map->asset_count; ++i) { + for (uint32_t i = 0; i < asset_locator_map.asset_count; ++i) { printf("For asset: %d:\n", i); - ret = check_asset_locator_attributes(asset_locator_map->assets[i], ASSET_MAP_EXPECTED_LOCATORS[i]); - if (ret > 0) { + ret = check_asset_locator_attributes(&(asset_locator_map.assets[i]), + &(ASSET_MAP_EXPECTED_LOCATORS[i])); + if (ret > 0) goto cleanup; - } } cleanup: - imf_asset_locator_map_free(asset_locator_map); + imf_asset_locator_map_deinit(&asset_locator_map); xmlFreeDoc(doc); return ret; } @@ -422,36 +434,48 @@ typedef struct PathTypeTestStruct { } PathTypeTestStruct; static const PathTypeTestStruct PATH_TYPE_TEST_STRUCTS[11] = { - [0] = {.path = "file://path/to/somewhere", .is_url = 1, .is_unix_absolute_path = 0, .is_dos_absolute_path = 0}, - [1] = {.path = "http://path/to/somewhere", .is_url = 1, .is_unix_absolute_path = 0, .is_dos_absolute_path = 0}, - [2] = {.path = "https://path/to/somewhere", .is_url = 1, .is_unix_absolute_path = 0, .is_dos_absolute_path = 0}, - [3] = {.path = "s3://path/to/somewhere", .is_url = 1, .is_unix_absolute_path = 0, .is_dos_absolute_path = 0}, - [4] = {.path = "ftp://path/to/somewhere", .is_url = 1, .is_unix_absolute_path = 0, .is_dos_absolute_path = 0}, - [5] = {.path = "/path/to/somewhere", .is_url = 0, .is_unix_absolute_path = 1, .is_dos_absolute_path = 0}, - [6] = {.path = "path/to/somewhere", .is_url = 0, .is_unix_absolute_path = 0, .is_dos_absolute_path = 0}, - [7] = {.path = "C:\\path\\to\\somewhere", .is_url = 0, .is_unix_absolute_path = 0, .is_dos_absolute_path = 1}, - [8] = {.path = "C:/path/to/somewhere", .is_url = 0, .is_unix_absolute_path = 0, .is_dos_absolute_path = 1}, - [9] = {.path = "\\\\path\\to\\somewhere", .is_url = 0, .is_unix_absolute_path = 0, .is_dos_absolute_path = 1}, - [10] = {.path = "path\\to\\somewhere", .is_url = 0, .is_unix_absolute_path = 0, .is_dos_absolute_path = 0}, + {.path = "file://path/to/somewhere", .is_url = 1, .is_unix_absolute_path = 0, .is_dos_absolute_path = 0}, + {.path = "http://path/to/somewhere", .is_url = 1, .is_unix_absolute_path = 0, .is_dos_absolute_path = 0}, + {.path = "https://path/to/somewhere", .is_url = 1, .is_unix_absolute_path = 0, .is_dos_absolute_path = 0}, + {.path = "s3://path/to/somewhere", .is_url = 1, .is_unix_absolute_path = 0, .is_dos_absolute_path = 0}, + {.path = "ftp://path/to/somewhere", .is_url = 1, .is_unix_absolute_path = 0, .is_dos_absolute_path = 0}, + {.path = "/path/to/somewhere", .is_url = 0, .is_unix_absolute_path = 1, .is_dos_absolute_path = 0}, + {.path = "path/to/somewhere", .is_url = 0, .is_unix_absolute_path = 0, .is_dos_absolute_path = 0}, + {.path = "C:\\path\\to\\somewhere", .is_url = 0, .is_unix_absolute_path = 0, .is_dos_absolute_path = 1}, + {.path = "C:/path/to/somewhere", .is_url = 0, .is_unix_absolute_path = 0, .is_dos_absolute_path = 1}, + {.path = "\\\\path\\to\\somewhere", .is_url = 0, .is_unix_absolute_path = 0, .is_dos_absolute_path = 1}, + {.path = "path\\to\\somewhere", .is_url = 0, .is_unix_absolute_path = 0, .is_dos_absolute_path = 0}, }; static int test_path_type_functions(void) { PathTypeTestStruct path_type; - for (int i = 0; i < 11; ++i) { + for (uint32_t i = 0; i < 11; ++i) { path_type = PATH_TYPE_TEST_STRUCTS[i]; if (imf_uri_is_url(path_type.path) != path_type.is_url) { - fprintf(stderr, "URL comparison test failed for '%s', got %d instead of expected %d\n", path_type.path, path_type.is_url, !path_type.is_url); + fprintf(stderr, + "URL comparison test failed for '%s', got %d instead of expected %d\n", + path_type.path, + path_type.is_url, + !path_type.is_url); goto fail; } if (imf_uri_is_unix_abs_path(path_type.path) != path_type.is_unix_absolute_path) { - fprintf(stderr, "Unix absolute path comparison test failed for '%s', got %d instead of expected %d\n", path_type.path, path_type.is_unix_absolute_path, !path_type.is_unix_absolute_path); + fprintf(stderr, + "Unix absolute path comparison test failed for '%s', got %d instead of expected %d\n", + path_type.path, + path_type.is_unix_absolute_path, + !path_type.is_unix_absolute_path); goto fail; } if (imf_uri_is_dos_abs_path(path_type.path) != path_type.is_dos_absolute_path) { - fprintf(stderr, "DOS absolute path comparison test failed for '%s', got %d instead of expected %d\n", path_type.path, path_type.is_dos_absolute_path, !path_type.is_dos_absolute_path); + fprintf(stderr, + "DOS absolute path comparison test failed for '%s', got %d instead of expected %d\n", + path_type.path, + path_type.is_dos_absolute_path, + !path_type.is_dos_absolute_path); goto fail; } }