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