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