xref: /third_party/ffmpeg/libavformat/imf_cpl.c (revision cabdff1a)
1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * This file is part of FFmpeg.
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
5cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
6cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
7cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
8cabdff1aSopenharmony_ci *
9cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
10cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
11cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12cabdff1aSopenharmony_ci * Lesser General Public License for more details.
13cabdff1aSopenharmony_ci *
14cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
15cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
16cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17cabdff1aSopenharmony_ci */
18cabdff1aSopenharmony_ci
19cabdff1aSopenharmony_ci/*
20cabdff1aSopenharmony_ci *
21cabdff1aSopenharmony_ci * Copyright (c) Sandflow Consulting LLC
22cabdff1aSopenharmony_ci *
23cabdff1aSopenharmony_ci * Redistribution and use in source and binary forms, with or without
24cabdff1aSopenharmony_ci * modification, are permitted provided that the following conditions are met:
25cabdff1aSopenharmony_ci *
26cabdff1aSopenharmony_ci * * Redistributions of source code must retain the above copyright notice, this
27cabdff1aSopenharmony_ci *   list of conditions and the following disclaimer.
28cabdff1aSopenharmony_ci * * Redistributions in binary form must reproduce the above copyright notice,
29cabdff1aSopenharmony_ci *   this list of conditions and the following disclaimer in the documentation
30cabdff1aSopenharmony_ci *   and/or other materials provided with the distribution.
31cabdff1aSopenharmony_ci *
32cabdff1aSopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
33cabdff1aSopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34cabdff1aSopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35cabdff1aSopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
36cabdff1aSopenharmony_ci * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
37cabdff1aSopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
38cabdff1aSopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
39cabdff1aSopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
40cabdff1aSopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41cabdff1aSopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42cabdff1aSopenharmony_ci * POSSIBILITY OF SUCH DAMAGE.
43cabdff1aSopenharmony_ci */
44cabdff1aSopenharmony_ci
45cabdff1aSopenharmony_ci/**
46cabdff1aSopenharmony_ci * Implements IMP CPL processing
47cabdff1aSopenharmony_ci *
48cabdff1aSopenharmony_ci * @author Pierre-Anthony Lemieux
49cabdff1aSopenharmony_ci * @file
50cabdff1aSopenharmony_ci * @ingroup lavu_imf
51cabdff1aSopenharmony_ci */
52cabdff1aSopenharmony_ci
53cabdff1aSopenharmony_ci#include "imf.h"
54cabdff1aSopenharmony_ci#include "libavformat/mxf.h"
55cabdff1aSopenharmony_ci#include "libavutil/bprint.h"
56cabdff1aSopenharmony_ci#include "libavutil/error.h"
57cabdff1aSopenharmony_ci#include <libxml/parser.h>
58cabdff1aSopenharmony_ci
59cabdff1aSopenharmony_cixmlNodePtr ff_imf_xml_get_child_element_by_name(xmlNodePtr parent, const char *name_utf8)
60cabdff1aSopenharmony_ci{
61cabdff1aSopenharmony_ci    xmlNodePtr cur_element;
62cabdff1aSopenharmony_ci
63cabdff1aSopenharmony_ci    cur_element = xmlFirstElementChild(parent);
64cabdff1aSopenharmony_ci    while (cur_element) {
65cabdff1aSopenharmony_ci        if (xmlStrcmp(cur_element->name, name_utf8) == 0)
66cabdff1aSopenharmony_ci            return cur_element;
67cabdff1aSopenharmony_ci
68cabdff1aSopenharmony_ci        cur_element = xmlNextElementSibling(cur_element);
69cabdff1aSopenharmony_ci    }
70cabdff1aSopenharmony_ci    return NULL;
71cabdff1aSopenharmony_ci}
72cabdff1aSopenharmony_ci
73cabdff1aSopenharmony_ciint ff_imf_xml_read_uuid(xmlNodePtr element, AVUUID uuid)
74cabdff1aSopenharmony_ci{
75cabdff1aSopenharmony_ci    xmlChar *element_text = NULL;
76cabdff1aSopenharmony_ci    int ret = 0;
77cabdff1aSopenharmony_ci
78cabdff1aSopenharmony_ci    element_text = xmlNodeListGetString(element->doc, element->xmlChildrenNode, 1);
79cabdff1aSopenharmony_ci    if (!element_text)
80cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
81cabdff1aSopenharmony_ci    ret = av_uuid_urn_parse(element_text, uuid);
82cabdff1aSopenharmony_ci    if (ret) {
83cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Invalid UUID\n");
84cabdff1aSopenharmony_ci        ret = AVERROR_INVALIDDATA;
85cabdff1aSopenharmony_ci    }
86cabdff1aSopenharmony_ci    xmlFree(element_text);
87cabdff1aSopenharmony_ci
88cabdff1aSopenharmony_ci    return ret;
89cabdff1aSopenharmony_ci}
90cabdff1aSopenharmony_ci
91cabdff1aSopenharmony_ciint ff_imf_xml_read_rational(xmlNodePtr element, AVRational *rational)
92cabdff1aSopenharmony_ci{
93cabdff1aSopenharmony_ci    xmlChar *element_text = NULL;
94cabdff1aSopenharmony_ci    int ret = 0;
95cabdff1aSopenharmony_ci
96cabdff1aSopenharmony_ci    element_text = xmlNodeListGetString(element->doc, element->xmlChildrenNode, 1);
97cabdff1aSopenharmony_ci    if (element_text == NULL || sscanf(element_text, "%i %i", &rational->num, &rational->den) != 2) {
98cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Invalid rational number\n");
99cabdff1aSopenharmony_ci        ret = AVERROR_INVALIDDATA;
100cabdff1aSopenharmony_ci    }
101cabdff1aSopenharmony_ci    xmlFree(element_text);
102cabdff1aSopenharmony_ci
103cabdff1aSopenharmony_ci    return ret;
104cabdff1aSopenharmony_ci}
105cabdff1aSopenharmony_ci
106cabdff1aSopenharmony_ciint ff_imf_xml_read_uint32(xmlNodePtr element, uint32_t *number)
107cabdff1aSopenharmony_ci{
108cabdff1aSopenharmony_ci    xmlChar *element_text = NULL;
109cabdff1aSopenharmony_ci    int ret = 0;
110cabdff1aSopenharmony_ci
111cabdff1aSopenharmony_ci    element_text = xmlNodeListGetString(element->doc, element->xmlChildrenNode, 1);
112cabdff1aSopenharmony_ci    if (element_text == NULL || sscanf(element_text, "%" PRIu32, number) != 1) {
113cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Invalid unsigned 32-bit integer");
114cabdff1aSopenharmony_ci        ret = AVERROR_INVALIDDATA;
115cabdff1aSopenharmony_ci    }
116cabdff1aSopenharmony_ci    xmlFree(element_text);
117cabdff1aSopenharmony_ci
118cabdff1aSopenharmony_ci    return ret;
119cabdff1aSopenharmony_ci}
120cabdff1aSopenharmony_ci
121cabdff1aSopenharmony_cistatic void imf_base_virtual_track_init(FFIMFBaseVirtualTrack *track)
122cabdff1aSopenharmony_ci{
123cabdff1aSopenharmony_ci    memset(track->id_uuid, 0, sizeof(track->id_uuid));
124cabdff1aSopenharmony_ci}
125cabdff1aSopenharmony_ci
126cabdff1aSopenharmony_cistatic void imf_marker_virtual_track_init(FFIMFMarkerVirtualTrack *track)
127cabdff1aSopenharmony_ci{
128cabdff1aSopenharmony_ci    imf_base_virtual_track_init((FFIMFBaseVirtualTrack *)track);
129cabdff1aSopenharmony_ci    track->resource_count = 0;
130cabdff1aSopenharmony_ci    track->resources = NULL;
131cabdff1aSopenharmony_ci}
132cabdff1aSopenharmony_ci
133cabdff1aSopenharmony_cistatic void imf_trackfile_virtual_track_init(FFIMFTrackFileVirtualTrack *track)
134cabdff1aSopenharmony_ci{
135cabdff1aSopenharmony_ci    imf_base_virtual_track_init((FFIMFBaseVirtualTrack *)track);
136cabdff1aSopenharmony_ci    track->resource_count = 0;
137cabdff1aSopenharmony_ci    track->resources_alloc_sz = 0;
138cabdff1aSopenharmony_ci    track->resources = NULL;
139cabdff1aSopenharmony_ci}
140cabdff1aSopenharmony_ci
141cabdff1aSopenharmony_cistatic void imf_base_resource_init(FFIMFBaseResource *rsrc)
142cabdff1aSopenharmony_ci{
143cabdff1aSopenharmony_ci    rsrc->duration = 0;
144cabdff1aSopenharmony_ci    rsrc->edit_rate = av_make_q(0, 1);
145cabdff1aSopenharmony_ci    rsrc->entry_point = 0;
146cabdff1aSopenharmony_ci    rsrc->repeat_count = 1;
147cabdff1aSopenharmony_ci}
148cabdff1aSopenharmony_ci
149cabdff1aSopenharmony_cistatic void imf_marker_resource_init(FFIMFMarkerResource *rsrc)
150cabdff1aSopenharmony_ci{
151cabdff1aSopenharmony_ci    imf_base_resource_init((FFIMFBaseResource *)rsrc);
152cabdff1aSopenharmony_ci    rsrc->marker_count = 0;
153cabdff1aSopenharmony_ci    rsrc->markers = NULL;
154cabdff1aSopenharmony_ci}
155cabdff1aSopenharmony_ci
156cabdff1aSopenharmony_cistatic void imf_marker_init(FFIMFMarker *marker)
157cabdff1aSopenharmony_ci{
158cabdff1aSopenharmony_ci    marker->label_utf8 = NULL;
159cabdff1aSopenharmony_ci    marker->offset = 0;
160cabdff1aSopenharmony_ci    marker->scope_utf8 = NULL;
161cabdff1aSopenharmony_ci}
162cabdff1aSopenharmony_ci
163cabdff1aSopenharmony_cistatic void imf_trackfile_resource_init(FFIMFTrackFileResource *rsrc)
164cabdff1aSopenharmony_ci{
165cabdff1aSopenharmony_ci    imf_base_resource_init((FFIMFBaseResource *)rsrc);
166cabdff1aSopenharmony_ci    memset(rsrc->track_file_uuid, 0, sizeof(rsrc->track_file_uuid));
167cabdff1aSopenharmony_ci}
168cabdff1aSopenharmony_ci
169cabdff1aSopenharmony_cistatic int fill_content_title(xmlNodePtr cpl_element, FFIMFCPL *cpl)
170cabdff1aSopenharmony_ci{
171cabdff1aSopenharmony_ci    xmlNodePtr element = NULL;
172cabdff1aSopenharmony_ci
173cabdff1aSopenharmony_ci    if (!(element = ff_imf_xml_get_child_element_by_name(cpl_element, "ContentTitle"))) {
174cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "ContentTitle element not found in the IMF CPL\n");
175cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
176cabdff1aSopenharmony_ci    }
177cabdff1aSopenharmony_ci    cpl->content_title_utf8 = xmlNodeListGetString(cpl_element->doc,
178cabdff1aSopenharmony_ci                                                   element->xmlChildrenNode,
179cabdff1aSopenharmony_ci                                                   1);
180cabdff1aSopenharmony_ci    if (!cpl->content_title_utf8)
181cabdff1aSopenharmony_ci        cpl->content_title_utf8 = xmlStrdup("");
182cabdff1aSopenharmony_ci    if (!cpl->content_title_utf8)
183cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
184cabdff1aSopenharmony_ci
185cabdff1aSopenharmony_ci    return 0;
186cabdff1aSopenharmony_ci}
187cabdff1aSopenharmony_ci
188cabdff1aSopenharmony_cistatic int fill_edit_rate(xmlNodePtr cpl_element, FFIMFCPL *cpl)
189cabdff1aSopenharmony_ci{
190cabdff1aSopenharmony_ci    xmlNodePtr element = NULL;
191cabdff1aSopenharmony_ci
192cabdff1aSopenharmony_ci    if (!(element = ff_imf_xml_get_child_element_by_name(cpl_element, "EditRate"))) {
193cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "EditRate element not found in the IMF CPL\n");
194cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
195cabdff1aSopenharmony_ci    }
196cabdff1aSopenharmony_ci
197cabdff1aSopenharmony_ci    return ff_imf_xml_read_rational(element, &cpl->edit_rate);
198cabdff1aSopenharmony_ci}
199cabdff1aSopenharmony_ci
200cabdff1aSopenharmony_cistatic int fill_id(xmlNodePtr cpl_element, FFIMFCPL *cpl)
201cabdff1aSopenharmony_ci{
202cabdff1aSopenharmony_ci    xmlNodePtr element = NULL;
203cabdff1aSopenharmony_ci
204cabdff1aSopenharmony_ci    if (!(element = ff_imf_xml_get_child_element_by_name(cpl_element, "Id"))) {
205cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Id element not found in the IMF CPL\n");
206cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
207cabdff1aSopenharmony_ci    }
208cabdff1aSopenharmony_ci
209cabdff1aSopenharmony_ci    return ff_imf_xml_read_uuid(element, cpl->id_uuid);
210cabdff1aSopenharmony_ci}
211cabdff1aSopenharmony_ci
212cabdff1aSopenharmony_cistatic int fill_marker(xmlNodePtr marker_elem, FFIMFMarker *marker)
213cabdff1aSopenharmony_ci{
214cabdff1aSopenharmony_ci    xmlNodePtr element = NULL;
215cabdff1aSopenharmony_ci    int ret = 0;
216cabdff1aSopenharmony_ci
217cabdff1aSopenharmony_ci    /* read Offset */
218cabdff1aSopenharmony_ci    if (!(element = ff_imf_xml_get_child_element_by_name(marker_elem, "Offset"))) {
219cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Offset element not found in a Marker\n");
220cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
221cabdff1aSopenharmony_ci    }
222cabdff1aSopenharmony_ci    if ((ret = ff_imf_xml_read_uint32(element, &marker->offset)))
223cabdff1aSopenharmony_ci        return ret;
224cabdff1aSopenharmony_ci
225cabdff1aSopenharmony_ci    /* read Label and Scope */
226cabdff1aSopenharmony_ci    if (!(element = ff_imf_xml_get_child_element_by_name(marker_elem, "Label"))) {
227cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Label element not found in a Marker\n");
228cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
229cabdff1aSopenharmony_ci    }
230cabdff1aSopenharmony_ci    if (!(marker->label_utf8 = xmlNodeListGetString(element->doc, element->xmlChildrenNode, 1))) {
231cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Empty Label element found in a Marker\n");
232cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
233cabdff1aSopenharmony_ci    }
234cabdff1aSopenharmony_ci    if (!(marker->scope_utf8 = xmlGetNoNsProp(element, "scope"))) {
235cabdff1aSopenharmony_ci        marker->scope_utf8
236cabdff1aSopenharmony_ci            = xmlCharStrdup("http://www.smpte-ra.org/schemas/2067-3/2013#standard-markers");
237cabdff1aSopenharmony_ci        if (!marker->scope_utf8) {
238cabdff1aSopenharmony_ci            xmlFree(marker->label_utf8);
239cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
240cabdff1aSopenharmony_ci        }
241cabdff1aSopenharmony_ci    }
242cabdff1aSopenharmony_ci
243cabdff1aSopenharmony_ci    return ret;
244cabdff1aSopenharmony_ci}
245cabdff1aSopenharmony_ci
246cabdff1aSopenharmony_cistatic int fill_base_resource(xmlNodePtr resource_elem, FFIMFBaseResource *resource, FFIMFCPL *cpl)
247cabdff1aSopenharmony_ci{
248cabdff1aSopenharmony_ci    xmlNodePtr element = NULL;
249cabdff1aSopenharmony_ci    int ret = 0;
250cabdff1aSopenharmony_ci
251cabdff1aSopenharmony_ci    /* read EditRate */
252cabdff1aSopenharmony_ci    if (!(element = ff_imf_xml_get_child_element_by_name(resource_elem, "EditRate"))) {
253cabdff1aSopenharmony_ci        resource->edit_rate = cpl->edit_rate;
254cabdff1aSopenharmony_ci    } else if ((ret = ff_imf_xml_read_rational(element, &resource->edit_rate))) {
255cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Invalid EditRate element found in a Resource\n");
256cabdff1aSopenharmony_ci        return ret;
257cabdff1aSopenharmony_ci    }
258cabdff1aSopenharmony_ci
259cabdff1aSopenharmony_ci    /* read EntryPoint */
260cabdff1aSopenharmony_ci    if ((element = ff_imf_xml_get_child_element_by_name(resource_elem, "EntryPoint"))) {
261cabdff1aSopenharmony_ci        if ((ret = ff_imf_xml_read_uint32(element, &resource->entry_point))) {
262cabdff1aSopenharmony_ci            av_log(NULL, AV_LOG_ERROR, "Invalid EntryPoint element found in a Resource\n");
263cabdff1aSopenharmony_ci            return ret;
264cabdff1aSopenharmony_ci        }
265cabdff1aSopenharmony_ci    } else {
266cabdff1aSopenharmony_ci        resource->entry_point = 0;
267cabdff1aSopenharmony_ci    }
268cabdff1aSopenharmony_ci
269cabdff1aSopenharmony_ci    /* read IntrinsicDuration */
270cabdff1aSopenharmony_ci    if (!(element = ff_imf_xml_get_child_element_by_name(resource_elem, "IntrinsicDuration"))) {
271cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "IntrinsicDuration element missing from Resource\n");
272cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
273cabdff1aSopenharmony_ci    }
274cabdff1aSopenharmony_ci    if ((ret = ff_imf_xml_read_uint32(element, &resource->duration))) {
275cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Invalid IntrinsicDuration element found in a Resource\n");
276cabdff1aSopenharmony_ci        return ret;
277cabdff1aSopenharmony_ci    }
278cabdff1aSopenharmony_ci    resource->duration -= resource->entry_point;
279cabdff1aSopenharmony_ci
280cabdff1aSopenharmony_ci    /* read SourceDuration */
281cabdff1aSopenharmony_ci    if ((element = ff_imf_xml_get_child_element_by_name(resource_elem, "SourceDuration"))) {
282cabdff1aSopenharmony_ci        if ((ret = ff_imf_xml_read_uint32(element, &resource->duration))) {
283cabdff1aSopenharmony_ci            av_log(NULL, AV_LOG_ERROR, "SourceDuration element missing from Resource\n");
284cabdff1aSopenharmony_ci            return ret;
285cabdff1aSopenharmony_ci        }
286cabdff1aSopenharmony_ci    }
287cabdff1aSopenharmony_ci
288cabdff1aSopenharmony_ci    /* read RepeatCount */
289cabdff1aSopenharmony_ci    if ((element = ff_imf_xml_get_child_element_by_name(resource_elem, "RepeatCount")))
290cabdff1aSopenharmony_ci        ret = ff_imf_xml_read_uint32(element, &resource->repeat_count);
291cabdff1aSopenharmony_ci
292cabdff1aSopenharmony_ci    return ret;
293cabdff1aSopenharmony_ci}
294cabdff1aSopenharmony_ci
295cabdff1aSopenharmony_cistatic int fill_trackfile_resource(xmlNodePtr tf_resource_elem,
296cabdff1aSopenharmony_ci                                   FFIMFTrackFileResource *tf_resource,
297cabdff1aSopenharmony_ci                                   FFIMFCPL *cpl)
298cabdff1aSopenharmony_ci{
299cabdff1aSopenharmony_ci    xmlNodePtr element = NULL;
300cabdff1aSopenharmony_ci    int ret = 0;
301cabdff1aSopenharmony_ci
302cabdff1aSopenharmony_ci    if ((ret = fill_base_resource(tf_resource_elem, (FFIMFBaseResource *)tf_resource, cpl)))
303cabdff1aSopenharmony_ci        return ret;
304cabdff1aSopenharmony_ci
305cabdff1aSopenharmony_ci    /* read TrackFileId */
306cabdff1aSopenharmony_ci    if ((element = ff_imf_xml_get_child_element_by_name(tf_resource_elem, "TrackFileId"))) {
307cabdff1aSopenharmony_ci        if ((ret = ff_imf_xml_read_uuid(element, tf_resource->track_file_uuid))) {
308cabdff1aSopenharmony_ci            av_log(NULL, AV_LOG_ERROR, "Invalid TrackFileId element found in Resource\n");
309cabdff1aSopenharmony_ci            return ret;
310cabdff1aSopenharmony_ci        }
311cabdff1aSopenharmony_ci    } else {
312cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "TrackFileId element missing from Resource\n");
313cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
314cabdff1aSopenharmony_ci    }
315cabdff1aSopenharmony_ci
316cabdff1aSopenharmony_ci    return ret;
317cabdff1aSopenharmony_ci}
318cabdff1aSopenharmony_ci
319cabdff1aSopenharmony_cistatic int fill_marker_resource(xmlNodePtr marker_resource_elem,
320cabdff1aSopenharmony_ci                                FFIMFMarkerResource *marker_resource,
321cabdff1aSopenharmony_ci                                FFIMFCPL *cpl)
322cabdff1aSopenharmony_ci{
323cabdff1aSopenharmony_ci    xmlNodePtr element = NULL;
324cabdff1aSopenharmony_ci    int ret = 0;
325cabdff1aSopenharmony_ci
326cabdff1aSopenharmony_ci    if ((ret = fill_base_resource(marker_resource_elem, (FFIMFBaseResource *)marker_resource, cpl)))
327cabdff1aSopenharmony_ci        return ret;
328cabdff1aSopenharmony_ci
329cabdff1aSopenharmony_ci    /* read markers */
330cabdff1aSopenharmony_ci    element = xmlFirstElementChild(marker_resource_elem);
331cabdff1aSopenharmony_ci    while (element) {
332cabdff1aSopenharmony_ci        if (xmlStrcmp(element->name, "Marker") == 0) {
333cabdff1aSopenharmony_ci            void *tmp;
334cabdff1aSopenharmony_ci
335cabdff1aSopenharmony_ci            if (marker_resource->marker_count == UINT32_MAX)
336cabdff1aSopenharmony_ci                return AVERROR(ENOMEM);
337cabdff1aSopenharmony_ci            tmp = av_realloc_array(marker_resource->markers,
338cabdff1aSopenharmony_ci                                   marker_resource->marker_count + 1,
339cabdff1aSopenharmony_ci                                   sizeof(FFIMFMarker));
340cabdff1aSopenharmony_ci            if (!tmp)
341cabdff1aSopenharmony_ci                return AVERROR(ENOMEM);
342cabdff1aSopenharmony_ci            marker_resource->markers = tmp;
343cabdff1aSopenharmony_ci
344cabdff1aSopenharmony_ci            imf_marker_init(&marker_resource->markers[marker_resource->marker_count]);
345cabdff1aSopenharmony_ci            ret = fill_marker(element,
346cabdff1aSopenharmony_ci                              &marker_resource->markers[marker_resource->marker_count]);
347cabdff1aSopenharmony_ci            marker_resource->marker_count++;
348cabdff1aSopenharmony_ci            if (ret)
349cabdff1aSopenharmony_ci                return ret;
350cabdff1aSopenharmony_ci        }
351cabdff1aSopenharmony_ci
352cabdff1aSopenharmony_ci        element = xmlNextElementSibling(element);
353cabdff1aSopenharmony_ci    }
354cabdff1aSopenharmony_ci
355cabdff1aSopenharmony_ci    return ret;
356cabdff1aSopenharmony_ci}
357cabdff1aSopenharmony_ci
358cabdff1aSopenharmony_cistatic int push_marker_sequence(xmlNodePtr marker_sequence_elem, FFIMFCPL *cpl)
359cabdff1aSopenharmony_ci{
360cabdff1aSopenharmony_ci    int ret = 0;
361cabdff1aSopenharmony_ci    AVUUID uuid;
362cabdff1aSopenharmony_ci    xmlNodePtr resource_list_elem = NULL;
363cabdff1aSopenharmony_ci    xmlNodePtr resource_elem = NULL;
364cabdff1aSopenharmony_ci    xmlNodePtr track_id_elem = NULL;
365cabdff1aSopenharmony_ci    unsigned long resource_elem_count;
366cabdff1aSopenharmony_ci    void *tmp;
367cabdff1aSopenharmony_ci
368cabdff1aSopenharmony_ci    /* read TrackID element */
369cabdff1aSopenharmony_ci    if (!(track_id_elem = ff_imf_xml_get_child_element_by_name(marker_sequence_elem, "TrackId"))) {
370cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "TrackId element missing from Sequence\n");
371cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
372cabdff1aSopenharmony_ci    }
373cabdff1aSopenharmony_ci    if (ff_imf_xml_read_uuid(track_id_elem, uuid)) {
374cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Invalid TrackId element found in Sequence\n");
375cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
376cabdff1aSopenharmony_ci    }
377cabdff1aSopenharmony_ci    av_log(NULL,
378cabdff1aSopenharmony_ci           AV_LOG_DEBUG,
379cabdff1aSopenharmony_ci           "Processing IMF CPL Marker Sequence for Virtual Track " AV_PRI_UUID "\n",
380cabdff1aSopenharmony_ci           AV_UUID_ARG(uuid));
381cabdff1aSopenharmony_ci
382cabdff1aSopenharmony_ci    /* create main marker virtual track if it does not exist */
383cabdff1aSopenharmony_ci    if (!cpl->main_markers_track) {
384cabdff1aSopenharmony_ci        cpl->main_markers_track = av_malloc(sizeof(FFIMFMarkerVirtualTrack));
385cabdff1aSopenharmony_ci        if (!cpl->main_markers_track)
386cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
387cabdff1aSopenharmony_ci        imf_marker_virtual_track_init(cpl->main_markers_track);
388cabdff1aSopenharmony_ci        av_uuid_copy(cpl->main_markers_track->base.id_uuid, uuid);
389cabdff1aSopenharmony_ci
390cabdff1aSopenharmony_ci    } else if (!av_uuid_equal(cpl->main_markers_track->base.id_uuid, uuid)) {
391cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Multiple marker virtual tracks were found\n");
392cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
393cabdff1aSopenharmony_ci    }
394cabdff1aSopenharmony_ci
395cabdff1aSopenharmony_ci    /* process resources */
396cabdff1aSopenharmony_ci    resource_list_elem = ff_imf_xml_get_child_element_by_name(marker_sequence_elem, "ResourceList");
397cabdff1aSopenharmony_ci    if (!resource_list_elem)
398cabdff1aSopenharmony_ci        return 0;
399cabdff1aSopenharmony_ci
400cabdff1aSopenharmony_ci    resource_elem_count = xmlChildElementCount(resource_list_elem);
401cabdff1aSopenharmony_ci    if (resource_elem_count > UINT32_MAX
402cabdff1aSopenharmony_ci        || cpl->main_markers_track->resource_count > UINT32_MAX - resource_elem_count)
403cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
404cabdff1aSopenharmony_ci    tmp = av_realloc_array(cpl->main_markers_track->resources,
405cabdff1aSopenharmony_ci                           cpl->main_markers_track->resource_count + resource_elem_count,
406cabdff1aSopenharmony_ci                           sizeof(FFIMFMarkerResource));
407cabdff1aSopenharmony_ci    if (!tmp) {
408cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Cannot allocate Marker Resources\n");
409cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
410cabdff1aSopenharmony_ci    }
411cabdff1aSopenharmony_ci    cpl->main_markers_track->resources = tmp;
412cabdff1aSopenharmony_ci
413cabdff1aSopenharmony_ci    resource_elem = xmlFirstElementChild(resource_list_elem);
414cabdff1aSopenharmony_ci    while (resource_elem) {
415cabdff1aSopenharmony_ci        imf_marker_resource_init(&cpl->main_markers_track->resources[cpl->main_markers_track->resource_count]);
416cabdff1aSopenharmony_ci        ret = fill_marker_resource(resource_elem,
417cabdff1aSopenharmony_ci                                   &cpl->main_markers_track->resources[cpl->main_markers_track->resource_count],
418cabdff1aSopenharmony_ci                                   cpl);
419cabdff1aSopenharmony_ci        cpl->main_markers_track->resource_count++;
420cabdff1aSopenharmony_ci        if (ret)
421cabdff1aSopenharmony_ci            return ret;
422cabdff1aSopenharmony_ci
423cabdff1aSopenharmony_ci        resource_elem = xmlNextElementSibling(resource_elem);
424cabdff1aSopenharmony_ci    }
425cabdff1aSopenharmony_ci
426cabdff1aSopenharmony_ci    return ret;
427cabdff1aSopenharmony_ci}
428cabdff1aSopenharmony_ci
429cabdff1aSopenharmony_cistatic int has_stereo_resources(xmlNodePtr element)
430cabdff1aSopenharmony_ci{
431cabdff1aSopenharmony_ci    if (xmlStrcmp(element->name, "Left") == 0 || xmlStrcmp(element->name, "Right") == 0)
432cabdff1aSopenharmony_ci        return 1;
433cabdff1aSopenharmony_ci
434cabdff1aSopenharmony_ci    element = xmlFirstElementChild(element);
435cabdff1aSopenharmony_ci    while (element) {
436cabdff1aSopenharmony_ci        if (has_stereo_resources(element))
437cabdff1aSopenharmony_ci            return 1;
438cabdff1aSopenharmony_ci
439cabdff1aSopenharmony_ci        element = xmlNextElementSibling(element);
440cabdff1aSopenharmony_ci    }
441cabdff1aSopenharmony_ci
442cabdff1aSopenharmony_ci    return 0;
443cabdff1aSopenharmony_ci}
444cabdff1aSopenharmony_ci
445cabdff1aSopenharmony_cistatic int push_main_audio_sequence(xmlNodePtr audio_sequence_elem, FFIMFCPL *cpl)
446cabdff1aSopenharmony_ci{
447cabdff1aSopenharmony_ci    int ret = 0;
448cabdff1aSopenharmony_ci    AVUUID uuid;
449cabdff1aSopenharmony_ci    xmlNodePtr resource_list_elem = NULL;
450cabdff1aSopenharmony_ci    xmlNodePtr resource_elem = NULL;
451cabdff1aSopenharmony_ci    xmlNodePtr track_id_elem = NULL;
452cabdff1aSopenharmony_ci    unsigned long resource_elem_count;
453cabdff1aSopenharmony_ci    FFIMFTrackFileVirtualTrack *vt = NULL;
454cabdff1aSopenharmony_ci    void *tmp;
455cabdff1aSopenharmony_ci
456cabdff1aSopenharmony_ci    /* read TrackID element */
457cabdff1aSopenharmony_ci    if (!(track_id_elem = ff_imf_xml_get_child_element_by_name(audio_sequence_elem, "TrackId"))) {
458cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "TrackId element missing from audio sequence\n");
459cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
460cabdff1aSopenharmony_ci    }
461cabdff1aSopenharmony_ci    if ((ret = ff_imf_xml_read_uuid(track_id_elem, uuid))) {
462cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Invalid TrackId element found in audio sequence\n");
463cabdff1aSopenharmony_ci        return ret;
464cabdff1aSopenharmony_ci    }
465cabdff1aSopenharmony_ci    av_log(NULL,
466cabdff1aSopenharmony_ci           AV_LOG_DEBUG,
467cabdff1aSopenharmony_ci           "Processing IMF CPL Audio Sequence for Virtual Track " AV_PRI_UUID "\n",
468cabdff1aSopenharmony_ci           AV_UUID_ARG(uuid));
469cabdff1aSopenharmony_ci
470cabdff1aSopenharmony_ci    /* get the main audio virtual track corresponding to the sequence */
471cabdff1aSopenharmony_ci    for (uint32_t i = 0; i < cpl->main_audio_track_count; i++) {
472cabdff1aSopenharmony_ci        if (av_uuid_equal(cpl->main_audio_tracks[i].base.id_uuid, uuid)) {
473cabdff1aSopenharmony_ci            vt = &cpl->main_audio_tracks[i];
474cabdff1aSopenharmony_ci            break;
475cabdff1aSopenharmony_ci        }
476cabdff1aSopenharmony_ci    }
477cabdff1aSopenharmony_ci
478cabdff1aSopenharmony_ci    /* create a main audio virtual track if none exists for the sequence */
479cabdff1aSopenharmony_ci    if (!vt) {
480cabdff1aSopenharmony_ci        if (cpl->main_audio_track_count == UINT32_MAX)
481cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
482cabdff1aSopenharmony_ci        tmp = av_realloc_array(cpl->main_audio_tracks,
483cabdff1aSopenharmony_ci                               cpl->main_audio_track_count + 1,
484cabdff1aSopenharmony_ci                               sizeof(FFIMFTrackFileVirtualTrack));
485cabdff1aSopenharmony_ci        if (!tmp)
486cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
487cabdff1aSopenharmony_ci
488cabdff1aSopenharmony_ci        cpl->main_audio_tracks = tmp;
489cabdff1aSopenharmony_ci        vt = &cpl->main_audio_tracks[cpl->main_audio_track_count];
490cabdff1aSopenharmony_ci        imf_trackfile_virtual_track_init(vt);
491cabdff1aSopenharmony_ci        cpl->main_audio_track_count++;
492cabdff1aSopenharmony_ci        av_uuid_copy(vt->base.id_uuid, uuid);
493cabdff1aSopenharmony_ci    }
494cabdff1aSopenharmony_ci
495cabdff1aSopenharmony_ci    /* process resources */
496cabdff1aSopenharmony_ci    resource_list_elem = ff_imf_xml_get_child_element_by_name(audio_sequence_elem, "ResourceList");
497cabdff1aSopenharmony_ci    if (!resource_list_elem)
498cabdff1aSopenharmony_ci        return 0;
499cabdff1aSopenharmony_ci
500cabdff1aSopenharmony_ci    resource_elem_count = xmlChildElementCount(resource_list_elem);
501cabdff1aSopenharmony_ci    if (resource_elem_count > UINT32_MAX
502cabdff1aSopenharmony_ci        || vt->resource_count > UINT32_MAX - resource_elem_count)
503cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
504cabdff1aSopenharmony_ci    tmp = av_fast_realloc(vt->resources,
505cabdff1aSopenharmony_ci                          &vt->resources_alloc_sz,
506cabdff1aSopenharmony_ci                          (vt->resource_count + resource_elem_count)
507cabdff1aSopenharmony_ci                              * sizeof(FFIMFTrackFileResource));
508cabdff1aSopenharmony_ci    if (!tmp) {
509cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Cannot allocate Main Audio Resources\n");
510cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
511cabdff1aSopenharmony_ci    }
512cabdff1aSopenharmony_ci    vt->resources = tmp;
513cabdff1aSopenharmony_ci
514cabdff1aSopenharmony_ci    resource_elem = xmlFirstElementChild(resource_list_elem);
515cabdff1aSopenharmony_ci    while (resource_elem) {
516cabdff1aSopenharmony_ci        imf_trackfile_resource_init(&vt->resources[vt->resource_count]);
517cabdff1aSopenharmony_ci        ret = fill_trackfile_resource(resource_elem,
518cabdff1aSopenharmony_ci                                      &vt->resources[vt->resource_count],
519cabdff1aSopenharmony_ci                                      cpl);
520cabdff1aSopenharmony_ci        if (ret)
521cabdff1aSopenharmony_ci            av_log(NULL, AV_LOG_ERROR, "Invalid Resource\n");
522cabdff1aSopenharmony_ci        else
523cabdff1aSopenharmony_ci            vt->resource_count++;
524cabdff1aSopenharmony_ci
525cabdff1aSopenharmony_ci        resource_elem = xmlNextElementSibling(resource_elem);
526cabdff1aSopenharmony_ci    }
527cabdff1aSopenharmony_ci
528cabdff1aSopenharmony_ci    return ret;
529cabdff1aSopenharmony_ci}
530cabdff1aSopenharmony_ci
531cabdff1aSopenharmony_cistatic int push_main_image_2d_sequence(xmlNodePtr image_sequence_elem, FFIMFCPL *cpl)
532cabdff1aSopenharmony_ci{
533cabdff1aSopenharmony_ci    int ret = 0;
534cabdff1aSopenharmony_ci    AVUUID uuid;
535cabdff1aSopenharmony_ci    xmlNodePtr resource_list_elem = NULL;
536cabdff1aSopenharmony_ci    xmlNodePtr resource_elem = NULL;
537cabdff1aSopenharmony_ci    xmlNodePtr track_id_elem = NULL;
538cabdff1aSopenharmony_ci    void *tmp;
539cabdff1aSopenharmony_ci    unsigned long resource_elem_count;
540cabdff1aSopenharmony_ci
541cabdff1aSopenharmony_ci    /* skip stereoscopic resources */
542cabdff1aSopenharmony_ci    if (has_stereo_resources(image_sequence_elem)) {
543cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Stereoscopic 3D image virtual tracks not supported\n");
544cabdff1aSopenharmony_ci        return AVERROR_PATCHWELCOME;
545cabdff1aSopenharmony_ci    }
546cabdff1aSopenharmony_ci
547cabdff1aSopenharmony_ci    /* read TrackId element*/
548cabdff1aSopenharmony_ci    if (!(track_id_elem = ff_imf_xml_get_child_element_by_name(image_sequence_elem, "TrackId"))) {
549cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "TrackId element missing from audio sequence\n");
550cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
551cabdff1aSopenharmony_ci    }
552cabdff1aSopenharmony_ci    if ((ret = ff_imf_xml_read_uuid(track_id_elem, uuid))) {
553cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Invalid TrackId element found in audio sequence\n");
554cabdff1aSopenharmony_ci        return ret;
555cabdff1aSopenharmony_ci    }
556cabdff1aSopenharmony_ci
557cabdff1aSopenharmony_ci    /* create main image virtual track if one does not exist */
558cabdff1aSopenharmony_ci    if (!cpl->main_image_2d_track) {
559cabdff1aSopenharmony_ci        cpl->main_image_2d_track = av_malloc(sizeof(FFIMFTrackFileVirtualTrack));
560cabdff1aSopenharmony_ci        if (!cpl->main_image_2d_track)
561cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
562cabdff1aSopenharmony_ci        imf_trackfile_virtual_track_init(cpl->main_image_2d_track);
563cabdff1aSopenharmony_ci        av_uuid_copy(cpl->main_image_2d_track->base.id_uuid, uuid);
564cabdff1aSopenharmony_ci
565cabdff1aSopenharmony_ci    } else if (!av_uuid_equal(cpl->main_image_2d_track->base.id_uuid, uuid)) {
566cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Multiple MainImage virtual tracks found\n");
567cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
568cabdff1aSopenharmony_ci    }
569cabdff1aSopenharmony_ci    av_log(NULL,
570cabdff1aSopenharmony_ci           AV_LOG_DEBUG,
571cabdff1aSopenharmony_ci           "Processing IMF CPL Main Image Sequence for Virtual Track " AV_PRI_UUID "\n",
572cabdff1aSopenharmony_ci           AV_UUID_ARG(uuid));
573cabdff1aSopenharmony_ci
574cabdff1aSopenharmony_ci    /* process resources */
575cabdff1aSopenharmony_ci    resource_list_elem = ff_imf_xml_get_child_element_by_name(image_sequence_elem, "ResourceList");
576cabdff1aSopenharmony_ci    if (!resource_list_elem)
577cabdff1aSopenharmony_ci        return 0;
578cabdff1aSopenharmony_ci
579cabdff1aSopenharmony_ci    resource_elem_count = xmlChildElementCount(resource_list_elem);
580cabdff1aSopenharmony_ci    if (resource_elem_count > UINT32_MAX
581cabdff1aSopenharmony_ci        || cpl->main_image_2d_track->resource_count > UINT32_MAX - resource_elem_count
582cabdff1aSopenharmony_ci        || (cpl->main_image_2d_track->resource_count + resource_elem_count)
583cabdff1aSopenharmony_ci            > INT_MAX / sizeof(FFIMFTrackFileResource))
584cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
585cabdff1aSopenharmony_ci    tmp = av_fast_realloc(cpl->main_image_2d_track->resources,
586cabdff1aSopenharmony_ci                          &cpl->main_image_2d_track->resources_alloc_sz,
587cabdff1aSopenharmony_ci                          (cpl->main_image_2d_track->resource_count + resource_elem_count)
588cabdff1aSopenharmony_ci                              * sizeof(FFIMFTrackFileResource));
589cabdff1aSopenharmony_ci    if (!tmp) {
590cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Cannot allocate Main Image Resources\n");
591cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
592cabdff1aSopenharmony_ci    }
593cabdff1aSopenharmony_ci    cpl->main_image_2d_track->resources = tmp;
594cabdff1aSopenharmony_ci
595cabdff1aSopenharmony_ci    resource_elem = xmlFirstElementChild(resource_list_elem);
596cabdff1aSopenharmony_ci    while (resource_elem) {
597cabdff1aSopenharmony_ci        imf_trackfile_resource_init(
598cabdff1aSopenharmony_ci            &cpl->main_image_2d_track->resources[cpl->main_image_2d_track->resource_count]);
599cabdff1aSopenharmony_ci        ret = fill_trackfile_resource(resource_elem,
600cabdff1aSopenharmony_ci                                      &cpl->main_image_2d_track->resources[cpl->main_image_2d_track->resource_count],
601cabdff1aSopenharmony_ci                                      cpl);
602cabdff1aSopenharmony_ci        if (ret)
603cabdff1aSopenharmony_ci            av_log(NULL, AV_LOG_ERROR, "Invalid Resource\n");
604cabdff1aSopenharmony_ci        else
605cabdff1aSopenharmony_ci            cpl->main_image_2d_track->resource_count++;
606cabdff1aSopenharmony_ci
607cabdff1aSopenharmony_ci        resource_elem = xmlNextElementSibling(resource_elem);
608cabdff1aSopenharmony_ci    }
609cabdff1aSopenharmony_ci
610cabdff1aSopenharmony_ci    return 0;
611cabdff1aSopenharmony_ci}
612cabdff1aSopenharmony_ci
613cabdff1aSopenharmony_cistatic int fill_virtual_tracks(xmlNodePtr cpl_element, FFIMFCPL *cpl)
614cabdff1aSopenharmony_ci{
615cabdff1aSopenharmony_ci    int ret = 0;
616cabdff1aSopenharmony_ci    xmlNodePtr segment_list_elem = NULL;
617cabdff1aSopenharmony_ci    xmlNodePtr segment_elem = NULL;
618cabdff1aSopenharmony_ci    xmlNodePtr sequence_list_elem = NULL;
619cabdff1aSopenharmony_ci    xmlNodePtr sequence_elem = NULL;
620cabdff1aSopenharmony_ci
621cabdff1aSopenharmony_ci    if (!(segment_list_elem = ff_imf_xml_get_child_element_by_name(cpl_element, "SegmentList"))) {
622cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "SegmentList element missing\n");
623cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
624cabdff1aSopenharmony_ci    }
625cabdff1aSopenharmony_ci
626cabdff1aSopenharmony_ci    /* process sequences */
627cabdff1aSopenharmony_ci    segment_elem = xmlFirstElementChild(segment_list_elem);
628cabdff1aSopenharmony_ci    while (segment_elem) {
629cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_DEBUG, "Processing IMF CPL Segment\n");
630cabdff1aSopenharmony_ci
631cabdff1aSopenharmony_ci        sequence_list_elem = ff_imf_xml_get_child_element_by_name(segment_elem, "SequenceList");
632cabdff1aSopenharmony_ci        if (!segment_list_elem)
633cabdff1aSopenharmony_ci            continue;
634cabdff1aSopenharmony_ci
635cabdff1aSopenharmony_ci        sequence_elem = xmlFirstElementChild(sequence_list_elem);
636cabdff1aSopenharmony_ci        while (sequence_elem) {
637cabdff1aSopenharmony_ci            if (xmlStrcmp(sequence_elem->name, "MarkerSequence") == 0)
638cabdff1aSopenharmony_ci                ret = push_marker_sequence(sequence_elem, cpl);
639cabdff1aSopenharmony_ci
640cabdff1aSopenharmony_ci            else if (xmlStrcmp(sequence_elem->name, "MainImageSequence") == 0)
641cabdff1aSopenharmony_ci                ret = push_main_image_2d_sequence(sequence_elem, cpl);
642cabdff1aSopenharmony_ci
643cabdff1aSopenharmony_ci            else if (xmlStrcmp(sequence_elem->name, "MainAudioSequence") == 0)
644cabdff1aSopenharmony_ci                ret = push_main_audio_sequence(sequence_elem, cpl);
645cabdff1aSopenharmony_ci
646cabdff1aSopenharmony_ci            else
647cabdff1aSopenharmony_ci                av_log(NULL,
648cabdff1aSopenharmony_ci                       AV_LOG_INFO,
649cabdff1aSopenharmony_ci                       "The following Sequence is not supported and is ignored: %s\n",
650cabdff1aSopenharmony_ci                       sequence_elem->name);
651cabdff1aSopenharmony_ci
652cabdff1aSopenharmony_ci            /* abort parsing only if memory error occurred */
653cabdff1aSopenharmony_ci            if (ret == AVERROR(ENOMEM))
654cabdff1aSopenharmony_ci                return ret;
655cabdff1aSopenharmony_ci
656cabdff1aSopenharmony_ci            sequence_elem = xmlNextElementSibling(sequence_elem);
657cabdff1aSopenharmony_ci        }
658cabdff1aSopenharmony_ci
659cabdff1aSopenharmony_ci        segment_elem = xmlNextElementSibling(segment_elem);
660cabdff1aSopenharmony_ci    }
661cabdff1aSopenharmony_ci
662cabdff1aSopenharmony_ci    return ret;
663cabdff1aSopenharmony_ci}
664cabdff1aSopenharmony_ci
665cabdff1aSopenharmony_ciint ff_imf_parse_cpl_from_xml_dom(xmlDocPtr doc, FFIMFCPL **cpl)
666cabdff1aSopenharmony_ci{
667cabdff1aSopenharmony_ci    int ret = 0;
668cabdff1aSopenharmony_ci    xmlNodePtr cpl_element = NULL;
669cabdff1aSopenharmony_ci
670cabdff1aSopenharmony_ci    *cpl = ff_imf_cpl_alloc();
671cabdff1aSopenharmony_ci    if (!*cpl) {
672cabdff1aSopenharmony_ci        ret = AVERROR(ENOMEM);
673cabdff1aSopenharmony_ci        goto cleanup;
674cabdff1aSopenharmony_ci    }
675cabdff1aSopenharmony_ci
676cabdff1aSopenharmony_ci    cpl_element = xmlDocGetRootElement(doc);
677cabdff1aSopenharmony_ci    if (!cpl_element || xmlStrcmp(cpl_element->name, "CompositionPlaylist")) {
678cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "The root element of the CPL is not CompositionPlaylist\n");
679cabdff1aSopenharmony_ci        ret = AVERROR_INVALIDDATA;
680cabdff1aSopenharmony_ci        goto cleanup;
681cabdff1aSopenharmony_ci    }
682cabdff1aSopenharmony_ci
683cabdff1aSopenharmony_ci    if ((ret = fill_content_title(cpl_element, *cpl)))
684cabdff1aSopenharmony_ci        goto cleanup;
685cabdff1aSopenharmony_ci    if ((ret = fill_id(cpl_element, *cpl)))
686cabdff1aSopenharmony_ci        goto cleanup;
687cabdff1aSopenharmony_ci    if ((ret = fill_edit_rate(cpl_element, *cpl)))
688cabdff1aSopenharmony_ci        goto cleanup;
689cabdff1aSopenharmony_ci    if ((ret = fill_virtual_tracks(cpl_element, *cpl)))
690cabdff1aSopenharmony_ci        goto cleanup;
691cabdff1aSopenharmony_ci
692cabdff1aSopenharmony_cicleanup:
693cabdff1aSopenharmony_ci    if (*cpl && ret) {
694cabdff1aSopenharmony_ci        ff_imf_cpl_free(*cpl);
695cabdff1aSopenharmony_ci        *cpl = NULL;
696cabdff1aSopenharmony_ci    }
697cabdff1aSopenharmony_ci    return ret;
698cabdff1aSopenharmony_ci}
699cabdff1aSopenharmony_ci
700cabdff1aSopenharmony_cistatic void imf_marker_free(FFIMFMarker *marker)
701cabdff1aSopenharmony_ci{
702cabdff1aSopenharmony_ci    if (!marker)
703cabdff1aSopenharmony_ci        return;
704cabdff1aSopenharmony_ci    xmlFree(marker->label_utf8);
705cabdff1aSopenharmony_ci    xmlFree(marker->scope_utf8);
706cabdff1aSopenharmony_ci}
707cabdff1aSopenharmony_ci
708cabdff1aSopenharmony_cistatic void imf_marker_resource_free(FFIMFMarkerResource *rsrc)
709cabdff1aSopenharmony_ci{
710cabdff1aSopenharmony_ci    if (!rsrc)
711cabdff1aSopenharmony_ci        return;
712cabdff1aSopenharmony_ci    for (uint32_t i = 0; i < rsrc->marker_count; i++)
713cabdff1aSopenharmony_ci        imf_marker_free(&rsrc->markers[i]);
714cabdff1aSopenharmony_ci    av_freep(&rsrc->markers);
715cabdff1aSopenharmony_ci}
716cabdff1aSopenharmony_ci
717cabdff1aSopenharmony_cistatic void imf_marker_virtual_track_free(FFIMFMarkerVirtualTrack *vt)
718cabdff1aSopenharmony_ci{
719cabdff1aSopenharmony_ci    if (!vt)
720cabdff1aSopenharmony_ci        return;
721cabdff1aSopenharmony_ci    for (uint32_t i = 0; i < vt->resource_count; i++)
722cabdff1aSopenharmony_ci        imf_marker_resource_free(&vt->resources[i]);
723cabdff1aSopenharmony_ci    av_freep(&vt->resources);
724cabdff1aSopenharmony_ci}
725cabdff1aSopenharmony_ci
726cabdff1aSopenharmony_cistatic void imf_trackfile_virtual_track_free(FFIMFTrackFileVirtualTrack *vt)
727cabdff1aSopenharmony_ci{
728cabdff1aSopenharmony_ci    if (!vt)
729cabdff1aSopenharmony_ci        return;
730cabdff1aSopenharmony_ci    av_freep(&vt->resources);
731cabdff1aSopenharmony_ci}
732cabdff1aSopenharmony_ci
733cabdff1aSopenharmony_cistatic void imf_cpl_init(FFIMFCPL *cpl)
734cabdff1aSopenharmony_ci{
735cabdff1aSopenharmony_ci    av_uuid_nil(cpl->id_uuid);
736cabdff1aSopenharmony_ci    cpl->content_title_utf8 = NULL;
737cabdff1aSopenharmony_ci    cpl->edit_rate = av_make_q(0, 1);
738cabdff1aSopenharmony_ci    cpl->main_markers_track = NULL;
739cabdff1aSopenharmony_ci    cpl->main_image_2d_track = NULL;
740cabdff1aSopenharmony_ci    cpl->main_audio_track_count = 0;
741cabdff1aSopenharmony_ci    cpl->main_audio_tracks = NULL;
742cabdff1aSopenharmony_ci}
743cabdff1aSopenharmony_ci
744cabdff1aSopenharmony_ciFFIMFCPL *ff_imf_cpl_alloc(void)
745cabdff1aSopenharmony_ci{
746cabdff1aSopenharmony_ci    FFIMFCPL *cpl;
747cabdff1aSopenharmony_ci
748cabdff1aSopenharmony_ci    cpl = av_malloc(sizeof(FFIMFCPL));
749cabdff1aSopenharmony_ci    if (!cpl)
750cabdff1aSopenharmony_ci        return NULL;
751cabdff1aSopenharmony_ci    imf_cpl_init(cpl);
752cabdff1aSopenharmony_ci    return cpl;
753cabdff1aSopenharmony_ci}
754cabdff1aSopenharmony_ci
755cabdff1aSopenharmony_civoid ff_imf_cpl_free(FFIMFCPL *cpl)
756cabdff1aSopenharmony_ci{
757cabdff1aSopenharmony_ci    if (!cpl)
758cabdff1aSopenharmony_ci        return;
759cabdff1aSopenharmony_ci
760cabdff1aSopenharmony_ci    xmlFree(cpl->content_title_utf8);
761cabdff1aSopenharmony_ci
762cabdff1aSopenharmony_ci    imf_marker_virtual_track_free(cpl->main_markers_track);
763cabdff1aSopenharmony_ci
764cabdff1aSopenharmony_ci    if (cpl->main_markers_track)
765cabdff1aSopenharmony_ci        av_freep(&cpl->main_markers_track);
766cabdff1aSopenharmony_ci
767cabdff1aSopenharmony_ci    imf_trackfile_virtual_track_free(cpl->main_image_2d_track);
768cabdff1aSopenharmony_ci
769cabdff1aSopenharmony_ci    if (cpl->main_image_2d_track)
770cabdff1aSopenharmony_ci        av_freep(&cpl->main_image_2d_track);
771cabdff1aSopenharmony_ci
772cabdff1aSopenharmony_ci    for (uint32_t i = 0; i < cpl->main_audio_track_count; i++)
773cabdff1aSopenharmony_ci        imf_trackfile_virtual_track_free(&cpl->main_audio_tracks[i]);
774cabdff1aSopenharmony_ci
775cabdff1aSopenharmony_ci    if (cpl->main_audio_tracks)
776cabdff1aSopenharmony_ci        av_freep(&cpl->main_audio_tracks);
777cabdff1aSopenharmony_ci
778cabdff1aSopenharmony_ci    av_freep(&cpl);
779cabdff1aSopenharmony_ci}
780cabdff1aSopenharmony_ci
781cabdff1aSopenharmony_ciint ff_imf_parse_cpl(AVIOContext *in, FFIMFCPL **cpl)
782cabdff1aSopenharmony_ci{
783cabdff1aSopenharmony_ci    AVBPrint buf;
784cabdff1aSopenharmony_ci    xmlDoc *doc = NULL;
785cabdff1aSopenharmony_ci    int ret = 0;
786cabdff1aSopenharmony_ci
787cabdff1aSopenharmony_ci    av_bprint_init(&buf, 0, INT_MAX); // xmlReadMemory uses integer length
788cabdff1aSopenharmony_ci
789cabdff1aSopenharmony_ci    ret = avio_read_to_bprint(in, &buf, SIZE_MAX);
790cabdff1aSopenharmony_ci    if (ret < 0 || !avio_feof(in)) {
791cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Cannot read IMF CPL\n");
792cabdff1aSopenharmony_ci        if (ret == 0)
793cabdff1aSopenharmony_ci            ret = AVERROR_INVALIDDATA;
794cabdff1aSopenharmony_ci        goto clean_up;
795cabdff1aSopenharmony_ci    }
796cabdff1aSopenharmony_ci
797cabdff1aSopenharmony_ci    LIBXML_TEST_VERSION
798cabdff1aSopenharmony_ci
799cabdff1aSopenharmony_ci    doc = xmlReadMemory(buf.str, buf.len, NULL, NULL, 0);
800cabdff1aSopenharmony_ci    if (!doc) {
801cabdff1aSopenharmony_ci        av_log(NULL,
802cabdff1aSopenharmony_ci                AV_LOG_ERROR,
803cabdff1aSopenharmony_ci                "XML parsing failed when reading the IMF CPL\n");
804cabdff1aSopenharmony_ci        ret = AVERROR_INVALIDDATA;
805cabdff1aSopenharmony_ci        goto clean_up;
806cabdff1aSopenharmony_ci    }
807cabdff1aSopenharmony_ci
808cabdff1aSopenharmony_ci    if ((ret = ff_imf_parse_cpl_from_xml_dom(doc, cpl))) {
809cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_ERROR, "Cannot parse IMF CPL\n");
810cabdff1aSopenharmony_ci    } else {
811cabdff1aSopenharmony_ci        av_log(NULL,
812cabdff1aSopenharmony_ci                AV_LOG_INFO,
813cabdff1aSopenharmony_ci                "IMF CPL ContentTitle: %s\n",
814cabdff1aSopenharmony_ci                (*cpl)->content_title_utf8);
815cabdff1aSopenharmony_ci        av_log(NULL,
816cabdff1aSopenharmony_ci                AV_LOG_INFO,
817cabdff1aSopenharmony_ci                "IMF CPL Id: " AV_PRI_UUID "\n",
818cabdff1aSopenharmony_ci                AV_UUID_ARG((*cpl)->id_uuid));
819cabdff1aSopenharmony_ci    }
820cabdff1aSopenharmony_ci
821cabdff1aSopenharmony_ci    xmlFreeDoc(doc);
822cabdff1aSopenharmony_ci
823cabdff1aSopenharmony_ciclean_up:
824cabdff1aSopenharmony_ci    av_bprint_finalize(&buf, NULL);
825cabdff1aSopenharmony_ci
826cabdff1aSopenharmony_ci    return ret;
827cabdff1aSopenharmony_ci}
828