headers/bsd: Add sys/queue.h.
[haiku.git] / src / kits / media / TimeCode.cpp
blobb805cfaa37fbbb6876c14e62d87d59db7058ac9a
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>
10 status_t us_to_timecode(bigtime_t micros, int * hours, int * minutes, int * seconds, int * frames, const timecode_info * code)
12 int32 l_frames;
14 CALLED();
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;
30 } else {
31 // Convert us to frames
32 l_frames = int32((((micros % 1000000) * 29.97) / 1000000) + (micros / 1000000 * 29.97));
35 return frames_to_timecode(l_frames, hours, minutes, seconds, frames, code);
38 status_t timecode_to_us(int hours, int minutes, int seconds, int frames, bigtime_t * micros, const timecode_info * code)
40 int32 l_frames;
42 CALLED();
44 if (timecode_to_frames(hours, minutes, seconds, frames, &l_frames, code) == B_OK) {
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;
61 } else {
62 *micros = bigtime_t(l_frames * ((1000000 / 29.97) + 0.5));
65 return B_OK;
67 return B_ERROR;
70 status_t frames_to_timecode(int32 l_frames, int * hours, int * minutes, int * seconds, int * frames, const timecode_info * code)
72 int fps_div;
73 int total_mins;
74 int32 extra_frames;
75 int32 extra_frames2;
77 CALLED();
79 if (code) {
80 // We have a valid timecode_info so use it
81 fps_div = code->fps_div;
83 if (code->every_nth > 0) {
84 // Handle Drop Frames format
86 total_mins = l_frames / fps_div / 60;
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;
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);
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;
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);
104 // l_frames should now include all adjusted frames
106 } else {
107 // no timecode_info so set default NTSC :-(
108 fps_div = 30; // NTSC Default
109 total_mins = l_frames / fps_div / 60;
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;
115 total_mins = l_frames / fps_div / 60;
116 extra_frames2 = 2*(total_mins) - 2*(total_mins/10);
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;
123 total_mins = l_frames / fps_div / 60;
124 extra_frames2 = 2*(total_mins) - 2*(total_mins/10);
128 // convert frames to seconds leaving the remainder as frames
129 *seconds = l_frames / fps_div; // DIV
130 *frames = l_frames % fps_div; // MOD
132 // Normalise to Hours Minutes Seconds Frames
133 *minutes = *seconds / 60;
134 *seconds = *seconds % 60;
136 *hours = *minutes / 60;
137 *minutes = *minutes % 60;
139 return B_OK;
142 status_t timecode_to_frames(int hours, int minutes, int seconds, int frames, int32 * l_frames, const timecode_info * code)
144 int fps_div;
145 int total_mins;
146 int32 extra_frames;
148 CALLED();
150 if (code) {
151 // We have a valid timecode_info
152 fps_div = code->fps_div;
154 total_mins = (hours * 60) + minutes;
155 *l_frames = (total_mins * 60) + seconds;
156 *l_frames = (*l_frames * fps_div) + frames;
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);
162 *l_frames = *l_frames - extra_frames;
164 } else {
166 total_mins = (hours * 60) + minutes;
167 *l_frames = (total_mins * 60) + seconds;
168 *l_frames = (*l_frames * 30) + frames;
170 // Adjust "every_nth" minute we lose "drop_frames" "except_nth" minute
171 extra_frames = 2*(total_mins) - 2*(total_mins/10);
173 *l_frames = *l_frames - extra_frames;
176 return B_OK;
179 status_t get_timecode_description(timecode_type type, timecode_info * out_timecode)
181 CALLED();
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;
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;
236 return B_OK;
239 status_t count_timecodes()
241 CALLED();
242 return 8; // Is this right?
245 /*************************************************************
246 * public BTimeCode
247 *************************************************************/
250 BTimeCode::BTimeCode()
252 CALLED();
256 BTimeCode::BTimeCode(bigtime_t us,
257 timecode_type type)
259 CALLED();
260 if (SetType(type) == B_OK) {
261 SetMicroseconds(us);
266 BTimeCode::BTimeCode(const BTimeCode &clone)
268 CALLED();
269 if (SetType(clone.Type()) == B_OK) {
270 SetData(clone.Hours(),clone.Minutes(),clone.Seconds(),clone.Frames());
275 BTimeCode::BTimeCode(int hours,
276 int minutes,
277 int seconds,
278 int frames,
279 timecode_type type)
281 CALLED();
282 if (SetType(type) == B_OK) {
283 SetData(hours,minutes,seconds,frames);
288 BTimeCode::~BTimeCode()
290 CALLED();
294 void
295 BTimeCode::SetData(int hours,
296 int minutes,
297 int seconds,
298 int frames)
300 CALLED();
301 fHours = hours;
302 fMinutes = minutes;
303 fSeconds = seconds;
304 fFrames = frames;
308 status_t
309 BTimeCode::SetType(timecode_type type)
311 CALLED();
313 return get_timecode_description(type, &fInfo);
317 void
318 BTimeCode::SetMicroseconds(bigtime_t us)
320 CALLED();
322 us_to_timecode(us, &fHours, &fMinutes, &fSeconds, &fFrames, &fInfo);
326 void
327 BTimeCode::SetLinearFrames(int32 linear_frames)
329 CALLED();
331 frames_to_timecode(linear_frames, &fHours, &fMinutes, &fSeconds, &fFrames, &fInfo);
335 BTimeCode &
336 BTimeCode::operator=(const BTimeCode &clone)
338 CALLED();
339 fHours = clone.Hours();
340 fMinutes = clone.Minutes();
341 fSeconds = clone.Seconds();
342 fFrames = clone.Frames();
343 SetType(clone.Type());
345 return *this;
349 bool
350 BTimeCode::operator==(const BTimeCode &other) const
352 CALLED();
354 return ((this->LinearFrames()) == (other.LinearFrames()));
358 bool
359 BTimeCode::operator<(const BTimeCode &other) const
361 CALLED();
363 return ((this->LinearFrames()) < (other.LinearFrames()));
367 BTimeCode &
368 BTimeCode::operator+=(const BTimeCode &other)
370 CALLED();
372 this->SetLinearFrames(this->LinearFrames() + other.LinearFrames());
374 return *this;
378 BTimeCode &
379 BTimeCode::operator-=(const BTimeCode &other)
381 CALLED();
383 this->SetLinearFrames(this->LinearFrames() - other.LinearFrames());
385 return *this;
389 BTimeCode
390 BTimeCode::operator+(const BTimeCode &other) const
392 CALLED();
393 BTimeCode tc(*this);
394 tc += other;
395 return tc;
399 BTimeCode
400 BTimeCode::operator-(const BTimeCode &other) const
402 CALLED();
403 BTimeCode tc(*this);
404 tc -= other;
405 return tc;
410 BTimeCode::Hours() const
412 CALLED();
414 return fHours;
419 BTimeCode::Minutes() const
421 CALLED();
423 return fMinutes;
428 BTimeCode::Seconds() const
430 CALLED();
432 return fSeconds;
437 BTimeCode::Frames() const
439 CALLED();
441 return fFrames;
445 timecode_type
446 BTimeCode::Type() const
448 CALLED();
450 return fInfo.type;
454 void
455 BTimeCode::GetData(int *out_hours,
456 int *out_minutes,
457 int *out_seconds,
458 int *out_frames,
459 timecode_type *out_type) const
461 CALLED();
462 *out_hours = fHours;
463 *out_minutes = fMinutes;
464 *out_seconds = fSeconds;
465 *out_frames = fFrames;
466 *out_type = fInfo.type;
470 bigtime_t
471 BTimeCode::Microseconds() const
473 bigtime_t us;
475 CALLED();
477 if (timecode_to_us(fHours,fMinutes,fSeconds,fFrames, &us, &fInfo) == B_OK) {
478 return us;
481 return 0;
485 int32
486 BTimeCode::LinearFrames() const
488 int32 linear_frames;
490 CALLED();
492 if (timecode_to_frames(fHours,fMinutes,fSeconds,fFrames,&linear_frames,&fInfo) == B_OK) {
493 return linear_frames;
496 return 0;
500 void
501 BTimeCode::GetString(char *str) const
503 CALLED();
504 sprintf(str,fInfo.format, fHours, fMinutes, fSeconds, fFrames);