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, uint8_t uuid[16])
74 {
75  xmlChar *element_text = NULL;
76  int scanf_ret;
77  int ret = 0;
78 
79  element_text = xmlNodeListGetString(element->doc, element->xmlChildrenNode, 1);
80  scanf_ret = sscanf(element_text,
82  &uuid[0],
83  &uuid[1],
84  &uuid[2],
85  &uuid[3],
86  &uuid[4],
87  &uuid[5],
88  &uuid[6],
89  &uuid[7],
90  &uuid[8],
91  &uuid[9],
92  &uuid[10],
93  &uuid[11],
94  &uuid[12],
95  &uuid[13],
96  &uuid[14],
97  &uuid[15]);
98  if (scanf_ret != 16) {
99  av_log(NULL, AV_LOG_ERROR, "Invalid UUID\n");
101  }
102  xmlFree(element_text);
103 
104  return ret;
105 }
106 
107 int ff_imf_xml_read_rational(xmlNodePtr element, AVRational *rational)
108 {
109  xmlChar *element_text = NULL;
110  int ret = 0;
111 
112  element_text = xmlNodeListGetString(element->doc, element->xmlChildrenNode, 1);
113  if (sscanf(element_text, "%i %i", &rational->num, &rational->den) != 2) {
114  av_log(NULL, AV_LOG_ERROR, "Invalid rational number\n");
116  }
117  xmlFree(element_text);
118 
119  return ret;
120 }
121 
122 int ff_imf_xml_read_uint32(xmlNodePtr element, uint32_t *number)
123 {
124  xmlChar *element_text = NULL;
125  int ret = 0;
126 
127  element_text = xmlNodeListGetString(element->doc, element->xmlChildrenNode, 1);
128  if (sscanf(element_text, "%" PRIu32, number) != 1) {
129  av_log(NULL, AV_LOG_ERROR, "Invalid unsigned 32-bit integer");
131  }
132  xmlFree(element_text);
133 
134  return ret;
135 }
136 
138 {
139  memset(track->id_uuid, 0, sizeof(track->id_uuid));
140 }
141 
143 {
145  track->resource_count = 0;
146  track->resources = NULL;
147 }
148 
150 {
152  track->resource_count = 0;
153  track->resources_alloc_sz = 0;
154  track->resources = NULL;
155 }
156 
158 {
159  rsrc->duration = 0;
160  rsrc->edit_rate = av_make_q(0, 1);
161  rsrc->entry_point = 0;
162  rsrc->repeat_count = 1;
163 }
164 
166 {
168  rsrc->marker_count = 0;
169  rsrc->markers = NULL;
170 }
171 
172 static void imf_marker_init(FFIMFMarker *marker)
173 {
174  marker->label_utf8 = NULL;
175  marker->offset = 0;
176  marker->scope_utf8 = NULL;
177 }
178 
180 {
182  memset(rsrc->track_file_uuid, 0, sizeof(rsrc->track_file_uuid));
183 }
184 
185 static int fill_content_title(xmlNodePtr cpl_element, FFIMFCPL *cpl)
186 {
187  xmlNodePtr element = NULL;
188 
189  if (!(element = ff_imf_xml_get_child_element_by_name(cpl_element, "ContentTitle"))) {
190  av_log(NULL, AV_LOG_ERROR, "ContentTitle element not found in the IMF CPL\n");
191  return AVERROR_INVALIDDATA;
192  }
193  cpl->content_title_utf8 = xmlNodeListGetString(cpl_element->doc,
194  element->xmlChildrenNode,
195  1);
196 
197  return 0;
198 }
199 
200 static int fill_edit_rate(xmlNodePtr cpl_element, FFIMFCPL *cpl)
201 {
202  xmlNodePtr element = NULL;
203 
204  if (!(element = ff_imf_xml_get_child_element_by_name(cpl_element, "EditRate"))) {
205  av_log(NULL, AV_LOG_ERROR, "EditRate element not found in the IMF CPL\n");
206  return AVERROR_INVALIDDATA;
207  }
208 
209  return ff_imf_xml_read_rational(element, &cpl->edit_rate);
210 }
211 
212 static int fill_id(xmlNodePtr cpl_element, FFIMFCPL *cpl)
213 {
214  xmlNodePtr element = NULL;
215 
216  if (!(element = ff_imf_xml_get_child_element_by_name(cpl_element, "Id"))) {
217  av_log(NULL, AV_LOG_ERROR, "Id element not found in the IMF CPL\n");
218  return AVERROR_INVALIDDATA;
219  }
220 
221  return ff_imf_xml_read_uuid(element, cpl->id_uuid);
222 }
223 
224 static int fill_marker(xmlNodePtr marker_elem, FFIMFMarker *marker)
225 {
226  xmlNodePtr element = NULL;
227  int ret = 0;
228 
229  /* read Offset */
230  if (!(element = ff_imf_xml_get_child_element_by_name(marker_elem, "Offset"))) {
231  av_log(NULL, AV_LOG_ERROR, "Offset element not found in a Marker\n");
232  return AVERROR_INVALIDDATA;
233  }
234  if ((ret = ff_imf_xml_read_uint32(element, &marker->offset)))
235  return ret;
236 
237  /* read Label and Scope */
238  if (!(element = ff_imf_xml_get_child_element_by_name(marker_elem, "Label"))) {
239  av_log(NULL, AV_LOG_ERROR, "Label element not found in a Marker\n");
240  return AVERROR_INVALIDDATA;
241  }
242  if (!(marker->label_utf8 = xmlNodeListGetString(element->doc, element->xmlChildrenNode, 1))) {
243  av_log(NULL, AV_LOG_ERROR, "Empty Label element found in a Marker\n");
244  return AVERROR_INVALIDDATA;
245  }
246  if (!(marker->scope_utf8 = xmlGetNoNsProp(element, "scope"))) {
247  marker->scope_utf8
248  = xmlCharStrdup("http://www.smpte-ra.org/schemas/2067-3/2013#standard-markers");
249  if (!marker->scope_utf8) {
250  xmlFree(marker->label_utf8);
251  return AVERROR(ENOMEM);
252  }
253  }
254 
255  return ret;
256 }
257 
258 static int fill_base_resource(xmlNodePtr resource_elem, FFIMFBaseResource *resource, FFIMFCPL *cpl)
259 {
260  xmlNodePtr element = NULL;
261  int ret = 0;
262 
263  /* read EditRate */
264  if (!(element = ff_imf_xml_get_child_element_by_name(resource_elem, "EditRate"))) {
265  resource->edit_rate = cpl->edit_rate;
266  } else if ((ret = ff_imf_xml_read_rational(element, &resource->edit_rate))) {
267  av_log(NULL, AV_LOG_ERROR, "Invalid EditRate element found in a Resource\n");
268  return ret;
269  }
270 
271  /* read EntryPoint */
272  if ((element = ff_imf_xml_get_child_element_by_name(resource_elem, "EntryPoint"))) {
273  if ((ret = ff_imf_xml_read_uint32(element, &resource->entry_point))) {
274  av_log(NULL, AV_LOG_ERROR, "Invalid EntryPoint element found in a Resource\n");
275  return ret;
276  }
277  } else {
278  resource->entry_point = 0;
279  }
280 
281  /* read IntrinsicDuration */
282  if (!(element = ff_imf_xml_get_child_element_by_name(resource_elem, "IntrinsicDuration"))) {
283  av_log(NULL, AV_LOG_ERROR, "IntrinsicDuration element missing from Resource\n");
284  return AVERROR_INVALIDDATA;
285  }
286  if ((ret = ff_imf_xml_read_uint32(element, &resource->duration))) {
287  av_log(NULL, AV_LOG_ERROR, "Invalid IntrinsicDuration element found in a Resource\n");
288  return ret;
289  }
290  resource->duration -= resource->entry_point;
291 
292  /* read SourceDuration */
293  if ((element = ff_imf_xml_get_child_element_by_name(resource_elem, "SourceDuration"))) {
294  if ((ret = ff_imf_xml_read_uint32(element, &resource->duration))) {
295  av_log(NULL, AV_LOG_ERROR, "SourceDuration element missing from Resource\n");
296  return ret;
297  }
298  }
299 
300  /* read RepeatCount */
301  if ((element = ff_imf_xml_get_child_element_by_name(resource_elem, "RepeatCount")))
302  ret = ff_imf_xml_read_uint32(element, &resource->repeat_count);
303 
304  return ret;
305 }
306 
307 static int fill_trackfile_resource(xmlNodePtr tf_resource_elem,
308  FFIMFTrackFileResource *tf_resource,
309  FFIMFCPL *cpl)
310 {
311  xmlNodePtr element = NULL;
312  int ret = 0;
313 
314  if ((ret = fill_base_resource(tf_resource_elem, (FFIMFBaseResource *)tf_resource, cpl)))
315  return ret;
316 
317  /* read TrackFileId */
318  if ((element = ff_imf_xml_get_child_element_by_name(tf_resource_elem, "TrackFileId"))) {
319  if ((ret = ff_imf_xml_read_uuid(element, tf_resource->track_file_uuid))) {
320  av_log(NULL, AV_LOG_ERROR, "Invalid TrackFileId element found in Resource\n");
321  return ret;
322  }
323  } else {
324  av_log(NULL, AV_LOG_ERROR, "TrackFileId element missing from Resource\n");
325  return AVERROR_INVALIDDATA;
326  }
327 
328  return ret;
329 }
330 
331 static int fill_marker_resource(xmlNodePtr marker_resource_elem,
332  FFIMFMarkerResource *marker_resource,
333  FFIMFCPL *cpl)
334 {
335  xmlNodePtr element = NULL;
336  int ret = 0;
337 
338  if ((ret = fill_base_resource(marker_resource_elem, (FFIMFBaseResource *)marker_resource, cpl)))
339  return ret;
340 
341  /* read markers */
342  element = xmlFirstElementChild(marker_resource_elem);
343  while (element) {
344  if (xmlStrcmp(element->name, "Marker") == 0) {
345  void *tmp;
346 
347  if (marker_resource->marker_count == UINT32_MAX)
348  return AVERROR(ENOMEM);
349  tmp = av_realloc_array(marker_resource->markers,
350  marker_resource->marker_count + 1,
351  sizeof(FFIMFMarker));
352  if (!tmp)
353  return AVERROR(ENOMEM);
354  marker_resource->markers = tmp;
355 
356  imf_marker_init(&marker_resource->markers[marker_resource->marker_count]);
357  ret = fill_marker(element,
358  &marker_resource->markers[marker_resource->marker_count]);
359  marker_resource->marker_count++;
360  if (ret)
361  return ret;
362  }
363 
364  element = xmlNextElementSibling(element);
365  }
366 
367  return ret;
368 }
369 
370 static int push_marker_sequence(xmlNodePtr marker_sequence_elem, FFIMFCPL *cpl)
371 {
372  int ret = 0;
373  uint8_t uuid[16];
374  xmlNodePtr resource_list_elem = NULL;
375  xmlNodePtr resource_elem = NULL;
376  xmlNodePtr track_id_elem = NULL;
377  unsigned long resource_elem_count;
378  void *tmp;
379 
380  /* read TrackID element */
381  if (!(track_id_elem = ff_imf_xml_get_child_element_by_name(marker_sequence_elem, "TrackId"))) {
382  av_log(NULL, AV_LOG_ERROR, "TrackId element missing from Sequence\n");
383  return AVERROR_INVALIDDATA;
384  }
385  if (ff_imf_xml_read_uuid(track_id_elem, uuid)) {
386  av_log(NULL, AV_LOG_ERROR, "Invalid TrackId element found in Sequence\n");
387  return AVERROR_INVALIDDATA;
388  }
389  av_log(NULL,
390  AV_LOG_DEBUG,
391  "Processing IMF CPL Marker Sequence for Virtual Track " FF_IMF_UUID_FORMAT "\n",
392  UID_ARG(uuid));
393 
394  /* create main marker virtual track if it does not exist */
395  if (!cpl->main_markers_track) {
397  if (!cpl->main_markers_track)
398  return AVERROR(ENOMEM);
400  memcpy(cpl->main_markers_track->base.id_uuid, uuid, sizeof(uuid));
401 
402  } else if (memcmp(cpl->main_markers_track->base.id_uuid, uuid, sizeof(uuid)) != 0) {
403  av_log(NULL, AV_LOG_ERROR, "Multiple marker virtual tracks were found\n");
404  return AVERROR_INVALIDDATA;
405  }
406 
407  /* process resources */
408  resource_list_elem = ff_imf_xml_get_child_element_by_name(marker_sequence_elem, "ResourceList");
409  if (!resource_list_elem)
410  return 0;
411 
412  resource_elem_count = xmlChildElementCount(resource_list_elem);
413  if (resource_elem_count > UINT32_MAX
414  || cpl->main_markers_track->resource_count > UINT32_MAX - resource_elem_count)
415  return AVERROR(ENOMEM);
417  cpl->main_markers_track->resource_count + resource_elem_count,
418  sizeof(FFIMFMarkerResource));
419  if (!tmp) {
420  av_log(NULL, AV_LOG_ERROR, "Cannot allocate Marker Resources\n");
421  return AVERROR(ENOMEM);
422  }
424 
425  resource_elem = xmlFirstElementChild(resource_list_elem);
426  while (resource_elem) {
428  ret = fill_marker_resource(resource_elem,
430  cpl);
432  if (ret)
433  return ret;
434 
435  resource_elem = xmlNextElementSibling(resource_elem);
436  }
437 
438  return ret;
439 }
440 
441 static int has_stereo_resources(xmlNodePtr element)
442 {
443  if (xmlStrcmp(element->name, "Left") == 0 || xmlStrcmp(element->name, "Right") == 0)
444  return 1;
445 
446  element = xmlFirstElementChild(element);
447  while (element) {
448  if (has_stereo_resources(element))
449  return 1;
450 
451  element = xmlNextElementSibling(element);
452  }
453 
454  return 0;
455 }
456 
457 static int push_main_audio_sequence(xmlNodePtr audio_sequence_elem, FFIMFCPL *cpl)
458 {
459  int ret = 0;
460  uint8_t uuid[16];
461  xmlNodePtr resource_list_elem = NULL;
462  xmlNodePtr resource_elem = NULL;
463  xmlNodePtr track_id_elem = NULL;
464  unsigned long resource_elem_count;
466  void *tmp;
467 
468  /* read TrackID element */
469  if (!(track_id_elem = ff_imf_xml_get_child_element_by_name(audio_sequence_elem, "TrackId"))) {
470  av_log(NULL, AV_LOG_ERROR, "TrackId element missing from audio sequence\n");
471  return AVERROR_INVALIDDATA;
472  }
473  if ((ret = ff_imf_xml_read_uuid(track_id_elem, uuid))) {
474  av_log(NULL, AV_LOG_ERROR, "Invalid TrackId element found in audio sequence\n");
475  return ret;
476  }
477  av_log(NULL,
478  AV_LOG_DEBUG,
479  "Processing IMF CPL Audio Sequence for Virtual Track " FF_IMF_UUID_FORMAT "\n",
480  UID_ARG(uuid));
481 
482  /* get the main audio virtual track corresponding to the sequence */
483  for (uint32_t i = 0; i < cpl->main_audio_track_count; i++) {
484  if (memcmp(cpl->main_audio_tracks[i].base.id_uuid, uuid, sizeof(uuid)) == 0) {
485  vt = &cpl->main_audio_tracks[i];
486  break;
487  }
488  }
489 
490  /* create a main audio virtual track if none exists for the sequence */
491  if (!vt) {
492  if (cpl->main_audio_track_count == UINT32_MAX)
493  return AVERROR(ENOMEM);
495  cpl->main_audio_track_count + 1,
497  if (!tmp)
498  return AVERROR(ENOMEM);
499 
500  cpl->main_audio_tracks = tmp;
501  vt = &cpl->main_audio_tracks[cpl->main_audio_track_count];
503  cpl->main_audio_track_count++;
504  memcpy(vt->base.id_uuid, uuid, sizeof(uuid));
505  }
506 
507  /* process resources */
508  resource_list_elem = ff_imf_xml_get_child_element_by_name(audio_sequence_elem, "ResourceList");
509  if (!resource_list_elem)
510  return 0;
511 
512  resource_elem_count = xmlChildElementCount(resource_list_elem);
513  if (resource_elem_count > UINT32_MAX
514  || vt->resource_count > UINT32_MAX - resource_elem_count)
515  return AVERROR(ENOMEM);
517  &vt->resources_alloc_sz,
518  (vt->resource_count + resource_elem_count)
519  * sizeof(FFIMFTrackFileResource));
520  if (!tmp) {
521  av_log(NULL, AV_LOG_ERROR, "Cannot allocate Main Audio Resources\n");
522  return AVERROR(ENOMEM);
523  }
524  vt->resources = tmp;
525 
526  resource_elem = xmlFirstElementChild(resource_list_elem);
527  while (resource_elem) {
529  ret = fill_trackfile_resource(resource_elem,
530  &vt->resources[vt->resource_count],
531  cpl);
532  vt->resource_count++;
533  if (ret) {
534  av_log(NULL, AV_LOG_ERROR, "Invalid Resource\n");
535  continue;
536  }
537 
538  resource_elem = xmlNextElementSibling(resource_elem);
539  }
540 
541  return ret;
542 }
543 
544 static int push_main_image_2d_sequence(xmlNodePtr image_sequence_elem, FFIMFCPL *cpl)
545 {
546  int ret = 0;
547  uint8_t uuid[16];
548  xmlNodePtr resource_list_elem = NULL;
549  xmlNodePtr resource_elem = NULL;
550  xmlNodePtr track_id_elem = NULL;
551  void *tmp;
552  unsigned long resource_elem_count;
553 
554  /* skip stereoscopic resources */
555  if (has_stereo_resources(image_sequence_elem)) {
556  av_log(NULL, AV_LOG_ERROR, "Stereoscopic 3D image virtual tracks not supported\n");
557  return AVERROR_PATCHWELCOME;
558  }
559 
560  /* read TrackId element*/
561  if (!(track_id_elem = ff_imf_xml_get_child_element_by_name(image_sequence_elem, "TrackId"))) {
562  av_log(NULL, AV_LOG_ERROR, "TrackId element missing from audio sequence\n");
563  return AVERROR_INVALIDDATA;
564  }
565  if ((ret = ff_imf_xml_read_uuid(track_id_elem, uuid))) {
566  av_log(NULL, AV_LOG_ERROR, "Invalid TrackId element found in audio sequence\n");
567  return ret;
568  }
569 
570  /* create main image virtual track if one does not exist */
571  if (!cpl->main_image_2d_track) {
573  if (!cpl->main_image_2d_track)
574  return AVERROR(ENOMEM);
576  memcpy(cpl->main_image_2d_track->base.id_uuid, uuid, sizeof(uuid));
577 
578  } else if (memcmp(cpl->main_image_2d_track->base.id_uuid, uuid, sizeof(uuid)) != 0) {
579  av_log(NULL, AV_LOG_ERROR, "Multiple MainImage virtual tracks found\n");
580  return AVERROR_INVALIDDATA;
581  }
582  av_log(NULL,
583  AV_LOG_DEBUG,
584  "Processing IMF CPL Main Image Sequence for Virtual Track " FF_IMF_UUID_FORMAT "\n",
585  UID_ARG(uuid));
586 
587  /* process resources */
588  resource_list_elem = ff_imf_xml_get_child_element_by_name(image_sequence_elem, "ResourceList");
589  if (!resource_list_elem)
590  return 0;
591 
592  resource_elem_count = xmlChildElementCount(resource_list_elem);
593  if (resource_elem_count > UINT32_MAX
594  || cpl->main_image_2d_track->resource_count > UINT32_MAX - resource_elem_count
595  || (cpl->main_image_2d_track->resource_count + resource_elem_count)
596  > INT_MAX / sizeof(FFIMFTrackFileResource))
597  return AVERROR(ENOMEM);
600  (cpl->main_image_2d_track->resource_count + resource_elem_count)
601  * sizeof(FFIMFTrackFileResource));
602  if (!tmp) {
603  av_log(NULL, AV_LOG_ERROR, "Cannot allocate Main Image Resources\n");
604  return AVERROR(ENOMEM);
605  }
607 
608  resource_elem = xmlFirstElementChild(resource_list_elem);
609  while (resource_elem) {
612  ret = fill_trackfile_resource(resource_elem,
614  cpl);
616  if (ret) {
617  av_log(NULL, AV_LOG_ERROR, "Invalid Resource\n");
618  continue;
619  }
620 
621  resource_elem = xmlNextElementSibling(resource_elem);
622  }
623 
624  return 0;
625 }
626 
627 static int fill_virtual_tracks(xmlNodePtr cpl_element, FFIMFCPL *cpl)
628 {
629  int ret = 0;
630  xmlNodePtr segment_list_elem = NULL;
631  xmlNodePtr segment_elem = NULL;
632  xmlNodePtr sequence_list_elem = NULL;
633  xmlNodePtr sequence_elem = NULL;
634 
635  if (!(segment_list_elem = ff_imf_xml_get_child_element_by_name(cpl_element, "SegmentList"))) {
636  av_log(NULL, AV_LOG_ERROR, "SegmentList element missing\n");
637  return AVERROR_INVALIDDATA;
638  }
639 
640  /* process sequences */
641  segment_elem = xmlFirstElementChild(segment_list_elem);
642  while (segment_elem) {
643  av_log(NULL, AV_LOG_DEBUG, "Processing IMF CPL Segment\n");
644 
645  sequence_list_elem = ff_imf_xml_get_child_element_by_name(segment_elem, "SequenceList");
646  if (!segment_list_elem)
647  continue;
648 
649  sequence_elem = xmlFirstElementChild(sequence_list_elem);
650  while (sequence_elem) {
651  if (xmlStrcmp(sequence_elem->name, "MarkerSequence") == 0)
652  ret = push_marker_sequence(sequence_elem, cpl);
653 
654  else if (xmlStrcmp(sequence_elem->name, "MainImageSequence") == 0)
655  ret = push_main_image_2d_sequence(sequence_elem, cpl);
656 
657  else if (xmlStrcmp(sequence_elem->name, "MainAudioSequence") == 0)
658  ret = push_main_audio_sequence(sequence_elem, cpl);
659 
660  else
661  av_log(NULL,
662  AV_LOG_INFO,
663  "The following Sequence is not supported and is ignored: %s\n",
664  sequence_elem->name);
665 
666  /* abort parsing only if memory error occurred */
667  if (ret == AVERROR(ENOMEM))
668  return ret;
669 
670  sequence_elem = xmlNextElementSibling(sequence_elem);
671  }
672 
673  segment_elem = xmlNextElementSibling(segment_elem);
674  }
675 
676  return ret;
677 }
678 
679 int ff_imf_parse_cpl_from_xml_dom(xmlDocPtr doc, FFIMFCPL **cpl)
680 {
681  int ret = 0;
682  xmlNodePtr cpl_element = NULL;
683 
684  *cpl = ff_imf_cpl_alloc();
685  if (!*cpl) {
686  ret = AVERROR(ENOMEM);
687  goto cleanup;
688  }
689 
690  cpl_element = xmlDocGetRootElement(doc);
691  if (!cpl_element || xmlStrcmp(cpl_element->name, "CompositionPlaylist")) {
692  av_log(NULL, AV_LOG_ERROR, "The root element of the CPL is not CompositionPlaylist\n");
694  goto cleanup;
695  }
696 
697  if ((ret = fill_content_title(cpl_element, *cpl)))
698  goto cleanup;
699  if ((ret = fill_id(cpl_element, *cpl)))
700  goto cleanup;
701  if ((ret = fill_edit_rate(cpl_element, *cpl)))
702  goto cleanup;
703  if ((ret = fill_virtual_tracks(cpl_element, *cpl)))
704  goto cleanup;
705 
706 cleanup:
707  if (*cpl && ret) {
708  ff_imf_cpl_free(*cpl);
709  *cpl = NULL;
710  }
711  return ret;
712 }
713 
714 static void imf_marker_free(FFIMFMarker *marker)
715 {
716  if (!marker)
717  return;
718  xmlFree(marker->label_utf8);
719  xmlFree(marker->scope_utf8);
720 }
721 
723 {
724  if (!rsrc)
725  return;
726  for (uint32_t i = 0; i < rsrc->marker_count; i++)
727  imf_marker_free(&rsrc->markers[i]);
728  av_freep(&rsrc->markers);
729 }
730 
732 {
733  if (!vt)
734  return;
735  for (uint32_t i = 0; i < vt->resource_count; i++)
737  av_freep(&vt->resources);
738 }
739 
741 {
742  if (!vt)
743  return;
744  av_freep(&vt->resources);
745 }
746 
747 static void imf_cpl_init(FFIMFCPL *cpl)
748 {
749  memset(cpl->id_uuid, 0, sizeof(cpl->id_uuid));
750  cpl->content_title_utf8 = NULL;
751  cpl->edit_rate = av_make_q(0, 1);
752  cpl->main_markers_track = NULL;
753  cpl->main_image_2d_track = NULL;
754  cpl->main_audio_track_count = 0;
755  cpl->main_audio_tracks = NULL;
756 }
757 
759 {
760  FFIMFCPL *cpl;
761 
762  cpl = av_malloc(sizeof(FFIMFCPL));
763  if (!cpl)
764  return NULL;
765  imf_cpl_init(cpl);
766  return cpl;
767 }
768 
770 {
771  if (!cpl)
772  return;
773 
774  xmlFree(cpl->content_title_utf8);
775 
777 
778  if (cpl->main_markers_track)
780 
782 
783  if (cpl->main_image_2d_track)
785 
786  for (uint32_t i = 0; i < cpl->main_audio_track_count; i++)
788 
789  if (cpl->main_audio_tracks)
791 
792  av_freep(&cpl);
793 }
794 
796 {
797  AVBPrint buf;
798  xmlDoc *doc = NULL;
799  int ret = 0;
800 
801  av_bprint_init(&buf, 0, INT_MAX); // xmlReadMemory uses integer length
802 
803  ret = avio_read_to_bprint(in, &buf, SIZE_MAX);
804  if (ret < 0 || !avio_feof(in)) {
805  av_log(NULL, AV_LOG_ERROR, "Cannot read IMF CPL\n");
806  if (ret == 0)
808  goto clean_up;
809  }
810 
811  LIBXML_TEST_VERSION
812 
813  doc = xmlReadMemory(buf.str, buf.len, NULL, NULL, 0);
814  if (!doc) {
815  av_log(NULL,
816  AV_LOG_ERROR,
817  "XML parsing failed when reading the IMF CPL\n");
819  goto clean_up;
820  }
821 
822  if ((ret = ff_imf_parse_cpl_from_xml_dom(doc, cpl))) {
823  av_log(NULL, AV_LOG_ERROR, "Cannot parse IMF CPL\n");
824  } else {
825  av_log(NULL,
826  AV_LOG_INFO,
827  "IMF CPL ContentTitle: %s\n",
828  (*cpl)->content_title_utf8);
829  av_log(NULL,
830  AV_LOG_INFO,
831  "IMF CPL Id: " FF_IMF_UUID_FORMAT "\n",
832  UID_ARG((*cpl)->id_uuid));
833  }
834 
835  xmlFreeDoc(doc);
836 
837 clean_up:
838  av_bprint_finalize(&buf, NULL);
839 
840  return ret;
841 }
imf_base_virtual_track_init
static void imf_base_virtual_track_init(FFIMFBaseVirtualTrack *track)
Definition: imf_cpl.c:137
FFIMFTrackFileVirtualTrack::resources
FFIMFTrackFileResource * resources
Resource elements of the Virtual Track.
Definition: imf.h:121
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:234
push_main_audio_sequence
static int push_main_audio_sequence(xmlNodePtr audio_sequence_elem, FFIMFCPL *cpl)
Definition: imf_cpl.c:457
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:68
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:769
FFIMFCPL::id_uuid
FFIMFUUID id_uuid
CompositionPlaylist/Id element.
Definition: imf.h:138
imf_marker_free
static void imf_marker_free(FFIMFMarker *marker)
Definition: imf_cpl.c:714
FFIMFMarkerVirtualTrack::resources
FFIMFMarkerResource * resources
Resource elements of the Virtual Track.
Definition: imf.h:131
ff_imf_cpl_alloc
FFIMFCPL * ff_imf_cpl_alloc(void)
Allocates and initializes an FFIMFCPL data structure.
Definition: imf_cpl.c:758
tmp
static uint8_t tmp[11]
Definition: aes_ctr.c:26
cleanup
static av_cold void cleanup(FlashSV2Context *s)
Definition: flashsv2enc.c:128
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:679
FFIMFTrackFileVirtualTrack::resource_count
uint32_t resource_count
Number of Resource elements present in the Virtual Track.
Definition: imf.h:120
ff_imf_xml_read_uuid
int ff_imf_xml_read_uuid(xmlNodePtr element, uint8_t uuid[16])
Reads a UUID from an XML element.
Definition: imf_cpl.c:73
imf_trackfile_virtual_track_init
static void imf_trackfile_virtual_track_init(FFIMFTrackFileVirtualTrack *track)
Definition: imf_cpl.c:149
FFIMFMarkerVirtualTrack
IMF Composition Playlist Virtual Track that consists of Marker Resources.
Definition: imf.h:128
FFIMFCPL::content_title_utf8
xmlChar * content_title_utf8
CompositionPlaylist/ContentTitle element.
Definition: imf.h:139
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:31
FFIMFCPL::main_audio_tracks
FFIMFTrackFileVirtualTrack * main_audio_tracks
Main Audio Virtual Tracks.
Definition: imf.h:144
mxf.h
imf_cpl_init
static void imf_cpl_init(FFIMFCPL *cpl)
Definition: imf_cpl.c:747
FFIMFBaseResource::duration
uint32_t duration
BaseResourceType/Duration.
Definition: imf.h:78
FFIMFMarker
IMF Marker.
Definition: imf.h:93
FFIMFCPL::main_markers_track
FFIMFMarkerVirtualTrack * main_markers_track
Main Marker Virtual Track.
Definition: imf.h:141
AVRational::num
int num
Numerator.
Definition: rational.h:59
FFIMFBaseVirtualTrack::id_uuid
FFIMFUUID id_uuid
TrackId associated with the Virtual Track.
Definition: imf.h:112
imf_marker_virtual_track_free
static void imf_marker_virtual_track_free(FFIMFMarkerVirtualTrack *vt)
Definition: imf_cpl.c:731
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:118
UID_ARG
#define UID_ARG(x)
Definition: mxf.h:129
push_main_image_2d_sequence
static int push_main_image_2d_sequence(xmlNodePtr image_sequence_elem, FFIMFCPL *cpl)
Definition: imf_cpl.c:544
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:504
imf_base_resource_init
static void imf_base_resource_init(FFIMFBaseResource *rsrc)
Definition: imf_cpl.c:157
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:1343
av_realloc_array
void * av_realloc_array(void *ptr, size_t nmemb, size_t size)
Definition: mem.c:224
imf_marker_virtual_track_init
static void imf_marker_virtual_track_init(FFIMFMarkerVirtualTrack *track)
Definition: imf_cpl.c:142
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:179
fill_base_resource
static int fill_base_resource(xmlNodePtr resource_elem, FFIMFBaseResource *resource, FFIMFCPL *cpl)
Definition: imf_cpl.c:258
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:122
FFIMFCPL::edit_rate
AVRational edit_rate
CompositionPlaylist/EditRate element.
Definition: imf.h:140
fill_trackfile_resource
static int fill_trackfile_resource(xmlNodePtr tf_resource_elem, FFIMFTrackFileResource *tf_resource, FFIMFCPL *cpl)
Definition: imf_cpl.c:307
FFIMFTrackFileVirtualTrack::resources_alloc_sz
unsigned int resources_alloc_sz
Size of the resources buffer.
Definition: imf.h:122
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:111
FFIMFBaseResource
IMF Composition Playlist Base Resource.
Definition: imf.h:75
AVRational
Rational number (pair of numerator and denominator).
Definition: rational.h:58
FFIMFMarkerVirtualTrack::base
FFIMFBaseVirtualTrack base
Definition: imf.h:129
FFIMFTrackFileVirtualTrack::base
FFIMFBaseVirtualTrack base
Definition: imf.h:119
error.h
has_stereo_resources
static int has_stereo_resources(xmlNodePtr element)
Definition: imf_cpl.c:441
FFIMFBaseResource::edit_rate
AVRational edit_rate
BaseResourceType/EditRate.
Definition: imf.h:76
AVIOContext
Bytestream IO Context.
Definition: avio.h:161
fill_content_title
static int fill_content_title(xmlNodePtr cpl_element, FFIMFCPL *cpl)
Definition: imf_cpl.c:185
fill_marker
static int fill_marker(xmlNodePtr marker_elem, FFIMFMarker *marker)
Definition: imf_cpl.c:224
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:722
fill_id
static int fill_id(xmlNodePtr cpl_element, FFIMFCPL *cpl)
Definition: imf_cpl.c:212
push_marker_sequence
static int push_marker_sequence(xmlNodePtr marker_sequence_elem, FFIMFCPL *cpl)
Definition: imf_cpl.c:370
FFIMFBaseResource::repeat_count
uint32_t repeat_count
BaseResourceType/RepeatCount.
Definition: imf.h:79
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:191
bprint.h
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:271
FFIMFBaseResource::entry_point
uint32_t entry_point
BaseResourceType/EntryPoint.
Definition: imf.h:77
ret
ret
Definition: filter_design.txt:187
fill_virtual_tracks
static int fill_virtual_tracks(xmlNodePtr cpl_element, FFIMFCPL *cpl)
Definition: imf_cpl.c:627
FFIMFMarkerResource
IMF Composition Playlist Marker Resource.
Definition: imf.h:102
FFIMFMarkerResource::markers
FFIMFMarker * markers
Marker elements.
Definition: imf.h:105
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:107
FFIMFTrackFileResource
IMF Composition Playlist Track File Resource.
Definition: imf.h:85
FFIMFMarker::offset
uint32_t offset
Marker/Offset.
Definition: imf.h:96
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:165
imf_marker_init
static void imf_marker_init(FFIMFMarker *marker)
Definition: imf_cpl.c:172
FFIMFCPL::main_audio_track_count
uint32_t main_audio_track_count
Number of Main Audio Virtual Tracks.
Definition: imf.h:143
FFIMFMarkerVirtualTrack::resource_count
uint32_t resource_count
Number of Resource elements present in the Virtual Track.
Definition: imf.h:130
imf_trackfile_virtual_track_free
static void imf_trackfile_virtual_track_free(FFIMFTrackFileVirtualTrack *vt)
Definition: imf_cpl.c:740
FFIMFCPL::main_image_2d_track
FFIMFTrackFileVirtualTrack * main_image_2d_track
Main Image Virtual Track.
Definition: imf.h:142
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
FFIMFMarkerResource::marker_count
uint32_t marker_count
Number of Marker elements.
Definition: imf.h:104
FFIMFCPL
IMF Composition Playlist.
Definition: imf.h:137
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
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:94
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:795
FFIMFMarker::scope_utf8
xmlChar * scope_utf8
Marker/Label/@scope.
Definition: imf.h:95
fill_marker_resource
static int fill_marker_resource(xmlNodePtr marker_resource_elem, FFIMFMarkerResource *marker_resource, FFIMFCPL *cpl)
Definition: imf_cpl.c:331
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
FF_IMF_UUID_FORMAT
#define FF_IMF_UUID_FORMAT
Definition: imf.h:63
fill_edit_rate
static int fill_edit_rate(xmlNodePtr cpl_element, FFIMFCPL *cpl)
Definition: imf_cpl.c:200
avio_feof
int avio_feof(AVIOContext *s)
Similar to feof() but also returns nonzero on read errors.
Definition: aviobuf.c:375