1 /*
2   Copyright (C) 2005 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 #include "config.h"
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <getopt.h>
39 
40 #include "oggz/oggz.h"
41 
42 #include "dirac.h"
43 #include "oggz_tools_dirac.h"
44 
45 #if defined (WIN32) || defined (__EMX__)
46 #include <fcntl.h>
47 #include <io.h>
48 #define snprintf _snprintf
49 #endif
50 
51 #ifdef HAVE_INTTYPES_H
52 #  include <inttypes.h>
53 #else
54 #  define PRId64 "I64d"
55 #endif
56 
57 
58 static  ogg_uint32_t
_le_32(ogg_uint32_t i)59 _le_32 (ogg_uint32_t i)
60 {
61    ogg_uint32_t ret=i;
62 #ifdef WORDS_BIGENDIAN
63    ret =  (i>>24);
64    ret += (i>>8) & 0x0000ff00;
65    ret += (i<<8) & 0x00ff0000;
66    ret += (i<<24);
67 #endif
68    return ret;
69 }
70 
71 static  ogg_uint16_t
_be_16(ogg_uint16_t s)72 _be_16 (ogg_uint16_t s)
73 {
74   unsigned short ret=s;
75 #ifndef WORDS_BIGENDIAN
76   ret = (s>>8) & 0x00ffU;
77   ret += (s<<8) & 0xff00U;
78 #endif
79   return ret;
80 }
81 
82 static  ogg_uint32_t
_be_32(ogg_uint32_t i)83 _be_32 (ogg_uint32_t i)
84 {
85    ogg_uint32_t ret=i;
86 #ifndef WORDS_BIGENDIAN
87    ret =  (i>>24);
88    ret += (i>>8) & 0x0000ff00;
89    ret += (i<<8) & 0x00ff0000;
90    ret += (i<<24);
91 #endif
92    return ret;
93 }
94 
95 static  ogg_int64_t
_le_64(ogg_int64_t l)96 _le_64 (ogg_int64_t l)
97 {
98   ogg_int64_t ret=l;
99   unsigned char *ucptr = (unsigned char *)&ret;
100 #ifdef WORDS_BIGENDIAN
101   unsigned char temp;
102 
103   temp = ucptr [0] ;
104   ucptr [0] = ucptr [7] ;
105   ucptr [7] = temp ;
106 
107   temp = ucptr [1] ;
108   ucptr [1] = ucptr [6] ;
109   ucptr [6] = temp ;
110 
111   temp = ucptr [2] ;
112   ucptr [2] = ucptr [5] ;
113   ucptr [5] = temp ;
114 
115   temp = ucptr [3] ;
116   ucptr [3] = ucptr [4] ;
117   ucptr [4] = temp ;
118 
119 #endif
120   return (*(ogg_int64_t *)ucptr);
121 }
122 
123 #define INT32_LE_AT(x) _le_32((*(ogg_int32_t *)(x)))
124 #define INT16_BE_AT(x) _be_16((*(ogg_uint16_t *)(x)))
125 #define INT32_BE_AT(x) _be_32((*(ogg_int32_t *)(x)))
126 #define INT64_LE_AT(x) _le_64((*(ogg_int64_t *)(x)))
127 
128 typedef char * (* OTCodecInfoFunc) (unsigned char * data, long n);
129 
130 static char *
ot_theora_info(unsigned char * data,long len)131 ot_theora_info (unsigned char * data, long len)
132 {
133   char * buf;
134   int width, height;
135 
136   if (len < 41) return NULL;
137 
138   buf = malloc (128);
139 
140   width = INT16_BE_AT(&data[15]);
141   height = INT16_BE_AT(&data[18]);
142 
143   snprintf (buf, 128,
144             "\tTheora-Version: %d.%d.%d\n"
145 	    "\tVideo-Framerate: %.3f fps\n"
146 	    "\tVideo-Width: %d\n\tVideo-Height: %d\n",
147             data[7], data[8], data[9],
148 	    (double)INT32_BE_AT(&data[22])/ (double)INT32_BE_AT(&data[26]),
149 	    width, height);
150 
151   return buf;
152 }
153 
154 static char *
ot_vorbis_info(unsigned char * data,long len)155 ot_vorbis_info (unsigned char * data, long len)
156 {
157   char * buf;
158 
159   if (len < 30) return NULL;
160 
161   buf = malloc (60);
162 
163   snprintf (buf, 60,
164 	    "\tAudio-Samplerate: %d Hz\n\tAudio-Channels: %d\n",
165 	    INT32_LE_AT(&data[12]), (int)(data[11]));
166 
167   return buf;
168 }
169 
170 static char *
ot_speex_info(unsigned char * data,long len)171 ot_speex_info (unsigned char * data, long len)
172 {
173   char * buf;
174 
175   if (len < 68) return NULL;
176 
177   buf = malloc (60);
178 
179   snprintf (buf, 60,
180 	    "\tAudio-Samplerate: %d Hz\n\tAudio-Channels: %d\n",
181 	    INT32_LE_AT(&data[36]), INT32_LE_AT(&data[48]));
182 
183   return buf;
184 }
185 
186 static char *
ot_celt_info(unsigned char * data,long len)187 ot_celt_info (unsigned char * data, long len)
188 {
189   char * buf;
190 
191   if (len < 56) return NULL;
192 
193   buf = malloc (60);
194 
195   snprintf (buf, 60,
196 	    "\tAudio-Samplerate: %d Hz\n\tAudio-Channels: %d\n",
197 	    INT32_LE_AT(&data[40]), INT32_LE_AT(&data[44]));
198 
199   return buf;
200 }
201 
202 static char *
ot_flac_info(unsigned char * data,long len)203 ot_flac_info (unsigned char * data, long len)
204 {
205   char * buf;
206   int n;
207   int version_major, version_minor;
208   int samplerate;
209   int channels;
210 
211   if (len < 30) return NULL;
212 
213   buf = malloc (120);
214 
215   version_major = data[5];
216   version_minor = data[6];
217 
218   samplerate = (ogg_int64_t) (data[27] << 12) | (data[28] << 4) |
219                ((data[29] >> 4)&0xf);
220   channels = 1 + ((data[29] >> 1)&0x7);
221 
222   n = snprintf (buf, 120,
223 	    "\tAudio-Samplerate: %d Hz\n\tAudio-Channels: %d\n",
224             samplerate, channels);
225 
226   snprintf (buf+n, 120-n,
227             "\tFLAC-Ogg-Mapping-Version: %d.%d\n",
228             version_major, version_minor);
229 
230   return buf;
231 }
232 
233 static char *
ot_oggpcm2_info(unsigned char * data,long len)234 ot_oggpcm2_info (unsigned char * data, long len)
235 {
236   char * buf;
237 
238   if (len < 28) return NULL;
239 
240   buf = malloc (60);
241 
242   snprintf (buf, 60,
243 	    "\tAudio-Samplerate: %d Hz\n\tAudio-Channels: %d\n",
244 	    INT32_BE_AT(&data[16]), (int)data[21]);
245 
246   return buf;
247 }
248 
249 static char *
ot_kate_info(unsigned char * data,long len)250 ot_kate_info (unsigned char * data, long len)
251 {
252   char * buf;
253 
254   static const size_t KATE_INFO_BUFFER_LEN =
255     1 /* tab */
256   +18 /* "Content-Language: " */
257   +15 /* 15 chars + NUL for language */
258    +1 /* \n */
259    +1 /* tab */
260   +18 /* "Content-Category: " */
261   +15 /* 15 chars + NUL for category */
262    +1 /* \n */
263    +1;/* terminating NUL */
264 
265   if (len < 64) return NULL;
266 
267   buf = malloc (KATE_INFO_BUFFER_LEN);
268 
269   /* Are these headers coming from some standard ? If so, need to find what should these be for Kate */
270   snprintf (buf, KATE_INFO_BUFFER_LEN,
271 	    "\tContent-Language: %s\n"
272             "\tContent-Category: %s\n",
273 	    &data[32], &data[48]);
274 
275 #undef KATE_INFO_BUFFER_LEN
276 
277   return buf;
278 }
279 
280 static char *
ot_dirac_info(unsigned char * data,long len)281 ot_dirac_info (unsigned char * data, long len)
282 {
283   char * buf;
284   dirac_info *info;
285 
286   /* read in useful bits from sequence header */
287   if (len < 24) return NULL;
288 
289   buf = malloc (80);
290   info = malloc(sizeof(dirac_info));
291 
292   if (dirac_parse_info(info, data, len) == -1) {
293     free (info);
294     free (buf);
295     return NULL;
296   }
297 
298   snprintf (buf, 80,
299 	    "\tVideo-Framerate: %.3f fps\n"
300 	    "\tVideo-Width: %d\n\tVideo-Height: %d\n",
301 	    (double)info->fps_numerator/ (double)info->fps_denominator,
302 	    info->width, info->height);
303 
304   free(info);
305 
306   return buf;
307 }
308 
309 
310 static char *
ot_skeleton_info(unsigned char * data,long len)311 ot_skeleton_info (unsigned char * data, long len)
312 {
313   char * buf;
314   double pres_n, pres_d, pres;
315   double base_n, base_d, base;
316 
317   if (len < 64L) return NULL;
318 
319   buf = malloc (60);
320 
321   pres_n = (double)INT64_LE_AT(&data[12]);
322   pres_d = (double)INT64_LE_AT(&data[20]);
323   if (pres_d != 0.0) {
324     pres = pres_n / pres_d;
325   } else {
326     pres = 0.0;
327   }
328 
329   base_n = (double)INT64_LE_AT(&data[28]);
330   base_d = (double)INT64_LE_AT(&data[36]);
331   if (base_d != 0.0) {
332     base = base_n / base_d;
333   } else {
334     base = 0.0;
335   }
336 
337   snprintf (buf, 60,
338 	    "\tPresentation-Time: %.3f\n\tBasetime: %.3f\n", pres, base);
339 
340   return buf;
341 }
342 
343 static const OTCodecInfoFunc codec_ident[] = {
344   ot_theora_info,
345   ot_vorbis_info,
346   ot_speex_info,
347   ot_oggpcm2_info,
348   NULL,             /* CMML */
349   NULL,             /* ANNODEX */
350   ot_skeleton_info,
351   NULL,             /* FLAC0 */
352   ot_flac_info,     /* FLAC */
353   NULL,             /* ANXDATA */
354   ot_celt_info,     /* CELT */
355   ot_kate_info,     /* KATE */
356   ot_dirac_info,    /* BBCD */
357   NULL              /* UNKNOWN */
358 };
359 
360 const char *
ot_page_identify(OGGZ * oggz,const ogg_page * og,char ** info)361 ot_page_identify (OGGZ *oggz, const ogg_page * og, char ** info)
362 {
363   const char * ret = NULL;
364   int serial_no;
365   int content;
366 
367   /*
368    * identify stream content using oggz_stream_get_content, identify
369    * stream content name using oggz_stream_get_content_type
370    */
371 
372   serial_no = ogg_page_serialno((ogg_page *)og);
373 
374   content = oggz_stream_get_content(oggz, serial_no);
375   if (content == OGGZ_ERR_BAD_SERIALNO) return NULL;
376 
377   ret = oggz_stream_get_content_type(oggz, serial_no);
378 
379   if (info != NULL)
380   {
381     if (codec_ident[content] != NULL)
382     {
383       *info = codec_ident[content](og->body, og->body_len);
384     }
385   }
386 
387   return ret;
388 }
389 
390 /*
391  * Print a number of bytes to 3 significant figures
392  * using standard abbreviations (GB, MB, kB, byte[s])
393  */
394 int
ot_fprint_bytes(FILE * stream,long nr_bytes)395 ot_fprint_bytes (FILE * stream, long nr_bytes)
396 {
397   if (nr_bytes > (1L<<30)) {
398     return fprintf (stream, "%0.3f GB",
399 		   (double)nr_bytes / (1024.0 * 1024.0 * 1024.0));
400   } else if (nr_bytes > (1L<<20)) {
401     return fprintf (stream, "%0.3f MB",
402 		   (double)nr_bytes / (1024.0 * 1024.0));
403   } else if (nr_bytes > (1L<<10)) {
404     return fprintf (stream, "%0.3f kB",
405 		   (double)nr_bytes / (1024.0));
406   } else if (nr_bytes == 1) {
407     return fprintf (stream, "1 byte");
408   } else {
409     return fprintf (stream, "%ld bytes", nr_bytes);
410   }
411 }
412 
413 /*
414  * Print a bitrate to 3 significant figures
415  * using quasi-standard abbreviations (Gbps, Mbps, kbps, bps)
416  */
417 int
ot_print_bitrate(long bps)418 ot_print_bitrate (long bps)
419 {
420   if (bps > (1000000000L)) {
421     return printf ("%0.3f Gbps",
422 		   (double)bps / (1000.0 * 1000.0 * 1000.0));
423   } else if (bps > (1000000L)) {
424     return printf ("%0.3f Mbps",
425 		   (double)bps / (1000.0 * 1000.0));
426   } else if (bps > (1000L)) {
427     return printf ("%0.3f kbps",
428 		   (double)bps / (1000.0));
429   } else {
430     return printf ("%ld bps", bps);
431   }
432 }
433 
434 int
ot_fprint_time(FILE * stream,double seconds)435 ot_fprint_time (FILE * stream, double seconds)
436 {
437   int hrs, min;
438   double sec;
439   char * sign;
440 
441   sign = (seconds < 0.0) ? "-" : "";
442 
443   if (seconds < 0.0) seconds = -seconds;
444 
445   hrs = (int) (seconds/3600.0);
446   min = (int) ((seconds - ((double)hrs * 3600.0)) / 60.0);
447   sec = seconds - ((double)hrs * 3600.0)- ((double)min * 60.0);
448 
449   return fprintf (stream, "%s%02d:%02d:%06.3f", sign, hrs, min, sec);
450 }
451 
452 void
ot_dirac_gpos_parse(ogg_int64_t iframe,ogg_int64_t pframe,struct ot_dirac_gpos * dg)453 ot_dirac_gpos_parse (ogg_int64_t iframe, ogg_int64_t pframe,
454                      struct ot_dirac_gpos * dg)
455 {
456   dg->pt = (iframe + pframe) >> 9;
457   dg->dist = ((iframe & 0xff) << 8) | (pframe & 0xff);
458   dg->delay = pframe >> 9;
459   dg->dt = (ogg_int64_t)dg->pt - dg->delay;
460 }
461 
462 int
ot_fprint_granulepos(FILE * stream,OGGZ * oggz,long serialno,ogg_int64_t granulepos)463 ot_fprint_granulepos (FILE * stream, OGGZ * oggz, long serialno,
464                       ogg_int64_t granulepos)
465 {
466   int ret, granuleshift = oggz_get_granuleshift (oggz, serialno);
467 
468   if (granuleshift < 1) {
469     ret = fprintf (stream, "%" PRId64, granulepos);
470   } else {
471     ogg_int64_t iframe, pframe;
472     iframe = granulepos >> granuleshift;
473     pframe = granulepos - (iframe << granuleshift);
474 
475     if (oggz_stream_get_content (oggz, serialno) != OGGZ_CONTENT_DIRAC) {
476       ret = fprintf (stream, "%" PRId64 "|%" PRId64, iframe, pframe);
477     } else {
478       struct ot_dirac_gpos dg;
479       ot_dirac_gpos_parse (iframe, pframe, &dg);
480       ret = fprintf (stream,
481 		     "(pt:%u,dt:%" PRId64 ",dist:%hu,delay:%hu)",
482 		     dg.pt, dg.dt, dg.dist, dg.delay);
483     }
484 
485 }
486 
487   return ret;
488 }
489 
490 void
ot_init(void)491 ot_init (void)
492 {
493 #ifdef _WIN32
494   /* We need to set stdin/stdout to binary mode on Win32 */
495 
496   _setmode( _fileno( stdin ), _O_BINARY );
497   _setmode( _fileno( stdout ), _O_BINARY );
498 #endif
499 #ifdef __EMX__
500   /* We need to set stdin/stdout to binary mode on OS/2*/
501 
502   setmode( fileno( stdin ), O_BINARY );
503   setmode( fileno( stdout ), O_BINARY );
504 #endif
505 }
506 
507 void
ot_print_short_options(char * optstring)508 ot_print_short_options (char * optstring)
509 {
510   char *c;
511 
512   for (c=optstring; *c; c++) {
513     if (*c != ':') printf ("-%c ", *c);
514   }
515 
516   printf ("\n");
517 }
518 
519 #ifdef HAVE_GETOPT_LONG
520 void
ot_print_options(struct option long_options[],char * optstring)521 ot_print_options (struct option long_options[], char * optstring)
522 {
523   int i;
524   for (i=0; long_options[i].name != NULL; i++)  {
525     printf ("--%s ", long_options[i].name);
526   }
527 
528   ot_print_short_options (optstring);
529 }
530 #endif
531