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

Revision 3811, 10.0 kB (checked in by conrad, 1 month ago)

print serialno as unsigned throughout

Line 
1 /*
2    Copyright (C) 2008 Annodex Association
3
4    Redistribution and use in source and binary forms, with or without
5    modification, are permitted provided that the following conditions
6    are met:
7
8    - Redistributions of source code must retain the above copyright
9    notice, this list of conditions and the following disclaimer.
10
11    - Redistributions in binary form must reproduce the above copyright
12    notice, this list of conditions and the following disclaimer in the
13    documentation and/or other materials provided with the distribution.
14
15    - Neither the name of the Annodex Association nor the names of its
16    contributors may be used to endorse or promote products derived from
17    this software without specific prior written permission.
18
19    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22    PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE ASSOCIATION OR
23    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include "config.h"
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <fcntl.h>
38
39 #include <getopt.h>
40 #include <errno.h>
41
42 #include <oggz/oggz.h>
43 #include "oggz_tools.h"
44
45 #define READ_SIZE 4096
46
47 static void
48 usage (char * progname)
49 {
50   printf ("Usage: %s [options] filename ...\n", progname);
51   printf ("Sort the pages of an Ogg file in order of presentation time.\n");
52   printf ("\nMiscellaneous options\n");
53   printf ("  -o filename, --output filename\n");
54   printf ("                         Specify output filename\n");
55   printf ("  -h, --help             Display this help and exit\n");
56   printf ("  -v, --version          Output version information and exit\n");
57   printf ("  -V, --verbose          Verbose operation\n");
58   printf ("\n");
59   printf ("Please report bugs to <ogg-dev@xiph.org>\n");
60 }
61
62 typedef struct _OSData OSData;
63 typedef struct _OSInput OSInput;
64 typedef struct _OSITrack OSITrack;
65
66 struct _OSData {
67   char * infilename;
68   OggzTable * inputs;
69   int verbose;
70 };
71
72 struct _OSInput {
73   OSData * osdata;
74   OGGZ * reader;
75   long serialno;
76   const ogg_page * og;
77 };
78
79 struct _OSITrack {
80   long output_serialno;
81 };
82
83 static ogg_page *
84 _ogg_page_copy (const ogg_page * og)
85 {
86   ogg_page * new_og;
87
88   new_og = malloc (sizeof (*og));
89   new_og->header = malloc (og->header_len);
90   new_og->header_len = og->header_len;
91   memcpy (new_og->header, og->header, og->header_len);
92   new_og->body = malloc (og->body_len);
93   new_og->body_len = og->body_len;
94   memcpy (new_og->body, og->body, og->body_len);
95
96   return new_og;
97 }
98
99 static int
100 _ogg_page_free (const ogg_page * og)
101 {
102   free (og->header);
103   free (og->body);
104   free ((ogg_page *)og);
105   return 0;
106 }
107
108 static void
109 osinput_delete (OSInput * input)
110 {
111   oggz_close (input->reader);
112
113   free (input);
114 }
115
116 static OSData *
117 osdata_new (void)
118 {
119   OSData * osdata;
120
121   osdata = (OSData *) malloc (sizeof (OSData));
122
123   osdata->inputs = oggz_table_new ();
124   osdata->verbose = 0;
125
126   return osdata;
127 }
128
129 static void
130 osdata_delete (OSData * osdata)
131 {
132   OSInput * input;
133   int i, ninputs;
134
135   ninputs = oggz_table_size (osdata->inputs);
136   for (i = 0; i < ninputs; i++) {
137     input = (OSInput *) oggz_table_nth (osdata->inputs, i, NULL);
138     osinput_delete (input);
139   }
140   oggz_table_delete (osdata->inputs);
141
142   free (osdata);
143 }
144
145 static int
146 read_page (OGGZ * oggz, const ogg_page * og, long serialno, void * user_data)
147 {
148   OSInput * input = (OSInput *) user_data;
149
150   /* If this is the serialno that this input is tracking, stash it;
151    * otherwise continue scanning the file */
152   if (serialno == input->serialno) {
153     ogg_page *iog;
154     iog = _ogg_page_copy (og);
155     /* If this page's granulepos should be -1 but isn't then fix that before
156      * storing and sorting the page. */
157     if(ogg_page_packets(iog)==0&&ogg_page_granulepos(iog)!=-1) {
158       memset(iog->header+6,0xFF,8);
159       ogg_page_checksum_set(iog);
160     }
161     input->og = iog;
162     return OGGZ_STOP_OK;
163   } else {
164     return OGGZ_CONTINUE;
165   }
166 }
167
168 static int
169 read_page_add_input (OGGZ * oggz, const ogg_page * og, long serialno,
170                      void * user_data)
171 {
172   OSData * osdata = (OSData *)user_data;
173   OSInput * input;
174   int is_bos, nfiles;
175
176 #ifdef OGG_H_CONST_CORRECT
177   is_bos = ogg_page_bos (og);
178 #else
179   is_bos = ogg_page_bos ((ogg_page *)og);
180 #endif
181
182   if (is_bos) {
183     input = (OSInput *) malloc (sizeof (OSInput));
184     if (input == NULL) return -1;
185
186     input->osdata = osdata;
187     input->reader = oggz_open (osdata->infilename, OGGZ_READ|OGGZ_AUTO);
188     input->serialno = serialno;
189     input->og = NULL;
190
191     oggz_set_read_page (input->reader, -1, read_page, input);
192
193     nfiles = oggz_table_size (osdata->inputs);
194     if (!oggz_table_insert (osdata->inputs, nfiles++, input)) {
195       osinput_delete (input);
196       return -1;
197     }
198
199     return OGGZ_CONTINUE;
200   } else {
201     return OGGZ_STOP_OK;
202   }
203 }
204
205 static int
206 osdata_add_file (OSData * osdata, char * infilename)
207 {
208   OGGZ * reader;
209
210   osdata->infilename = infilename;
211
212   if ((reader = oggz_open (infilename, OGGZ_READ|OGGZ_AUTO)) != NULL) {
213     oggz_set_read_page (reader, -1, read_page_add_input, osdata);
214     oggz_run (reader);
215     oggz_close (reader);
216     return 0;
217   } else {
218     return -1;
219   }
220 }
221
222 static int
223 oggz_sort (OSData * osdata, FILE * outfile)
224 {
225   OSInput * input;
226   int ninputs, i, min_i;
227   long key, n;
228   ogg_int64_t units, min_units;
229   const ogg_page * og;
230   int active;
231
232   /* For theora+vorbis, ensure theora bos is first */
233   int careful_for_theora = 0;
234
235   int v;
236
237   if (oggz_table_size (osdata->inputs) == 2)
238     careful_for_theora = 1;
239
240   while ((ninputs = oggz_table_size (osdata->inputs)) > 0) {
241     min_units = -1;
242     min_i = -1;
243     active = 1;
244
245     if (osdata->verbose)
246       printf ("------------------------------------------------------------\n");
247
248     /* Reload all pages, and find the min (earliest) */
249     for (i = 0; active && i < oggz_table_size (osdata->inputs); i++) {
250       input = (OSInput *) oggz_table_nth (osdata->inputs, i, &key);
251       if (input != NULL) {
252         while (input && input->og == NULL) {
253           n = oggz_read (input->reader, READ_SIZE);
254           if (n == 0) {
255             oggz_table_remove (osdata->inputs, key);
256             osinput_delete (input);
257             input = NULL;
258           }
259         }
260         if (input && input->og) {
261           if (ogg_page_bos ((ogg_page *)input->og)) {
262             min_i = i;
263
264             if (careful_for_theora) {
265               if (i == 0 && oggz_stream_get_content (input->reader, input->serialno) == OGGZ_CONTENT_VORBIS)
266                 careful_for_theora = 0;
267               else
268                 active = 0;
269             } else {
270               active = 0;
271             }
272           }
273           units = oggz_tell_units (input->reader);
274
275           if (osdata->verbose) {
276             ot_fprint_time (stdout, (double)units/1000);
277             printf (": Got index %d serialno %010u %lld units: ",
278                     i, ogg_page_serialno ((ogg_page *)input->og), (long long) units);
279           }
280
281           if (min_units == -1 || units == 0 ||
282               (units > -1 && units < min_units)) {
283             min_units = units;
284             min_i = i;
285             if (osdata->verbose)
286               printf ("Min\n");
287           } else {
288             if (osdata->verbose)
289               printf ("Moo\n");
290           }
291         } else if (osdata->verbose) {
292           if (input == NULL) {
293             printf ("*** index %d NULL\n", i);
294           } else {
295             printf ("*** No page from index %d\n", i);
296           }
297         }
298       }
299     }
300
301     if (osdata->verbose)
302       printf ("Min index %d\n", min_i);
303
304     /* Write the earliest page */
305     if (min_i != -1) {
306       input = (OSInput *) oggz_table_nth (osdata->inputs, min_i, &key);
307       og = input->og;
308       fwrite (og->header, 1, og->header_len, outfile);
309       fwrite (og->body, 1, og->body_len, outfile);
310
311       _ogg_page_free (og);
312       input->og = NULL;
313     }
314   }
315
316   return 0;
317 }
318
319 int
320 main (int argc, char * argv[])
321 {
322   int show_version = 0;
323   int show_help = 0;
324
325   char * progname;
326   char * infilename = NULL, * outfilename = NULL;
327   FILE * infile = NULL, * outfile = NULL;
328   OSData * osdata;
329   int i;
330
331   char * optstring = "hvVo:";
332
333 #ifdef HAVE_GETOPT_LONG
334   static struct option long_options[] = {
335     {"help", no_argument, 0, 'h'},
336     {"version", no_argument, 0, 'v'},
337     {"verbose", no_argument, 0, 'V'},
338     {"output", required_argument, 0, 'o'},
339     {0,0,0,0}
340   };
341 #endif
342
343   ot_init ();
344
345   progname = argv[0];
346
347   if (argc < 2) {
348     usage (progname);
349     return (1);
350   }
351
352   if (!strncmp (argv[1], "-?", 2)) {
353 #ifdef HAVE_GETOPT_LONG
354     ot_print_options (long_options, optstring);
355 #else
356     ot_print_short_options (optstring);
357 #endif
358     exit (0);
359   }
360
361   osdata = osdata_new();
362
363   while (1) {
364 #ifdef HAVE_GETOPT_LONG
365     i = getopt_long (argc, argv, optstring, long_options, NULL);
366 #else
367     i = getopt (argc, argv, optstring);
368 #endif
369     if (i == -1) break;
370     if (i == ':') {
371       usage (progname);
372       goto exit_err;
373     }
374
375     switch (i) {
376     case 'h': /* help */
377       show_help = 1;
378       break;
379     case 'v': /* version */
380       show_version = 1;
381       break;
382     case 'o': /* output */
383       outfilename = optarg;
384       break;
385     case 'V': /* verbose */
386       osdata->verbose = 1;
387     default:
388       break;
389     }
390   }
391
392   if (show_version) {
393     printf ("%s version " VERSION "\n", progname);
394   }
395
396   if (show_help) {
397     usage (progname);
398   }
399
400   if (show_version || show_help) {
401     goto exit_ok;
402   }
403
404   if (optind >= argc) {
405     usage (progname);
406     goto exit_err;
407   }
408
409   infilename = argv[optind++];
410   osdata_add_file (osdata, infilename);
411
412   if (outfilename == NULL) {
413     outfile = stdout;
414   } else {
415     outfile = fopen (outfilename, "wb");
416     if (outfile == NULL) {
417       fprintf (stderr, "%s: unable to open output file %s\n",
418                progname, outfilename);
419       goto exit_err;
420     }
421   }
422
423   oggz_sort (osdata, outfile);
424
425  exit_ok:
426   osdata_delete (osdata);
427   exit (0);
428
429  exit_err:
430   osdata_delete (osdata);
431   exit (1);
432 }
Note: See TracBrowser for help on using the browser.