Camera tracking integration
[blender.git] / source / blender / imbuf / intern / indexer_dv.c
1 #include "IMB_indexer.h"
2 #include "MEM_guardedalloc.h"
3 #include <time.h>
4
5 typedef struct indexer_dv_bitstream {
6         unsigned char* buffer;
7         int bit_pos;
8 } indexer_dv_bitstream;
9
10 static indexer_dv_bitstream bitstream_new(unsigned char* buffer_) 
11 {
12         indexer_dv_bitstream rv;
13
14         rv.buffer = buffer_;
15         rv.bit_pos = 0;
16
17         return rv;
18 }
19
20 static unsigned long bitstream_get_bits(indexer_dv_bitstream * This, int num) 
21 {
22         int byte_pos = This->bit_pos >> 3;
23         unsigned long i = 
24                 This->buffer[byte_pos] | (This->buffer[byte_pos + 1] << 8) |
25                 (This->buffer[byte_pos + 2] << 16) | 
26                 (This->buffer[byte_pos + 3] << 24);
27         int rval = (i >> (This->bit_pos & 0x7)) & ((1 << num) - 1);
28         This->bit_pos += num;
29         return rval;
30 }
31
32 static int parse_num(indexer_dv_bitstream * b, int numbits) {
33         return bitstream_get_bits(b, numbits);
34 }
35
36 static int parse_bcd(indexer_dv_bitstream * b, int n) 
37 {
38         char s[256];
39         char * p = s + (n+3)/4;
40
41         *p-- = 0;
42
43         while (n > 4) {
44                 char a;
45                 int v = bitstream_get_bits(b, 4);
46
47                 n -= 4;
48                 a = '0' + v;
49
50                 if (a > '9') {
51                         bitstream_get_bits(b, n); 
52                         return -1;
53                 }
54
55                 *p-- = a;
56         }
57         if (n) {
58                 char a;
59                 int v = bitstream_get_bits(b, n);
60                 a = '0' + v;
61                 if (a > '9') {
62                         return -1;
63                 }
64                 *p-- = a;
65         }
66
67         return atol(s);
68 }
69
70 typedef struct indexer_dv_context
71 {
72         int rec_curr_frame;
73         int rec_curr_second;
74         int rec_curr_minute;
75         int rec_curr_hour;
76
77         int rec_curr_day;
78         int rec_curr_month;
79         int rec_curr_year;
80
81         char got_record_date;
82         char got_record_time;
83
84         time_t ref_time_read;
85         time_t ref_time_read_new;
86         int curr_frame;
87
88         time_t gap_start;
89         int gap_frame;
90
91         int frameno_offset;
92
93         anim_index_entry backbuffer[31];
94         int fsize;
95
96         anim_index_builder * idx;
97 } indexer_dv_context;
98
99 static void parse_packet(indexer_dv_context * This, unsigned char * p)
100 {
101         indexer_dv_bitstream b;
102         int type = p[0];
103
104         b = bitstream_new(p + 1);
105
106         switch (type) {
107         case 0x62: // Record date
108                 parse_num(&b, 8);
109                 This->rec_curr_day = parse_bcd(&b, 6);
110                 parse_num(&b, 2);
111                 This->rec_curr_month = parse_bcd(&b, 5);
112                 parse_num(&b, 3);
113                 This->rec_curr_year = parse_bcd(&b, 8);
114                 if (This->rec_curr_year < 25) {
115                         This->rec_curr_year += 2000;
116                 } else {
117                         This->rec_curr_year += 1900;
118                 }
119                 This->got_record_date = 1;
120                 break;
121         case 0x63: // Record time
122                 This->rec_curr_frame = parse_bcd(&b, 6);
123                 parse_num(&b, 2);
124                 This->rec_curr_second = parse_bcd(&b, 7);
125                 parse_num(&b, 1);
126                 This->rec_curr_minute = parse_bcd(&b, 7);
127                 parse_num(&b, 1);
128                 This->rec_curr_hour = parse_bcd(&b, 6);
129                 This->got_record_time = 1;
130                 break;
131         }
132 }
133
134 static void parse_header_block(indexer_dv_context * This, unsigned char* target)
135 {
136         int i;
137         for (i = 3; i < 80; i += 5) {
138                   if (target[i] != 0xff) {
139                           parse_packet(This, target + i);
140                   }
141         }
142 }
143
144 static void parse_subcode_blocks(
145         indexer_dv_context * This, unsigned char* target)
146 {
147         int i,j;
148
149         for (j = 0; j < 2; j++) {
150                 for (i = 3; i < 80; i += 5) {
151                         if (target[i] != 0xff) {
152                                 parse_packet(This, target + i);
153                         }
154                 }
155         }
156 }
157
158 static void parse_vaux_blocks(
159         indexer_dv_context * This, unsigned char* target)
160 {
161         int i,j;
162
163         for (j = 0; j < 3; j++) {
164                 for (i = 3; i < 80; i += 5) {
165                         if (target[i] != 0xff) {
166                                 parse_packet(This, target + i);
167                         }
168                 }
169                 target += 80;
170         }
171 }
172
173 static void parse_audio_headers(
174         indexer_dv_context * This, unsigned char* target)
175 {
176         int i;
177
178         for(i = 0; i < 9; i++) {
179                 if (target[3] != 0xff) {
180                         parse_packet(This, target + 3);
181                 }
182                 target += 16 * 80;
183         }
184 }
185
186 static void parse_frame(indexer_dv_context * This, 
187                         unsigned char * framebuffer, int isPAL)
188 {
189         int numDIFseq = isPAL ? 12 : 10;
190         unsigned char* target = framebuffer;
191         int ds;
192
193         for (ds = 0; ds < numDIFseq; ds++) { 
194                 parse_header_block(This, target);
195                 target +=   1 * 80;
196                 parse_subcode_blocks(This, target);
197                 target +=   2 * 80;
198                 parse_vaux_blocks(This, target);
199                 target +=   3 * 80;
200                 parse_audio_headers(This, target);
201                 target += 144 * 80;
202         }
203 }
204
205 static void inc_frame(int * frame, time_t * t, int isPAL)
206 {
207         if ((isPAL && *frame >= 25) || (!isPAL && *frame >= 30)) {
208                 fprintf(stderr, "Ouchie: inc_frame: invalid_frameno: %d\n",
209                         *frame);
210         }
211         (*frame)++;
212         if (isPAL && *frame >= 25) {
213                 (*t)++;
214                 *frame = 0;
215         } else if (!isPAL && *frame >= 30) {
216                 (*t)++;
217                 *frame = 0;
218         }
219 }
220
221 static void write_index(indexer_dv_context * This, anim_index_entry * entry)
222 {
223         IMB_index_builder_add_entry(
224                 This->idx, entry->frameno + This->frameno_offset, 
225                 entry->seek_pos, entry->seek_pos_dts, entry->pts);
226 }
227
228 static void fill_gap(indexer_dv_context * This, int isPAL)
229 {
230         int i;
231
232         for (i = 0; i < This->fsize; i++) {
233                 if (This->gap_start == This->ref_time_read && 
234                     This->gap_frame == This->curr_frame) {
235                         fprintf(stderr, 
236                                 "indexer_dv::fill_gap: "
237                                 "can't seek backwards !\n");
238                         break;
239                 }
240                 inc_frame(&This->gap_frame, &This->gap_start, isPAL);
241         }
242
243         while (This->gap_start != This->ref_time_read || 
244                This->gap_frame != This->curr_frame) {
245                 inc_frame(&This->gap_frame, &This->gap_start, isPAL);
246                 This->frameno_offset++;
247         }
248
249         for (i = 0; i < This->fsize; i++) {
250                 write_index(This, This->backbuffer + i);
251         }
252         This->fsize = 0;
253 }
254
255 static void proc_frame(indexer_dv_context * This,
256                        unsigned char* framebuffer, int isPAL)
257 {
258         struct tm recDate;
259         time_t t;
260
261         if (!This->got_record_date || !This->got_record_time) {
262                 return;
263         }
264
265         recDate.tm_sec = This->rec_curr_second;
266         recDate.tm_min = This->rec_curr_minute;
267         recDate.tm_hour = This->rec_curr_hour;
268         recDate.tm_mday = This->rec_curr_day;
269         recDate.tm_mon = This->rec_curr_month - 1;
270         recDate.tm_year = This->rec_curr_year - 1900;
271         recDate.tm_wday = -1;
272         recDate.tm_yday = -1;
273         recDate.tm_isdst = -1;
274         
275         t = mktime(&recDate);
276         if (t == -1) {
277                 return;
278         }
279
280         This->ref_time_read_new = t;
281
282         if (This->ref_time_read < 0) {
283                 This->ref_time_read = This->ref_time_read_new;
284                 This->curr_frame = 0;
285         } else {
286                 if (This->ref_time_read_new - This->ref_time_read == 1) {
287                         This->curr_frame = 0;
288                         This->ref_time_read = This->ref_time_read_new;
289                         if (This->gap_frame >= 0) {
290                                 fill_gap(This, isPAL);
291                                 This->gap_frame = -1;
292                         }
293                 } else if (This->ref_time_read_new  == This->ref_time_read) {
294                         // do nothing
295                 } else {
296                         This->gap_start = This->ref_time_read;
297                         This->gap_frame = This->curr_frame;
298                         This->ref_time_read = This->ref_time_read_new;
299                         This->curr_frame = -1;
300                 }
301         }
302 }
303
304 static void indexer_dv_proc_frame(anim_index_builder * idx, 
305                                   unsigned char * buffer,
306                                   int data_size, 
307                                   struct anim_index_entry * entry)
308 {
309         int isPAL;
310         
311         indexer_dv_context * This = (indexer_dv_context *) idx->private_data;
312
313         isPAL = (buffer[3] & 0x80);
314
315         This->got_record_date = FALSE;
316         This->got_record_time = FALSE;
317
318         parse_frame(This, buffer, isPAL);
319         proc_frame(This, buffer, isPAL);
320
321         if (This->curr_frame >= 0) {
322                 write_index(This, entry);
323                 inc_frame(&This->curr_frame, &This->ref_time_read, isPAL);
324         } else {
325                 This->backbuffer[This->fsize++] = *entry;
326                 if (This->fsize >= 31) {
327                         int i;
328
329                         fprintf(stderr, "indexer_dv::indexer_dv_proc_frame: "
330                                 "backbuffer overrun, emergency flush");
331
332                         for (i = 0; i < This->fsize; i++) {
333                                 write_index(This, This->backbuffer+i);
334                         }
335                         This->fsize = 0;
336                 }
337         }
338 }
339
340 static void indexer_dv_delete(anim_index_builder * idx)
341 {
342         int i = 0;
343         indexer_dv_context * This = (indexer_dv_context *) idx->private_data;
344
345         for (i = 0; i < This->fsize; i++) {
346                 write_index(This, This->backbuffer+i);
347         }
348
349         MEM_freeN(This);
350 }
351
352 void IMB_indexer_dv_new(anim_index_builder * idx)
353 {
354         indexer_dv_context * rv = MEM_callocN( 
355                 sizeof(indexer_dv_context), "index_dv builder context");
356
357         rv->ref_time_read = -1;
358         rv->curr_frame = -1;
359         rv->gap_frame = -1;
360         rv->idx = idx;
361         
362         idx->private_data = rv;
363         idx->proc_frame = indexer_dv_proc_frame;
364         idx->delete_priv_data = indexer_dv_delete;
365 }