root/liboggz/trunk/src/liboggz/oggz_auto.c

Revision 3607, 31.2 kB (checked in by conrad, 3 weeks ago)

fit kate magic into the first 8 bytes. Patch by ogg.k.ogg.k

<
Line 
1 /*
2    Copyright (C) 2003 Commonwealth Scientific and Industrial Research
3    Organisation (CSIRO) Australia
4
5    Redistribution and use in source and binary forms, with or without
6    modification, are permitted provided that the following conditions
7    are met:
8
9    - Redistributions of source code must retain the above copyright
10    notice, this list of conditions and the following disclaimer.
11
12    - Redistributions in binary form must reproduce the above copyright
13    notice, this list of conditions and the following disclaimer in the
14    documentation and/or other materials provided with the distribution.
15
16    - Neither the name of CSIRO Australia nor the names of its
17    contributors may be used to endorse or promote products derived from
18    this software without specific prior written permission.
19
20    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23    PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE ORGANISATION OR
24    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /*
34  * oggz_auto.c
35  *
36  * Conrad Parker <conrad@annodex.net>
37  */
38
39 #include "config.h"
40
41 #include <stdlib.h>
42 #include <string.h>
43
44 #include "oggz_private.h"
45 #include "oggz_byteorder.h"
46
47 #include <oggz/oggz_stream.h>
48
49 /*#define DEBUG*/
50
51 /* Allow use of internal metrics; ie. the user_data for these gets free'd
52  * when the metric is overwritten, or on close */
53 int oggz_set_metric_internal (OGGZ * oggz, long serialno, OggzMetric metric,
54                               void * user_data, int internal);
55
56 int oggz_set_metric_linear (OGGZ * oggz, long serialno,
57                             ogg_int64_t granule_rate_numerator,
58                             ogg_int64_t granule_rate_denominator);
59
60 #define INT16_BE_AT(x) _be_16((*(ogg_int32_t *)(x)))
61 #define INT32_LE_AT(x) _le_32((*(ogg_int32_t *)(x)))
62 #define INT32_BE_AT(x) _be_32((*(ogg_int32_t *)(x)))
63 #define INT64_LE_AT(x) _le_64((*(ogg_int64_t *)(x)))
64
65 #define OGGZ_AUTO_MULT 1000Ull
66
67 static int
68 oggz_stream_set_numheaders (OGGZ * oggz, long serialno, int numheaders)
69 {
70   oggz_stream_t * stream;
71
72   if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
73
74   stream = oggz_get_stream (oggz, serialno);
75   if (stream == NULL) return OGGZ_ERR_BAD_SERIALNO;
76
77   stream->numheaders = numheaders;
78
79   return 0;
80 }
81
82 static int
83 auto_speex (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
84 {
85   unsigned char * header = op->packet;
86   ogg_int64_t granule_rate = 0;
87   int numheaders;
88
89   if (op->bytes < 68) return 0;
90
91   granule_rate = (ogg_int64_t) INT32_LE_AT(&header[36]);
92 #ifdef DEBUG
93   printf ("Got speex rate %d\n", (int)granule_rate);
94 #endif
95
96   oggz_set_granulerate (oggz, serialno, granule_rate, OGGZ_AUTO_MULT);
97
98   numheaders = (ogg_int64_t) INT32_LE_AT(&header[68]) + 2;
99   oggz_stream_set_numheaders (oggz, serialno, numheaders);
100
101   return 1;
102 }
103
104 static int
105 auto_vorbis (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
106 {
107   unsigned char * header = op->packet;
108   ogg_int64_t granule_rate = 0;
109
110   if (op->bytes < 30) return 0;
111
112   granule_rate = (ogg_int64_t) INT32_LE_AT(&header[12]);
113 #ifdef DEBUG
114   printf ("Got vorbis rate %d\n", (int)granule_rate);
115 #endif
116
117   oggz_set_granulerate (oggz, serialno, granule_rate, OGGZ_AUTO_MULT);
118
119   oggz_stream_set_numheaders (oggz, serialno, 3);
120
121   return 1;
122 }
123
124 #if USE_THEORA_PRE_ALPHA_3_FORMAT
125 static int intlog(int num) {
126   int ret=0;
127   while(num>0){
128     num=num/2;
129     ret=ret+1;
130   }
131   return(ret);
132 }
133 #endif
134
135 static int
136 auto_theora (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
137 {
138   unsigned char * header = op->packet;
139   ogg_int32_t fps_numerator, fps_denominator;
140   char keyframe_granule_shift = 0;
141   int keyframe_shift;
142
143   /* TODO: this should check against 42 for the relevant version numbers */
144   if (op->bytes < 41) return 0;
145
146   fps_numerator = INT32_BE_AT(&header[22]);
147   fps_denominator = INT32_BE_AT(&header[26]);
148
149   /* Very old theora versions used a value of 0 to mean 1.
150    * Unfortunately theora hasn't incremented its version field,
151    * hence we hardcode this workaround for old or broken streams.
152    */
153   if (fps_numerator == 0) fps_numerator = 1;
154
155 #if USE_THEORA_PRE_ALPHA_3_FORMAT
156   /* old header format, used by Theora alpha2 and earlier */
157   keyframe_granule_shift = (header[36] & 0xf8) >> 3;
158   keyframe_shift = intlog (keyframe_granule_shift - 1);
159 #else
160   keyframe_granule_shift = (char) ((header[40] & 0x03) << 3);
161   keyframe_granule_shift |= (header[41] & 0xe0) >> 5; /* see TODO above */
162   keyframe_shift = keyframe_granule_shift;
163 #endif
164
165 #ifdef DEBUG
166   printf ("Got theora fps %d/%d, keyframe_shift %d\n",
167           fps_numerator, fps_denominator, keyframe_shift);
168 #endif
169
170   oggz_set_granulerate (oggz, serialno, (ogg_int64_t)fps_numerator,
171                         OGGZ_AUTO_MULT * (ogg_int64_t)fps_denominator);
172   oggz_set_granuleshift (oggz, serialno, keyframe_shift);
173
174   oggz_stream_set_numheaders (oggz, serialno, 3);
175
176   return 1;
177 }
178
179 static int
180 auto_annodex (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
181 {
182   /* Apply a zero metric */
183   oggz_set_granulerate (oggz, serialno, 0, 1);
184
185   return 1;
186 }
187
188 static int
189 auto_anxdata (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
190 {
191   unsigned char * header = op->packet;
192   ogg_int64_t granule_rate_numerator = 0, granule_rate_denominator = 0;
193
194   if (op->bytes < 28) return 0;
195
196   granule_rate_numerator = INT64_LE_AT(&header[8]);
197   granule_rate_denominator = INT64_LE_AT(&header[16]);
198 #ifdef DEBUG
199   printf ("Got AnxData rate %lld/%lld\n", granule_rate_numerator,
200           granule_rate_denominator);
201 #endif
202
203   oggz_set_granulerate (oggz, serialno,
204                         granule_rate_numerator,
205                         OGGZ_AUTO_MULT * granule_rate_denominator);
206
207   return 1;
208 }
209
210 static int
211 auto_flac0 (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
212 {
213   unsigned char * header = op->packet;
214   ogg_int64_t granule_rate = 0;
215
216   granule_rate = (ogg_int64_t) (header[14] << 12) | (header[15] << 4) |
217             ((header[16] >> 4)&0xf);
218 #ifdef DEBUG
219     printf ("Got flac rate %d\n", (int)granule_rate);
220 #endif
221     
222   oggz_set_granulerate (oggz, serialno, granule_rate, OGGZ_AUTO_MULT);
223
224   oggz_stream_set_numheaders (oggz, serialno, 3);
225
226   return 1;
227 }
228
229 static int
230 auto_flac (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
231 {
232   unsigned char * header = op->packet;
233   ogg_int64_t granule_rate = 0;
234   int numheaders;
235
236   if (op->bytes < 51) return 0;
237
238   granule_rate = (ogg_int64_t) (header[27] << 12) | (header[28] << 4) |
239             ((header[29] >> 4)&0xf);
240 #ifdef DEBUG
241   printf ("Got flac rate %d\n", (int)granule_rate);
242 #endif
243
244   oggz_set_granulerate (oggz, serialno, granule_rate, OGGZ_AUTO_MULT);
245
246   numheaders = INT16_BE_AT(&header[7]);
247   oggz_stream_set_numheaders (oggz, serialno, numheaders);
248
249   return 1;
250 }
251
252 /**
253  * Recognizer for OggPCM2:
254  * http://wiki.xiph.org/index.php/OggPCM2
255  */
256 static int
257 auto_oggpcm2 (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
258 {
259   unsigned char * header = op->packet;
260   ogg_int64_t granule_rate;
261
262   if (op->bytes < 28) return 0;
263
264   granule_rate = (ogg_int64_t) INT32_BE_AT(&header[16]);
265 #ifdef DEBUG
266   printf ("Got OggPCM2 rate %d\n", (int)granule_rate);
267 #endif
268
269   oggz_set_granulerate (oggz, serialno, granule_rate, OGGZ_AUTO_MULT);
270
271   oggz_stream_set_numheaders (oggz, serialno, 3);
272
273   return 1;
274 }
275
276 static int
277 auto_celt (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
278 {
279   unsigned char * header = op->packet;
280   ogg_int64_t granule_rate = 0;
281   int numheaders;
282
283   if (op->bytes < 56) return 0;
284
285   granule_rate = (ogg_int64_t) INT32_LE_AT(&header[40]);
286 #ifdef DEBUG
287   printf ("Got celt sample rate %d\n", (int)granule_rate);
288 #endif
289
290   oggz_set_granulerate (oggz, serialno, granule_rate, OGGZ_AUTO_MULT);
291
292   numheaders = (ogg_int64_t) INT32_LE_AT(&header[52]) + 2;
293   oggz_stream_set_numheaders (oggz, serialno, numheaders);
294
295   return 1;
296 }
297
298 static int
299 auto_cmml (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
300 {
301   unsigned char * header = op->packet;
302   ogg_int64_t granule_rate_numerator = 0, granule_rate_denominator = 0;
303   int granuleshift;
304
305   if (op->bytes < 28) return 0;
306
307   granule_rate_numerator = INT64_LE_AT(&header[12]);
308   granule_rate_denominator = INT64_LE_AT(&header[20]);
309   if (op->bytes > 28)
310     granuleshift = (int)header[28];
311   else
312     granuleshift = 0;
313
314 #ifdef DEBUG
315   printf ("Got CMML rate %lld/%lld\n", granule_rate_numerator,
316           granule_rate_denominator);
317 #endif
318
319   oggz_set_granulerate (oggz, serialno,
320                         granule_rate_numerator,
321                         OGGZ_AUTO_MULT * granule_rate_denominator);
322   oggz_set_granuleshift (oggz, serialno, granuleshift);
323
324   oggz_stream_set_numheaders (oggz, serialno, 3);
325
326   return 1;
327 }
328
329 static int
330 auto_kate (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
331 {
332   unsigned char * header = op->packet;
333   ogg_int32_t gps_numerator, gps_denominator;
334   unsigned char granule_shift = 0;
335   int numheaders;
336
337   if (op->bytes < 64) return 0;
338
339   gps_numerator = INT32_LE_AT(&header[24]);
340   gps_denominator = INT32_LE_AT(&header[28]);
341
342   granule_shift = (header[15]);
343   numheaders = (header[11]);
344
345 #ifdef DEBUG
346   printf ("Got kate gps %d/%d, granule shift %d\n",
347           gps_numerator, gps_denominator, granule_shift);
348 #endif
349
350   oggz_set_granulerate (oggz, serialno, gps_numerator,
351                         OGGZ_AUTO_MULT * gps_denominator);
352   oggz_set_granuleshift (oggz, serialno, granule_shift);
353  
354   oggz_stream_set_numheaders (oggz, serialno, numheaders);
355
356   return 1;
357 }
358
359 static int
360 auto_fisbone (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
361 {
362   unsigned char * header = op->packet;
363   long fisbone_serialno; /* The serialno referred to in this fisbone */
364   ogg_int64_t granule_rate_numerator = 0, granule_rate_denominator = 0;
365   int granuleshift, numheaders;
366
367   if (op->bytes < 48) return 0;
368
369   fisbone_serialno = (long) INT32_LE_AT(&header[12]);
370
371   /* Don't override an already assigned metric */
372   if (oggz_stream_has_metric (oggz, fisbone_serialno)) return 1;
373
374   granule_rate_numerator = INT64_LE_AT(&header[20]);
375   granule_rate_denominator = INT64_LE_AT(&header[28]);
376   granuleshift = (int)header[48];
377
378 #ifdef DEBUG
379   printf ("Got fisbone granulerate %lld/%lld, granuleshift %d for serialno %010ld\n",
380           granule_rate_numerator, granule_rate_denominator, granuleshift,
381           fisbone_serialno);
382 #endif
383
384   oggz_set_granulerate (oggz, fisbone_serialno,
385                         granule_rate_numerator,
386                         OGGZ_AUTO_MULT * granule_rate_denominator);
387   oggz_set_granuleshift (oggz, fisbone_serialno, granuleshift);
388
389   /* Increment the number of headers for this stream */
390   numheaders = oggz_stream_get_numheaders (oggz, serialno);
391   oggz_stream_set_numheaders (oggz, serialno, numheaders+1);
392                                
393   return 1;
394 }
395
396 static int
397 auto_fishead (OGGZ * oggz, ogg_packet * op, long serialno, void * user_data)
398 {
399   if (!op->b_o_s)
400   {
401     return auto_fisbone(oggz, op, serialno, user_data);
402   }
403  
404   oggz_set_granulerate (oggz, serialno, 0, 1);
405
406   /* For skeleton, numheaders will get incremented as each header is seen */
407   oggz_stream_set_numheaders (oggz, serialno, 1);
408  
409   return 1;
410 }
411
412 /*
413  * The first two speex packets are header and comment packets (granulepos = 0)
414  */
415
416 typedef struct {
417   int headers_encountered;
418   int packet_size;
419   int encountered_first_data_packet;
420 } auto_calc_speex_info_t;
421
422 static ogg_int64_t
423 auto_calc_speex(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
424  
425   /*
426    * on the first (b_o_s) packet, set calculate_data to be the number
427    * of speex frames per packet
428    */
429
430   auto_calc_speex_info_t *info
431           = (auto_calc_speex_info_t *)stream->calculate_data;
432
433   if (stream->calculate_data == NULL) {
434     stream->calculate_data = malloc(sizeof(auto_calc_speex_info_t));
435     info = stream->calculate_data;
436     info->encountered_first_data_packet = 0;
437     info->packet_size =
438             (*(int *)(op->packet + 64)) * (*(int *)(op->packet + 56));
439     info->headers_encountered = 1;
440     return 0;
441   }
442  
443   if (info->headers_encountered < 2) {
444     info->headers_encountered += 1;
445   } else {
446     info->encountered_first_data_packet = 1;
447   }
448
449   if (now > -1) {
450     return now;
451   }
452
453   if (info->encountered_first_data_packet) {
454     if (stream->last_granulepos > 0) {
455       return stream->last_granulepos + info->packet_size;
456     }
457    
458     return -1;
459   }
460
461   return 0;
462
463 }
464
465 /*
466  * The first two CELT packets are header and comment packets (granulepos = 0)
467  */
468
469 typedef struct {
470   int headers_encountered;
471   int packet_size;
472   int encountered_first_data_packet;
473 } auto_calc_celt_info_t;
474
475 static ogg_int64_t
476 auto_calc_celt (ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
477  
478   /*
479    * on the first (b_o_s) packet, set calculate_data to be the number
480    * of celt frames per packet
481    */
482
483   auto_calc_celt_info_t *info
484           = (auto_calc_celt_info_t *)stream->calculate_data;
485
486   if (stream->calculate_data == NULL) {
487     stream->calculate_data = malloc(sizeof(auto_calc_celt_info_t));
488     info = stream->calculate_data;
489     info->encountered_first_data_packet = 0;
490
491     /* In general, the number of frames per packet depends on the mode.
492      * Currently (20080213) both available modes, mono and stereo, have 256
493      * frames per packet.
494      */
495     info->packet_size = 256;
496
497     info->headers_encountered = 1;
498     return 0;
499   }
500  
501   if (info->headers_encountered < 2) {
502     info->headers_encountered += 1;
503   } else {
504     info->encountered_first_data_packet = 1;
505   }
506
507   if (now > -1) {
508     return now;
509   }
510
511   if (info->encountered_first_data_packet) {
512     if (stream->last_granulepos > 0) {
513       return stream->last_granulepos + info->packet_size;
514     }
515    
516     return -1;
517   }
518
519   return 0;
520
521 }
522 /*
523  * Header packets are marked by a set MSB in the first byte.  Inter packets
524  * are marked by a set 2MSB in the first byte.  Intra packets (keyframes)
525  * are any that are left over ;-)
526  *
527  * (see http://www.theora.org/doc/Theora_I_spec.pdf for the theora
528  * specification)
529  */
530
531 typedef struct {
532   int encountered_first_data_packet;
533 } auto_calc_theora_info_t;
534
535
536 static ogg_int64_t
537 auto_calc_theora(ogg_int64_t now, oggz_stream_t *stream, ogg_packet *op) {
538
539   long keyframe_no;
540   int keyframe_shift;
541   unsigned char first_byte;
542   auto_calc_theora_info_t *info;
543
544   first_byte = op->packet[0];
545
546   info = (auto_calc_theora_info_t *)stream->calculate_data;
547
548   /* header packet */
549   if (first_byte & 0x80)
550   {
551     if (info == NULL) {
552       stream->calculate_data = malloc(sizeof(auto_calc_theora_info_t));
553       info = stream->calculate_data;
554     }
555     info->encountered_first_data_packet = 0;
556     return (ogg_int64_t)0;
557   }
558  
559   /* known granulepos */
560   if (now > (ogg_int64_t)(-1)) {
561     info->encountered_first_data_packet = 1;
562     return now;
563   }
564
565   /* last granulepos unknown */
566   if (stream->last_granulepos == -1) {
567     info->encountered_first_data_packet = 1;
568     return (ogg_int64_t)-1;
569   }
570
571   /*
572    * first data packet is -1 if gp not set
573    */
574   if (!info->encountered_first_data_packet) {
575     info->encountered_first_data_packet = 1;
576     return (ogg_int64_t)-1;
577   }
578
579   /* inter-coded packet */
580   if (first_byte & 0x40)
581   {
582     return stream->last_granulepos + 1;
583   }
584
585   keyframe_shift = stream->granuleshift;
586   /*
587    * retrieve last keyframe number
588    */
589   keyframe_no = (int)(stream->last_granulepos >> keyframe_shift);
590   /*
591    * add frames since last keyframe number
592    */