diff --git a/src/kits/media/TimeCode.cpp b/src/kits/media/TimeCode.cpp index a12ee81c80..c2f7c983ca 100644 --- a/src/kits/media/TimeCode.cpp +++ b/src/kits/media/TimeCode.cpp @@ -1,7 +1,7 @@ /*********************************************************************** - * AUTHOR: Marcus Overhagen, David McPaul + * AUTHOR: David McPaul * FILE: TimeCode.cpp - * DESCR: + * DESCR: Handles all TimeCode functions. ***********************************************************************/ #include #include "debug.h" @@ -9,32 +9,188 @@ status_t us_to_timecode(bigtime_t micros, int * hours, int * minutes, int * seconds, int * frames, const timecode_info * code = NULL) { - UNIMPLEMENTED(); - return B_ERROR; + int fps_div; + int32 l_frames; + + CALLED(); + + if (code) { + // We have a valid timecode_info + fps_div = code->fps_div; + } else { + fps_div = 25; // PAL Default + } + + // Convert us to frames + l_frames = (((micros % 1000) * fps_div) / 1000) + (micros / 1000 * fps_div); + + return frames_to_timecode(l_frames, hours, minutes, seconds, frames, code); } status_t timecode_to_us(int hours, int minutes, int seconds, int frames, bigtime_t * micros, const timecode_info * code = NULL) { - UNIMPLEMENTED(); + int fps_div; + int32 l_frames; + + CALLED(); + + if (timecode_to_frames(hours, minutes, seconds, frames, &l_frames, code) == B_OK) { + + if (code) { + // We have a valid timecode_info + fps_div = code->fps_div; + } else { + fps_div = 25; // PAL Default + } + + *micros = l_frames * 1000 / fps_div; + return B_OK; + } return B_ERROR; } status_t frames_to_timecode(int32 l_frames, int * hours, int * minutes, int * seconds, int * frames, const timecode_info * code = NULL) { - UNIMPLEMENTED(); - return B_ERROR; + int fps_div; + int total_mins; + int32 extra_frames; + int32 extra_frames2; + + CALLED(); + + if (code) { + // We have a valid timecode_info so get the fps_div + fps_div = code->fps_div; + + if (code->every_nth > 0) { + // Handle Drop Frames format + + total_mins = l_frames / fps_div / 60; + + // "every_nth" minute we gain "drop_frames" "except_nth" minute + extra_frames = code->drop_frames*(total_mins/code->every_nth) - code->drop_frames*(total_mins/code->except_nth); + l_frames += extra_frames; + + total_mins = l_frames / fps_div / 60; + extra_frames2 = code->drop_frames*(total_mins/code->every_nth) - code->drop_frames*(total_mins/code->except_nth); + + // Gaining frames may mean that we gain more frames so we keep adjusting until no more to adjust + while (extra_frames != extra_frames2) { + l_frames += extra_frames2 - extra_frames; + extra_frames = extra_frames2; + + total_mins = l_frames / fps_div / 60; + extra_frames2 = code->drop_frames*(total_mins/code->every_nth) - code->drop_frames*(total_mins/code->except_nth); + } + + // l_frames should now include all adjusted frames + } + } else { + // no timecode_info so set a default that doesn't use drop frames :-) + fps_div = 25; // PAL Default + } + + // convert frames to seconds leaving the remainder as frames + *seconds = l_frames / fps_div; // DIV + *frames = l_frames % fps_div; // MOD + + // Normalise to Hours Minutes Seconds Frames + *minutes = *seconds / 60; + *seconds = *seconds % 60; + + *hours = *minutes / 60; + *minutes = *minutes % 60; + + return B_OK; } status_t timecode_to_frames(int hours, int minutes, int seconds, int frames, int32 * l_frames, const timecode_info * code = NULL) { - UNIMPLEMENTED(); - return B_ERROR; + int fps_div; + int total_mins; + int32 extra_frames; + + CALLED(); + + if (code) { + // We have a valid timecode_info + fps_div = code->fps_div; + + total_mins = (hours * 60) + minutes; + *l_frames = (total_mins * 60) + seconds; + *l_frames = (*l_frames * fps_div) + frames; + + // Adjust "every_nth" minute we lose "drop_frames" "except_nth" minute + if (code->every_nth > 0) { + extra_frames = code->drop_frames*(total_mins/code->every_nth) - code->drop_frames*(total_mins/code->except_nth); + + *l_frames = *l_frames - extra_frames; + } + } else { + + *l_frames = (hours * 60) + minutes; + *l_frames = (*l_frames * 60) + seconds; + *l_frames = (*l_frames * 25) + frames; + } + + return B_OK; } status_t get_timecode_description(timecode_type type, timecode_info * out_timecode) { - UNIMPLEMENTED(); - return B_ERROR; + CALLED(); + + out_timecode->type = type; + strncpy(out_timecode->format,"%.2i:%.2i:%.2i.%.2i",31); + out_timecode->every_nth = 0; + out_timecode->except_nth = 0; + + switch (type) { + case B_TIMECODE_100: + strncpy(out_timecode->name,"100 FPS",31); + out_timecode->fps_div = 100; + break; + case B_TIMECODE_75: // CD + strncpy(out_timecode->name,"CD",31); + out_timecode->fps_div = 75; + break; + case B_TIMECODE_30: // MIDI + strncpy(out_timecode->name,"MIDI",31); + out_timecode->fps_div = 30; + break; + case B_TIMECODE_30_DROP_2: // NTSC + strncpy(out_timecode->name,"NTSC",31); + out_timecode->fps_div = 30; // This is supposed to be 29.97fps but can be simulated using the drop frame format below + out_timecode->drop_frames = 2; // Drop 2 frames + out_timecode->every_nth = 1; // every 1 minutes + out_timecode->except_nth = 10; // except every 10 minutes + break; + case B_TIMECODE_30_DROP_4: // Brazil + strncpy(out_timecode->name,"NTSC Brazil",31); + out_timecode->fps_div = 30; + out_timecode->drop_frames = 4; // Drop 4 frames + out_timecode->every_nth = 1; // every 1 minutes + out_timecode->except_nth = 10; // except every 10 minutes + break; + case B_TIMECODE_25: // PAL + strncpy(out_timecode->name,"PAL",31); + out_timecode->fps_div = 25; + break; + case B_TIMECODE_24: // Film + strncpy(out_timecode->name,"FILM",31); + out_timecode->fps_div = 24; + break; + case B_TIMECODE_18: // Super8 + strncpy(out_timecode->name,"Super 8",31); + out_timecode->fps_div = 18; + break; + default: + strncpy(out_timecode->name,"PAL",31); + out_timecode->fps_div = 25; + break; + } + + return B_OK; } status_t count_timecodes() @@ -110,90 +266,26 @@ status_t BTimeCode::SetType(timecode_type type) { CALLED(); - m_info.type = type; - strncpy(m_info.format,"%.2i:%.2i:%.2i:%.2i",31); - m_info.every_nth = 0; - m_info.except_nth = 0; - - switch (type) { - case B_TIMECODE_100: - strncpy(m_info.name,"TIMECODE 100",31); - m_info.fps_div = 100; - break; - case B_TIMECODE_75: // CD - strncpy(m_info.name,"CD",31); - m_info.fps_div = 75; - break; - case B_TIMECODE_30: // MIDI - strncpy(m_info.name,"MIDI",31); - m_info.fps_div = 30; - break; - case B_TIMECODE_30_DROP_2: // NTSC - strncpy(m_info.name,"NTSC",31); - m_info.fps_div = 30; // This is supposed to be 29.97fps - m_info.drop_frames = 2; // Drop 2 frames every minute except every 10 minutes - break; - case B_TIMECODE_30_DROP_4: // Brazil - strncpy(m_info.name,"NTSC Brazil",31); - m_info.fps_div = 30; - m_info.drop_frames = 4; // Drop 4 frames every minute except every 10 minutes - break; - case B_TIMECODE_25: // PAL - strncpy(m_info.name,"PAL",31); - m_info.fps_div = 25; - break; - case B_TIMECODE_24: // Film - strncpy(m_info.name,"FILM",31); - m_info.fps_div = 24; - break; - case B_TIMECODE_18: // Super8 - strncpy(m_info.name,"Super 8",31); - m_info.fps_div = 18; - break; - default: - SetType(B_TIMECODE_25); // PAL default :-) - break; - } - - return B_OK; + + return get_timecode_description(type, &m_info); } void BTimeCode::SetMicroseconds(bigtime_t us) { -// Does not handle Drop formats correctly CALLED(); - m_seconds = us / 1000; - m_frames = (us % 1000) / m_info.fps_div; - - // Now normalise to Hours Minutes Seconds - m_minutes = m_seconds / 60; - m_seconds = m_seconds % 60; - - m_hours = m_minutes / 60; - m_minutes = m_minutes % 60; + us_to_timecode(us, &m_hours, &m_minutes, &m_seconds, &m_frames, &m_info); } void BTimeCode::SetLinearFrames(int32 linear_frames) { -// Does not handle Drop formats correctly - CALLED(); - // First convert frames to seconds leaving the remainder as frames - m_seconds = linear_frames / m_info.fps_div; // DIV - m_frames = linear_frames % m_info.fps_div; // MOD - - // Now normalise to Hours Minutes Seconds - m_minutes = m_seconds / 60; - m_seconds = m_seconds % 60; - - m_hours = m_minutes / 60; - m_minutes = m_minutes % 60; + frames_to_timecode(linear_frames, &m_hours, &m_minutes, &m_seconds, &m_frames, &m_info); } @@ -335,30 +427,30 @@ BTimeCode::GetData(int *out_hours, bigtime_t BTimeCode::Microseconds() const { + bigtime_t us; + CALLED(); - bigtime_t us; + if (timecode_to_us(m_hours,m_minutes,m_seconds,m_frames, &us, &m_info) == B_OK) { + return us; + } - us = m_hours*60+m_minutes; - us = us*60+m_seconds; - us = us*1000+m_frames*m_info.fps_div; - - return us; + return 0; } int32 BTimeCode::LinearFrames() const { - CALLED(); - int32 linear_frames; + + CALLED(); - linear_frames = (m_hours * 60) + m_minutes; - linear_frames = (linear_frames * 60) + m_seconds; - linear_frames = (linear_frames * m_info.fps_div) + m_frames; - - return linear_frames; + if (timecode_to_frames(m_hours,m_minutes,m_seconds,m_frames,&linear_frames,&m_info) == B_OK) { + return linear_frames; + } + + return 0; } @@ -368,5 +460,3 @@ BTimeCode::GetString(char *str) const CALLED(); sprintf(str,m_info.format, m_hours, m_minutes, m_seconds, m_frames); } - -