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>
12 * Simona-Marinela Prodea <simona dot marinela dot prodea at gmail dot com>
14 * This program is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU Lesser General Public License as published by
16 * the Free Software Foundation; either version 2.1 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public License
25 * along with this program; if not, write to the Free Software Foundation,
26 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
27 *****************************************************************************/
31 * @brief Parsing of DCP XML files
37 /* VLC core API headers */
38 #include <vlc_common.h>
39 #include <vlc_plugin.h>
48 #include "dcpparser.h"
64 ASSET_ANNOTATION_TEXT
,
70 ASSET_ORIGINAL_FILENAME
73 static const string g_asset_names
[] = {
92 PKL_ANNOTATION_TEXT
, /* start of optional tags */
102 CPL_ANNOTATION_TEXT
, /* optional */
103 CPL_ICON_ID
, /* optional */
105 CPL_ISSUER
, /* optional */
106 CPL_CREATOR
, /* optional */
109 CPL_CONTENT_VERSION
, /* not optional, but not always present*/
110 CPL_RATING_LIST
, /* not handled */
112 CPL_SIGNER
, /* optional - not handled */
113 CPL_SIGNATURE
/* optional - not handled */
117 class ChunkList
: public std::list
<Chunk
> {
126 int Chunk::Parse( xml_reader_t
*p_xmlReader
, string p_node
, int p_type
){
130 static const string names
[] = {"Path", "VolumeIndex", "Offset",
132 if (p_type
!= XML_READER_STARTELEM
)
134 if( p_node
!= "Chunk")
136 /* loop on Chunks Node */
137 while( ( type
= XmlFile::ReadNextNode( this->p_demux
, p_xmlReader
, node
) ) > 0 ) {
139 case XML_READER_STARTELEM
:
141 ChunkTag_t chunk_tag
= CHUNK_UNKNOWN
;
142 for(ChunkTag_t i
= CHUNK_PATH
; i
<= CHUNK_LENGTH
; i
= ChunkTag_t(i
+1)) {
143 if( node
== names
[i
-1]) {
145 if ( XmlFile::ReadEndNode( this->p_demux
, p_xmlReader
, node
, type
, s_value
) )
149 this->s_path
= s_value
;
151 case CHUNK_VOL_INDEX
:
152 this->i_vol_index
= atoi(s_value
.c_str());
155 this->i_offset
= atoi(s_value
.c_str());
158 this->i_length
= atoi(s_value
.c_str());
164 /* break the for loop as a tag is found*/
168 if(chunk_tag
== CHUNK_UNKNOWN
)
172 case XML_READER_TEXT
:
174 if (unlikely(node
.empty()))
177 case XML_READER_ENDELEM
:
178 /* Verify if we reach Chuk endelem */
179 if ( node
== p_node
) {
181 if ( this->s_path
.empty() ) {
182 msg_Err(this->p_demux
, "Chunk::Parse No path found");
185 if ( this->i_vol_index
!= 1 ) {
186 msg_Err(this->p_demux
, "Only one VOLINDEX supported. Patch welcome.");
189 /* end of chunk tag parse */
201 AssetMap::~AssetMap() { }
203 int AssetMap::Parse ( )
209 int sum_duration_vid
= 0;
210 int sum_duration_aud
= 0;
217 AssetList
*_p_asset_list
= NULL
;
219 vector
<string
> pklfiles
;
221 /* init XML parser */
222 if( this->OpenXml() ) {
223 msg_Err( p_demux
, "Failed to initialize Assetmap XML parser" );
227 /* reading ASSETMAP file to get the asset_list */
228 msg_Dbg( p_demux
, "reading ASSETMAP file..." );
229 while( ( type
= XmlFile::ReadNextNode( this->p_demux
, this->p_xmlReader
, node
) ) ) {
235 if ( (type
== XML_READER_STARTELEM
) && ( node
=="AssetList")) {
236 _p_asset_list
= new (nothrow
) AssetList();
237 if ( unlikely(_p_asset_list
== NULL
) ) {
241 p_dcp
->p_asset_list
= _p_asset_list
;
242 if (this->ParseAssetList(p_xmlReader
, node
, type
)) {
246 /* asset list found so break*/
251 /* Look for PKLs path */
252 if ( (_p_asset_list
== NULL
) || (_p_asset_list
->size() == 0) ) {
253 msg_Err( p_demux
, "Asset list empty" );
258 for (AssetList::iterator iter
= _p_asset_list
->begin();
259 iter
!= _p_asset_list
->end() ; ++iter
) {
261 s_filepath
= (*iter
)->getPath();
262 if (s_filepath
.empty()) {
263 msg_Err( p_demux
, "No path element for asset" );
266 /* set an absolute file path */
267 s_filepath
= p_dcp
->path
+ s_filepath
;
269 /* case of packing list */
270 if ((*iter
)->isPackingList()) {
271 pklfiles
.push_back( s_filepath
);
275 /* TODO: case of only on PKL managed.
276 * Future work needed for managing severals
277 * the PKL vector will be used to select the required PKL */
278 if( (pklfiles
.size() == 0) || (pklfiles
[0].empty()) )
280 msg_Err( p_demux
, "Could not find PKL file in ASSETMAP" );
285 /* Create the first PKL */
286 pkl
= new (nothrow
) PKL(p_demux
, pklfiles
[0], _p_asset_list
, p_dcp
->path
);
287 if ( unlikely(pkl
== NULL
) ) {
296 p_dcp
->pkls
.push_back( pkl
);
299 if ( pkl
->FindCPLs() <= 0 ) {
300 msg_Err(p_demux
, " No CPL found");
304 /* TODO: Only one CPL managed.
305 * Future work needed for managing severals
308 cpl
= pkl
->getCPL(0);
310 msg_Err(p_demux
, " No CPL found");
314 if ( cpl
->Parse() ) {
320 for( AssetList::iterator iter
= _p_asset_list
->begin(); iter
!= _p_asset_list
->end(); ++iter
)
321 if( ! (*iter
)->getKeyId().empty() )
323 msg_Dbg( p_demux
, "DCP is encrypted, searching KDM file...");
324 psz_kdm_path
= var_InheritString( p_demux
, "kdm" );
325 if( !psz_kdm_path
|| !*psz_kdm_path
)
327 msg_Err( p_demux
, "cryptographic key IDs found in CPL and no path to KDM given");
328 free( psz_kdm_path
);
332 KDM
p_kdm( p_demux
, psz_kdm_path
, p_dcp
);
333 free( psz_kdm_path
);
334 if( ( retval
= p_kdm
.Parse() ) )
342 reel_nbr
= cpl
->getReelList().size();
343 for(index
= 0; index
!= reel_nbr
; ++index
)
345 reel
= cpl
->getReel(index
);
348 struct info_reel video
;
349 struct info_reel audio
;
352 asset
= reel
->getTrack(TRACK_PICTURE
);
355 sum_duration_vid
+= asset
->getDuration();
356 video
.filename
= p_dcp
->path
+ asset
->getPath();
357 video
.i_entrypoint
= asset
->getEntryPoint();
358 video
.i_duration
= asset
->getDuration();
359 video
.i_correction
= video
.i_entrypoint
- sum_duration_vid
+ video
.i_duration
;
360 video
.i_absolute_end
= sum_duration_vid
;
361 video
.p_key
= asset
->getAESKeyById( p_dcp
->p_key_list
, asset
->getKeyId() );
362 p_dcp
->video_reels
.push_back(video
);
363 msg_Dbg( this->p_demux
, "Video Track: %s",asset
->getPath().c_str());
364 msg_Dbg( this->p_demux
, "Entry point: %i",asset
->getEntryPoint());
367 asset
= reel
->getTrack(TRACK_SOUND
);
370 /*if (!p_dcp->audio_reels.empty())
372 sum_duration_aud = 0;
373 for (int i = 0; i != p_dcp->audio_reels.size(); ++i)
375 sum_duration_aud += p_dcp->audio_reels(i).i_duration;
378 sum_duration_aud
+= asset
->getDuration();
379 audio
.filename
= p_dcp
->path
+ asset
->getPath();
380 audio
.i_entrypoint
= asset
->getEntryPoint();
381 audio
.i_duration
= asset
->getDuration();
382 audio
.i_correction
= audio
.i_entrypoint
- sum_duration_aud
+ audio
.i_duration
;
383 audio
.i_absolute_end
= sum_duration_aud
;
384 audio
.p_key
= asset
->getAESKeyById( p_dcp
->p_key_list
, asset
->getKeyId() );
385 p_dcp
->audio_reels
.push_back(audio
);
386 msg_Dbg( this->p_demux
, "Audio Track: %s",asset
->getPath().c_str());
387 msg_Dbg( this->p_demux
, "Entry point: %i",asset
->getEntryPoint());
402 int Asset::Parse( xml_reader_t
*p_xmlReader
, string p_node
, int p_type
)
407 const string s_root_node
= "Asset";
409 if (p_type
!= XML_READER_STARTELEM
)
411 if( p_node
!= s_root_node
)
413 /* loop on Assets Node */
414 while( ( type
= XmlFile::ReadNextNode( this->p_demux
, p_xmlReader
, node
) ) > 0 ) {
416 case XML_READER_STARTELEM
:
418 AssetTag_t _tag
= ASSET_UNKNOWN
;
419 for(AssetTag_t i
= ASSET_ID
; i
<= ASSET_ORIGINAL_FILENAME
; i
= AssetTag_t(i
+1)) {
420 if( node
== g_asset_names
[i
-1]) {
423 /* Case of complex nodes */
424 case ASSET_PACKING_LIST
:
425 /* case of <PackingList/> tag, bur not compliant with SMPTE-429-9 2007*/
426 if (xml_ReaderIsEmptyElement( p_xmlReader
))
428 this->b_is_packing_list
= true;
430 else if ( XmlFile::ReadEndNode( this->p_demux
, p_xmlReader
, node
, type
, s_value
) )
432 msg_Err(this->p_demux
, "Missing end node in %s", node
.c_str());
435 if ( s_value
== "true" )
436 this->b_is_packing_list
= true;
438 case ASSET_CHUNK_LIST
:
439 if ( this->parseChunkList(p_xmlReader
, node
, type
) )
441 msg_Err(this->p_demux
, "Error parsing chunk list: %s", node
.c_str());
444 this->s_path
= this->chunk_vec
[0].getPath();
447 if ( XmlFile::ReadEndNode( this->p_demux
, p_xmlReader
, node
, type
, s_value
) )
449 msg_Err(this->p_demux
, "Missing end node in %s", node
.c_str());
452 this->s_id
= s_value
;
454 case ASSET_ANNOTATION_TEXT
:
455 if ( XmlFile::ReadEndNode( this->p_demux
, p_xmlReader
, node
, type
, s_value
) )
457 msg_Err(this->p_demux
, "Missing end node in %s", node
.c_str());
460 this->s_annotation
= s_value
;
462 case ASSET_ORIGINAL_FILENAME
:
466 /* Asset tags not in AssetMap */
469 msg_Warn(this->p_demux
, "Unknown ASSET_TAG: %i", _tag
);
472 /* break the for loop as a tag is found*/
476 if( _tag
== ASSET_UNKNOWN
)
478 msg_Err(this->p_demux
, "Unknown ASSET_TAG: %s", node
.c_str());
483 case XML_READER_TEXT
:
484 msg_Err(this->p_demux
, " Text element found in Asset");
486 case XML_READER_ENDELEM
:
487 if ( node
!= s_root_node
) {
488 msg_Err(this->p_demux
,
489 "Something goes wrong in Asset parsing on Assetmap (node %s)", node
.c_str());
492 /*Check Presence of Id and Chunklist */
493 if ( this->s_id
.empty() ) {
494 msg_Err(this->p_demux
, " No Id element found in Asset");
497 if ( this->s_path
.empty() ) {
498 msg_Err(this->p_demux
, " No path element found in Asset");
511 int Asset::ParsePKL( xml_reader_t
*p_xmlReader
)
516 const string s_root_node
= "Asset";
518 while( ( type
= XmlFile::ReadNextNode( this->p_demux
, p_xmlReader
, node
) ) > 0 ) {
520 case XML_READER_STARTELEM
:
522 AssetTag_t _tag
= ASSET_UNKNOWN
;
523 for(AssetTag_t i
= ASSET_ID
; i
<= ASSET_ORIGINAL_FILENAME
; i
= AssetTag_t(i
+1)) {
524 if( node
== g_asset_names
[i
-1]) {
527 case ASSET_ANNOTATION_TEXT
:
528 if ( XmlFile::ReadEndNode( this->p_demux
, p_xmlReader
, node
, type
, s_value
) )
530 if ( this->s_annotation
.empty() )
531 this->s_annotation
= s_value
;
533 this->s_annotation
= this->s_annotation
+ "--" + s_value
;
536 if ( XmlFile::ReadEndNode( this->p_demux
, p_xmlReader
, node
, type
, s_value
) )
538 this->s_hash
= s_value
;
541 if ( XmlFile::ReadEndNode( this->p_demux
, p_xmlReader
, node
, type
, s_value
) )
543 this->ui_size
= atol(s_value
.c_str());
546 if ( XmlFile::ReadEndNode( this->p_demux
, p_xmlReader
, node
, type
, s_value
) )
548 this->s_type
= s_value
;
550 case ASSET_ORIGINAL_FILENAME
:
551 if ( XmlFile::ReadEndNode( this->p_demux
, p_xmlReader
, node
, type
, s_value
) )
553 this->s_original_filename
= s_value
;
555 case ASSET_ID
: /* already verified */
556 case ASSET_PACKING_LIST
:
557 case ASSET_CHUNK_LIST
:
558 /* Asset tags not in PKL */
561 msg_Warn(this->p_demux
, "Unknow ASSET_TAG: %i", _tag
);
564 /* break the for loop as a tag is found*/
568 if( _tag
== ASSET_UNKNOWN
)
572 case XML_READER_TEXT
:
574 case XML_READER_ENDELEM
:
575 if ( node
!= s_root_node
) {
576 msg_Err(this->p_demux
,
577 "Something goes wrong in Asset parsing on PKL (node %s)", node
.c_str());
580 /* Verify that mandatory attributes are filled */
581 if (this->s_hash
.empty()) {
582 msg_Err(this->p_demux
,"Asset Hash tag invalid");
585 if (this->ui_size
== 0) {
586 msg_Err(this->p_demux
,"Asset Size tag invalid");
589 if (this->s_type
.empty()) {
590 msg_Err(this->p_demux
,"Asset Type tag invalid");
605 msg_Dbg(this->p_demux
,"Id = %s", this->s_id
.c_str());
606 msg_Dbg(this->p_demux
,"Path = %s", this->s_path
.c_str());
607 msg_Dbg(this->p_demux
,"Is PKL = %s", this->b_is_packing_list
? "True" : "False");
608 msg_Dbg(this->p_demux
,"Hash = %s", this->s_hash
.c_str());
609 msg_Dbg(this->p_demux
,"Size = %i", this->ui_size
);
610 msg_Dbg(this->p_demux
,"Type = %s", this->s_type
.c_str());
611 msg_Dbg(this->p_demux
,"OrignalFileName = %s", this->s_original_filename
.c_str());
612 msg_Dbg(this->p_demux
,"AnnotationText = %s", this->s_annotation
.c_str());
615 int Asset::parseChunkList( xml_reader_t
*p_xmlReader
, string p_node
, int p_type
)
620 std::vector
<Chunk
> chunk_vec
;
622 if (p_type
!= XML_READER_STARTELEM
)
624 if( p_node
!= "ChunkList" )
626 /* loop on Assets Node */
627 while( ( type
= XmlFile::ReadNextNode( this->p_demux
, p_xmlReader
, node
) ) > 0 ) {
629 case XML_READER_STARTELEM
:
631 Chunk
chunk(this->p_demux
);
632 if (node
!= "Chunk" )
634 if ( chunk
.Parse(p_xmlReader
, node
, type
) )
636 chunk_vec
.push_back(chunk
);
639 case XML_READER_ENDELEM
:
640 if ( node
== p_node
) {
641 if (chunk_vec
.size() != 1 ) {
642 msg_Err(this->p_demux
, "chunklist of size greater than one not supported");
645 this->chunk_vec
= chunk_vec
;
654 AESKey
* Asset::getAESKeyById( AESKeyList
* p_key_list
, const string s_id
)
656 /* return NULL if DCP is not encrypted */
657 if( !p_key_list
|| s_id
.empty() )
660 for( AESKeyList::iterator index
= p_key_list
->begin(); index
!= p_key_list
->end(); ++index
)
661 if( (*index
)->getKeyId() == s_id
)
668 int AssetMap::ParseAssetList (xml_reader_t
*p_xmlReader
, const string p_node
, int p_type
)
674 if (p_type
!= XML_READER_STARTELEM
)
676 if( p_node
!= "AssetList" )
678 /* loop on AssetList nodes */
679 while( ( type
= XmlFile::ReadNextNode( this->p_demux
, p_xmlReader
, node
) ) > 0 ) {
681 case XML_READER_STARTELEM
:
682 if (node
!= "Asset" )
684 asset
= new (nothrow
) Asset(this->p_demux
);
685 if ( unlikely(asset
== NULL
) )
687 if (asset
->Parse(p_xmlReader
, node
, type
)){
688 msg_Err(this->p_demux
, "Error parsing Asset in AssetMap");
692 p_dcp
->p_asset_list
->push_back(asset
);
695 case XML_READER_ENDELEM
:
700 case XML_READER_TEXT
:
701 msg_Err(this->p_demux
, "Error parsing AssetList in AssetMap");
708 Asset
* AssetMap::getAssetById(AssetList
*asset_list
, const string p_id
)
710 AssetList::iterator index
= asset_list
->begin() ;
711 for (index
= asset_list
->begin(); index
!= asset_list
->end(); ++index
)
712 if ((*index
)->getId() == p_id
)
720 XmlFile::~XmlFile() {}
722 int XmlFile::OpenXml()
726 psz_uri
= vlc_path2uri( this->s_path
.c_str(), "file" );
727 this->p_stream
= vlc_stream_NewURL(this->p_demux
, psz_uri
);
729 if( ! this->p_stream
) {
733 this->p_xmlReader
= xml_ReaderCreate( this->p_demux
, this->p_stream
);
734 if( ! this->p_xmlReader
) {
735 vlc_stream_Delete( this->p_stream
);
741 int XmlFile::ReadNextNode( demux_t
*p_demux
, xml_reader_t
*p_xmlReader
, string
& p_node
)
744 int i
= xml_ReaderNextNode( p_xmlReader
, &c_node
);
746 /* remove namespaces, if there are any */
747 string s_node
= c_node
;
748 size_t ui_pos
= s_node
.find( ":" );
750 if( ( i
== XML_READER_STARTELEM
|| i
== XML_READER_ENDELEM
) && ( ui_pos
!= string::npos
) )
754 p_node
= s_node
.substr( ui_pos
+ 1 );
758 msg_Err( p_demux
, "error while handling string" );
768 int XmlFile::ReadEndNode( demux_t
*p_demux
, xml_reader_t
*p_xmlReader
, string p_node
, int p_type
, string
&s_value
)
772 if ( xml_ReaderIsEmptyElement( p_xmlReader
) )
775 if (p_type
!= XML_READER_STARTELEM
)
778 int n
= XmlFile::ReadNextNode( p_demux
, p_xmlReader
, node
);
779 if( n
== XML_READER_TEXT
)
782 n
= XmlFile::ReadNextNode( p_demux
, p_xmlReader
, node
);
783 if( ( n
== XML_READER_ENDELEM
) && node
== p_node
)
786 return n
== XML_READER_ENDELEM
? 0 : -1;
789 * Reads first node in XML and returns
799 if( this->OpenXml() )
801 msg_Err( this->p_demux
, "Failed to open CPL XML file" );
805 /* read 1st node and verify that is a CPL */
806 type
= XmlFile::ReadNextNode( this->p_demux
, p_xmlReader
, node
);
807 if( type
== -1 ) /* error */
809 if( type
== XML_READER_STARTELEM
&& node
== "CompositionPlaylist" )
817 void XmlFile::CloseXml() {
819 vlc_stream_Delete( this->p_stream
);
820 if( this->p_xmlReader
)
821 xml_ReaderDelete( this->p_xmlReader
);
829 vlc_delete_all(vec_cpl
);
837 const string s_root_node
= "PackingList";
839 static const string names
[] = {
855 /* read 1st node and verify that is a PKL*/
856 if ( ! ( ( XML_READER_STARTELEM
== XmlFile::ReadNextNode( this->p_demux
, this->p_xmlReader
, node
) ) &&
857 (node
== s_root_node
) ) ) {
858 msg_Err( this->p_demux
, "Not a valid XML Packing List");
861 while( ( type
= XmlFile::ReadNextNode( this->p_demux
, this->p_xmlReader
, node
) ) ) {
863 case XML_READER_STARTELEM
: {
864 PKLTag_t _tag
= PKL_UNKNOWN
;
865 for(PKLTag_t i
= PKL_ID
; i
<= PKL_SIGNATURE
; i
= PKLTag_t(i
+1)) {
866 if( node
== names
[i
-1]) {
869 /* case for parsing non terminal nodes */
871 if ( this->ParseAssetList(node
, type
) )
875 if ( this->ParseSigner(node
, type
) )
879 if ( this->ParseSignature(node
, type
) )
882 /* Parse simple/end nodes */
884 if ( XmlFile::ReadEndNode( this->p_demux
, p_xmlReader
, node
, type
, s_value
) )
886 this->s_id
= s_value
;
889 if ( XmlFile::ReadEndNode( this->p_demux
, p_xmlReader
, node
, type
, s_value
) )
891 this->s_issue_date
= s_value
;
894 if ( XmlFile::ReadEndNode( this->p_demux
, p_xmlReader
, node
, type
, s_value
) )
896 this->s_issuer
= s_value
;
899 if ( XmlFile::ReadEndNode( this->p_demux
, p_xmlReader
, node
, type
, s_value
) )
901 this->s_creator
= s_value
;
903 case PKL_ANNOTATION_TEXT
:
904 if ( XmlFile::ReadEndNode( this->p_demux
, p_xmlReader
, node
, type
, s_value
) )
906 this->s_annotation
= s_value
;
909 if ( XmlFile::ReadEndNode( this->p_demux
, p_xmlReader
, node
, type
, s_value
) )
911 this->s_icon_id
= s_value
;
914 if ( XmlFile::ReadEndNode( this->p_demux
, p_xmlReader
, node
, type
, s_value
) )
916 this->s_group_id
= s_value
;
919 msg_Warn(this->p_demux
, "Unknow PKG_TAG: %i", _tag
);
922 /* break the for loop as a tag is found*/
926 if( _tag
== PKL_UNKNOWN
)
930 case XML_READER_TEXT
:
933 case XML_READER_ENDELEM
:
934 if ( node
!= s_root_node
) {
935 msg_Err(this->p_demux
,
936 "Something goes wrong in PKL parsing (node %s)", node
.c_str());
942 /* TODO verify presence of mandatory fields*/
948 msg_Err( this->p_demux
, "PKL parsing failed");
955 if ( this->vec_cpl
.size() != 0 ) {
956 msg_Err(this->p_demux
, "CPLs already checked");
960 for (AssetList::iterator index
= this->asset_list
->begin();
961 index
!= this->asset_list
->end(); ++index
) {
962 Asset
*asset
= *index
;
963 if ( asset
->getType().find("text/xml") == string::npos
) {
964 /* not an xml file */
968 CPL
*cpl
= new (nothrow
) CPL(this->p_demux
,
969 this->s_dcp_path
+ asset
->getPath(),
971 if ( unlikely(cpl
== NULL
) )
973 switch( cpl
->isCPL() )
977 this->vec_cpl
.push_back(cpl
);
988 return this->vec_cpl
.size();
992 int PKL::ParseAssetList(string p_node
, int p_type
) {
996 if (p_type
!= XML_READER_STARTELEM
)
998 if( p_node
!= "AssetList")
1000 while( ( type
= XmlFile::ReadNextNode( this->p_demux
, this->p_xmlReader
, node
) ) ) {
1002 case XML_READER_STARTELEM
:
1003 if( node
=="Asset") {
1004 if ( this->ParseAsset(node
, type
) )
1009 case XML_READER_ENDELEM
:
1010 if ( node
== p_node
) {
1011 /* parse of chunklist finished */
1024 int PKL::ParseAsset(string p_node
, int p_type
) {
1028 Asset
*asset
= NULL
;
1030 if (p_type
!= XML_READER_STARTELEM
)
1032 if( p_node
!= "Asset")
1035 /* 1st node shall be Id" */
1036 if( ( type
= XmlFile::ReadNextNode( this->p_demux
, this->p_xmlReader
, node
) ) )
1037 if ( ! ( ( type
== XML_READER_STARTELEM
) && ( node
== "Id" ) ) || type
== -1 )
1039 if( ( type
= XmlFile::ReadNextNode( this->p_demux
, this->p_xmlReader
, node
) ) != -1 )
1041 if( type
== XML_READER_TEXT
)
1044 if (unlikely(node
.empty()))
1051 if( ( type
= XmlFile::ReadNextNode( this->p_demux
, this->p_xmlReader
, node
) ) != -1 )
1053 if( type
== XML_READER_ENDELEM
)
1055 asset
= AssetMap::getAssetById(this->asset_list
, s_value
);
1065 if ( asset
->ParsePKL(this->p_xmlReader
) )
1070 int PKL::ParseSigner(string p_node
, int p_type
)
1075 if (p_type
!= XML_READER_STARTELEM
)
1077 if( p_node
!= "Signer")
1080 while( ( type
= XmlFile::ReadNextNode( this->p_demux
, this->p_xmlReader
, node
) ) > 0 ) {
1081 /* TODO not implemented. Just parse until end of Signer node */
1082 if ((node
== p_node
) && (type
= XML_READER_ENDELEM
))
1086 msg_Err(this->p_demux
, "Parse of Signer finished bad");
1090 int PKL::ParseSignature(string p_node
, int p_type
)
1095 if (p_type
!= XML_READER_STARTELEM
)
1097 if( p_node
!= "Signature")
1100 while( ( type
= XmlFile::ReadNextNode( this->p_demux
, this->p_xmlReader
, node
) ) > 0 ) {
1101 /* TODO not implemented. Just parse until end of Signature node */
1102 if ((node
== p_node
) && (type
= XML_READER_ENDELEM
))
1105 msg_Err(this->p_demux
, "Parse of Signature finished bad");
1112 int Reel::Parse(string p_node
, int p_type
) {
1117 if (p_type
!= XML_READER_STARTELEM
)
1119 if( p_node
!= "Reel")
1122 while( ( type
= XmlFile::ReadNextNode( this->p_demux
, this->p_xmlReader
, node
) ) > 0 ) {
1124 case XML_READER_STARTELEM
:
1126 if ( XmlFile::ReadEndNode( this->p_demux
, this->p_xmlReader
, node
, type
, s_value
) )
1128 this->s_id
= s_value
;
1129 } else if (node
== "AnnotationText") {
1130 if ( XmlFile::ReadEndNode( this->p_demux
, this->p_xmlReader
, node
, type
, s_value
) )
1132 this->s_annotation
= s_value
;
1133 } else if ( node
=="AssetList" ) {
1134 if (this->ParseAssetList(node
, type
))
1138 msg_Err(this->p_demux
, "Reel::Parse, unknown tag:%s", node
.c_str());
1142 case XML_READER_TEXT
:
1144 msg_Err(this->p_demux
, "Reel parsing error");
1146 case XML_READER_ENDELEM
:
1147 /* verify correctness of end node */
1148 if ( node
== p_node
) {
1149 /* TODO : verify Reel id */
1159 Asset
* Reel::getTrack(TrackType_t e_track
)
1163 return this->p_picture_track
;
1165 return this->p_sound_track
;
1166 case TRACK_SUBTITLE
:
1167 return this->p_subtitle_track
;
1175 int Reel::ParseAssetList(string p_node
, int p_type
) {
1180 if (p_type
!= XML_READER_STARTELEM
)
1182 if( p_node
!= "AssetList")
1185 while( ( type
= XmlFile::ReadNextNode( this->p_demux
, this->p_xmlReader
, node
) ) > 0 ) {
1187 case XML_READER_STARTELEM
:
1188 if (node
=="MainPicture") {
1189 if ( this->ParseAsset(node
, type
, TRACK_PICTURE
) )
1191 } else if (node
=="MainSound") {
1192 if ( this->ParseAsset(node
, type
, TRACK_SOUND
) )
1194 } else if (node
=="MainSubtitle") {
1195 if ( this->ParseAsset(node
, type
, TRACK_SUBTITLE
) )
1199 msg_Err(this->p_demux
, "Reel::ParseAssetList, unknown tag:%s", node
.c_str());
1203 case XML_READER_TEXT
:
1205 msg_Err(this->p_demux
, "AssetList parsing error");
1207 case XML_READER_ENDELEM
:
1208 /* verify correctness of end node */
1209 if ( node
== p_node
) {
1210 /* TODO : verify id */
1219 int Reel::ParseAsset(string p_node
, int p_type
, TrackType_t e_track
) {
1223 bool b_stop_parse
= false;
1224 Asset
*asset
= NULL
;
1226 if (p_type
!= XML_READER_STARTELEM
)
1229 /* 1st node shall be Id */
1230 if( ( type
= XmlFile::ReadNextNode( this->p_demux
, this->p_xmlReader
, node
) ) )
1231 if( ! ( ( type
== XML_READER_STARTELEM
) && ( node
== "Id" ) ) || type
== -1 )
1234 if ( XmlFile::ReadEndNode( this->p_demux
, this->p_xmlReader
, node
, type
, s_value
) )
1237 asset
= AssetMap::getAssetById(this->p_asset_list
, s_value
);
1241 while( (! b_stop_parse
) &&
1242 ( type
= XmlFile::ReadNextNode( this->p_demux
, this->p_xmlReader
, node
) ) ) {
1244 case XML_READER_STARTELEM
:
1245 if (node
=="EditRate") {
1246 if ( XmlFile::ReadEndNode( this->p_demux
, this->p_xmlReader
, node
, type
, s_value
) )
1248 } else if (node
== "AnnotationText") {
1249 if ( XmlFile::ReadEndNode( this->p_demux
, this->p_xmlReader
, node
, type
, s_value
) )
1251 asset
->setAnnotation(s_value
);
1252 } else if (node
== "IntrinsicDuration") {
1253 if ( XmlFile::ReadEndNode( this->p_demux
, this->p_xmlReader
, node
, type
, s_value
) )
1255 asset
->setIntrinsicDuration(atoi(s_value
.c_str()));
1256 } else if (node
== "EntryPoint") {
1257 if ( XmlFile::ReadEndNode( this->p_demux
, this->p_xmlReader
, node
, type
, s_value
) )
1259 asset
->setEntryPoint(atoi(s_value
.c_str()));
1260 } else if (node
== "Duration") {
1261 if ( XmlFile::ReadEndNode( this->p_demux
, this->p_xmlReader
, node
, type
, s_value
) )
1263 asset
->setDuration(atoi(s_value
.c_str()));
1264 } else if (node
== "KeyId") {
1265 if ( XmlFile::ReadEndNode( this->p_demux
, this->p_xmlReader
, node
, type
, s_value
) )
1267 asset
->setKeyId( s_value
);
1268 } else if (node
== "Hash") {
1269 if ( XmlFile::ReadEndNode( this->p_demux
, this->p_xmlReader
, node
, type
, s_value
) )
1271 } else if (node
== "FrameRate") {
1272 if ( XmlFile::ReadEndNode( this->p_demux
, this->p_xmlReader
, node
, type
, s_value
) )
1274 } else if (node
== "ScreenAspectRatio") {
1275 if ( XmlFile::ReadEndNode( this->p_demux
, this->p_xmlReader
, node
, type
, s_value
) )
1277 } else if (node
== "Language") {
1278 if ( XmlFile::ReadEndNode( this->p_demux
, this->p_xmlReader
, node
, type
, s_value
) )
1282 msg_Err(this->p_demux
, "Reel::ParseAsset unknown tag:%s", node
.c_str());
1286 case XML_READER_TEXT
:
1291 case XML_READER_ENDELEM
:
1292 /* verify correctness of end node */
1293 if ( node
== p_node
) {
1294 /* TODO : verify id */
1295 b_stop_parse
= true;
1299 /* store by track */
1302 this->p_picture_track
= asset
;
1305 this->p_sound_track
= asset
;
1307 case TRACK_SUBTITLE
:
1308 this->p_subtitle_track
= asset
;
1322 vlc_delete_all(vec_reel
);
1330 const string s_root_node
= "CompositionPlaylist";
1332 static const string names
[] = {
1348 if (this->OpenXml())
1351 /* read 1st node and verify that is a CPL*/
1352 if( ! ( ( XML_READER_STARTELEM
== XmlFile::ReadNextNode( this->p_demux
, this->p_xmlReader
, node
) ) &&
1353 (node
== s_root_node
) ) ) {
1354 msg_Err( this->p_demux
, "Not a valid XML Packing List");
1358 while( ( type
= XmlFile::ReadNextNode( this->p_demux
, this->p_xmlReader
, node
) ) ) {
1360 case XML_READER_STARTELEM
: {
1361 CPLTag_t _tag
= CPL_UNKNOWN
;
1362 for(CPLTag_t i
= CPL_ID
; i
<= CPL_SIGNATURE
; i
= CPLTag_t(i
+1)) {
1363 if( node
== names
[i
-1]) {
1366 /* case for parsing non terminal nodes */
1368 if ( this->ParseReelList(node
, type
) )
1371 case CPL_CONTENT_VERSION
:
1374 case CPL_RATING_LIST
:
1375 if ( this->DummyParse(node
,type
) )
1378 /* Parse simple/end nodes */
1380 if ( XmlFile::ReadEndNode( this->p_demux
, p_xmlReader
, node
, type
, s_value
) )
1382 this->s_id
= s_value
;
1384 case CPL_ANNOTATION_TEXT
:
1385 if ( XmlFile::ReadEndNode( this->p_demux
, p_xmlReader
, node
, type
, s_value
) )
1387 this->s_annotation
= s_value
;
1390 if ( XmlFile::ReadEndNode( this->p_demux
, p_xmlReader
, node
, type
, s_value
) )
1392 this->s_icon_id
= s_value
;
1394 case CPL_ISSUE_DATE
:
1395 if ( XmlFile::ReadEndNode( this->p_demux
, p_xmlReader
, node
, type
, s_value
) )
1397 this->s_issue_date
= s_value
;
1400 if ( XmlFile::ReadEndNode( this->p_demux
, p_xmlReader
, node
, type
, s_value
) )
1402 this->s_issuer
= s_value
;
1405 if ( XmlFile::ReadEndNode( this->p_demux
, p_xmlReader
, node
, type
, s_value
) )
1407 this->s_creator
= s_value
;
1409 case CPL_CONTENT_TITLE
:
1410 if ( XmlFile::ReadEndNode( this->p_demux
, p_xmlReader
, node
, type
, s_value
) )
1412 this->s_content_title
= s_value
;
1414 case CPL_CONTENT_KIND
:
1415 if ( XmlFile::ReadEndNode( this->p_demux
, p_xmlReader
, node
, type
, s_value
) )
1417 this->s_content_kind
= s_value
;
1420 msg_Warn(this->p_demux
, "Unknow CPL_TAG: %i", _tag
);
1424 /* break the for loop as a tag is found*/
1428 if( _tag
== CPL_UNKNOWN
)
1432 case XML_READER_TEXT
:
1435 case XML_READER_ENDELEM
:
1436 if ( node
!= s_root_node
) {
1437 msg_Err(this->p_demux
,
1438 "Something goes wrong in CKL parsing (node %s)", node
.c_str());
1445 /* TODO verify presence of mandatory fields*/
1455 int CPL::ParseReelList(string p_node
, int p_type
) {
1459 if (p_type
!= XML_READER_STARTELEM
)
1461 if( p_node
!= "ReelList")
1463 while( ( type
= XmlFile::ReadNextNode( this->p_demux
, this->p_xmlReader
, node
) ) > 0 ) {
1465 case XML_READER_STARTELEM
: {
1466 Reel
*p_reel
= new (nothrow
) Reel( this->p_demux
, this->asset_list
, this->p_xmlReader
);
1467 if ( unlikely(p_reel
== NULL
) )
1469 if( node
=="Reel") {
1470 if ( p_reel
->Parse(node
, type
) ) {
1478 this->vec_reel
.push_back(p_reel
);
1482 case XML_READER_TEXT
:
1485 case XML_READER_ENDELEM
:
1486 if ( node
== p_node
)
1495 int CPL::DummyParse(string p_node
, int p_type
)
1500 if (p_type
!= XML_READER_STARTELEM
)
1503 if (xml_ReaderIsEmptyElement( this->p_xmlReader
))
1506 while( ( type
= XmlFile::ReadNextNode( this->p_demux
, this->p_xmlReader
, node
) ) > 0 ) {
1507 /* TODO not implemented. Just pase until end of input node */
1508 if ((node
== p_node
) && (type
= XML_READER_ENDELEM
))