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