00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifdef HAVE_CONFIG_H
00022 #include <config.h>
00023 #endif
00024
00025
00026 #include <iostream>
00027 #include <fstream>
00028 #include <sstream>
00029 #include <string>
00030 #include <list>
00031 #include <map>
00032
00033 using std::cerr;
00034 using std::endl;
00035 using std::ends;
00036 using std::ofstream;
00037 using std::ostringstream;
00038 using std::list;
00039 using std::map;
00040
00041
00042 #include <libxml/xmlmemory.h>
00043 #include <libxml/parser.h>
00044 #include <libxml/tree.h>
00045 #include <pthread.h>
00046 #include <unistd.h>
00047 #include <sys/stat.h>
00048 #include <sys/types.h>
00049 #include <dirent.h>
00050
00051
00052 #include "playlist.h"
00053 #include "error.h"
00054 #include "filehandler.h"
00055 #include "frame.h"
00056 #include "stringutils.h"
00057
00058 const xmlChar* SMIL20_NAMESPACE_HREF = reinterpret_cast< const xmlChar* >( "http://www.w3.org/2001/SMIL20/Language" );
00059 const string KINO_AUTOSAVE_DIR = string( getenv("HOME") ) + string( "/.kino-history" );
00060
00065 class KinoFileMap : public FileMap
00066 {
00067 private:
00068 map < string, FileHandler* > filemap;
00069
00070 public:
00071 virtual ~KinoFileMap()
00072 {}
00073
00074 map<string, FileHandler*> &GetMap()
00075 {
00076 return filemap;
00077 }
00078
00079 void Clear( )
00080 {
00081 map<string, FileHandler*>::iterator n;
00082 for ( n = filemap.begin(); n != filemap.end(); ++n )
00083 delete ( *n ).second;
00084 filemap.erase( filemap.begin(), filemap.end() );
00085 }
00086
00087 void GetUnusedFxFiles( PlayList &list, vector< string > &unused )
00088 {
00089 unused.erase( unused.begin(), unused.end() );
00090 map<string, FileHandler*>::iterator n;
00091 for ( n = filemap.begin(); n != filemap.end(); ++n )
00092 {
00093 if ( n->first.find( ".kinofx.dv" ) != string::npos && !list.IsFileUsed( n->first ) )
00094 {
00095 unused.push_back( n->first );
00096 }
00097 }
00098 }
00099 };
00100
00104 FileMap *GetFileMap( )
00105 {
00106 static FileMap * thismap = new KinoFileMap( );
00107 return thismap;
00108 }
00109
00121 string directory_utils::join_file_to_directory( const string directory, const string &file )
00122 {
00123 vector <string> items;
00124
00125
00126 if ( file[ 0 ] != '/' && directory[ 0 ] != '/' )
00127 {
00128 char path[ PATH_MAX ];
00129 getcwd( path, PATH_MAX );
00130 StringUtils::split( path, "/", items );
00131 }
00132
00133
00134 if ( file[ 0 ] != '/' )
00135 StringUtils::split( directory, "/", items );
00136
00137
00138 StringUtils::split( file, "/", items );
00139
00140
00141 for ( vector< string >::iterator item = items.begin( ); item != items.end( ); )
00142 {
00143 if ( *item == ".." )
00144 {
00145 if ( item == items.begin( ) )
00146 {
00147 items.erase( item );
00148 item = items.begin();
00149 }
00150 else
00151 {
00152 items.erase( -- item + 1 );
00153 items.erase( -- item + 1 );
00154 item ++;
00155 }
00156 }
00157 else
00158 {
00159 item ++;
00160 }
00161 }
00162
00163 return "/" + StringUtils::join( items, "/" );
00164 }
00165
00173 string directory_utils::get_directory_from_file( const string &file )
00174 {
00175 return join_file_to_directory( "", file + "/.." );
00176 }
00177
00190 string directory_utils::get_absolute_path_to_file( const string &directory, const string &file )
00191 {
00192 return join_file_to_directory( directory, file );
00193 }
00194
00201 string directory_utils::get_relative_path_to_file( const string &directory, const string &file )
00202 {
00203 string output = "";
00204 string absolute = join_file_to_directory( directory, file );
00205 vector < string > directory_items;
00206 vector < string > absolute_items;
00207 StringUtils::split( absolute, "/", absolute_items );
00208 StringUtils::split( directory, "/", directory_items );
00209
00210 vector < string >::iterator directory_item;
00211 vector < string >::iterator absolute_item;
00212
00213
00214 for ( directory_item = directory_items.begin(), absolute_item = absolute_items.begin();
00215 directory_item != directory_items.end() && absolute_item != absolute_items.end() && *directory_item == *absolute_item; )
00216 {
00217 directory_items.erase( directory_item );
00218 absolute_items.erase( absolute_item );
00219 directory_item = directory_items.begin();
00220 absolute_item = absolute_items.begin();
00221 }
00222
00223
00224 for ( directory_item = directory_items.begin(); directory_item != directory_items.end() ; directory_item ++ )
00225 output += "../";
00226
00227
00228 output += StringUtils::join( absolute_items, "/" );
00229 return output;
00230 }
00231
00235 string directory_utils::expand_directory( const string directory )
00236 {
00237 string output;
00238 vector <string> items;
00239 StringUtils::split( directory, "/", items );
00240 vector< string >::iterator item = items.begin( );
00241
00242 if ( item != items.end( ) && *item == "~" )
00243 {
00244 output = getenv( "HOME" );
00245 item ++;
00246 }
00247
00248 for ( ; item != items.end( ); item ++ )
00249 output += "/" + *item;
00250
00251 return output;
00252 }
00253
00254 typedef bool ( *callback ) ( xmlNodePtr node, void *p, bool *freed );
00255
00256 typedef struct
00257 {
00258 int absFrame;
00259 int absBegin;
00260 int absEnd;
00261 int clipFrame;
00262 int clipBegin;
00263 int clipEnd;
00264 int clipNumber;
00265 int clipLength;
00266 char fileName[ 1024 ];
00267 xmlNodePtr sequence;
00268 xmlNodePtr video;
00269 }
00270 MovieInfo;
00271
00293 static bool findFile( xmlNodePtr node, void *p, bool *freed )
00294 {
00295 MovieInfo * data = ( MovieInfo* ) p;
00296
00297 if ( xmlStrcmp( node->name, ( const xmlChar* ) "seq" ) == 0 )
00298 {
00299 data->sequence = node;
00300 data->clipNumber++;
00301 }
00302
00303
00304
00305 else if ( xmlStrcmp( node->name, ( const xmlChar* ) "video" ) == 0 )
00306 {
00307
00308 data->video = node;
00309
00310
00311
00312 xmlChar *src = xmlGetProp( node, ( const xmlChar* ) "src" );
00313 xmlChar *clipBegin = xmlGetProp( node, ( const xmlChar* ) "clipBegin" );
00314 xmlChar *clipEnd = xmlGetProp( node, ( const xmlChar* ) "clipEnd" );
00315
00316 if ( ( src != NULL ) && ( clipBegin != NULL ) && ( clipEnd != NULL ) )
00317 {
00318
00319 data->clipBegin = atoi( ( const char* ) clipBegin );
00320 data->clipEnd = atoi( ( const char* ) clipEnd );
00321
00322 data->absBegin += data->clipLength;
00323 data->clipLength = data->clipEnd - data->clipBegin + 1;
00324 data->absEnd = data->absBegin + data->clipLength - 1;
00325
00326
00327
00328
00329
00330
00331 if ( data->absFrame <= data->absEnd )
00332 {
00333 strcpy( data->fileName, ( char * ) src );
00334 data->clipFrame = data->absFrame - data->absBegin + data->clipBegin;
00335
00336
00337 xmlFree( src );
00338 xmlFree( clipEnd );
00339 xmlFree( clipBegin );
00340
00341
00342
00343 return true;
00344 }
00345 }
00346
00347 if ( src )
00348 xmlFree( src );
00349 if ( clipEnd )
00350 xmlFree( clipEnd );
00351 if ( clipBegin )
00352 xmlFree( clipBegin );
00353
00354 }
00355 return false;
00356 }
00357
00358
00365 static bool fillMap( xmlNodePtr node, void *p, bool *freed )
00366 {
00367 if ( xmlStrcmp( node->name, ( const xmlChar* ) "video" ) == 0 )
00368 {
00369
00370
00371
00372 xmlChar * src = xmlGetProp( node, ( const xmlChar* ) "src" );
00373 xmlChar *clipBegin = xmlGetProp( node, ( const xmlChar* ) "clipBegin" );
00374 xmlChar *clipEnd = xmlGetProp( node, ( const xmlChar* ) "clipEnd" );
00375
00376 if ( ( src != NULL ) && ( clipBegin != NULL ) && ( clipEnd != NULL ) )
00377 {
00378
00379
00380 string & directory = *( string * ) p;
00381 string index = directory_utils::get_absolute_path_to_file( directory, ( char * ) src );
00382
00383
00384 xmlSetProp( node, ( const xmlChar* ) "src", ( xmlChar * ) index.c_str() );
00385
00386
00387 if ( GetFileMap() ->GetMap().find( index ) == GetFileMap() ->GetMap().end() )
00388 {
00389
00390 FileHandler * mediaFile;
00391
00392 if ( strncasecmp( strrchr( ( char* ) src, '.' ), ".avi", 4 ) == 0 )
00393 mediaFile = new AVIHandler();
00394 else if ( strncasecmp( strrchr( ( char* ) src, '.' ), ".dv", 3 ) == 0 ||
00395 strncasecmp( strrchr( ( char* ) src, '.' ), ".dif", 4 ) == 0 )
00396 mediaFile = new RawHandler();
00397 #ifdef HAVE_LIBQUICKTIME
00398
00399 else if ( strncasecmp( strrchr( ( char* ) src, '.' ), ".mov", 4 ) == 0 )
00400 mediaFile = new QtHandler();
00401 #endif
00402
00403 else
00404 {
00405 xmlFree( src );
00406 xmlFree( clipEnd );
00407 xmlFree( clipBegin );
00408 return false;
00409 }
00410
00411 if ( mediaFile->Open( index.c_str() ) )
00412 {
00413 GetFileMap() ->GetMap() [ index ] = mediaFile;
00414 }
00415 else
00416 {
00417 cerr << "Unable to open " << ( char * ) src
00418 << " - removing from list" << endl;
00419 xmlUnlinkNode( node );
00420 xmlFreeNode( node );
00421 *freed = true;
00422 }
00423 }
00424 }
00425
00426 xmlFree( src );
00427 xmlFree( clipEnd );
00428 xmlFree( clipBegin );
00429 }
00430 return false;
00431 }
00432
00433
00443 static bool findSceneStart( xmlNodePtr node, void *p, bool *freed )
00444 {
00445 int fileCount = 0;
00446 MovieInfo *data = ( MovieInfo* ) p;
00447 int begin = data->absBegin;
00448
00449
00450
00451 if ( xmlStrcmp( node->name, ( const xmlChar* ) "seq" ) == 0 )
00452 {
00453
00454 data->sequence = node;
00455
00456 node = node->children;
00457 while ( node != NULL )
00458 {
00459 if ( xmlStrcmp( node->name, ( const xmlChar* ) "video" ) == 0 )
00460 {
00461
00462 data->video = node;
00463
00464 xmlChar *src = xmlGetProp( node, ( const xmlChar* ) "src" );
00465 xmlChar *clipBegin = xmlGetProp( node, ( const xmlChar* ) "clipBegin" );
00466 xmlChar *clipEnd = xmlGetProp( node, ( const xmlChar* ) "clipEnd" );
00467
00468 if ( ( src != NULL ) && ( clipBegin != NULL ) && ( clipEnd != NULL ) )
00469 {
00470
00471 data->clipBegin = atoi( ( const char* ) clipBegin );
00472 data->clipEnd = atoi( ( const char* ) clipEnd );
00473
00474
00475
00476 if ( fileCount == 0 )
00477 {
00478 data->clipFrame = data->clipBegin;
00479 strcpy( data->fileName, ( char * ) src );
00480 }
00481
00482
00483
00484
00485
00486 if ( data->absFrame <= begin + data->clipEnd - data->clipBegin )
00487 {
00488 xmlFree( clipBegin );
00489 xmlFree( clipEnd );
00490 xmlFree( src );
00491 return true;
00492 }
00493 else
00494 {
00495 begin += ( data->clipEnd - data->clipBegin + 1 );
00496 }
00497 fileCount++;
00498 }
00499 if ( src )
00500 xmlFree( src );
00501 if ( clipEnd )
00502 xmlFree( clipEnd );
00503 if ( clipBegin )
00504 xmlFree( clipBegin );
00505 }
00506 node = node->next;
00507 }
00508 }
00509 data->absBegin = begin;
00510 data->clipFrame = 0;
00511 strcpy( data->fileName, "" );
00512 return false;
00513 }
00514
00515
00516 static bool findSceneEnd( xmlNodePtr node, void *p, bool *freed )
00517 {
00518 bool found = false;
00519 xmlChar *src = NULL;
00520 MovieInfo *data = ( MovieInfo* ) p;
00521
00522
00523
00524 if ( xmlStrcmp( node->name, ( const xmlChar* ) "seq" ) == 0 )
00525 {
00526
00527 data->sequence = node;
00528
00529 node = node->children;
00530 while ( node != NULL )
00531 {
00532 if ( xmlStrcmp( node->name, ( const xmlChar* ) "video" ) == 0 )
00533 {
00534
00535 data->video = node;
00536
00537 if ( src )
00538 xmlFree( src );
00539
00540 src = xmlGetProp( node, ( const xmlChar* ) "src" );
00541 xmlChar *clipBegin = xmlGetProp( node, ( const xmlChar* ) "clipBegin" );
00542 xmlChar *clipEnd = xmlGetProp( node, ( const xmlChar* ) "clipEnd" );
00543
00544 if ( ( src != NULL ) && ( clipBegin != NULL ) && ( clipEnd != NULL ) )
00545 {
00546
00547 data->clipBegin = atoi( ( const char* ) clipBegin );
00548 data->clipEnd = atoi( ( const char* ) clipEnd );
00549 data->clipFrame = data->clipEnd;
00550
00551 if ( data->absFrame <= data->absBegin + data->clipEnd - data->clipBegin )
00552 found = true;
00553 data->absBegin += ( data->clipEnd - data->clipBegin + 1 );
00554 }
00555
00556 if ( clipEnd )
00557 xmlFree( clipEnd );
00558 if ( clipBegin )
00559 xmlFree( clipBegin );
00560 }
00561 node = node->next;
00562 }
00563
00564 if ( found )
00565 {
00566 strcpy( data->fileName, ( char * ) src );
00567 xmlFree( src );
00568 data->absEnd = data->absBegin - 1;
00569 return true;
00570 }
00571
00572 if ( src )
00573 xmlFree( src );
00574 }
00575 data->clipFrame = 0;
00576 strcpy( data->fileName, "" );
00577 return false;
00578 }
00579
00594 static bool countFrames( xmlNodePtr node, void *p, bool *freed )
00595 {
00596 if ( xmlStrcmp( node->name, ( const xmlChar* ) "video" ) == 0 )
00597 {
00598
00599 xmlChar * src = xmlGetProp( node, ( const xmlChar* ) "src" );
00600 xmlChar *clipBegin = xmlGetProp( node, ( const xmlChar* ) "clipBegin" );
00601 xmlChar *clipEnd = xmlGetProp( node, ( const xmlChar* ) "clipEnd" );
00602
00603 if ( ( src != NULL ) && ( clipBegin != NULL ) && ( clipEnd != NULL ) )
00604 * ( ( int* ) p ) += atoi( ( const char* ) clipEnd ) - atoi( ( const char* ) clipBegin ) + 1;
00605
00606 if ( clipEnd )
00607 xmlFree( clipEnd );
00608 if ( clipBegin )
00609 xmlFree( clipBegin );
00610 if ( src )
00611 xmlFree( src );
00612 }
00613 return false;
00614 }
00615
00617 typedef struct
00618 {
00619 string file;
00620 string clipBegin;
00621 string clipEnd;
00622 }
00623 EliInfo;
00624
00625 typedef list<EliInfo> EliInfos;
00626 typedef EliInfos::iterator EliInfosIterator;
00627
00640 static bool convertEli( xmlNodePtr node, void *p, bool *freed )
00641 {
00642 if ( xmlStrcmp( node->name, ( const xmlChar* ) "video" ) == 0 )
00643 {
00644
00645 xmlChar * src = xmlGetProp( node, ( const xmlChar* ) "src" );
00646 xmlChar *clipBegin = xmlGetProp( node, ( const xmlChar* ) "clipBegin" );
00647 xmlChar *clipEnd = xmlGetProp( node, ( const xmlChar* ) "clipEnd" );
00648
00649 if ( ( src != NULL ) && ( clipBegin != NULL ) && ( clipEnd != NULL ) )
00650 {
00651
00652
00653
00654
00655 EliInfos * Eli = ( EliInfos * ) p;
00656 EliInfo tmp;
00657 tmp.file = ( const char* ) src;
00658 tmp.clipBegin = ( const char* ) clipBegin;
00659 tmp.clipEnd = ( const char* ) clipEnd;
00660 Eli->push_back( tmp );
00661 }
00662
00663 if ( clipEnd )
00664 xmlFree( clipEnd );
00665 if ( clipBegin )
00666 xmlFree( clipBegin );
00667 if ( src )
00668 xmlFree( src );
00669 }
00670 return false;
00671 }
00672
00673 class SrtContext
00674 {
00675 public:
00676 ofstream file;
00677 unsigned counter;
00678 xmlChar* title;
00679 xmlChar* abstract;
00680 xmlChar* src;
00681 unsigned begin;
00682 unsigned duration;
00683
00684 SrtContext( const char* filename ) :
00685 file(filename), counter(0), title(NULL), abstract(NULL), src(NULL),
00686 begin(0), duration(0)
00687 {
00688 }
00689
00690 ~SrtContext()
00691 {
00692 printEntry();
00693 file.close();
00694 }
00695
00696 void printEntry(void)
00697 {
00698 if ( title || abstract )
00699 {
00700 Frame *frame = GetFramePool( )->GetFrame( );
00701 FileHandler *mediaFile = GetFileMap()->GetMap() [ string( ( const char* ) src ) ];
00702 SMIL::MediaClippingTime time;
00703
00704 mediaFile->GetFrame( *frame, 0 );
00705 time.setFramerate( frame->GetFrameRate() );
00706 GetFramePool( )->DoneWithFrame( frame );
00707 string beginString = time.parseFramesToString( begin, SMIL::Time::TIME_FORMAT_CLOCK );
00708 string durationString = time.parseFramesToString( duration - begin, SMIL::Time::TIME_FORMAT_CLOCK );
00709 begin = 0;
00710
00711 file << ++counter << endl;
00712 file << StringUtils::replaceAll( beginString, ".", "," );
00713 file << " --> " << StringUtils::replaceAll( durationString, ".", "," ) << endl;
00714 if ( title )
00715 file << title << endl;
00716 if ( abstract )
00717 file << abstract << endl;
00718 file << endl;
00719 }
00720 if ( src )
00721 {
00722 xmlFree( src );
00723 src = NULL;
00724 }
00725 if ( title )
00726 {
00727 xmlFree( title );
00728 title = NULL;
00729 }
00730 if ( abstract )
00731 {
00732 xmlFree( abstract );
00733 abstract = NULL;
00734 }
00735 }
00736 };
00737
00738 static bool convertSrt( xmlNodePtr node, void *data, bool *freed )
00739 {
00740 SrtContext* srt = static_cast< SrtContext* >( data );
00741
00742 if ( xmlStrcmp( node->name, ( const xmlChar* ) "seq" ) == 0 )
00743 {
00744 srt->printEntry();
00745 srt->title = xmlGetProp( node, ( const xmlChar * ) "title" );
00746 srt->abstract = xmlGetProp( node, ( const xmlChar * ) "abstract" );
00747 }
00748 else if ( xmlStrcmp( node->name, ( const xmlChar* ) "video" ) == 0 )
00749 {
00750 xmlChar* clipBegin = xmlGetProp( node, ( const xmlChar* ) "clipBegin" );
00751 xmlChar* clipEnd = xmlGetProp( node, ( const xmlChar* ) "clipEnd" );
00752
00753 srt->src = xmlGetProp( node, ( const xmlChar* ) "src" );
00754 if ( !srt->begin && ( srt->title || srt->abstract ) )
00755 srt->begin = srt->duration;
00756 srt->duration += atoi( ( const char* ) clipEnd ) - atoi( ( const char* ) clipBegin ) + 1;
00757
00758 xmlFree( clipBegin );
00759 xmlFree( clipEnd );
00760 }
00761
00762 return false;
00763 }
00764
00765 static bool convertFramesToSmilTime( xmlNodePtr node, void *data, bool *freed )
00766 {
00767 if ( xmlStrcmp( node->name, ( const xmlChar* ) "video" ) == 0 )
00768 {
00769 Frame *frame = GetFramePool( )->GetFrame( );
00770 xmlChar *src = xmlGetProp( node, ( const xmlChar* ) "src" );
00771 string index( ( char* ) src );
00772 xmlFree( src );
00773 FileHandler *mediaFile = GetFileMap()->GetMap() [ index ];
00774 mediaFile->GetFrame( *frame, 0 );
00775 SMIL::MediaClippingTime time;
00776 time.setFramerate( frame->GetFrameRate() );
00777 GetFramePool( )->DoneWithFrame( frame );
00778
00779 xmlChar *prop = xmlGetProp( node, ( const xmlChar* ) "clipBegin" );
00780 if ( prop )
00781 {
00782 std::string newValue = time.parseFramesToString( atoi( ( const char* ) prop ), SMIL::Time::TIME_FORMAT_CLOCK );
00783 xmlFree( prop );
00784 xmlSetProp( node, ( const xmlChar* ) "clipBegin", ( const xmlChar* ) newValue.c_str() );
00785 }
00786 prop = xmlGetProp( node, ( const xmlChar* ) "clipEnd" );
00787 if ( prop )
00788 {
00789 std::string newValue = time.parseFramesToString( atoi( ( const char* ) prop ), SMIL::Time::TIME_FORMAT_CLOCK );
00790 xmlFree( prop );
00791 xmlSetProp( node, ( const xmlChar* ) "clipEnd", ( const xmlChar* ) newValue.c_str() );
00792 }
00793 }
00794 return false;
00795 }
00796
00797 static bool convertSmilTimeToFrames( xmlNodePtr node, void *data, bool *freed )
00798 {
00799 if ( xmlStrcmp( node->name, ( const xmlChar* ) "video" ) == 0 )
00800 {
00801 Frame *frame = GetFramePool( )->GetFrame( );
00802 xmlChar *src = xmlGetProp( node, ( const xmlChar* ) "src" );
00803 string index( ( char* ) src );
00804 xmlFree( src );
00805 FileHandler *mediaFile = GetFileMap()->GetMap() [ index ];
00806 mediaFile->GetFrame( *frame, 0 );
00807 SMIL::MediaClippingTime time;
00808 time.setFramerate( frame->GetFrameRate() );
00809 GetFramePool( )->DoneWithFrame( frame );
00810
00811 xmlChar *prop = xmlGetProp( node, ( const xmlChar* ) "clipBegin" );
00812 if ( prop )
00813 {
00814 time.parseValue( ( const char* ) prop );
00815 xmlFree( prop );
00816 std::string newValue = time.toString( SMIL::Time::TIME_FORMAT_FRAMES );
00817 xmlSetProp( node, ( const xmlChar* ) "clipBegin", ( const xmlChar* ) newValue.c_str() );
00818 }
00819 prop = xmlGetProp( node, ( const xmlChar* ) "clipEnd" );
00820 if ( prop )
00821 {
00822 time.parseValue( ( const char* ) prop );
00823 xmlFree( prop );
00824 std::string newValue = time.toString( SMIL::Time::TIME_FORMAT_FRAMES );
00825 xmlSetProp( node, ( const xmlChar* ) "clipEnd", ( const xmlChar* ) newValue.c_str() );
00826 }
00827 }
00828 return false;
00829 }
00830
00831 static bool clone( xmlNodePtr node, void *data, bool *freed )
00832 {
00833 xmlNodePtr* parent = (xmlNodePtr*) data;
00834
00835 xmlNodePtr child = xmlNewNode( NULL, node->name );
00836 xmlAddChild( *parent, child );
00837 for ( xmlAttr* attr = node->properties; attr; attr = attr->next )
00838 xmlNewProp( child, attr->name, xmlGetProp( attr->parent, attr->name) );
00839 if ( node->children )
00840 *parent = child;
00841 else if ( node == node->parent->last )
00842 *parent = (*parent)->parent;
00843
00844 return false;
00845 }
00846
00861 static bool parse( xmlNodePtr node, callback func, void *p )
00862 {
00863 bool done = false;
00864
00865 while ( node != NULL && done == false )
00866 {
00867 bool freed = false;
00868 xmlNodePtr next = node->next;
00869 done = ( *func ) ( node, p, &freed );
00870 if ( !done && !freed && node->children )
00871 done = parse( node->children, func, p );
00872 node = next;
00873 }
00874 return done;
00875 }
00876
00877
00880 PlayList::PlayList() : dirty( false ), doc_name( "" ), count( 0 )
00881 {
00882 xmlNsPtr ns;
00883 xmlNodePtr root;
00884
00885
00886
00887 doc = xmlNewDoc( ( const xmlChar* ) "1.0" );
00888 root = xmlNewNode( NULL, ( const xmlChar* ) "smil" );
00889 ns = xmlNewNs( root, SMIL20_NAMESPACE_HREF, ( const xmlChar* ) NULL );
00890 xmlDocSetRootElement( doc, root );
00891 xmlAddChild( root, xmlNewNode( NULL, ( const xmlChar* ) "body" ) );
00892 }
00893
00894
00897 PlayList::PlayList( const PlayList& playList )
00898 {
00899 xmlNsPtr ns;
00900 xmlNodePtr root;
00901
00902 doc = xmlNewDoc( ( const xmlChar* ) "1.0" );
00903 root = xmlNewNode( NULL, ( const xmlChar* ) "smil" );
00904 ns = xmlNewNs( root, ( const xmlChar* ) SMIL20_NAMESPACE_HREF, ( const xmlChar* ) NULL );
00905 xmlDocSetRootElement( doc, root );
00906 parse( playList.GetBody(), clone, &root );
00907 dirty = playList.dirty;
00908 doc_name = playList.GetDocName( );
00909 RefreshCount( );
00910 }
00911
00912
00915 PlayList& PlayList::operator=( const PlayList& playList )
00916 {
00917
00918
00919 if ( doc != playList.doc )
00920 {
00921 xmlNsPtr ns;
00922 xmlNodePtr root;
00923
00924 xmlFreeDoc( doc );
00925 doc = xmlNewDoc( ( const xmlChar* ) "1.0" );
00926 root = xmlNewNode( NULL, ( const xmlChar* ) "smil" );
00927 ns = xmlNewNs( root, ( const xmlChar* ) SMIL20_NAMESPACE_HREF, ( const xmlChar* ) NULL );
00928 xmlDocSetRootElement( doc, root );
00929 parse( playList.GetBody(), clone, &root );
00930 dirty = playList.dirty;
00931 doc_name = playList.GetDocName( );
00932 RefreshCount( );
00933 }
00934 return *this;
00935 }
00936
00937
00941 PlayList::~PlayList()
00942 {
00943
00944 if ( doc != NULL )
00945 {
00946 xmlFreeDoc( doc );
00947 doc = NULL;
00948 }
00949 }
00950
00955 xmlNodePtr PlayList::GetBody( ) const
00956 {
00957 return xmlDocGetRootElement( doc )->children;
00958 }
00959
00960
00961 void PlayList::RefreshCount( )
00962 {
00963 count = 0;
00964 if ( doc != NULL )
00965 parse( GetBody(), countFrames, &count );
00966 }
00967
00972 int PlayList::GetNumFrames() const
00973 {
00974 return count;
00975 }
00976
00977
00978 char* PlayList::GetFileNameOfFrame( int frameNum ) const
00979 {
00980
00981 MovieInfo data;
00982
00983 memset( &data, 0, sizeof( MovieInfo ) );
00984 data.absBegin = 0;
00985 data.absEnd = 0;
00986 data.absFrame = frameNum;
00987
00988 parse( GetBody(), findFile, &data );
00989 return strdup( data.fileName );
00990 }
00991
00992
01002 bool PlayList::GetFrame( int frameNum, Frame &frame )
01003 {
01004 MovieInfo data;
01005
01006
01007
01008 memset( &data, 0, sizeof( MovieInfo ) );
01009 data.absBegin = 0;
01010 data.absEnd = 0;
01011 data.absFrame = frameNum;
01012
01013 parse( GetBody(), findFile, &data );
01014
01015 if ( strcmp( data.fileName, "" ) )
01016 {
01017
01018
01019 string index( ( char * ) data.fileName );
01020 FileHandler *mediaFile = GetFileMap() ->GetMap() [ index ];
01021 if ( data.clipFrame >= mediaFile->GetTotalFrames() )
01022 data.clipFrame = mediaFile->GetTotalFrames() - 1;
01023 return ( mediaFile->GetFrame( frame, data.clipFrame ) >= 0 );
01024 }
01025
01026 return false;
01027 }
01028
01029
01036 bool PlayList::GetMediaObject( int frameNum, FileHandler **media )
01037 {
01038 MovieInfo data;
01039
01040 memset( &data, 0, sizeof( MovieInfo ) );
01041 data.absBegin = 0;
01042 data.absEnd = 0;
01043 data.absFrame = frameNum;
01044
01045 parse( GetBody(), findFile, &data );
01046
01047 if ( strcmp( data.fileName, "" ) )
01048 {
01049
01050 string index( ( char * ) data.fileName );
01051 *media = GetFileMap() ->GetMap() [ index ];
01052 return true;
01053 }
01054
01055 return false;
01056 }
01057
01058
01059 int PlayList::GetClipBegin( int frameNum ) const
01060 {
01061 MovieInfo data;
01062
01063 memset( &data, 0, sizeof( MovieInfo ) );
01064 data.absBegin = 0;
01065 data.absEnd = 0;
01066 data.absFrame = frameNum;
01067
01068 if ( parse( GetBody(), findSceneStart, &data ) )
01069 return data.clipBegin;
01070 else
01071 return 0;
01072 }
01073
01074
01075 int PlayList::GetClipEnd( int frameNum ) const
01076 {
01077 MovieInfo data;
01078
01079 memset( &data, 0, sizeof( MovieInfo ) );
01080 data.absBegin = 0;
01081 data.absEnd = 0;
01082 data.absFrame = frameNum;
01083
01084 if ( parse( GetBody(), findSceneEnd, &data ) )
01085 return data.clipEnd;
01086 else
01087 return 0;
01088 }
01089
01090
01091 bool PlayList::SetClipBegin( int frameNum, const char* value )
01092 {
01093 MovieInfo data;
01094
01095 memset( &data, 0, sizeof( MovieInfo ) );
01096 data.absBegin = 0;
01097 data.absEnd = 0;
01098 data.absFrame = frameNum;
01099
01100 if ( parse( GetBody(), findSceneStart, &data ) )
01101 {
01102 xmlSetProp( data.video, ( const xmlChar * ) "clipBegin", ( const xmlChar * ) value );
01103 RefreshCount( );
01104 return true;
01105 }
01106 else
01107 return false;
01108 }
01109
01110
01111 bool PlayList::SetClipEnd( int frameNum, const char* value )
01112 {
01113 MovieInfo data;
01114
01115 memset( &data, 0, sizeof( MovieInfo ) );
01116 data.absBegin = 0;
01117 data.absEnd = 0;
01118 data.absFrame = frameNum;
01119
01120 if ( parse( GetBody(), findSceneEnd, &data ) )
01121 {
01122 xmlSetProp( data.video, ( const xmlChar * ) "clipEnd", ( const xmlChar * ) value );
01123 RefreshCount( );
01124 return true;
01125 }
01126 else
01127 return false;
01128 }
01129
01130
01131 int PlayList::FindStartOfScene( int frameNum ) const
01132 {
01133 MovieInfo data;
01134
01135
01136
01137 memset( &data, 0, sizeof( MovieInfo ) );
01138 data.absBegin = 0;
01139 data.absEnd = 0;
01140 data.absFrame = frameNum;
01141
01142 parse( GetBody(), findSceneStart, &data );
01143
01144 if ( strcmp( data.fileName, "" ) )
01145 return data.absBegin;
01146 else
01147 return 0;
01148 }
01149
01150
01151 int PlayList::FindEndOfScene( int frameNum ) const
01152 {
01153 MovieInfo data;
01154
01155
01156
01157 data.absBegin = 0;
01158 data.absEnd = 0;
01159 data.absFrame = frameNum;
01160
01161 parse( GetBody(), findSceneEnd, &data );
01162
01163 if ( strcmp( data.fileName, "" ) )
01164 return data.absEnd;
01165 else
01166 return 999999;
01167 }
01168
01169
01170 void PlayList::AutoSplit( int start, int end )
01171 {
01172 MovieInfo firstFile;
01173 MovieInfo lastFile;
01174 Frame *frame = GetFramePool( ) ->GetFrame( );
01175 struct tm recDate;
01176 time_t startTime;
01177 time_t endTime;
01178
01179
01180
01181
01182 memset( &firstFile, 0, sizeof( MovieInfo ) );
01183 firstFile.absBegin = 0;
01184 firstFile.absEnd = 0;
01185 firstFile.absFrame = start;
01186
01187 parse( GetBody(), findFile, &firstFile );
01188 string index1( ( char* ) firstFile.fileName );
01189 FileHandler *mediaFile1 = GetFileMap() ->GetMap() [ index1 ];
01190 mediaFile1->GetFrame( *frame, firstFile.clipFrame );
01191 frame->GetRecordingDate( recDate );
01192 startTime = mktime( &recDate );
01193
01194 memset( &lastFile, 0, sizeof( MovieInfo ) );
01195 lastFile.absBegin = 0;
01196 lastFile.absEnd = 0;
01197 lastFile.absFrame = end;
01198
01199 parse( GetBody(), findFile, &lastFile );
01200
01201 string index2( ( char* ) lastFile.fileName );
01202 FileHandler *mediaFile2 = GetFileMap() ->GetMap() [ index2 ];
01203 mediaFile2->GetFrame( *frame, lastFile.clipFrame );
01204 frame->GetRecordingDate( recDate );
01205 endTime = mktime( &recDate );
01206
01207 int fps = frame->IsPAL() ? 25 : 30;
01208
01209 GetFramePool( ) ->DoneWithFrame( frame );
01210
01211
01212 if ( startTime < 0 || endTime < 0 )
01213 return ;
01214
01215 AutoSplit ( start, startTime, end, endTime, fps );
01216 }
01217
01218
01219 void PlayList::AutoSplit( int start, time_t startTime, int end, time_t endTime, int fps )
01220 {
01221 time_t diffTime = static_cast<time_t>( difftime( endTime, startTime ) );
01222 if ( ( ( diffTime * fps ) - ( end - start ) ) > fps || diffTime < 0.0 )
01223 {
01224 if ( ( end - start ) > 1 )
01225 {
01226 time_t mid = start + ( end - start ) / 2;
01227 time_t midTime;
01228
01229 {
01230 MovieInfo midFile;
01231 struct tm recDate;
01232 Frame *frame = GetFramePool( ) ->GetFrame( );
01233
01234 memset( &midFile, 0, sizeof( MovieInfo ) );
01235 midFile.absFrame = mid;
01236
01237 parse( GetBody(), findFile, &midFile );
01238
01239 string index( ( char* ) midFile.fileName );
01240 FileHandler *mediaFile = GetFileMap() ->GetMap() [ index ];
01241 mediaFile->GetFrame( *frame, midFile.clipFrame );
01242 frame->GetRecordingDate( recDate );
01243 midTime = mktime( &recDate );
01244
01245 GetFramePool( ) ->DoneWithFrame( frame );
01246 }
01247
01248
01249 if ( midTime < 0 )
01250 return ;
01251
01252 AutoSplit ( start, startTime, mid, midTime, fps );
01253 AutoSplit ( mid, midTime, end, endTime, fps );
01254 }
01255 else
01256 {
01257 SplitSceneBefore( end );
01258 }
01259 }
01260 }
01261
01262
01263 bool PlayList::SplitSceneBefore( int frameNum )
01264 {
01265 MovieInfo data;
01266
01267
01268
01269 if ( GetNumFrames() == 0 )
01270 return false;
01271
01272 memset( &data, 0, sizeof( MovieInfo ) );
01273 data.absBegin = 0;
01274 data.absEnd = 0;
01275 data.absFrame = frameNum;
01276 parse( GetBody(), findSceneStart, &data );
01277 int begin = data.absBegin;
01278
01279 memset( &data, 0, sizeof( MovieInfo ) );
01280 data.absBegin = 0;
01281 data.absEnd = 0;
01282 data.absFrame = frameNum;
01283 parse( GetBody(), findSceneEnd, &data );
01284 int end = data.absEnd;
01285
01286 if ( strcmp( data.fileName, "" ) && begin != frameNum )
01287 {
01288
01289 dirty = true;
01290
01291
01292 xmlNode *firstSequence = data.sequence;
01293 PlayList playlist;
01294 GetPlayList( frameNum, end, playlist );
01295
01296
01297 xmlAddNextSibling( firstSequence, playlist.GetBody()->children );
01298
01299
01300 Delete( frameNum, end );
01301
01302 return true;
01303 }
01304 else
01305 {
01306 return false;
01307 }
01308 }
01309
01310 bool PlayList::JoinScenesAt( int frameNum )
01311 {
01312 MovieInfo scene1;
01313 MovieInfo scene2;
01314 MovieInfo scene2end;
01315
01316 if ( GetNumFrames() == 0 )
01317 return false;
01318
01319
01320
01321 memset( &scene1, 0, sizeof( MovieInfo ) );
01322 scene1.absBegin = 0;
01323 scene1.absEnd = 0;
01324 scene1.absFrame = frameNum;
01325 parse( GetBody(), findSceneStart, &scene1 );
01326
01327 memset( &scene2, 0, sizeof( MovieInfo ) );
01328 scene2.absBegin = 0;
01329 scene2.absEnd = 0;
01330 scene2.absFrame = frameNum;
01331 parse( GetBody(), findSceneEnd, &scene2 );
01332 int end = scene2.absEnd + 1;
01333
01334 memset( &scene2end, 0, sizeof( MovieInfo ) );
01335 scene2end.absBegin = 0;
01336 scene2end.absEnd = 0;
01337 scene2end.absFrame = end;
01338 parse( GetBody(), findSceneEnd, &scene2end );
01339
01340 if ( scene1.sequence != scene2end.sequence )
01341 {
01342
01343 dirty = true;
01344
01345
01346
01347
01348
01349 xmlNode *lastchild = xmlGetLastChild( scene1.sequence );
01350 xmlNodePtr next = NULL;
01351 for ( xmlNodePtr ptr = scene2end.sequence->children; ptr != NULL; ptr = next )
01352 {
01353 next = ptr->next;
01354 lastchild = xmlAddNextSibling( lastchild, ptr );
01355 ptr = next;
01356 }
01357
01358 for ( xmlAttr* attr = scene2end.sequence->properties; attr; attr = attr->next )
01359 {
01360 const char *valueB = ( const char* ) xmlGetProp( attr->parent, ( const xmlChar * ) attr->name );
01361
01362 if ( valueB && strcmp( valueB, "" ) )
01363 {
01364
01365 const char *valueA = ( const char* ) xmlGetProp( scene1.sequence, ( const xmlChar * ) attr->name );
01366 if ( valueA && strcmp( valueA, "" ) )
01367 {
01368 xmlChar* value = new xmlChar[ strlen(valueA) + strlen(valueB) + 1 ];
01369 strcpy( (char*) value, (const char*) valueA );
01370 strcat( (char*) value, " " );
01371 strcat( (char*) value, (const char*) valueB );
01372 xmlSetProp( scene1.sequence, attr->name, ( const xmlChar * ) value );
01373 delete[] value;
01374 }
01375 else
01376 {
01377 xmlSetProp( scene1.sequence, attr->name, ( const xmlChar * ) valueB );
01378 }
01379 }
01380 }
01381 xmlUnlinkNode( scene2end.sequence );
01382 xmlFreeNode( scene2end.sequence );
01383 RefreshCount( );
01384
01385 return true;
01386 }
01387 else
01388 {
01389 return false;
01390 }
01391 }
01392
01393
01405 bool PlayList::GetPlayList( int first, int last, PlayList &playlist ) const
01406 {
01407 MovieInfo firstFile, lastFile;
01408 bool copyFlag = false;
01409
01410 if ( GetNumFrames() == 0 )
01411 return false;
01412
01413 playlist.dirty = false;
01414
01415
01416
01417 memset( &firstFile, 0, sizeof( MovieInfo ) );
01418 firstFile.absBegin = 0;
01419 firstFile.absEnd = 0;
01420 firstFile.absFrame = first;
01421
01422 parse( GetBody(), findFile, &firstFile );
01423
01424 memset( &lastFile, 0, sizeof( MovieInfo ) );
01425 lastFile.absBegin = 0;
01426 lastFile.absEnd = 0;
01427 lastFile.absFrame = last;
01428
01429 parse( GetBody(), findFile, &lastFile );
01430
01431 if ( strcmp( firstFile.fileName, "" ) && strcmp( lastFile.fileName, "" ) )
01432 {
01433
01434 xmlNodePtr srcNode = GetBody();
01435 xmlNodePtr dstNode = playlist.GetBody();
01436 xmlNodePtr nextSeq = NULL;
01437
01438 for ( xmlNodePtr srcSeq = srcNode->children; srcSeq != NULL; srcSeq = nextSeq )
01439 {
01440 nextSeq = srcSeq->next;
01441 if ( xmlStrcmp( srcSeq->name, ( const xmlChar* ) "seq" ) == 0 )
01442 {
01443 xmlNodePtr seq = xmlNewNode( NULL, ( const xmlChar* ) "seq" );
01444 xmlAddChild( dstNode, seq );
01445 xmlNodePtr nextVideo = NULL;
01446
01447 for ( xmlNodePtr srcVideo = srcSeq->children; srcVideo != NULL; srcVideo = nextVideo )
01448 {
01449 nextVideo = srcVideo->next;
01450 if ( xmlStrcmp( srcVideo->name, ( const xmlChar* ) "video" ) == 0 )
01451 {
01452
01453
01454
01455 if ( copyFlag && srcVideo != firstFile.video && srcVideo != lastFile.video )
01456 {
01457 xmlNodePtr video = xmlNewNode( NULL, ( const xmlChar* ) "video" );
01458 xmlAddChild( seq, video );
01459 for ( xmlAttr* attr = srcVideo->properties; attr; attr = attr->next )
01460 xmlNewProp( video, attr->name, xmlGetProp( attr->parent, attr->name) );
01461 }
01462
01463
01464
01465 else if ( srcVideo == firstFile.video && srcVideo != lastFile.video )
01466 {
01467
01468 ostringstream sb1, sb2;
01469
01470 xmlNodePtr video = xmlNewNode( NULL, ( const xmlChar* ) "video" );
01471 xmlNewProp( video, ( const xmlChar* ) "src", ( const xmlChar* ) firstFile.fileName );
01472 sb1 << firstFile.clipFrame << ends;
01473 xmlNewProp( video, ( const xmlChar* ) "clipBegin", ( const xmlChar* ) sb1.str().c_str() );
01474 sb2 << firstFile.clipEnd << ends;
01475 xmlNewProp( video, ( const xmlChar* ) "clipEnd", ( const xmlChar* ) sb2.str().c_str() );
01476 xmlAddChild( seq, video );
01477 copyFlag = true;
01478 }
01479
01480
01481
01482 else if ( srcVideo != firstFile.video && srcVideo == lastFile.video )
01483 {
01484
01485 ostringstream sb1, sb2;
01486
01487 xmlNodePtr video = xmlNewNode( NULL, ( const xmlChar* ) "video" );
01488 xmlNewProp( video, ( const xmlChar* ) "src", ( const xmlChar* ) lastFile.fileName );
01489 sb1 << lastFile.clipBegin << ends;
01490 xmlNewProp( video, ( const xmlChar* ) "clipBegin", ( const xmlChar* ) sb1.str().c_str() );
01491 sb2 << lastFile.clipFrame << ends;
01492 xmlNewProp( video, ( const xmlChar* ) "clipEnd", ( const xmlChar* ) sb2.str().c_str() );
01493 xmlAddChild( seq, video );
01494 copyFlag = false;
01495 }
01496
01497
01498
01499 else if ( srcVideo == firstFile.video && srcVideo == lastFile.video )
01500 {
01501
01502 ostringstream sb1, sb2;
01503
01504 xmlNodePtr video = xmlNewNode( NULL, ( const xmlChar* ) "video" );
01505 xmlNewProp( video, ( const xmlChar* ) "src", ( const xmlChar* ) firstFile.fileName );
01506 sb1 << firstFile.clipFrame << ends;
01507 xmlNewProp( video, ( const xmlChar* ) "clipBegin", ( const xmlChar* ) sb1.str().c_str() );
01508 sb2 << lastFile.clipFrame << ends;
01509 xmlNewProp( video, ( const xmlChar* ) "clipEnd", ( const xmlChar* ) sb2.str().c_str() );
01510 xmlAddChild( seq, video );
01511 }
01512 }
01513 }
01514
01515
01516
01517 if ( seq->children == NULL )
01518 {
01519 xmlUnlinkNode( seq );
01520 xmlFreeNode( seq );
01521 }
01522 else
01523
01524 {
01525 for ( xmlAttr* attr = srcSeq->properties; attr; attr = attr->next )
01526 xmlNewProp( seq, attr->name, xmlGetProp( attr->parent, attr->name) );
01527 }
01528 }
01529 }
01530
01531 string path = directory_utils::get_directory_from_file( GetDocName() );
01532 parse( playlist.GetBody(), fillMap, &path );
01533 }
01534 playlist.RefreshCount( );
01535 return true;
01536 }
01537
01538
01550 bool PlayList::InsertPlayList( PlayList &playlist, int before )
01551 {
01552
01553
01554 if ( playlist.GetNumFrames() == 0 )
01555 return false;
01556
01557
01558 string path = directory_utils::get_directory_from_file( GetDocName() );
01559 parse( playlist.GetBody(), fillMap, &path );
01560
01561 MovieInfo file;
01562
01563 memset( &file, 0, sizeof( MovieInfo ) );
01564 file.absBegin = 0;
01565 file.absEnd = 0;
01566 file.absFrame = before;
01567 file.sequence = NULL;
01568 file.video = NULL;
01569
01570
01571 parse( GetBody(), findFile, &file );
01572
01573 xmlNodePtr node = playlist.GetBody();
01574 bool first = true;
01575 xmlNodePtr next = NULL;
01576 xmlNodePtr sequence = file.sequence;
01577
01578 if ( GetNumFrames() > 0 )
01579 {
01580 dirty = true;
01581 }
01582 else
01583 {
01584 dirty = playlist.dirty;
01585
01586 if ( doc_name == "" )
01587 doc_name = playlist.GetDocName( );
01588
01589 }
01590
01591 for ( xmlNodePtr ptr = node->children; ptr != NULL; ptr = next )
01592 {
01593
01594
01595
01596
01597
01598
01599 next = ptr->next;
01600
01601
01602
01603
01604 if ( first && sequence == NULL )
01605 {
01606
01607 xmlNodePtr tmp = xmlNewNode( NULL, ( const xmlChar* ) "seq" );
01608 xmlAddChild( GetBody(), tmp );
01609 sequence = xmlAddNextSibling( tmp, ptr );
01610 xmlUnlinkNode( tmp );
01611 xmlFreeNode( tmp );
01612 }
01613 else if ( first && before == file.absBegin && before != ( file.absEnd + 1 ) )
01614 {
01615
01616 sequence = xmlAddPrevSibling( sequence, ptr );
01617 }
01618 else if ( first && before != ( file.absEnd + 1 ) )
01619 {
01620
01621
01622
01623
01624
01625
01626 SplitSceneBefore( before );
01627
01628
01629 memset( &file, 0, sizeof( MovieInfo ) );
01630 file.absBegin = 0;
01631 file.absFrame = before;
01632 file.sequence = NULL;
01633 file.video = NULL;
01634
01635 parse( GetBody(), findFile, &file );
01636
01637
01638
01639
01640
01641
01642 sequence = xmlAddPrevSibling( file.sequence, ptr );
01643 }
01644 else
01645 {
01646
01647 sequence = xmlAddNextSibling( sequence, ptr );
01648 }
01649
01650
01651 first = false;
01652 }
01653
01654 RefreshCount( );
01655 return true;
01656 }
01657
01658
01659 bool PlayList::Delete( int first, int last )
01660 {
01661 int absClipBegin;
01662 int clipBegin;
01663 int clipEnd;
01664 static int firstCall = 0;
01665
01666
01667
01668
01669
01670 if ( GetNumFrames() == 0 )
01671 return false;
01672
01673 if ( firstCall == 0 )
01674 {
01675 firstCall = 1;
01676 SplitSceneBefore( first );
01677 firstCall = 0;
01678 }
01679
01680 xmlNodePtr srcNode = GetBody();
01681 absClipBegin = 0;
01682 xmlNodePtr nextSequence = NULL;
01683 for ( xmlNodePtr srcSeq = srcNode->children; srcSeq != NULL; srcSeq = nextSequence )
01684 {
01685
01686 dirty = true;
01687
01688
01689 nextSequence = srcSeq->next;
01690
01691 if ( xmlStrcmp( srcSeq->name, ( const xmlChar* ) "seq" ) == 0 )
01692 {
01693 xmlNodePtr nextVideo = NULL;
01694
01695 for ( xmlNodePtr srcVideo = srcSeq->children; srcVideo != NULL; srcVideo = nextVideo )
01696 {
01697
01698
01699 nextVideo = srcVideo->next;
01700
01701 if ( xmlStrcmp( srcVideo->name, ( const xmlChar* ) "video" ) == 0 )
01702 {
01703
01704 ostringstream sb1, sb2;
01705 xmlChar *s;
01706
01707 sb1 << ( s = xmlGetProp( srcVideo, ( const xmlChar* ) "clipBegin" ) ) << ends;
01708 clipBegin = atoi( sb1.str().c_str() );
01709 if ( s )
01710 xmlFree( s );
01711 s = xmlGetProp( srcVideo, ( const xmlChar* ) "clipEnd" );
01712 clipEnd = atoi( ( char * ) s );
01713 sb2 << ( s = xmlGetProp( srcVideo, ( const xmlChar* ) "clipEnd" ) ) << ends;
01714 clipEnd = atoi( sb2.str().c_str() );
01715 if ( s )
01716 xmlFree( s );
01717
01718
01719
01720 if ( first <= absClipBegin && last >= absClipBegin + clipEnd - clipBegin )
01721 {
01722 xmlUnlinkNode( srcVideo );
01723 xmlFreeNode( srcVideo );
01724
01725 }
01726
01727
01728
01729
01730 else if ( first <= absClipBegin && last >= absClipBegin && last <= absClipBegin + clipEnd - clipBegin )
01731 {
01732
01733 ostringstream sb;
01734
01735 sb << last - absClipBegin + clipBegin + 1 << ends;
01736 xmlSetProp( srcVideo, ( const xmlChar* ) "clipBegin", ( const xmlChar* ) sb.str().c_str() );
01737
01738 }
01739
01740
01741
01742
01743 else if ( first > absClipBegin && first <= absClipBegin + clipEnd - clipBegin && last >= absClipBegin + clipEnd - clipBegin )
01744 {
01745
01746 ostringstream sb;
01747
01748 sb << first - absClipBegin + clipBegin - 1 << ends;
01749 xmlSetProp( srcVideo, ( const xmlChar* ) "clipEnd", ( const xmlChar* ) sb.str().c_str() );
01750
01751 }
01752
01753
01754
01755
01756
01757 else if ( first > absClipBegin && last < absClipBegin + clipEnd - clipBegin )
01758 {
01759
01760 ostringstream sb1, sb2;
01761 xmlChar *s;
01762
01763 xmlNodePtr video = xmlNewNode( NULL, ( const xmlChar* ) "video" );
01764 xmlNewProp( video, ( const xmlChar* ) "src", ( s = xmlGetProp( srcVideo, ( const xmlChar* ) "src" ) ) );
01765 if ( s )
01766 xmlFree( s );
01767 sb1 << last - absClipBegin + clipBegin + 1 << ends;
01768 xmlNewProp( video, ( const xmlChar* ) "clipBegin", ( const xmlChar* ) sb1.str().c_str() );
01769 xmlNewProp( video, ( const xmlChar* ) "clipEnd", ( s = xmlGetProp( srcVideo, ( const xmlChar* ) "clipEnd" ) ) );
01770 if ( s )
01771 xmlFree( s );
01772 xmlAddNextSibling( srcVideo, video );
01773 sb2 << first - absClipBegin + clipBegin - 1 << ends;
01774 xmlSetProp( srcVideo, ( const xmlChar* ) "clipEnd", ( const xmlChar* ) sb2.str().c_str() );
01775
01776 }
01777
01778 absClipBegin += clipEnd - clipBegin + 1;
01779 }
01780 }
01781
01782
01783
01784 if ( srcSeq->children == NULL )
01785 {
01786 xmlUnlinkNode( srcSeq );
01787 xmlFreeNode( srcSeq );
01788 }
01789 }
01790 }
01791
01792 RefreshCount( );
01793
01794 return true;
01795 }
01796
01797
01798 bool PlayList::LoadMediaObject( char *filename )
01799 {
01800
01801
01802 xmlNodePtr seq;
01803 xmlNodePtr node;
01804 ostringstream sb;
01805 FileHandler *mediaFile = NULL;
01806 int existingFrames;
01807 int framesInFile;
01808
01809 dirty = true;
01810
01811
01812 string index = directory_utils::get_absolute_path_to_file( "", ( char * ) filename );
01813 if ( GetFileMap() ->GetMap().find( index ) == GetFileMap() ->GetMap().end( ) )
01814 {
01815 if ( strrchr( filename, '.' ) )
01816 {
01817 if ( strncasecmp( strrchr( filename, '.' ), ".avi", 4 ) == 0 )
01818 mediaFile = new AVIHandler();
01819 else if ( strncasecmp( strrchr( filename, '.' ), ".dv", 3 ) == 0 ||
01820 strncasecmp( strrchr( filename, '.' ), ".dif", 4 ) == 0 )
01821 mediaFile = new RawHandler();
01822 #ifdef HAVE_LIBQUICKTIME
01823 else if ( strncasecmp( strrchr( filename, '.' ), ".mov", 4 ) == 0 )
01824 mediaFile = new QtHandler();
01825 #endif
01826 }
01827
01828 if ( mediaFile == NULL )
01829 return false;
01830 if ( mediaFile->Open( filename ) == false )
01831 return false;
01832 GetFileMap() ->GetMap() [ index ] = mediaFile;
01833 }
01834 else
01835 {
01836 mediaFile = GetFileMap() ->GetMap() [ index ];
01837 }
01838
01839 framesInFile = mediaFile->GetTotalFrames();
01840 existingFrames = GetNumFrames();
01841
01842 seq = xmlNewNode( NULL, ( const xmlChar* ) "seq" );
01843 xmlAddChild( GetBody(), seq );
01844 node = xmlNewNode( NULL, ( const xmlChar* ) "video" );
01845 xmlNewProp( node, ( const xmlChar* ) "src", ( const xmlChar* ) index.c_str() );
01846 xmlNewProp( node, ( const xmlChar* ) "clipBegin", ( const xmlChar* ) "0" );
01847 sb << framesInFile - 1 << ends;
01848 xmlNewProp( node, ( const xmlChar* ) "clipEnd", ( const xmlChar* ) sb.str().c_str() );
01849 xmlAddChild( seq, node );
01850
01851 if ( framesInFile > 0 )
01852 {
01853 RefreshCount( );
01854 AutoSplit( existingFrames, existingFrames + framesInFile - 1 );
01855 }
01856 return true;
01857 }
01858
01859
01860 bool PlayList::LoadPlayList( char *filename )
01861 {
01862
01863
01864 dirty = false;
01865
01866 xmlNsPtr ns;
01867 xmlNodePtr node;
01868
01869 xmlFreeDoc( doc );
01870 doc = xmlParseFile( filename );
01871 if ( !doc )
01872 {
01873 cerr << "file does not exist or failed to parse XML" << endl;
01874 return false;
01875 }
01876
01877 node = xmlDocGetRootElement( doc );
01878 if ( node == NULL )
01879 {
01880 cerr << "empty document" << endl;
01881 xmlFreeDoc( doc );
01882 doc = NULL;
01883 return false;
01884 }
01885 ns = xmlSearchNsByHref( doc, node, SMIL20_NAMESPACE_HREF );
01886 if ( ns == NULL )
01887 {
01888 cerr << "document of the wrong type, Namespace not found" << endl;
01889 xmlFreeDoc( doc );
01890 doc = NULL;
01891 return false;
01892 }
01893 if ( xmlStrcmp( node->name, ( const xmlChar * ) "smil" ) )
01894 {
01895 cerr << "document of the wrong type, root node != smil" << endl;
01896 xmlFreeDoc( doc );
01897 doc = NULL;
01898 return false;
01899 }
01900 CleanPlayList( node );
01901
01902
01903 string path = directory_utils::get_directory_from_file( filename );
01904 parse( GetBody(), fillMap, &path );
01905 dirty = false;
01906
01907
01908 if ( xmlSearchNs( doc, node, ( const xmlChar * ) "smil2" ) == NULL )
01909 {
01910
01911
01912 parse( node, convertSmilTimeToFrames, NULL );
01913 }
01914 else
01915 {
01916
01917 xmlNodePtr root = xmlDocGetRootElement( doc );
01918 xmlNodePtr seq = root->children;
01919 if ( !seq )
01920 return false;
01921 if ( xmlStrcmp( seq->name, ( const xmlChar* ) "seq" ) == 0 )
01922 {
01923 xmlNodePtr body = xmlNewNode( NULL, ( const xmlChar * ) "body" );
01924 while ( seq )
01925 {
01926 xmlNodePtr next = seq->next;
01927 xmlUnlinkNode( seq );
01928 xmlAddChild( body, seq );
01929 seq = next;
01930 }
01931 xmlAddChild( root, body );
01932 }
01933 dirty = true;
01934 }
01935
01936 RefreshCount( );
01937
01938 return true;
01939 }
01940
01941 static bool relativeMap( xmlNodePtr node, void *p, bool *freed )
01942 {
01943 if ( xmlStrcmp( node->name, ( const xmlChar* ) "video" ) == 0 )
01944 {
01945
01946 xmlChar * src = xmlGetProp( node, ( const xmlChar* ) "src" );
01947
01948 if ( src != NULL )
01949 {
01950
01951 string & directory = *( string * ) p;
01952 string index = directory_utils::get_relative_path_to_file( directory, ( char * ) src );
01953
01954
01955 xmlSetProp( node, ( const xmlChar* ) "src", ( xmlChar * ) index.c_str() );
01956 }
01957
01958 xmlFree( src );
01959 }
01960 return false;
01961 }
01962
01963
01964 bool PlayList::SavePlayList( char *filename, bool isLegacyFormat )
01965 {
01966
01967 bool ret = false;
01968
01969 xmlDocPtr copy_doc = xmlNewDoc( ( const xmlChar* ) "1.0" );
01970 xmlNodePtr root = xmlNewNode( NULL, ( const xmlChar* ) "smil" );
01971 xmlNewNs( root, ( const xmlChar* ) SMIL20_NAMESPACE_HREF, ( const xmlChar* ) NULL );
01972 xmlDocSetRootElement( copy_doc, root );
01973
01974 if ( isLegacyFormat )
01975 {
01976
01977 parse( this->GetBody()->children, clone, &root );
01978
01979
01980 xmlNewNs( xmlDocGetRootElement( copy_doc ), SMIL20_NAMESPACE_HREF, ( const xmlChar* ) "smil2" );
01981 }
01982 else
01983 {
01984
01985 parse( this->GetBody(), clone, &root );
01986
01987
01988 parse( copy_doc->children, convertFramesToSmilTime, NULL );
01989 }
01990
01991 if ( Preferences::getInstance().relativeSave )
01992 {
01993
01994 string path = directory_utils::get_directory_from_file( filename );
01995
01996 parse( copy_doc->children, relativeMap, &path );
01997
01998 ret = xmlSaveFormatFile( filename, copy_doc, 1 ) != -1;
01999 }
02000 else
02001 {
02002
02003 ret = xmlSaveFormatFile( filename, copy_doc, 1 ) != -1;
02004 }
02005
02006 xmlFreeDoc( copy_doc );
02007
02008
02009 if ( !isLegacyFormat && ret )
02010 {
02011
02012
02013 if ( doc_name == "" )
02014 {
02015 doc_name = string( filename );
02016 dirty = false;
02017 GetEditorBackup( ) ->SetAllDirty( );
02018 }
02019
02020
02021 else if ( !strcmp( filename, doc_name.c_str() ) )
02022 {
02023 dirty = false;
02024 GetEditorBackup( ) ->SetAllDirty( );
02025 }
02026
02027 }
02028
02029 return ret;
02030 }
02031
02042 bool PlayList::SavePlayListEli( char * filename, bool isPAL )
02043 {
02044 EliInfos eli;
02045 if ( doc != NULL )
02046 {
02047 parse( GetBody(), convertEli, &eli );
02048 }
02049
02050
02051 ofstream eli_file( filename );
02052 if ( !eli_file )
02053 {
02054 return false;
02055 }
02056
02057 eli_file << "LAV Edit List" << endl;
02058 eli_file << ( isPAL ? "PAL" : "NTSC" ) << endl;
02059
02060
02061 eli_file << eli.size() << endl;
02062
02063
02064 EliInfosIterator End = eli.end();
02065 EliInfosIterator i;
02066 for ( i = eli.begin(); i != End; i++ )
02067 {
02068 eli_file << ( *i ).file << endl;
02069 }
02070
02071
02072 int count = 0;
02073 for ( i = eli.begin(); i != End; i++ )
02074 {
02075 eli_file << count
02076 << " " << ( *i ).clipBegin
02077 << " " << ( *i ).clipEnd << endl;
02078 ++count;
02079 }
02080
02081
02082 if ( eli_file.bad() )
02083 {
02084 return false;
02085 }
02086
02087
02088 eli_file.close();
02089
02090 return true;
02091 }
02092
02093
02094 bool PlayList::SavePlayListSrt( const char* filename )
02095 {
02096 SrtContext srt( filename );
02097
02098
02099 if ( !srt.file )
02100 {
02101 return false;
02102 }
02103 if ( doc )
02104 {
02105 parse( GetBody(), convertSrt, &srt );
02106 }
02107
02108 return !srt.file.bad();
02109 }
02110
02111
02121 void PlayList::CleanPlayList( xmlNodePtr node )
02122 {
02123 while ( node != NULL )
02124 {
02125
02126 xmlNodePtr nodeToDelete = NULL;
02127
02128 CleanPlayList( node->children );
02129 if ( xmlStrcmp( node->name, ( const xmlChar* ) "smil" ) == 0 )
02130 {
02131
02132 }
02133 else if ( xmlStrcmp( node->name, ( const xmlChar* ) "body" ) == 0 )
02134 {
02135
02136 }
02137 else if ( xmlStrcmp( node->name, ( const xmlChar* ) "seq" ) == 0 )
02138 {
02139 if ( node->children == NULL )
02140 {
02141 nodeToDelete = node;
02142 }
02143 }
02144 else if ( xmlStrcmp( node->name, ( const xmlChar* ) "video" ) == 0 )
02145 {
02146
02147 }
02148 else
02149 nodeToDelete = node;
02150 node = node->next;
02151
02152 if ( nodeToDelete != NULL )
02153 {
02154 xmlUnlinkNode( nodeToDelete );
02155 xmlFreeNode( nodeToDelete );
02156 }
02157 }
02158 RefreshCount( );
02159 }
02160
02164 void PlayList::CleanPlayList( )
02165 {
02166 if ( GetNumFrames() > 0 )
02167 Delete( 0, GetNumFrames() );
02168 dirty = false;
02169 doc_name = "";
02170 RefreshCount( );
02171 }
02172
02180 static bool checkIfFileUsed( xmlNodePtr node, void *p, bool *freed )
02181 {
02182 if ( xmlStrcmp( node->name, ( const xmlChar* ) "video" ) == 0 )
02183 {
02184
02185 xmlChar * src = xmlGetProp( node, ( const xmlChar* ) "src" );
02186 string index( ( char * ) src );
02187 xmlFree( src );
02188 return *( string * ) p == index;
02189 }
02190 return false;
02191 }
02192
02199 bool PlayList::IsFileUsed( string filename ) const
02200 {
02201 return parse( GetBody(), checkIfFileUsed, &filename );
02202 }
02203
02209 bool PlayList::IsDirty( ) const
02210 {
02211 return dirty;
02212 }
02213
02219 void PlayList::SetDirty( bool value )
02220 {
02221 dirty = value;
02222 }
02223
02232 string PlayList::GetDocName( ) const
02233 {
02234 return doc_name;
02235 }
02236
02245 void PlayList::SetDocName( string m_doc_name )
02246 {
02247 doc_name = m_doc_name;
02248 }
02249
02250 void PlayList::GetLastCleanPlayList( PlayList &playlist )
02251 {
02252 if ( playlist.GetNumFrames() > 0 )
02253 playlist.Delete( 0, playlist.GetNumFrames() );
02254
02255
02256 if ( doc_name != "" )
02257 playlist.LoadPlayList( ( char * ) doc_name.c_str() );
02258 }
02259
02265 string PlayList::GetProjectDirectory( )
02266 {
02267 string output = "";
02268
02269 if ( GetDocName() != "" )
02270 output = directory_utils::get_directory_from_file( GetDocName( ) );
02271
02272 if ( output == "" && strcmp( Preferences::getInstance().defaultDirectory, "" ) )
02273 output = directory_utils::expand_directory( Preferences::getInstance().defaultDirectory );
02274
02275 if ( output == "" )
02276 output = directory_utils::join_file_to_directory( "", "" );
02277
02278 return output;
02279 }
02280
02281 string PlayList::GetSeqAttribute( int frameNum, const char* name ) const
02282 {
02283 MovieInfo data;
02284
02285 memset( &data, 0, sizeof( MovieInfo ) );
02286 data.absBegin = 0;
02287 data.absEnd = 0;
02288 data.absFrame = frameNum;
02289
02290 if ( parse( GetBody(), findSceneStart, &data ) && data.sequence )
02291 {
02292 const char *value = ( const char* ) xmlGetProp( data.sequence, ( const xmlChar * ) name );
02293 if ( value )
02294 return value;
02295 }
02296 return "";
02297 }
02298
02299
02300 bool PlayList::SetSeqAttribute( int frameNum, const char* name, const char* value )
02301 {
02302 MovieInfo data;
02303
02304 memset( &data, 0, sizeof( MovieInfo ) );
02305 data.absBegin = 0;
02306 data.absEnd = 0;
02307 data.absFrame = frameNum;
02308
02309 if ( parse( GetBody(), findSceneStart, &data ) && data.sequence )
02310 {
02311 xmlSetProp( data.sequence, ( const xmlChar * ) name, ( const xmlChar * ) value );
02312 dirty = true;
02313 return true;
02314 }
02315 return false;
02316 }
02317
02318
02319 bool PlayList::SetDocId( const char* value )
02320 {
02321 if ( GetBody() )
02322 {
02323 xmlSetProp( GetBody(), ( const xmlChar * ) "id", ( const xmlChar * ) value );
02324 dirty = true;
02325 return true;
02326 }
02327 return false;
02328 }
02329
02330
02331 string PlayList::GetDocId( ) const
02332 {
02333 if ( GetBody() )
02334 {
02335 const char *value = ( const char* ) xmlGetProp( GetBody(), ( const xmlChar * ) "id" );
02336 if ( value )
02337 return value;
02338 }
02339 return "";
02340 }
02341
02342
02343 bool PlayList::SetDocTitle( const char* value )
02344 {
02345 if ( GetBody() )
02346 {
02347 xmlSetProp( GetBody(), ( const xmlChar * ) "title", ( const xmlChar * ) value );
02348 dirty = true;
02349 return true;
02350 }
02351 return false;
02352 }
02353
02354
02355 string PlayList::GetDocTitle( ) const
02356 {
02357 if ( GetBody() )
02358 {
02359 const char *value = ( const char* ) xmlGetProp( GetBody(), ( const xmlChar * ) "title" );
02360 if ( value )
02361 return value;
02362 }
02363 return "";
02364 }
02365
02366
02371 EditorBackup::EditorBackup() : position( -1 )
02372 {
02373 cerr << ">> Creating undo/redo buffer" << endl;
02374 maxUndos = Preferences::getInstance().maxUndos;
02375 }
02376
02380 EditorBackup::~EditorBackup()
02381 {
02382 cerr << ">> Destroying undo/redo buffer" << endl;
02383
02384 while ( backups.size() )
02385 {
02386 delete backups[ backups.size() - 1 ];
02387 backups.pop_back();
02388 }
02389 }
02390
02391 void EditorBackup::Store( PlayList *playlist, bool isPersisted )
02392 {
02393 cerr << ">>> Received playlist to store at position " << position + 1 << endl;
02394
02395
02396
02397
02398
02399
02400
02401 if ( ( position + 1 ) == ( int ) backups.size() && ( position < maxUndos || maxUndos == 0 ) )
02402 {
02403 cerr << ">>>> Adding to end" << endl;
02404 position ++;
02405 PlayList *temp = new PlayList;
02406 playlist->GetPlayList( 0, playlist->GetNumFrames() - 1, *temp );
02407 temp->SetDirty( playlist->IsDirty( ) );
02408 backups.push_back( temp );
02409 }
02410
02411
02412
02413
02414
02415
02416 else if ( ( position + 1 ) < ( int ) backups.size() )
02417 {
02418 cerr << ">>>> Cleaning from " << position + 1 << " to " << backups.size() << endl;
02419 position ++;
02420 while ( position < ( int ) backups.size() )
02421 {
02422 delete backups[ backups.size() - 1 ];
02423 backups.pop_back();
02424 }
02425 PlayList *temp = new PlayList;
02426 playlist->GetPlayList( 0, playlist->GetNumFrames() - 1, *temp );
02427 temp->SetDirty( playlist->IsDirty( ) );
02428 backups.push_back( temp );
02429 }
02430
02431
02432
02433
02434
02435 else if ( position == maxUndos )
02436 {
02437 cerr << ">>>> Removing the earliest playlist to make room" << endl;
02438 delete backups[ 0 ];
02439 backups.erase( backups.begin() );
02440 PlayList *temp = new PlayList;
02441 playlist->GetPlayList( 0, playlist->GetNumFrames() - 1, *temp );
02442 temp->SetDirty( playlist->IsDirty( ) );
02443 backups.push_back( temp );
02444 }
02445
02446
02447
02448
02449
02450 else
02451 {
02452 cerr << ">>>> Unknown condition - position = " << position << " size = " << backups.size() << endl;
02453 }
02454
02455
02456 if ( isPersisted )
02457 {
02458
02459 string directory = KINO_AUTOSAVE_DIR;
02460 mkdir( directory.c_str(), 0700 );
02461 DIR* dir = opendir( directory.c_str( ) );
02462 struct dirent* entry;
02463 if ( dir )
02464 {
02465 while ( ( entry = readdir( dir ) ) != NULL )
02466 {
02467 if ( entry->d_name[0] != '.' )
02468 {
02469 ostringstream sb;
02470 sb << directory << "/" << entry->d_name << ends;
02471 unlink( sb.str().c_str() );
02472 }
02473 }
02474 closedir( dir );
02475
02476
02477
02478 bool isRelative = Preferences::getInstance().relativeSave;
02479 Preferences::getInstance().relativeSave = false;
02480 for ( size_t i = 0; i < backups.size(); ++i )
02481 {
02482 if ( backups[i]->IsDirty() )
02483 {
02484 ostringstream sb;
02485 sb << directory << "/" << i << ".xml" << ends;
02486
02487 backups[i]->SavePlayList( const_cast<char*>( sb.str().c_str() ), true );
02488 }
02489 }
02490 Preferences::getInstance().relativeSave = isRelative;
02491 }
02492 }
02493 }
02494
02495 void EditorBackup::Undo( PlayList *playlist )
02496 {
02497 cerr << ">>> Received request to undo from position " << position - 1 << endl;
02498 if ( position > 0 )
02499 {
02500 position --;
02501 playlist->Delete( 0, playlist->GetNumFrames() - 1 );
02502 PlayList temp( *( backups[ position ] ) );
02503 playlist->InsertPlayList( temp, 0 );
02504 playlist->SetDirty( temp.IsDirty( ) );
02505 }
02506 else
02507 {
02508 cerr << ">>>> Unable to satisfy request." << endl;
02509 }
02510 }
02511
02512 void EditorBackup::Redo( PlayList *playlist )
02513 {
02514 cerr << ">>> Received request to recover from position " << position + 1 << endl;
02515 if ( ( position + 1 ) < ( int ) backups.size() )
02516 {
02517 position ++;
02518 playlist->Delete( 0, playlist->GetNumFrames() - 1 );
02519 PlayList temp( *( backups[ position ] ) );
02520 playlist->InsertPlayList( temp, 0 );
02521 playlist->SetDirty( temp.IsDirty( ) );
02522 }
02523 else
02524 {
02525 cerr << ">>>> Unable to satisfy request." << endl;
02526 }
02527 }
02528
02536 void EditorBackup::SetAllDirty( )
02537 {
02538 vector< PlayList *>::iterator n;
02539 for ( n = backups.begin(); n != backups.end(); ++n )
02540 ( **n ).SetDirty( true );
02541 if ( position >= 0 )
02542 backups[ position ] ->SetDirty( false );
02543 }
02544
02548 void EditorBackup::Clear( )
02549 {
02550 while ( backups.size() )
02551 {
02552 delete backups[ backups.size() - 1 ];
02553 backups.pop_back();
02554 }
02555 position = -1;
02556 }
02557
02561 EditorBackup *GetEditorBackup( )
02562 {
02563 static EditorBackup * backup = new EditorBackup( );
02564 return backup;
02565 }
02566
02567 bool EditorBackup::Restore( PlayList * playlist )
02568 {
02569 string directory = KINO_AUTOSAVE_DIR;
02570 DIR* dir = opendir( directory.c_str( ) );
02571 struct dirent* entry;
02572 bool result = false;
02573
02574 if ( dir )
02575 {
02576 std::vector<int> names;
02577 while ( ( entry = readdir( dir ) ) != NULL )
02578 {
02579 if ( entry->d_name[0] != '.' )
02580 names.push_back( atoi( entry->d_name ) );
02581 }
02582 closedir( dir );
02583
02584 if ( !names.empty() )
02585 {
02586 std::sort( names.begin(), names.end() );
02587 Clear();
02588 PlayList pl;
02589 for ( size_t i = 0; i < names.size(); ++i )
02590 {
02591 ostringstream sb;
02592 sb << directory << "/" << names[i] << ".xml" << ends;
02593 if ( pl.LoadPlayList( const_cast<char*>( sb.str().c_str() ) ) )
02594 Store( &pl, false );
02595 }
02596 ++position;
02597 Undo( playlist );
02598 result = true;
02599 }
02600 }
02601 return result;
02602 }