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