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 #include "smiltime.h"
00026
00027 #include <iostream>
00028 #include <iomanip>
00029 #include <sstream>
00030
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <math.h>
00034
00035 #include "stringutils.h"
00036
00037 namespace SMIL
00038 {
00039
00040 Time::Time()
00041 {
00042 Time( 0L );
00043 indefinite = true;
00044 timeType = SMIL_TIME_INDEFINITE;
00045 resolved = true;
00046 }
00047
00048
00049 Time::Time( long time ) :
00050 timeValue( time ),
00051 offset( 0 ),
00052 indefinite( false ),
00053 resolved( true ),
00054 syncbaseBegin( false ),
00055 timeType( SMIL_TIME_OFFSET )
00056 {
00057 }
00058
00059
00060 Time::Time( string time )
00061 {
00062 Time( 0L );
00063 parseTimeValue( time );
00064 }
00065
00066 void Time::parseTimeValue( string time )
00067 {
00068 time = StringUtils::stripWhite( time );
00069
00070 resolved = false;
00071
00072 if ( StringUtils::begins ( time, "indefinite" ) || time.empty() || time.size() == 0 )
00073 {
00074 indefinite = true;
00075 timeType = SMIL_TIME_INDEFINITE;
00076 resolved = true;
00077
00078 }
00079 else if ( time.at( 0 ) == '+' || time.at( 0 ) == '-' )
00080 {
00081
00082 timeValue = parseClockValue( time.substr( 1 ) );
00083 if ( time.at( 0 ) == '-' )
00084 timeValue *= -1;
00085 timeType = SMIL_TIME_OFFSET;
00086 resolved = true;
00087 indefinite = false;
00088 }
00089 else if ( StringUtils::begins ( time, "wallclock(" ) )
00090 {
00091
00092 timeType = SMIL_TIME_WALLCLOCK;
00093 resolved = true;
00094 indefinite = false;
00095
00096 }
00097 else if ( StringUtils::begins ( time, "accesskey(" ) )
00098 {
00099 timeType = SMIL_TIME_ACCESSKEY;
00100
00101 }
00102 else
00103 {
00104 std::ostringstream token;
00105 char c;
00106 string::size_type pos = 0;
00107 string base;
00108 for ( ; pos < time.size(); ++pos )
00109 {
00110 c = time.at( pos );
00111 if ( c == '+' || c == '-' )
00112 {
00113 string symbol = token.str();
00114 token.str( string() );
00115
00116
00117 if ( symbol == string( "begin" ) )
00118 {
00119
00120 syncbaseBegin = true;
00121 timeType = SMIL_TIME_SYNC_BASED;
00122 }
00123 else if ( symbol == string( "end" ) )
00124 {
00125
00126 syncbaseBegin = false;
00127 timeType = SMIL_TIME_SYNC_BASED;
00128 }
00129 else if ( StringUtils::begins( symbol, "marker(" ) )
00130 {
00131
00132
00133 timeType = SMIL_TIME_MEDIA_MARKER;
00134 }
00135 else if ( StringUtils::begins( symbol, "repeat(" ) )
00136 {
00137
00138
00139 timeType = SMIL_TIME_REPEAT;
00140 }
00141 else
00142 {
00143
00144
00145 timeType = SMIL_TIME_EVENT_BASED;
00146 }
00147 offset = parseClockValue( time.substr( pos + 1 ) );
00148 if ( c == '-' )
00149 offset *= -1;
00150 break;
00151 }
00152 else if ( c == '.' && ( pos == 0 || time.at( pos - 1 ) != '\\' ) )
00153 {
00154 base = token.str();
00155 token.str( string() );
00156
00157 }
00158 else
00159 {
00160 token << c;
00161 }
00162 }
00163 string remaining = token.str();
00164
00165 if ( !remaining.empty() )
00166 {
00167
00168 offset = parseClockValue( time );
00169 timeType = SMIL_TIME_OFFSET;
00170 resolved = true;
00171 indefinite = false;
00172 }
00173 }
00174 }
00175
00176
00177 static inline
00178 string getFraction( string& time )
00179 {
00180 string::size_type pos;
00181 string fraction;
00182 if ( ( pos = time.find( '.' ) ) != string::npos )
00183 {
00184 fraction = time.substr( pos + 1 );
00185
00186 time = time.substr( 0, pos );
00187 }
00188 return fraction;
00189 }
00190
00191
00192 long Time::parseClockValue( string time )
00193 {
00194 long total = 0;
00195 string hours;
00196 string minutes;
00197 string seconds;
00198 string milliseconds;
00199 string::size_type pos1, pos2;
00200
00201 if ( ( pos1 = time.find( ':' ) ) != string::npos )
00202 {
00203 if ( ( pos2 = time.find( ':', pos1 + 1 ) ) != string::npos )
00204 {
00205
00206
00207 hours = time.substr( 0, pos1 );
00208 time = time.substr( pos1 + 1 );
00209 pos1 = pos2 - pos1 - 1;
00210 }
00211
00212
00213 if ( ( pos2 = time.find( '.' ) ) != string::npos )
00214 {
00215 milliseconds = time.substr( pos2 + 1, 3 );
00216 time = time.substr( 0, pos2 );
00217 }
00218 minutes = time.substr( 0, pos1 );
00219 seconds = time.substr( pos1 + 1 );
00220 }
00221 else
00222 {
00223
00224
00225 if ( StringUtils::ends( time, "h" ) )
00226 {
00227 total = ( long ) ( atof( getFraction( time ).c_str() ) * 3600 );
00228 hours = time;
00229 }
00230 else if ( StringUtils::ends( time, "min" ) )
00231 {
00232 total = ( long ) ( atof( getFraction( time ).c_str() ) * 60 );
00233 minutes = time;
00234 }
00235 else if ( StringUtils::ends( time, "ms" ) )
00236 {
00237 total = ( long ) ( atof( time.c_str() ) + 0.5 );
00238 }
00239 else
00240 {
00241 total = atol( getFraction( time ).c_str() );
00242 seconds = time;
00243 }
00244 }
00245
00246
00247
00248 total += ( atol( hours.c_str() ) * 3600 + atol( minutes.c_str() ) * 60 +
00249 atol( seconds.c_str() ) ) * 1000 + atol( milliseconds.c_str() );
00250 return total;
00251 }
00252
00253
00254 long Time::getResolvedOffset()
00255 {
00256 return ( resolved ? ( timeValue + offset ) : 0 );
00257 }
00258
00259 bool Time::isNegative()
00260 {
00261 return ( resolved && !indefinite && ( getResolvedOffset() < 0 ) );
00262 }
00263
00264
00265 bool Time::operator< ( Time& time )
00266 {
00267 return !( ( *this > time ) || ( *this == time ) );
00268 }
00269
00270
00271 bool Time::operator==( Time& time )
00272 {
00273 return (
00274 ( this->isIndefinite() && time.isIndefinite() ) ||
00275 ( this->getResolvedOffset() == time.getResolvedOffset() )
00276 );
00277 }
00278
00279
00280 bool Time::operator> ( Time& time )
00281 {
00282 return (
00283 ( !resolved ) ||
00284 ( indefinite && time.isResolved() && !time.isIndefinite() ) ||
00285 ( resolved && time.isResolved() && this->getResolvedOffset() > time.getResolvedOffset() )
00286 );
00287 }
00288
00289
00290 void Time::setTimeValue( Time& source )
00291 {
00292 resolved = source.isResolved();
00293 indefinite = source.isIndefinite();
00294 timeValue = source.getTimeValue();
00295 }
00296
00297
00298 string Time::toString( TimeFormat format )
00299 {
00300 long ms = getResolvedOffset();
00301 ostringstream str;
00302
00303 if ( indefinite )
00304 {
00305 str << "indefinite";
00306 }
00307 else if ( !resolved )
00308 {
00309 str << "unresolved";
00310 }
00311 else switch( format )
00312 {
00313 case TIME_FORMAT_CLOCK:
00314 {
00315 int hh = ( ms / 3600000 );
00316 ms -= hh * 3600000;
00317 int mm = ( ms / 60000 );
00318 ms -= mm * 60000;
00319 int ss = ms / 1000;
00320 ms -= ss * 1000;
00321
00322 str << std::setfill( '0' ) << std::setw( 2 ) << hh <<
00323 ":" << std::setfill( '0' ) << std::setw( 2 ) << mm <<
00324 ":" << std::setfill( '0' ) << std::setw( 2 ) << ss << "." <<
00325 std::setfill( '0' ) << std::setw( 3 ) << ms;
00326 break;
00327 }
00328 case TIME_FORMAT_MS:
00329 str << ms << "ms";
00330 break;
00331
00332 case TIME_FORMAT_S:
00333 str << ( ms / 1000 ) << "." <<
00334 std::setfill( '0' ) << std::setw( 3 ) << ( ms % 1000 );
00335 break;
00336
00337 case TIME_FORMAT_MIN:
00338 str << ( ms / 60000 ) << "." <<
00339 std::setfill( '0' ) << std::setw( 4 ) <<
00340 floor( ( float )( ms % 60000 ) / 6 + 0.5 ) << "min";
00341 break;
00342
00343 case TIME_FORMAT_H:
00344 str << ( ms / 3600000 ) << "." <<
00345 std::setfill( '0' ) << std::setw( 5 ) <<
00346 floor( ( float )( ms % 3600000 ) / 36 + 0.5 ) << "h";
00347 break;
00348
00349 default:
00350 break;
00351 }
00352 return str.str();
00353
00354 }
00355
00356 string Time::serialise()
00357 {
00358 return toString();
00359 }
00360
00361
00362 MediaClippingTime::MediaClippingTime( ) :
00363 Time( 0L ),
00364 m_framerate( 0.0 ),
00365 m_isSmpteValue( false ),
00366 m_subframe( SMIL_SUBFRAME_NONE )
00367 {
00368 }
00369
00370 MediaClippingTime::MediaClippingTime( float framerate ) :
00371 Time( 0L ),
00372 m_framerate( framerate ),
00373 m_isSmpteValue( false ),
00374 m_subframe( SMIL_SUBFRAME_NONE )
00375 {
00376 }
00377
00378 MediaClippingTime::MediaClippingTime( string time, float framerate ) :
00379 Time( 0L ),
00380 m_framerate( framerate ),
00381 m_isSmpteValue( false ),
00382 m_subframe( SMIL_SUBFRAME_NONE )
00383 {
00384 parseValue( time );
00385 }
00386
00387
00388 void MediaClippingTime::setFramerate( float framerate )
00389 {
00390 m_framerate = framerate;
00391 }
00392
00393
00394 void MediaClippingTime::parseValue( string time )
00395 {
00396 time = StringUtils::stripWhite( time );
00397
00398 if ( StringUtils::begins( time, "smpte=" ) ||
00399 StringUtils::begins( time, "smpte-30-drop=" ) ||
00400 StringUtils::begins( time, "smpte-25=" ) )
00401 {
00402 parseSmpteValue( time.substr( time.find( '=' ) + 1 ) );
00403 }
00404 else if ( time.find( '=' ) != string::npos )
00405 {
00406 parseTimeValue( time.substr( time.find( '=' ) + 1 ) );
00407 } else
00408 {
00409 parseTimeValue( time );
00410 }
00411 }
00412
00413 void MediaClippingTime::parseSmpteValue( string time )
00414 {
00415 string hours;
00416 string minutes;
00417 string seconds;
00418 string frames;
00419 string::size_type pos;
00420
00421 if ( m_framerate == 0 )
00422 return;
00423
00424 m_isSmpteValue = true;
00425
00426 if ( ( pos = time.find( ':' ) ) != string::npos || ( pos = time.find( ';' ) ) != string::npos )
00427 {
00428
00429 hours = time.substr( 0, pos );
00430 time = time.substr( pos + 1 );
00431
00432 if ( ( pos = time.find( ':' ) ) != string::npos || ( pos = time.find( ';' ) ) != string::npos )
00433 {
00434
00435 minutes = time.substr( 0, pos );
00436 time = time.substr( pos + 1 );
00437
00438 if ( ( pos = time.find( ':' ) ) != string::npos || ( pos = time.find( ';' ) ) != string::npos )
00439 {
00440
00441 seconds = time.substr( 0, pos );
00442 time = time.substr( pos + 1 );
00443
00444 if ( ( pos = time.find( '.' ) ) != string::npos )
00445 {
00446
00447 frames = time.substr( 0, pos );
00448 switch ( time.at( pos + 1 ) )
00449 {
00450 case '0' :
00451 m_subframe = SMIL_SUBFRAME_0;
00452 break;
00453 case '1' :
00454 m_subframe = SMIL_SUBFRAME_1;
00455 break;
00456 default:
00457 m_subframe = SMIL_SUBFRAME_NONE;
00458 break;
00459 }
00460 }
00461 else
00462 {
00463 frames = time;
00464 }
00465 }
00466 else
00467 {
00468
00469 frames = time;
00470 seconds = minutes;
00471 minutes = hours;
00472 hours = "";
00473 }
00474 }
00475 else
00476 {
00477
00478 frames = time;
00479 seconds = hours;
00480 hours = "";
00481 }
00482 }
00483 else
00484 {
00485
00486 frames = time;
00487 }
00488
00489
00490 timeValue = ( atol( hours.c_str() ) * 3600 + atol( minutes.c_str() ) * 60 +
00491 atol( seconds.c_str() ) ) * 1000 +
00492 ( long )( atof( frames.c_str() ) / m_framerate * 1000 + 0.5 );
00493
00494 resolved = true;
00495 indefinite = false;
00496 }
00497
00498 string MediaClippingTime::toString( TimeFormat format )
00499 {
00500 if ( format == TIME_FORMAT_SMPTE )
00501 {
00502 if ( indefinite )
00503 return "indefinite";
00504 else if ( !resolved )
00505 return "unresolved";
00506 else
00507 {
00508 long ms = getResolvedOffset();
00509 int hh = ( ms / 3600000 );
00510 ms -= hh * 3600000;
00511 int mm = ( ms / 60000 );
00512 ms -= mm * 60000;
00513 int ss = ms / 1000;
00514 ms -= ss * 1000;
00515
00516 ostringstream str;
00517 str << hh << ":" << std::setfill( '0' ) << std::setw( 2 ) <<
00518 mm << ":" << std::setfill( '0' ) << std::setw( 2 ) << ss <<
00519 ( m_framerate == 25.0 ? ":" : ";" ) <<
00520 std::setfill( '0' ) << std::setw( 2 ) <<
00521 floor( m_framerate * ms / 1000.0 + 0.5 );
00522 if ( m_subframe == SMIL_SUBFRAME_0 )
00523 str << ".0";
00524 else if ( m_subframe == SMIL_SUBFRAME_1 )
00525 str << ".1";
00526
00527 return str.str();
00528 }
00529 }
00530 else if ( format == TIME_FORMAT_FRAMES )
00531 {
00532 std::ostringstream str;
00533 str << getFrames();
00534 return str.str();
00535 }
00536 else
00537 {
00538 return Time::toString( format );
00539 }
00540 }
00541
00542 string MediaClippingTime::serialise()
00543 {
00544 std::string s;
00545 if ( m_isSmpteValue )
00546 {
00547 if ( m_framerate == 25.0 )
00548 s = "smpte-25=";
00549 else
00550 s = "smpte=";
00551
00552 return s + toString();
00553 }
00554 return Time::toString();
00555 }
00556
00557
00558 string framesToSmpte( int frames, int fps )
00559 {
00560 char s[ 12 ];
00561 int hours, mins, secs;
00562 int cur = frames;
00563
00564 if ( fps == 29 )
00565 fps = 30;
00566
00567 if ( frames == 0 )
00568 {
00569 hours = 0;
00570 mins = 0;
00571 secs = 0;
00572 }
00573 else
00574 {
00575
00576 if ( fps == 30 )
00577 {
00578 int max_frames = cur;
00579 for ( int j = 1800; j <= max_frames; j += 1800 )
00580 {
00581 if ( j % 18000 )
00582 {
00583 max_frames += 2;
00584 cur += 2;
00585 }
00586 }
00587 }
00588 hours = cur / ( fps * 3600 );
00589 cur -= hours * ( fps * 3600 );
00590 mins = cur / ( fps * 60 );
00591 cur -= mins * ( fps * 60 );
00592 secs = cur / fps;
00593 cur -= secs * fps;
00594 }
00595
00596 snprintf( s, 12, "%2.2d:%2.2d:%2.2d%s%2.2d", hours, mins, secs, ( fps == 30 ) ? ";" : ":", cur );
00597 return string( s );
00598 }
00599
00600
00601 string MediaClippingTime::parseValueToString( string time, TimeFormat format )
00602 {
00603 offset = 0;
00604 timeValue = 0;
00605 if ( format == TIME_FORMAT_NONE || format == TIME_FORMAT_FRAMES || format == TIME_FORMAT_SMPTE )
00606 parseSmpteValue( time );
00607 else
00608 parseValue( time );
00609 return toString( format );
00610 }
00611
00612
00613 string MediaClippingTime::parseFramesToString( int frames, TimeFormat format )
00614 {
00615 if ( m_framerate == 0 )
00616 return "";
00617 offset = 0;
00618 timeValue = ( long )( 1000.0 * frames / m_framerate + 0.5 );
00619 resolved = true;
00620 indefinite = false;
00621
00622 switch ( format )
00623 {
00624 case TIME_FORMAT_NONE:
00625 return "";
00626
00627 case TIME_FORMAT_FRAMES:
00628 {
00629 std::ostringstream str;
00630 str << frames;
00631 return str.str();
00632 }
00633
00634 case TIME_FORMAT_SMPTE:
00635 return framesToSmpte( frames, ( int )m_framerate );
00636
00637 default:
00638 return toString( format );
00639 }
00640 }
00641
00642 int MediaClippingTime::getFrames()
00643 {
00644 return ( int )( m_framerate * getResolvedOffset() / 1000.0 + 0.5 );
00645 }
00646
00647 }