1 /*****************************************************************************
2 * Copyright (C) 2013 VLC authors and VideoLAN
5 * Nicolas Bertrand <nico@isf.cc>
6 * Jean-Baptiste Kempf <jb@videolan.org>
8 * Valentin Vetter <vvetter@outlook.com>
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU Lesser General Public License as published by
15 * the Free Software Foundation; either version 2.1 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public License
24 * along with this program; if not, write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26 *****************************************************************************/
30 * @brief Parsing of DCP XML files
36 /* VLC core API headers */
37 #include <vlc_common.h>
38 #include <vlc_plugin.h>
47 #include "dcpparser.h"
51 static int ReadNextNode(xml_reader_t *p_xmlReader, string& p_node) {
54 i = xml_ReaderNextNode( p_xmlReader, &c_node );
59 static int ReadEndNode( xml_reader_t *p_xmlReader, string p_node,
60 int p_type, string &s_value) {
63 if ( xml_ReaderIsEmptyElement( p_xmlReader) )
66 if (p_type != XML_READER_STARTELEM)
69 if (ReadNextNode(p_xmlReader, node) == XML_READER_TEXT)
72 if((ReadNextNode(p_xmlReader, node) == XML_READER_ENDELEM) &&
91 ASSET_ANNOTATION_TEXT,
97 ASSET_ORIGINAL_FILENAME
100 static const string g_asset_names[] = {
119 PKL_ANNOTATION_TEXT, /* start of optional tags */
129 CPL_ANNOTATION_TEXT, /* optional */
130 CPL_ICON_ID, /* optional */
132 CPL_ISSUER, /* optional */
133 CPL_CREATOR, /* optional */
136 CPL_CONTENT_VERSION, /* not optional, but not always present*/
137 CPL_RATING_LIST, /* not handled */
139 CPL_SIGNER, /* optional - not handled */
140 CPL_SIGNATURE /* optional - not handled */
144 class ChunkList: public std::list<Chunk> {
153 int Chunk::Parse( xml_reader_t *p_xmlReader, string p_node, int p_type){
157 static const string names[] = {"Path", "VolumeIndex", "Offset",
159 if (p_type != XML_READER_STARTELEM)
161 if( p_node != "Chunk")
163 /* loop on Chunks Node */
164 while( ( type = ReadNextNode( p_xmlReader, node ) ) > 0 ) {
166 case XML_READER_STARTELEM:
168 ChunkTag_t chunk_tag = CHUNK_UNKNOWN;
169 for(ChunkTag_t i = CHUNK_PATH; i <= CHUNK_LENGTH; i = ChunkTag_t(i+1)) {
170 if( node == names[i-1]) {
172 if ( ReadEndNode(p_xmlReader, node, type, s_value))
176 this->s_path = s_value;
178 case CHUNK_VOL_INDEX:
179 this->i_vol_index = atoi(s_value.c_str());
182 this->i_offset = atoi(s_value.c_str());
185 this->i_length = atoi(s_value.c_str());
191 /* break the for loop as a tag is found*/
195 if(chunk_tag == CHUNK_UNKNOWN)
199 case XML_READER_TEXT:
201 if (unlikely(node.empty()))
204 case XML_READER_ENDELEM:
205 /* Verify if we reach Chuk endelem */
206 if ( node == p_node) {
208 if ( this->s_path.empty() ) {
209 msg_Err(this->p_demux, "Chunk::Parse No path found");
212 if ( this->i_vol_index != 1 ) {
213 msg_Err(this->p_demux, "Only one VOLINDEX suported. Patch welcome.");
216 /* end of chunk tag parse */
228 AssetMap::~AssetMap() { }
230 int AssetMap::Parse ( )
235 int sum_duration_vid = 0;
236 int sum_duration_aud = 0;
242 AssetList *_p_asset_list = NULL;
244 vector<string> pklfiles;
246 /* init XML parser */
247 if( this->OpenXml() ) {
248 msg_Err( p_demux, "Failed to initialize Assetmap XML parser" );
252 /* reading ASSETMAP file to get the asset_list */
253 msg_Dbg( p_demux, "reading ASSETMAP file..." );
254 while( ( type = ReadNextNode( this->p_xmlReader, node ) ) > 0 ) {
255 if ( (type == XML_READER_STARTELEM) && ( node =="AssetList")) {
256 _p_asset_list = new (nothrow) AssetList();
257 if ( unlikely(_p_asset_list == NULL) ) {
261 p_dcp->p_asset_list = _p_asset_list;
262 if (this->ParseAssetList(p_xmlReader, node, type )) {
266 /* asset list found so break*/
272 /* Look for PKLs path */
273 if ( (_p_asset_list == NULL) || (_p_asset_list->size() == 0) ) {
274 msg_Err( p_demux, "Asset list empty" );
279 for (AssetList::iterator iter = _p_asset_list->begin();
280 iter != _p_asset_list->end() ; ++iter) {
282 s_filepath = (*iter)->getPath();
283 if (s_filepath.empty()) {
284 msg_Err( p_demux, "No path element for asset" );
287 /* set an absolute file path */
288 s_filepath = p_dcp->path + s_filepath;
290 /* case of packing list */
291 if ((*iter)->isPackingList()) {
292 pklfiles.push_back( s_filepath );
296 /* TODO: case of only on PKL managed.
297 * Future work needed for managing severals
298 * the PKL vector will be used to select the required PKL */
299 if( (pklfiles.size() == 0) || (pklfiles[0].empty()) )
301 msg_Err( p_demux, "Could not find PKL file in ASSETMAP" );
306 /* Create the first PKL */
307 pkl = new (nothrow) PKL(p_demux, pklfiles[0], _p_asset_list, p_dcp->path);
308 if ( unlikely(pkl == NULL) ) {
317 p_dcp->pkls.push_back( pkl );
320 if ( pkl->FindCPLs() <= 0 ) {
321 msg_Err(p_demux, " No CPL found");
325 /* TODO: Only one CPL managed.
326 * Future work needed for managing severals
329 cpl = pkl->getCPL(0);
331 msg_Err(p_demux, " No CPL found");
335 if ( cpl->Parse() ) {
340 reel_nbr = cpl->getReelList().size();
341 for(index = 0; index != reel_nbr; ++index)
343 reel = cpl->getReel(index);
346 struct info_reel video;
347 struct info_reel audio;
350 asset = reel->getTrack(TRACK_PICTURE);
353 sum_duration_vid += asset->getDuration();
354 video.filename = p_dcp->path + asset->getPath();
355 video.i_entrypoint = asset->getEntryPoint();
356 video.i_duration = asset->getDuration();
357 video.i_correction = video.i_entrypoint - sum_duration_vid + video.i_duration;
358 video.i_absolute_end = sum_duration_vid;
359 p_dcp->video_reels.push_back(video);
360 msg_Dbg( this->p_demux, "Video Track: %s",asset->getPath().c_str());
361 msg_Dbg( this->p_demux, "Entry point: %i",asset->getEntryPoint());
364 asset = reel->getTrack(TRACK_SOUND);
367 /*if (!p_dcp->audio_reels.empty())
369 sum_duration_aud = 0;
370 for (int i = 0; i != p_dcp->audio_reels.size(); ++i)
372 sum_duration_aud += p_dcp->audio_reels(i).i_duration;
375 sum_duration_aud += asset->getDuration();
376 audio.filename = p_dcp->path + asset->getPath();
377 audio.i_entrypoint = asset->getEntryPoint();
378 audio.i_duration = asset->getDuration();
379 audio.i_correction = audio.i_entrypoint - sum_duration_aud + audio.i_duration;
380 audio.i_absolute_end = sum_duration_aud;
381 p_dcp->audio_reels.push_back(audio);
382 msg_Dbg( this->p_demux, "Audio Track: %s",asset->getPath().c_str());
383 msg_Dbg( this->p_demux, "Entry point: %i",asset->getEntryPoint());
398 int Asset::Parse( xml_reader_t *p_xmlReader, string p_node, int p_type)
403 const string s_root_node = "Asset";
405 if (p_type != XML_READER_STARTELEM)
407 if( p_node != s_root_node)
409 /* loop on Assets Node */
410 while( ( type = ReadNextNode( p_xmlReader, node ) ) > 0 ) {
412 case XML_READER_STARTELEM:
414 AssetTag_t _tag = ASSET_UNKNOWN;
415 for(AssetTag_t i = ASSET_ID; i <= ASSET_ORIGINAL_FILENAME; i = AssetTag_t(i+1)) {
416 if( node == g_asset_names[i-1]) {
419 /* Case of complex nodes */
420 case ASSET_PACKING_LIST:
421 /* case of <PackinkList/> tag, bur not compliant with SMPTE-429-9 2007*/
422 if (xml_ReaderIsEmptyElement( p_xmlReader))
423 this->b_is_packing_list = true;
424 else if ( ReadEndNode(p_xmlReader, node, type, s_value) )
426 if ( s_value == "true" )
427 this->b_is_packing_list = true;
429 case ASSET_CHUNK_LIST:
430 if ( this->parseChunkList(p_xmlReader, node, type ) )
432 this->s_path = this->chunk_vec[0].getPath();
435 if ( ReadEndNode(p_xmlReader, node, type, s_value) )
437 this->s_id = s_value;
439 case ASSET_ANNOTATION_TEXT:
440 if ( ReadEndNode(p_xmlReader, node, type, s_value) )
442 this->s_annotation = s_value;
444 case ASSET_ORIGINAL_FILENAME:
448 /* Asset tags not in AssetMap */
451 msg_Warn(this->p_demux, "Unknow ASSET_TAG: %i", _tag );
454 /* break the for loop as a tag is found*/
458 if( _tag == ASSET_UNKNOWN )
462 case XML_READER_TEXT:
464 case XML_READER_ENDELEM:
465 if ( node != s_root_node) {
466 msg_Err(this->p_demux,
467 "Something goes wrong in Asset parsing on Assetmap (node %s)", node.c_str());
470 /*Check Presence of Id and Chunklist */
471 if ( this->s_id.empty() ) {
472 msg_Err(this->p_demux, " No Id element found in Asset");
475 if ( this->s_path.empty() ) {
476 msg_Err(this->p_demux, " No path element found in Asset");
489 int Asset::ParsePKL( xml_reader_t *p_xmlReader)
494 const string s_root_node = "Asset";
496 while( ( type = ReadNextNode( p_xmlReader, node ) ) > 0 ) {
498 case XML_READER_STARTELEM:
500 AssetTag_t _tag = ASSET_UNKNOWN;
501 for(AssetTag_t i = ASSET_ID; i <= ASSET_ORIGINAL_FILENAME; i = AssetTag_t(i+1)) {
502 if( node == g_asset_names[i-1]) {
505 case ASSET_ANNOTATION_TEXT:
506 if ( ReadEndNode(p_xmlReader, node, type, s_value) )
508 if ( this->s_annotation.empty() )
509 this->s_annotation = s_value;
511 this->s_annotation = this->s_annotation + "--" + s_value;
514 if ( ReadEndNode(p_xmlReader, node, type, s_value) )
516 this->s_hash = s_value;
519 if ( ReadEndNode(p_xmlReader, node, type, s_value) )
521 this->ui_size = atol(s_value.c_str());
524 if ( ReadEndNode(p_xmlReader, node, type, s_value) )
526 this->s_type = s_value;
528 case ASSET_ORIGINAL_FILENAME:
529 if ( ReadEndNode(p_xmlReader, node, type, s_value) )
531 this->s_original_filename = s_value;
533 case ASSET_ID: /* already verified */
534 case ASSET_PACKING_LIST:
535 case ASSET_CHUNK_LIST:
536 /* Asset tags not in PKL */
539 msg_Warn(this->p_demux, "Unknow ASSET_TAG: %i", _tag );
542 /* break the for loop as a tag is found*/
546 if( _tag == ASSET_UNKNOWN )
550 case XML_READER_TEXT:
552 case XML_READER_ENDELEM:
553 if ( node != s_root_node) {
554 msg_Err(this->p_demux,
555 "Something goes wrong in Asset parsing on PKL (node %s)", node.c_str());
558 /* Verify that mandatory attributes are filled */
559 if (this->s_hash.empty()) {
560 msg_Err(this->p_demux,"Asset Hash tag invalid");
563 if (this->ui_size == 0) {
564 msg_Err(this->p_demux,"Asset Size tag invalid");
567 if (this->s_type.empty()) {
568 msg_Err(this->p_demux,"Asset Type tag invalid");
583 msg_Dbg(this->p_demux,"Id = %s", this->s_id.c_str());
584 msg_Dbg(this->p_demux,"Path = %s", this->s_path.c_str());
585 msg_Dbg(this->p_demux,"Is PKL = %s", this->b_is_packing_list ? "True" : "False");
586 msg_Dbg(this->p_demux,"Hash = %s", this->s_hash.c_str());
587 msg_Dbg(this->p_demux,"Size = %i", this->ui_size);
588 msg_Dbg(this->p_demux,"Type = %s", this->s_type.c_str());
589 msg_Dbg(this->p_demux,"OrignalFileName = %s", this->s_original_filename.c_str());
590 msg_Dbg(this->p_demux,"AnnotationText = %s", this->s_annotation.c_str());
593 int Asset::parseChunkList( xml_reader_t *p_xmlReader, string p_node, int p_type)
598 std::vector<Chunk> chunk_vec;
600 if (p_type != XML_READER_STARTELEM)
602 if( p_node != "ChunkList" )
604 /* loop on Assets Node */
605 while( ( type = ReadNextNode( p_xmlReader, node ) ) > 0 ) {
607 case XML_READER_STARTELEM:
609 Chunk chunk(this->p_demux);
610 if (node != "Chunk" )
612 if ( chunk.Parse(p_xmlReader, node, type) )
614 chunk_vec.push_back(chunk);
617 case XML_READER_ENDELEM:
618 if ( node == p_node) {
619 if (chunk_vec.size() != 1 ) {
620 msg_Err(this->p_demux, "chunklist of size greater than one not supported");
623 this->chunk_vec = chunk_vec;
632 int AssetMap::ParseAssetList (xml_reader_t *p_xmlReader, const string p_node, int p_type)
638 if (p_type != XML_READER_STARTELEM)
640 if( p_node != "AssetList" )
642 /* loop on AssetList nodes */
643 while( ( type = ReadNextNode( p_xmlReader, node ) ) > 0 ) {
645 case XML_READER_STARTELEM:
646 if (node != "Asset" )
648 asset = new (nothrow) Asset(this->p_demux);
649 if ( unlikely(asset == NULL) )
651 if (asset->Parse(p_xmlReader, node, type)){
655 p_dcp->p_asset_list->push_back(asset);
658 case XML_READER_ENDELEM:
663 case XML_READER_TEXT:
664 msg_Err(this->p_demux, "Error parsing AssetList in AssetMap");
671 Asset * AssetMap::getAssetById(AssetList *asset_list, const string p_id)
673 AssetList::iterator index = asset_list->begin() ;
674 for (index = asset_list->begin(); index != asset_list->end(); ++index)
675 if ((*index)->getId() == p_id )
683 XmlFile::~XmlFile() {}
685 int XmlFile::OpenXml()
689 this->p_xml = xml_Create( this->p_demux );
693 psz_uri = vlc_path2uri( this->s_path.c_str(), "file" );
694 this->p_stream = stream_UrlNew(this->p_demux, psz_uri );
696 if( ! this->p_stream ) {
697 xml_Delete(this->p_xml );
701 this->p_xmlReader = xml_ReaderCreate( this->p_xml, this->p_stream);
702 if( ! this->p_xmlReader ) {
703 stream_Delete( this->p_stream );
704 xml_Delete(this->p_xml );
710 void XmlFile::CloseXml() {
712 stream_Delete( this->p_stream );
713 if( this->p_xmlReader )
714 xml_ReaderDelete( this->p_xmlReader );
716 xml_Delete( this->p_xml );
724 PKL::PKL(demux_t * p_demux, string s_path, AssetList *_asset_list, string s):
725 XmlFile(p_demux, s_path),
726 asset_list(_asset_list), s_dcp_path(s)
732 vlc_delete_all(vec_cpl);
740 const string s_root_node = "PackingList";
742 static const string names[] = {
758 /* read 1st node and verify that is a PKL*/
759 if (! ( ( XML_READER_STARTELEM == ReadNextNode(this->p_xmlReader, node) ) &&
760 (node == s_root_node) ) ) {
761 msg_Err( this->p_demux, "Not a valid XML Packing List");
764 while( ( type = ReadNextNode( this->p_xmlReader, node ) ) > 0 ) {
766 case XML_READER_STARTELEM: {
767 PKLTag_t _tag = PKL_UNKNOWN;
768 for(PKLTag_t i = PKL_ID; i <= PKL_SIGNATURE; i = PKLTag_t(i+1)) {
769 if( node == names[i-1]) {
772 /* case for parsing non terminal nodes */
774 if ( this->ParseAssetList(node, type) )
778 if ( this->ParseSigner(node, type) )
782 if ( this->ParseSignature(node, type) )
785 /* Parse simple/end nodes */
787 if ( ReadEndNode(p_xmlReader, node, type, s_value) )
789 this->s_id = s_value;
792 if ( ReadEndNode(p_xmlReader, node, type, s_value) )
794 this->s_issue_date = s_value;
797 if ( ReadEndNode(p_xmlReader, node, type, s_value) )
799 this->s_issuer = s_value;
802 if ( ReadEndNode(p_xmlReader, node, type, s_value) )
804 this->s_creator = s_value;
806 case PKL_ANNOTATION_TEXT:
807 if ( ReadEndNode(p_xmlReader, node, type, s_value) )
809 this->s_annotation = s_value;
812 if ( ReadEndNode(p_xmlReader, node, type, s_value) )
814 this->s_icon_id = s_value;
817 if ( ReadEndNode(p_xmlReader, node, type, s_value) )
819 this->s_group_id = s_value;
822 msg_Warn(this->p_demux, "Unknow PKG_TAG: %i", _tag );
825 /* break the for loop as a tag is found*/
829 if( _tag == PKL_UNKNOWN )
833 case XML_READER_TEXT:
835 case XML_READER_ENDELEM:
836 if ( node != s_root_node) {
837 msg_Err(this->p_demux,
838 "Something goes wrong in PKL parsing (node %s)", node.c_str());
844 /* TODO verify presence of mandatory fields*/
850 msg_Err( this->p_demux, "PKL parsing failed");
857 if ( this->vec_cpl.size() != 0 ) {
858 msg_Err(this->p_demux, "CPLs already checked");
862 for (AssetList::iterator index = this->asset_list->begin();
863 index != this->asset_list->end(); ++index) {
864 Asset *asset = *index;
865 if ( asset->getType().find("text/xml") == string::npos) {
866 /* not an xml file */
870 CPL *cpl = new (nothrow) CPL(this->p_demux,
871 this->s_dcp_path + asset->getPath(),
873 if ( unlikely(cpl == NULL) )
877 this->vec_cpl.push_back(cpl);
881 return this->vec_cpl.size();
885 int PKL::ParseAssetList(string p_node, int p_type) {
889 if (p_type != XML_READER_STARTELEM)
891 if( p_node != "AssetList")
893 while( ( type = ReadNextNode( this->p_xmlReader, node ) ) > 0 ) {
895 case XML_READER_STARTELEM:
896 if( node =="Asset") {
897 if ( this->ParseAsset(node, type) )
902 case XML_READER_ENDELEM:
903 if ( node == p_node) {
904 /* parse of chunklist finished */
914 int PKL::ParseAsset(string p_node, int p_type) {
920 if (p_type != XML_READER_STARTELEM)
922 if( p_node != "Asset")
925 /* 1st node shall be Id" */
926 if (( type = ReadNextNode( this->p_xmlReader, node ) ) > 0)
927 if ( ! ((type == XML_READER_STARTELEM) && (node == "Id")))
929 if (( type = ReadNextNode( this->p_xmlReader, node ) ) > 0)
930 if (type == XML_READER_TEXT) {
932 if (unlikely(node.empty()))
935 if (( type = ReadNextNode( this->p_xmlReader, node ) ) > 0)
936 if (type == XML_READER_ENDELEM) {
937 asset = AssetMap::getAssetById(this->asset_list, s_value);
943 if ( asset->ParsePKL(this->p_xmlReader) )
948 int PKL::ParseSigner(string p_node, int p_type)
953 if (p_type != XML_READER_STARTELEM)
955 if( p_node != "Signer")
958 while( ( type = ReadNextNode( this->p_xmlReader, node ) ) > 0 ) {
959 /* TODO not implemented. Just parse until end of Signer node */
960 if ((node == p_node) && (type = XML_READER_ENDELEM))
964 msg_Err(this->p_demux, "Parse of Signer finished bad");
968 int PKL::ParseSignature(string p_node, int p_type)
973 if (p_type != XML_READER_STARTELEM)
975 if( p_node != "ds:Signature")
978 while (( type = ReadNextNode( this->p_xmlReader, node ) ) > 0 ) {
979 /* TODO not implemented. Just parse until end of Signature node */
980 if ((node == p_node) && (type = XML_READER_ENDELEM))
983 msg_Err(this->p_demux, "Parse of Signature finished bad");
990 int Reel::Parse(string p_node, int p_type) {
995 if (p_type != XML_READER_STARTELEM)
997 if( p_node != "Reel")
1000 while (( type = ReadNextNode(this->p_xmlReader, node ) ) > 0 ) {
1002 case XML_READER_STARTELEM:
1004 if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
1006 this->s_id = s_value;
1007 } else if (node == "AnnotationText") {
1008 if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
1010 this->s_annotation = s_value;
1011 } else if ( node =="AssetList" ) {
1012 if (this->ParseAssetList(node, type))
1016 msg_Err(this->p_demux, "Reel::Parse, unknown tag:%s", node.c_str());
1020 case XML_READER_TEXT:
1022 msg_Err(this->p_demux, "Reel parsing error");
1024 case XML_READER_ENDELEM:
1025 /* verify correctness of end node */
1026 if ( node == p_node) {
1027 /* TODO : verify Reel id */
1037 Asset * Reel::getTrack(TrackType_t e_track)
1041 return this->p_picture_track;
1043 return this->p_sound_track;
1044 case TRACK_SUBTITLE:
1045 return this->p_subtitle_track;
1053 int Reel::ParseAssetList(string p_node, int p_type) {
1058 if (p_type != XML_READER_STARTELEM)
1060 if( p_node != "AssetList")
1063 while (( type = ReadNextNode( this->p_xmlReader, node ) ) > 0 ) {
1065 case XML_READER_STARTELEM:
1066 if (node =="MainPicture") {
1067 if ( this->ParseAsset(node, type, TRACK_PICTURE) )
1069 } else if (node =="MainSound") {
1070 if ( this->ParseAsset(node, type, TRACK_SOUND) )
1072 } else if (node =="MainSubtitle") {
1073 if ( this->ParseAsset(node, type, TRACK_SUBTITLE) )
1077 msg_Err(this->p_demux, "Reel::ParseAssetList, unknown tag:%s", node.c_str());
1081 case XML_READER_TEXT:
1083 msg_Err(this->p_demux, "AssetList parsing error");
1085 case XML_READER_ENDELEM:
1086 /* verify correctness of end node */
1087 if ( node == p_node) {
1088 /* TODO : verify id */
1097 int Reel::ParseAsset(string p_node, int p_type, TrackType_t e_track) {
1101 bool b_stop_parse = false;
1102 Asset *asset = NULL;
1104 if (p_type != XML_READER_STARTELEM)
1107 /* 1st node shall be Id */
1108 if (( type = ReadNextNode( this->p_xmlReader, node ) ) > 0)
1109 if ( ! ((type == XML_READER_STARTELEM) && (node == "Id")))
1112 if ( ReadEndNode(this->p_xmlReader, node, type, s_value) )
1115 asset = AssetMap::getAssetById(this->p_asset_list, s_value);
1119 while( (! b_stop_parse) &&
1120 (( type = ReadNextNode( this->p_xmlReader, node ) ) > 0 ) ) {
1122 case XML_READER_STARTELEM:
1123 if (node =="EditRate") {
1124 if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
1126 } else if (node == "AnnotationText") {
1127 if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
1129 asset->setAnnotation(s_value);
1130 } else if (node == "IntrinsicDuration") {
1131 if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
1133 asset->setIntrinsicDuration(atoi(s_value.c_str()));
1134 } else if (node == "EntryPoint") {
1135 if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
1137 asset->setEntryPoint(atoi(s_value.c_str()));
1138 } else if (node == "Duration") {
1139 if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
1141 asset->setDuration(atoi(s_value.c_str()));
1142 } else if (node == "KeyId") {
1143 if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
1145 } else if (node == "Hash") {
1146 if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
1148 } else if (node == "FrameRate") {
1149 if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
1151 } else if (node == "ScreenAspectRatio") {
1152 if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
1154 } else if (node == "Language") {
1155 if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
1159 msg_Err(this->p_demux, "Reel::ParseAsset unknown tag:%s", node.c_str());
1163 case XML_READER_TEXT:
1167 case XML_READER_ENDELEM:
1168 /* verify correctness of end node */
1169 if ( node == p_node) {
1170 /* TODO : verify id */
1171 b_stop_parse = true;
1175 /* store by track */
1178 this->p_picture_track = asset;
1181 this->p_sound_track = asset;
1183 case TRACK_SUBTITLE:
1184 this->p_subtitle_track = asset;
1197 CPL::CPL(demux_t * p_demux, string s_path, AssetList *_asset_list)
1198 : XmlFile(p_demux, s_path), asset_list( _asset_list)
1203 this->type = XML_UNKNOWN;
1205 if (this->OpenXml()) {
1206 msg_Err(this->p_demux, "Failed to open CPL XML file");
1210 /* read 1st node and verify that is a CPL */
1211 if ( (type = ReadNextNode(p_xmlReader, node)) > 0) {
1212 if ( (type == XML_READER_STARTELEM) && (node == "CompositionPlaylist") ) {
1213 this->type = XML_CPL;
1221 vlc_delete_all(vec_reel);
1229 const string s_root_node = "CompositionPlaylist";
1231 static const string names[] = {
1247 if (this->OpenXml())
1250 /* read 1st node and verify that is a CPL*/
1251 if (! ( ( XML_READER_STARTELEM == ReadNextNode(this->p_xmlReader, node) ) &&
1252 (node == s_root_node) ) ) {
1253 msg_Err( this->p_demux, "Not a valid XML Packing List");
1257 while( ( type = ReadNextNode( this->p_xmlReader, node ) ) > 0 ) {
1259 case XML_READER_STARTELEM: {
1260 CPLTag_t _tag = CPL_UNKNOWN;
1261 for(CPLTag_t i = CPL_ID; i <= CPL_SIGNATURE; i = CPLTag_t(i+1)) {
1262 if( node == names[i-1]) {
1265 /* case for parsing non terminal nodes */
1267 if ( this->ParseReelList(node, type) )
1270 case CPL_CONTENT_VERSION:
1273 case CPL_RATING_LIST:
1274 if ( this->DummyParse(node,type) )
1277 /* Parse simple/end nodes */
1279 if ( ReadEndNode(p_xmlReader, node, type, s_value) )
1281 this->s_id = s_value;
1283 case CPL_ANNOTATION_TEXT:
1284 if ( ReadEndNode(p_xmlReader, node, type, s_value) )
1286 this->s_annotation = s_value;
1289 if ( ReadEndNode(p_xmlReader, node, type, s_value) )
1291 this->s_icon_id = s_value;
1293 case CPL_ISSUE_DATE:
1294 if ( ReadEndNode(p_xmlReader, node, type, s_value) )
1296 this->s_issue_date= s_value;
1299 if ( ReadEndNode(p_xmlReader, node, type, s_value) )
1301 this->s_issuer = s_value;
1304 if ( ReadEndNode(p_xmlReader, node, type, s_value) )
1306 this->s_creator = s_value;
1308 case CPL_CONTENT_TITLE:
1309 if ( ReadEndNode(p_xmlReader, node, type, s_value) )
1311 this->s_content_title = s_value;
1313 case CPL_CONTENT_KIND:
1314 if ( ReadEndNode(p_xmlReader, node, type, s_value) )
1316 this->s_content_kind = s_value;
1319 msg_Warn(this->p_demux, "Unknow CPL_TAG: %i", _tag );
1323 /* break the for loop as a tag is found*/
1327 if( _tag == CPL_UNKNOWN )
1331 case XML_READER_TEXT:
1333 case XML_READER_ENDELEM:
1334 if ( node != s_root_node) {
1335 msg_Err(this->p_demux,
1336 "Something goes wrong in CKL parsing (node %s)", node.c_str());
1343 /* TODO verify presence of mandatory fields*/
1353 int CPL::ParseReelList(string p_node, int p_type) {
1357 if (p_type != XML_READER_STARTELEM)
1359 if( p_node != "ReelList")
1361 while( ( type = ReadNextNode( this->p_xmlReader, node ) ) > 0 ) {
1363 case XML_READER_STARTELEM: {
1364 Reel *p_reel = new (nothrow) Reel( this->p_demux, this->asset_list, this->p_xmlReader);
1365 if ( unlikely(p_reel == NULL) )
1367 if( node =="Reel") {
1368 if ( p_reel->Parse(node, type) ) {
1376 this->vec_reel.push_back(p_reel);
1380 case XML_READER_TEXT:
1383 case XML_READER_ENDELEM:
1384 if ( node == p_node)
1393 int CPL::DummyParse(string p_node, int p_type)
1398 if (p_type != XML_READER_STARTELEM)
1401 if (xml_ReaderIsEmptyElement( this->p_xmlReader))
1404 while (( type = ReadNextNode( this->p_xmlReader, node ) ) > 0 ) {
1405 /* TODO not implemented. Just pase until end of input node */
1406 if ((node == p_node) && (type = XML_READER_ENDELEM))