1 /*
2 libltc - en+decode linear timecode
3
4 Copyright (C) 2006-2012 Robin Gareus <robin@gareus.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation, either version 3 of the
9 License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library.
18 If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "ltc.h"
26
27 #ifdef HAVE_CONFIG_H
28 # include <config.h>
29 #endif
30
31 /**
32 * SMPTE Timezones
33 */
34 struct SMPTETimeZonesStruct {
35 unsigned char code; //actually 6 bit!
36 char timezone[6];
37 };
38
39 /**
40 * SMPTE Timezone codes as per http://www.barney-wol.net/time/timecode.html
41 */
42 static const struct SMPTETimeZonesStruct smpte_time_zones[] =
43 {
44 /* code, timezone (UTC+) //Standard time //Daylight saving */
45 { 0x00, "+0000" /* Greenwich */ /* - */ },
46 { 0x00, "-0000" /* Greenwich */ /* - */ },
47 { 0x01, "-0100" /* Azores */ /* - */ },
48 { 0x02, "-0200" /* Mid-Atlantic */ /* - */ },
49 { 0x03, "-0300" /* Buenos Aires */ /* Halifax */ },
50 { 0x04, "-0400" /* Halifax */ /* New York */ },
51 { 0x05, "-0500" /* New York */ /* Chicago */ },
52 { 0x06, "-0600" /* Chicago Denver */ /* - */ },
53 { 0x07, "-0700" /* Denver */ /* Los Angeles */ },
54 { 0x08, "-0800" /* Los Angeles */ /* - */ },
55 { 0x09, "-0900" /* Alaska */ /* - */ },
56 { 0x10, "-1000" /* Hawaii */ /* - */ },
57 { 0x11, "-1100" /* Midway Island */ /* - */ },
58 { 0x12, "-1200" /* Kwaialein */ /* - */ },
59 { 0x13, "+1300" /* - */ /* New Zealand */ },
60 { 0x14, "+1200" /* New Zealand */ /* - */ },
61 { 0x15, "+1100" /* Solomon Islands */ /* - */ },
62 { 0x16, "+1000" /* Guam */ /* - */ },
63 { 0x17, "+0900" /* Tokyo */ /* - */ },
64 { 0x18, "+0800" /* Beijing */ /* - */ },
65 { 0x19, "+0700" /* Bangkok */ /* - */ },
66 { 0x20, "+0600" /* Dhaka */ /* - */ },
67 { 0x21, "+0500" /* Islamabad */ /* - */ },
68 { 0x22, "+0400" /* Abu Dhabi */ /* - */ },
69 { 0x23, "+0300" /* Moscow */ /* - */ },
70 { 0x24, "+0200" /* Eastern Europe */ /* - */ },
71 { 0x25, "+0100" /* Central Europe */ /* - */ },
72 /* { 0x26, "Undefined" Reserved; do not use },*/
73 /* { 0x27, "Undefined" Reserved; do not use },*/
74 { 0x28, "TP-03" /* Time precision class 3 */ /* - */ },
75 { 0x29, "TP-02" /* Time precision class 2 */ /* - */ },
76 { 0x30, "TP-01" /* Time precision class 1 */ /* - */ },
77 { 0x31, "TP-00" /* Time precision class 0 */ /* - */ },
78 { 0x0A, "-0030" /* - */ /* - */ },
79 { 0x0B, "-0130" /* - */ /* - */ },
80 { 0x0C, "-0230" /* - */ /* Newfoundland */ },
81 { 0x0D, "-0330" /* Newfoundland */ /* - */ },
82 { 0x0E, "-0430" /* - */ /* - */ },
83 { 0x0F, "-0530" /* - */ /* - */ },
84 { 0x1A, "-0630" /* - */ /* - */ },
85 { 0x1B, "-0730" /* - */ /* - */ },
86 { 0x1C, "-0830" /* - */ /* - */ },
87 { 0x1D, "-0930" /* Marquesa Islands */ /* - */ },
88 { 0x1E, "-1030" /* - */ /* - */ },
89 { 0x1F, "-1130" /* - */ /* - */ },
90 { 0x2A, "+1130" /* Norfolk Island */ /* - */ },
91 { 0x2B, "+1030" /* Lord Howe Is. */ /* - */ },
92 { 0x2C, "+0930" /* Darwin */ /* - */ },
93 { 0x2D, "+0830" /* - */ /* - */ },
94 { 0x2E, "+0730" /* - */ /* - */ },
95 { 0x2F, "+0630" /* Rangoon */ /* - */ },
96 { 0x3A, "+0530" /* Bombay */ /* - */ },
97 { 0x3B, "+0430" /* Kabul */ /* - */ },
98 { 0x3C, "+0330" /* Tehran */ /* - */ },
99 { 0x3D, "+0230" /* - */ /* - */ },
100 { 0x3E, "+0130" /* - */ /* - */ },
101 { 0x3F, "+0030" /* - */ /* - */ },
102 { 0x32, "+1245" /* Chatham Island */ /* - */ },
103 /* { 0x33, "Undefined" Reserved; do not use },*/
104 /* { 0x34, "Undefined" Reserved; do not use },*/
105 /* { 0x35, "Undefined" Reserved; do not use },*/
106 /* { 0x36, "Undefined" Reserved; do not use },*/
107 /* { 0x37, "Undefined" Reserved; do not use },*/
108 { 0x38, "+XXXX" /* User defined time offset */ /* - */ },
109 /* { 0x39, "Undefined" Unknown Unknown },*/
110 /* { 0x39, "Undefined" Unknown Unknown },*/
111
112 { 0xFF, "" /* The End */ }
113 };
114
smpte_set_timezone_string(LTCFrame * frame,SMPTETimecode * stime)115 static void smpte_set_timezone_string(LTCFrame *frame, SMPTETimecode *stime) {
116 int i = 0;
117
118 const unsigned char code = frame->user7 + (frame->user8 << 4);
119
120 char timezone[6] = "+0000";
121
122 for (i = 0 ; smpte_time_zones[i].code != 0xFF ; i++) {
123 if ( smpte_time_zones[i].code == code ) {
124 strcpy(timezone, smpte_time_zones[i].timezone);
125 break;
126 }
127 }
128 strcpy(stime->timezone, timezone);
129 }
130
smpte_set_timezone_code(SMPTETimecode * stime,LTCFrame * frame)131 static void smpte_set_timezone_code(SMPTETimecode *stime, LTCFrame *frame) {
132 int i = 0;
133 unsigned char code = 0x00;
134
135 // Find code for timezone string
136 // Primitive search
137 for (i=0; smpte_time_zones[i].code != 0xFF; i++) {
138 if ( (strcmp(smpte_time_zones[i].timezone, stime->timezone)) == 0 ) {
139 code = smpte_time_zones[i].code;
140 break;
141 }
142 }
143
144 frame->user7 = code & 0x0F;
145 frame->user8 = (code & 0xF0) >> 4;
146 }
147
148 /** Drop-frame support function
149 * We skip the first two frame numbers (0 and 1) at the beginning of each minute,
150 * except for minutes 0, 10, 20, 30, 40, and 50
151 * (i.e. we skip frame numbers at the beginning of minutes for which mins_units is not 0).
152 */
skip_drop_frames(LTCFrame * frame)153 static void skip_drop_frames(LTCFrame* frame) {
154 if ((frame->mins_units != 0)
155 && (frame->secs_units == 0)
156 && (frame->secs_tens == 0)
157 && (frame->frame_units == 0)
158 && (frame->frame_tens == 0)
159 ) {
160 frame->frame_units += 2;
161 }
162 }
163
ltc_frame_to_time(SMPTETimecode * stime,LTCFrame * frame,int flags)164 void ltc_frame_to_time(SMPTETimecode *stime, LTCFrame *frame, int flags) {
165 if (!stime) return;
166
167 if (flags & LTC_USE_DATE) {
168 smpte_set_timezone_string(frame, stime);
169
170 stime->years = frame->user5 + frame->user6*10;
171 stime->months = frame->user3 + frame->user4*10;
172 stime->days = frame->user1 + frame->user2*10;
173 } else {
174 stime->years = 0;
175 stime->months = 0;
176 stime->days = 0;
177 sprintf(stime->timezone,"+0000");
178 }
179
180 stime->hours = frame->hours_units + frame->hours_tens*10;
181 stime->mins = frame->mins_units + frame->mins_tens*10;
182 stime->secs = frame->secs_units + frame->secs_tens*10;
183 stime->frame = frame->frame_units + frame->frame_tens*10;
184 }
185
ltc_time_to_frame(LTCFrame * frame,SMPTETimecode * stime,enum LTC_TV_STANDARD standard,int flags)186 void ltc_time_to_frame(LTCFrame* frame, SMPTETimecode* stime, enum LTC_TV_STANDARD standard, int flags) {
187 if (flags & LTC_USE_DATE) {
188 smpte_set_timezone_code(stime, frame);
189 frame->user6 = stime->years/10;
190 frame->user5 = stime->years - frame->user6*10;
191 frame->user4 = stime->months/10;
192 frame->user3 = stime->months - frame->user4*10;
193 frame->user2 = stime->days/10;
194 frame->user1 = stime->days - frame->user2*10;
195 }
196
197 frame->hours_tens = stime->hours/10;
198 frame->hours_units = stime->hours - frame->hours_tens*10;
199 frame->mins_tens = stime->mins/10;
200 frame->mins_units = stime->mins - frame->mins_tens*10;
201 frame->secs_tens = stime->secs/10;
202 frame->secs_units = stime->secs - frame->secs_tens*10;
203 frame->frame_tens = stime->frame/10;
204 frame->frame_units = stime->frame - frame->frame_tens*10;
205
206 // Prevent illegal SMPTE frames
207 if (frame->dfbit) {
208 skip_drop_frames(frame);
209 }
210
211 if ((flags & LTC_NO_PARITY) == 0) {
212 ltc_frame_set_parity(frame, standard);
213 }
214 }
215
ltc_frame_reset(LTCFrame * frame)216 void ltc_frame_reset(LTCFrame* frame) {
217 memset(frame, 0, sizeof(LTCFrame));
218 // syncword = 0x3FFD
219 #ifdef LTC_BIG_ENDIAN
220 // mirrored BE bit order: FCBF
221 frame->sync_word = 0xFCBF;
222 #else
223 // mirrored LE bit order: BFFC
224 frame->sync_word = 0xBFFC;
225 #endif
226 }
227
ltc_frame_increment(LTCFrame * frame,int fps,enum LTC_TV_STANDARD standard,int flags)228 int ltc_frame_increment(LTCFrame* frame, int fps, enum LTC_TV_STANDARD standard, int flags) {
229 int rv = 0;
230
231 frame->frame_units++;
232
233 if (frame->frame_units == 10)
234 {
235 frame->frame_units = 0;
236 frame->frame_tens++;
237 }
238 if (fps == frame->frame_units+frame->frame_tens*10)
239 {
240 frame->frame_units = 0;
241 frame->frame_tens = 0;
242 frame->secs_units++;
243 if (frame->secs_units == 10)
244 {
245 frame->secs_units = 0;
246 frame->secs_tens++;
247 if (frame->secs_tens == 6)
248 {
249 frame->secs_tens = 0;
250 frame->mins_units++;
251 if (frame->mins_units == 10)
252 {
253 frame->mins_units = 0;
254 frame->mins_tens++;
255 if (frame->mins_tens == 6)
256 {
257 frame->mins_tens = 0;
258 frame->hours_units++;
259 if (frame->hours_units == 10)
260 {
261 frame->hours_units = 0;
262 frame->hours_tens++;
263 }
264 if (frame->hours_units == 4 && frame->hours_tens==2)
265 {
266 /* 24h wrap around */
267 rv=1;
268 frame->hours_tens=0;
269 frame->hours_units = 0;
270
271 if (flags&1)
272 {
273 /* wrap date */
274 SMPTETimecode stime;
275 stime.years = frame->user5 + frame->user6*10;
276 stime.months = frame->user3 + frame->user4*10;
277 stime.days = frame->user1 + frame->user2*10;
278
279 if (stime.months > 0 && stime.months < 13)
280 {
281 unsigned char dpm[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
282 /* proper leap-year calc:
283 * ((stime.years%4)==0 && ( (stime.years%100) != 0 || (stime.years%400) == 0) )
284 * simplified since year is 0..99
285 */
286 if ((stime.years%4)==0 /* && stime.years!=0 */ ) /* year 2000 was a leap-year */
287 dpm[1]=29;
288 stime.days++;
289 if (stime.days > dpm[stime.months-1])
290 {
291 stime.days=1;
292 stime.months++;
293 if (stime.months > 12) {
294 stime.months=1;
295 stime.years=(stime.years+1)%100;
296 }
297 }
298 frame->user6 = stime.years/10;
299 frame->user5 = stime.years%10;
300 frame->user4 = stime.months/10;
301 frame->user3 = stime.months%10;
302 frame->user2 = stime.days/10;
303 frame->user1 = stime.days%10;
304 } else {
305 rv=-1;
306 }
307 }
308 }
309 }
310 }
311 }
312 }
313 }
314
315 if (frame->dfbit) {
316 skip_drop_frames(frame);
317 }
318
319 if ((flags & LTC_NO_PARITY) == 0) {
320 ltc_frame_set_parity(frame, standard);
321 }
322
323 return rv;
324 }
325
ltc_frame_decrement(LTCFrame * frame,int fps,enum LTC_TV_STANDARD standard,int flags)326 int ltc_frame_decrement(LTCFrame* frame, int fps, enum LTC_TV_STANDARD standard, int flags) {
327 int rv = 0;
328
329 int frames = frame->frame_units + frame->frame_tens * 10;
330 if (frames > 0) {
331 frames--;
332 } else {
333 frames = fps -1;
334 }
335
336 frame->frame_units = frames % 10;
337 frame->frame_tens = frames / 10;
338
339 if (frames == fps -1) {
340 int secs = frame->secs_units + frame->secs_tens * 10;
341 if (secs > 0) {
342 secs--;
343 } else {
344 secs = 59;
345 }
346 frame->secs_units = secs % 10;
347 frame->secs_tens = secs / 10;
348
349 if (secs == 59) {
350 int mins = frame->mins_units + frame->mins_tens * 10;
351 if (mins > 0) {
352 mins--;
353 } else {
354 mins = 59;
355 }
356 frame->mins_units = mins % 10;
357 frame->mins_tens = mins / 10;
358
359 if (mins == 59) {
360 int hours = frame->hours_units + frame->hours_tens * 10;
361 if (hours > 0) {
362 hours--;
363 } else {
364 hours = 23;
365 }
366 frame->hours_units = hours % 10;
367 frame->hours_tens = hours / 10;
368
369 if (hours == 23) {
370 /* 24h wrap around */
371 rv=1;
372 if (flags<C_USE_DATE)
373 {
374 /* wrap date */
375 SMPTETimecode stime;
376 stime.years = frame->user5 + frame->user6*10;
377 stime.months = frame->user3 + frame->user4*10;
378 stime.days = frame->user1 + frame->user2*10;
379
380 if (stime.months > 0 && stime.months < 13)
381 {
382 unsigned char dpm[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
383 /* proper leap-year calc:
384 * ((stime.years%4)==0 && ( (stime.years%100) != 0 || (stime.years%400) == 0) )
385 * simplified since year is 0..99
386 */
387 if ((stime.years%4)==0 /* && stime.years!=0 */ ) /* year 2000 was a leap-year */
388 dpm[1]=29;
389 //
390 if (stime.days > 1) {
391 stime.days--;
392 } else {
393 stime.months = 1 + (stime.months + 10)%12;
394 stime.days = dpm[stime.months-1];
395 if (stime.months == 12) {
396 stime.years=(stime.years+99)%100; // XXX
397 }
398 }
399
400 frame->user6 = stime.years/10;
401 frame->user5 = stime.years%10;
402 frame->user4 = stime.months/10;
403 frame->user3 = stime.months%10;
404 frame->user2 = stime.days/10;
405 frame->user1 = stime.days%10;
406 } else {
407 rv=-1;
408 }
409 }
410 }
411 }
412 }
413 }
414
415 if (frame->dfbit && /* prevent endless recursion */ fps > 2) {
416 if ((frame->mins_units != 0)
417 && (frame->secs_units == 0)
418 && (frame->secs_tens == 0)
419 && (frame->frame_units == 1)
420 && (frame->frame_tens == 0)
421 ) {
422 ltc_frame_decrement(frame, fps, standard, flags<C_USE_DATE);
423 ltc_frame_decrement(frame, fps, standard, flags<C_USE_DATE);
424 }
425 }
426
427 if ((flags & LTC_NO_PARITY) == 0) {
428 ltc_frame_set_parity(frame, standard);
429 }
430
431 return rv;
432 }
433
parse_bcg_flags(LTCFrame * f,enum LTC_TV_STANDARD standard)434 int parse_bcg_flags(LTCFrame *f, enum LTC_TV_STANDARD standard) {
435 switch (standard) {
436 case LTC_TV_625_50: /* 25 fps mode */
437 return (
438 ((f->binary_group_flag_bit0)?4:0)
439 | ((f->binary_group_flag_bit1)?2:0)
440 | ((f->biphase_mark_phase_correction)?1:0)
441 );
442 break;
443 default: /* 24,30 fps mode */
444 return (
445 ((f->binary_group_flag_bit2)?4:0)
446 | ((f->binary_group_flag_bit1)?2:0)
447 | ((f->binary_group_flag_bit0)?1:0)
448 );
449 break;
450 }
451 }
452