1/*********************************************************************** 2 * AUTHOR: David McPaul 3 * FILE: TimeCode.cpp 4 * DESCR: Handles all TimeCode functions. 5 ***********************************************************************/ 6#include <TimeCode.h> 7#include "MediaDebug.h" 8#include <string.h> 9 10status_t us_to_timecode(bigtime_t micros, int * hours, int * minutes, int * seconds, int * frames, const timecode_info * code) 11{ 12 int32 l_frames; 13 14 CALLED(); 15 16 if (code) { 17 // We have a valid timecode_info 18 switch (code->type) { 19 case B_TIMECODE_DEFAULT: // NTSC 20 case B_TIMECODE_30_DROP_2: // NTSC 21 l_frames = int32((((micros % 1000000) * 29.97) / 1000000) + (micros / 1000000 * 29.97)); 22 break; 23 case B_TIMECODE_30_DROP_4: // Brazil 24 l_frames = int32((((micros % 1000000) * 29.95) / 1000000) + (micros / 1000000 * 29.95)); 25 break; 26 default: 27 l_frames = (((micros % 1000000) * code->fps_div) / 1000000) + (micros / 1000000 * code->fps_div); 28 break; 29 }; 30 } else { 31 // Convert us to frames 32 l_frames = int32((((micros % 1000000) * 29.97) / 1000000) + (micros / 1000000 * 29.97)); 33 } 34 35 return frames_to_timecode(l_frames, hours, minutes, seconds, frames, code); 36} 37 38status_t timecode_to_us(int hours, int minutes, int seconds, int frames, bigtime_t * micros, const timecode_info * code) 39{ 40 int32 l_frames; 41 42 CALLED(); 43 44 if (timecode_to_frames(hours, minutes, seconds, frames, &l_frames, code) == B_OK) { 45 46 if (code) { 47 // We have a valid timecode_info 48 switch (code->type) { 49 case B_TIMECODE_DEFAULT: // NTSC 50 case B_TIMECODE_30_DROP_2: // NTSC 51 *micros = bigtime_t(l_frames * ((1000000 / 29.97) + 0.5)); 52 break; 53 case B_TIMECODE_30_DROP_4: // Brazil 54 *micros = bigtime_t(l_frames * ((1000000 / 29.95) + 0.5)); 55 break; 56 default: 57 *micros = l_frames * 1000000 / code->fps_div; 58 break; 59 }; 60 61 } else { 62 *micros = bigtime_t(l_frames * ((1000000 / 29.97) + 0.5)); 63 } 64 65 return B_OK; 66 } 67 return B_ERROR; 68} 69 70status_t frames_to_timecode(int32 l_frames, int * hours, int * minutes, int * seconds, int * frames, const timecode_info * code) 71{ 72 int fps_div; 73 int total_mins; 74 int32 extra_frames; 75 int32 extra_frames2; 76 77 CALLED(); 78 79 if (code) { 80 // We have a valid timecode_info so use it 81 fps_div = code->fps_div; 82 83 if (code->every_nth > 0) { 84 // Handle Drop Frames format 85 86 total_mins = l_frames / fps_div / 60; 87 88 // "every_nth" minute we gain "drop_frames" "except_nth" minute 89 extra_frames = code->drop_frames*(total_mins/code->every_nth) - code->drop_frames*(total_mins/code->except_nth); 90 l_frames += extra_frames; 91 92 total_mins = l_frames / fps_div / 60; 93 extra_frames2 = code->drop_frames*(total_mins/code->every_nth) - code->drop_frames*(total_mins/code->except_nth); 94 95 // Gaining frames may mean that we gain more frames so we keep adjusting until no more to adjust 96 while (extra_frames != extra_frames2) { 97 l_frames += extra_frames2 - extra_frames; 98 extra_frames = extra_frames2; 99 100 total_mins = l_frames / fps_div / 60; 101 extra_frames2 = code->drop_frames*(total_mins/code->every_nth) - code->drop_frames*(total_mins/code->except_nth); 102 } 103 104 // l_frames should now include all adjusted frames 105 } 106 } else { 107 // no timecode_info so set default NTSC :-( 108 fps_div = 30; // NTSC Default 109 total_mins = l_frames / fps_div / 60; 110 111 // "every_nth" minute we gain "drop_frames" "except_nth" minute 112 extra_frames = 2*(total_mins) - 2*(total_mins/10); 113 l_frames += extra_frames; 114 115 total_mins = l_frames / fps_div / 60; 116 extra_frames2 = 2*(total_mins) - 2*(total_mins/10); 117 118 // Gaining frames may mean that we gain more frames so we keep adjusting until no more to adjust 119 while (extra_frames != extra_frames2) { 120 l_frames += extra_frames2 - extra_frames; 121 extra_frames = extra_frames2; 122 123 total_mins = l_frames / fps_div / 60; 124 extra_frames2 = 2*(total_mins) - 2*(total_mins/10); 125 } 126 } 127 128 // convert frames to seconds leaving the remainder as frames 129 *seconds = l_frames / fps_div; // DIV 130 *frames = l_frames % fps_div; // MOD 131 132 // Normalise to Hours Minutes Seconds Frames 133 *minutes = *seconds / 60; 134 *seconds = *seconds % 60; 135 136 *hours = *minutes / 60; 137 *minutes = *minutes % 60; 138 139 return B_OK; 140} 141 142status_t timecode_to_frames(int hours, int minutes, int seconds, int frames, int32 * l_frames, const timecode_info * code) 143{ 144 int fps_div; 145 int total_mins; 146 int32 extra_frames; 147 148 CALLED(); 149 150 if (code) { 151 // We have a valid timecode_info 152 fps_div = code->fps_div; 153 154 total_mins = (hours * 60) + minutes; 155 *l_frames = (total_mins * 60) + seconds; 156 *l_frames = (*l_frames * fps_div) + frames; 157 158 // Adjust "every_nth" minute we lose "drop_frames" "except_nth" minute 159 if (code->every_nth > 0) { 160 extra_frames = code->drop_frames*(total_mins/code->every_nth) - code->drop_frames*(total_mins/code->except_nth); 161 162 *l_frames = *l_frames - extra_frames; 163 } 164 } else { 165 166 total_mins = (hours * 60) + minutes; 167 *l_frames = (total_mins * 60) + seconds; 168 *l_frames = (*l_frames * 30) + frames; 169 170 // Adjust "every_nth" minute we lose "drop_frames" "except_nth" minute 171 extra_frames = 2*(total_mins) - 2*(total_mins/10); 172 173 *l_frames = *l_frames - extra_frames; 174 } 175 176 return B_OK; 177} 178 179status_t get_timecode_description(timecode_type type, timecode_info * out_timecode) 180{ 181 CALLED(); 182 183 out_timecode->type = type; 184 strncpy(out_timecode->format,"%.2ih:%.2im:%.2is.%.2i",31); 185 out_timecode->every_nth = 0; 186 out_timecode->except_nth = 0; 187 188 switch (type) { 189 case B_TIMECODE_100: 190 strncpy(out_timecode->name,"100 FPS",31); 191 out_timecode->fps_div = 100; 192 break; 193 case B_TIMECODE_75: // CD 194 strncpy(out_timecode->name,"CD",31); 195 out_timecode->fps_div = 75; 196 break; 197 case B_TIMECODE_30: // MIDI 198 strncpy(out_timecode->name,"MIDI",31); 199 out_timecode->fps_div = 30; 200 break; 201 case B_TIMECODE_30_DROP_2: // NTSC 202 strncpy(out_timecode->name,"NTSC",31); 203 out_timecode->fps_div = 30; // This is supposed to be 29.97fps but can be simulated using the drop frame format below 204 out_timecode->drop_frames = 2; // Drop 2 frames 205 out_timecode->every_nth = 1; // every 1 minutes 206 out_timecode->except_nth = 10; // except every 10 minutes 207 break; 208 case B_TIMECODE_30_DROP_4: // Brazil 209 strncpy(out_timecode->name,"NTSC Brazil",31); 210 out_timecode->fps_div = 30; 211 out_timecode->drop_frames = 4; // Drop 4 frames 212 out_timecode->every_nth = 1; // every 1 minutes 213 out_timecode->except_nth = 10; // except every 10 minutes 214 break; 215 case B_TIMECODE_25: // PAL 216 strncpy(out_timecode->name,"PAL",31); 217 out_timecode->fps_div = 25; 218 break; 219 case B_TIMECODE_24: // Film 220 strncpy(out_timecode->name,"FILM",31); 221 out_timecode->fps_div = 24; 222 break; 223 case B_TIMECODE_18: // Super8 224 strncpy(out_timecode->name,"Super 8",31); 225 out_timecode->fps_div = 18; 226 break; 227 default: 228 strncpy(out_timecode->name,"NTSC",31); 229 out_timecode->fps_div = 30; // This is supposed to be 29.97fps but can be simulated using the drop frame format below 230 out_timecode->drop_frames = 2; // Drop 2 frames 231 out_timecode->every_nth = 1; // every 1 minutes 232 out_timecode->except_nth = 10; // except every 10 minutes 233 break; 234 } 235 236 return B_OK; 237} 238 239status_t count_timecodes() 240{ 241 CALLED(); 242 return 8; // Is this right? 243} 244 245/************************************************************* 246 * public BTimeCode 247 *************************************************************/ 248 249 250BTimeCode::BTimeCode() 251{ 252 CALLED(); 253} 254 255 256BTimeCode::BTimeCode(bigtime_t us, 257 timecode_type type) 258{ 259 CALLED(); 260 if (SetType(type) == B_OK) { 261 SetMicroseconds(us); 262 } 263} 264 265 266BTimeCode::BTimeCode(const BTimeCode &clone) 267{ 268 CALLED(); 269 if (SetType(clone.Type()) == B_OK) { 270 SetData(clone.Hours(),clone.Minutes(),clone.Seconds(),clone.Frames()); 271 } 272} 273 274 275BTimeCode::BTimeCode(int hours, 276 int minutes, 277 int seconds, 278 int frames, 279 timecode_type type) 280{ 281 CALLED(); 282 if (SetType(type) == B_OK) { 283 SetData(hours,minutes,seconds,frames); 284 } 285} 286 287 288BTimeCode::~BTimeCode() 289{ 290 CALLED(); 291} 292 293 294void 295BTimeCode::SetData(int hours, 296 int minutes, 297 int seconds, 298 int frames) 299{ 300 CALLED(); 301 fHours = hours; 302 fMinutes = minutes; 303 fSeconds = seconds; 304 fFrames = frames; 305} 306 307 308status_t 309BTimeCode::SetType(timecode_type type) 310{ 311 CALLED(); 312 313 return get_timecode_description(type, &fInfo); 314} 315 316 317void 318BTimeCode::SetMicroseconds(bigtime_t us) 319{ 320 CALLED(); 321 322 us_to_timecode(us, &fHours, &fMinutes, &fSeconds, &fFrames, &fInfo); 323} 324 325 326void 327BTimeCode::SetLinearFrames(int32 linear_frames) 328{ 329 CALLED(); 330 331 frames_to_timecode(linear_frames, &fHours, &fMinutes, &fSeconds, &fFrames, &fInfo); 332} 333 334 335BTimeCode & 336BTimeCode::operator=(const BTimeCode &clone) 337{ 338 CALLED(); 339 fHours = clone.Hours(); 340 fMinutes = clone.Minutes(); 341 fSeconds = clone.Seconds(); 342 fFrames = clone.Frames(); 343 SetType(clone.Type()); 344 345 return *this; 346} 347 348 349bool 350BTimeCode::operator==(const BTimeCode &other) const 351{ 352 CALLED(); 353 354 return ((this->LinearFrames()) == (other.LinearFrames())); 355} 356 357 358bool 359BTimeCode::operator<(const BTimeCode &other) const 360{ 361 CALLED(); 362 363 return ((this->LinearFrames()) < (other.LinearFrames())); 364} 365 366 367BTimeCode & 368BTimeCode::operator+=(const BTimeCode &other) 369{ 370 CALLED(); 371 372 this->SetLinearFrames(this->LinearFrames() + other.LinearFrames()); 373 374 return *this; 375} 376 377 378BTimeCode & 379BTimeCode::operator-=(const BTimeCode &other) 380{ 381 CALLED(); 382 383 this->SetLinearFrames(this->LinearFrames() - other.LinearFrames()); 384 385 return *this; 386} 387 388 389BTimeCode 390BTimeCode::operator+(const BTimeCode &other) const 391{ 392 CALLED(); 393 BTimeCode tc(*this); 394 tc += other; 395 return tc; 396} 397 398 399BTimeCode 400BTimeCode::operator-(const BTimeCode &other) const 401{ 402 CALLED(); 403 BTimeCode tc(*this); 404 tc -= other; 405 return tc; 406} 407 408 409int 410BTimeCode::Hours() const 411{ 412 CALLED(); 413 414 return fHours; 415} 416 417 418int 419BTimeCode::Minutes() const 420{ 421 CALLED(); 422 423 return fMinutes; 424} 425 426 427int 428BTimeCode::Seconds() const 429{ 430 CALLED(); 431 432 return fSeconds; 433} 434 435 436int 437BTimeCode::Frames() const 438{ 439 CALLED(); 440 441 return fFrames; 442} 443 444 445timecode_type 446BTimeCode::Type() const 447{ 448 CALLED(); 449 450 return fInfo.type; 451} 452 453 454void 455BTimeCode::GetData(int *out_hours, 456 int *out_minutes, 457 int *out_seconds, 458 int *out_frames, 459 timecode_type *out_type) const 460{ 461 CALLED(); 462 *out_hours = fHours; 463 *out_minutes = fMinutes; 464 *out_seconds = fSeconds; 465 *out_frames = fFrames; 466 *out_type = fInfo.type; 467} 468 469 470bigtime_t 471BTimeCode::Microseconds() const 472{ 473 bigtime_t us; 474 475 CALLED(); 476 477 if (timecode_to_us(fHours,fMinutes,fSeconds,fFrames, &us, &fInfo) == B_OK) { 478 return us; 479 } 480 481 return 0; 482} 483 484 485int32 486BTimeCode::LinearFrames() const 487{ 488 int32 linear_frames; 489 490 CALLED(); 491 492 if (timecode_to_frames(fHours,fMinutes,fSeconds,fFrames,&linear_frames,&fInfo) == B_OK) { 493 return linear_frames; 494 } 495 496 return 0; 497} 498 499 500void 501BTimeCode::GetString(char *str) const 502{ 503 CALLED(); 504 sprintf(str,fInfo.format, fHours, fMinutes, fSeconds, fFrames); 505} 506