root/liboggz/trunk/src/tools/oggz-rip.c

Revision 3806, 11.1 kB (checked in by conrad, 2 months ago)

oggz-rip: use oggz_stream_get_content_type instead of local ot_identify(),
fix oggz_read() error check

Line 
1 /* -*- c-file-style: "gnu" -*- */
2 /*
3   Copyright (C) 2005 Commonwealth Scientific and Industrial Research
4   Organisation (CSIRO) Australia
5
6   Redistribution and use in source and binary forms, with or without
7   modification, are permitted provided that the following conditions
8   are met:
9
10   - Redistributions of source code must retain the above copyright
11   notice, this list of conditions and the following disclaimer.
12
13   - Redistributions in binary form must reproduce the above copyright
14   notice, this list of conditions and the following disclaimer in the
15   documentation and/or other materials provided with the distribution.
16
17   - Neither the name of CSIRO Australia nor the names of its
18   contributors may be used to endorse or promote products derived from
19   this software without specific prior written permission.
20
21   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24   PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE ORGANISATION OR
25   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
33   Author: David Kuehling <dvdkhlng@gmx.de>
34   Created: 20041231
35 */
36
37 #include "config.h"
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #ifndef WIN32
43 #include <strings.h>
44 #endif
45 #include <fcntl.h>
46 #include <assert.h>
47
48 #include <getopt.h>
49 #include <errno.h>
50
51 #include <oggz/oggz.h>
52 #include "oggz_tools.h"
53
54 #ifdef WIN32                                                                   
55 #define strcasecmp _stricmp
56 #endif 
57
58 #define READ_SIZE 4096
59 #define WRITE_SIZE 4096
60
61 typedef struct {
62   OGGZ *reader;
63   FILE *outfile;
64   int numwrite;
65   OggzTable *streams;
66   int verbose;
67   OggzTable *serialno_table;
68   OggzTable *stream_index_table;
69   OggzTable *content_types_table;
70 } ORData;
71
72 typedef struct {
73   long serialno;
74   int streamid;
75   const char *content_type;
76   int bos;
77 } ORStream;
78
79 static int streamid_count = 0;
80
81 static void
82 usage (char * progname)
83 {
84   printf ("Usage: %s [options] filename ...\n", progname);
85   printf ("\nFilter options\n");
86   printf ("  These options can be used multiple times. Pages matching ANY of\n");
87   printf ("  the filter options will be included into the output.\n\n");
88   printf ("  -s serialno, --serialno serialno\n");
89   printf ("                         Output streams with given serialno.\n");
90   printf ("  -i index, --stream-index index\n");
91   printf ("                         Filter by stream index. These are assigned to\n");
92   printf ("                         streams in the order of their BOS pages,\n");
93   printf ("                         starting at 0.\n");
94   printf ("  -c content-type --content-type content-type\n");
95   printf ("                         Filter by content-type.  The following codec\n");
96   printf ("                         names are currently detected: \"theora\",\n");
97   printf ("                         \"vorbis\", \"speex\", \"cmml\", \"kate\"\n");
98   printf ("\nMiscellaneous options\n");
99   printf ("  -o filename, --output filename\n");
100   printf ("                         Specify output filename\n");
101   printf ("  -h, --help             Display this help and exit\n");
102   printf ("  -v, --version          Output version information and exit\n");
103   printf ("  -V, --verbose          Verbose operation\n");
104   printf ("\n");
105   printf ("Please report bugs to <ogg-dev@xiph.org>\n");
106 }
107
108 static ORData *
109 ordata_new ()
110 {
111   ORData *ordata = malloc (sizeof (ORData));
112   assert (ordata != NULL);
113   memset (ordata, 0, sizeof (ORData));
114  
115   ordata->streams = oggz_table_new ();
116   assert (ordata->streams != NULL);
117
118   ordata->serialno_table = oggz_table_new();
119   assert (ordata->serialno_table != NULL);
120
121   ordata->stream_index_table = oggz_table_new();
122   assert (ordata->stream_index_table != NULL);
123
124   ordata->content_types_table = oggz_table_new();
125   assert (ordata->content_types_table != NULL);
126  
127   return ordata;
128 }
129
130 static void
131 ordata_delete (ORData *ordata)
132 {
133   oggz_table_delete (ordata->streams);
134   oggz_table_delete (ordata->serialno_table);
135   oggz_table_delete (ordata->stream_index_table);
136   oggz_table_delete (ordata->content_types_table);
137  
138   if (ordata->reader)
139     oggz_close (ordata->reader);
140   if (ordata->outfile)
141     fclose (ordata->outfile);
142  
143   free (ordata);
144 }
145
146 static int
147 filter_stream_p (const ORData *ordata, ORStream *stream,
148                  const ogg_page *og, long serialno)
149 {
150   int i, n;
151  
152   if (oggz_table_lookup (ordata->serialno_table, serialno) != NULL)
153     return 1;
154
155   if (stream == NULL)
156     return 0;
157
158   if (oggz_table_lookup (ordata->stream_index_table, (long)stream->streamid) != NULL)
159     return 1;
160
161   n = oggz_table_size (ordata->content_types_table);
162   for (i = 0; i < n; i++) {
163     char * c = oggz_table_nth (ordata->content_types_table, i, NULL);
164     if (strcasecmp (c, stream->content_type) == 0)
165       return 1;
166   }
167
168   return 0;
169 }
170
171 static ORStream *
172 orstream_new (OGGZ *oggz, const ORData *ordata, const ogg_page *og,
173                 long serialno)
174 {
175   const char * ident;
176  
177   ORStream *stream = malloc (sizeof (ORStream));
178   assert (stream != NULL);
179
180   stream->serialno = serialno;
181   stream->streamid = streamid_count++;
182   stream->content_type = "unknown";
183
184   stream->content_type = oggz_stream_get_content_type (oggz, serialno);
185    
186   if (ordata->verbose)
187     fprintf (stderr,
188              "New logical stream, serialno %li, id %i, codec %s, will be %s\n",
189              stream->serialno, stream->streamid, stream->content_type,
190              (filter_stream_p (ordata, stream, og, serialno) ?
191               "copied" :"dropped"));
192
193   return stream;
194 }
195
196 static void
197 orstream_delete (ORData *ordata, ORStream *stream)
198 {
199   if (ordata->verbose)
200     fprintf (stderr, "End of logical stream %li   \n", stream->serialno);
201
202   free (stream);
203 }
204
205 static void
206 checked_fwrite (const void *data, size_t size, size_t count, FILE *stream)
207 {
208   int n = fwrite (data, size, count, stream);
209   if ((size_t)n != count) {
210     perror ("write failed");
211     exit (1);
212   }
213 }
214
215 static int
216 rip_page (OGGZ * oggz, const ogg_page * og, long serialno, void * user_data)
217 {
218   ORData *ordata = (ORData *) user_data;
219   ORStream *stream = oggz_table_lookup (ordata->streams, serialno);
220
221   checked_fwrite (og->header, 1, og->header_len, ordata->outfile);
222   checked_fwrite (og->body, 1, og->body_len, ordata->outfile);
223
224   if (ogg_page_eos ((ogg_page *)og) && stream != NULL) {
225     oggz_table_remove (ordata->streams, serialno);
226     orstream_delete (ordata, stream);
227   }
228
229   return 0;
230 }
231
232 static int
233 read_page (OGGZ *oggz, const ogg_page *og, long serialno, void *user_data)
234 {
235   ORData *ordata = (ORData *) user_data;
236   ORStream *stream = oggz_table_lookup (ordata->streams, serialno);
237
238   if (ogg_page_bos ((ogg_page *)og)) {
239     stream = orstream_new (oggz, ordata, og, serialno);
240     stream = oggz_table_insert (ordata->streams, serialno, stream);
241     assert (stream != NULL);
242
243     if (filter_stream_p (ordata, stream, og, serialno)) {
244       oggz_set_read_page (oggz, serialno, rip_page, user_data);
245       rip_page (oggz, og, serialno, user_data);
246     }
247   }
248
249   return 0;
250 }
251
252 static int
253 oggz_rip (ORData * ordata)
254 {
255   long n;
256
257   oggz_set_read_page (ordata->reader, -1, read_page, ordata);
258  
259   while ((n = oggz_read (ordata->reader, READ_SIZE)) != 0) {
260     if (ordata->verbose) {
261       fprintf (stderr, "\r Read %li k, wrote %li k ...\r",
262                (long) (oggz_tell (ordata->reader)/1024),
263                (long) (ftell (ordata->outfile)/1024));
264     }
265   }
266
267   if (ordata->verbose)
268     fprintf (stderr, "\r Done.                                 \n");
269
270   return 0;
271 }
272
273 static int
274 or_get_long (const char *optarg, const char *currentopt,
275                         long *value)
276 {
277   char *tailptr;
278
279   *value = strtol (optarg, &tailptr, 10);
280
281   if (*tailptr != '\0') {
282     fprintf (stderr, "ERROR: non-integer argument to option `%s': %s\n",
283              currentopt, optarg);
284     return -1;
285   }
286
287   return 0;
288 }
289
290 int
291 main (int argc, char * argv[])
292 {
293   int show_version = 0;
294   int show_help = 0;
295
296   char * progname;
297   char * infilename = NULL, * outfilename = NULL;
298   FILE * infile = NULL;
299   const char *currentopt = argv[1];
300   ORData * ordata;
301   long l;
302   int i, n;
303
304   char * optstring = "hvVo:s:i:c:";
305
306 #ifdef HAVE_GETOPT_LONG
307   static struct option long_options[] = {
308     {"help", no_argument, 0, 'h'},
309     {"version", no_argument, 0, 'v'},
310     {"output", required_argument, 0, 'o'},
311     {"verbose", no_argument, 0, 'V'},
312     {"serialno", required_argument, 0, 's'},
313     {"stream-index", required_argument, 0, 'i'},
314     {"content-type", required_argument, 0, 'c'},
315     {0,0,0,0}
316   };
317 #endif
318
319   ot_init();
320
321   progname = argv[0];
322
323   if (argc < 2) {
324     usage (progname);
325     return (1);
326   }
327
328   if (!strncmp (argv[1], "-?", 2)) {
329 #ifdef HAVE_GETOPT_LONG
330     ot_print_options (long_options, optstring);
331 #else
332     ot_print_short_options (optstring);
333 #endif
334     exit (0);
335   }
336
337   ordata = ordata_new ();
338
339   while (1) {
340 #ifdef HAVE_GETOPT_LONG
341     i = getopt_long (argc, argv, optstring, long_options, NULL);
342 #else
343     i = getopt (argc, argv, optstring);
344 #endif
345     if (i == -1) break;
346     if (i == ':') {
347       usage (progname);
348       goto exit_err;
349     }
350
351     switch (i) {
352     case 'h': /* help */
353       show_help = 1;
354       break;
355     case 'v': /* version */
356       show_version = 1;
357       break;
358     case 'o': /* output */
359       outfilename = optarg;
360       break;
361     case 'V': /* verbose */
362       ordata->verbose = 1;
363       break;
364     case 's': /* serialno */
365       if (or_get_long (optarg, currentopt, &l))
366         goto exit_err;
367       oggz_table_insert (ordata->serialno_table, l, (void *)0x7);
368       break;
369     case 'i': /* stream index */
370       if (or_get_long (optarg, currentopt, &l))
371         goto exit_err;
372       oggz_table_insert (ordata->stream_index_table, l, (void *)0x7);
373       break;
374     case 'c': /* content-type */
375       n = oggz_table_size (ordata->content_types_table);
376       oggz_table_insert (ordata->content_types_table, (long)n, optarg);
377       break;
378     default:
379       break;
380     }
381
382     currentopt = argv[optind];
383   }
384
385   if (show_version) {
386     printf ("%s version " VERSION "\n", progname);
387   }
388
389   if (show_help) {
390     usage (progname);
391   }
392
393   if (show_version || show_help) {
394     goto exit_ok;
395   }
396
397   if (optind != argc-1) {
398     usage (progname);
399     goto exit_err;
400   }
401
402   infilename = argv[optind];
403   infile = fopen (infilename, "rb");
404   if (infile == NULL) {
405     fprintf (stderr, "%s: unable to open input file %s : %s\n", progname,
406              infilename, strerror (errno));
407     goto exit_err;
408   } else {
409     ordata->reader = oggz_open_stdio (infile, OGGZ_READ|OGGZ_AUTO);
410   }
411
412   if (outfilename == NULL) {
413     ordata->outfile = stdout;
414   } else {
415     ordata->outfile = fopen (outfilename, "wb");
416     if (ordata->outfile == NULL) {
417       fprintf (stderr, "%s: unable to open output file %s : %s\n",
418                progname, outfilename, strerror (errno));
419       goto exit_err;
420     }
421   }
422
423   oggz_rip (ordata);
424
425  exit_ok:
426   ordata_delete (ordata);
427   exit (0);
428
429  exit_err:
430   ordata_delete (ordata);
431   exit (1);
432 }
Note: See TracBrowser for help on using the browser.