~ubuntu-branches/ubuntu/precise/liboggz/precise

« back to all changes in this revision

Viewing changes to src/tools/oggzmerge.c

  • Committer: Bazaar Package Importer
  • Author(s): Jamie Wilkinson
  • Date: 2005-04-16 01:19:44 UTC
  • mfrom: (1.2.1 upstream) (2.1.1 hoary)
  • Revision ID: james.westby@ubuntu.com-20050416011944-5ipwrrc260ihkpp8
Tags: 0.9.1-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#include "config.h"
 
34
 
 
35
#include <stdio.h>
 
36
#include <stdlib.h>
 
37
#include <string.h>
 
38
#include <fcntl.h>
 
39
 
 
40
#include <getopt.h>
 
41
#include <errno.h>
 
42
 
 
43
#include <oggz/oggz.h>
 
44
#include "oggz_tools.h"
 
45
 
 
46
#define READ_SIZE 4096
 
47
 
 
48
static void
 
49
usage (char * progname)
 
50
{
 
51
  printf ("Usage: %s [options] filename ...\n", progname);
 
52
  printf ("Merge Ogg files together, interleaving pages in order of presentation time.\n");
 
53
  printf ("\nMiscellaneous options\n");
 
54
  printf ("  -o filename, --output filename\n");
 
55
  printf ("                         Specify output filename\n");
 
56
  printf ("  -h, --help             Display this help and exit\n");
 
57
  printf ("  -v, --version          Output version information and exit\n");
 
58
  printf ("\n");
 
59
  printf ("Please report bugs to <ogg-dev@xiph.org>\n");
 
60
}
 
61
 
 
62
typedef struct _OMData OMData;
 
63
typedef struct _OMInput OMInput;
 
64
typedef struct _OMITrack OMITrack;
 
65
 
 
66
struct _OMData {
 
67
  OggzTable * inputs;
 
68
};
 
69
 
 
70
struct _OMInput {
 
71
  OMData * omdata;
 
72
  OGGZ * reader;
 
73
  const ogg_page * og;
 
74
};
 
75
 
 
76
struct _OMITrack {
 
77
  long output_serialno;
 
78
};
 
79
 
 
80
static ogg_page *
 
81
_ogg_page_copy (const ogg_page * og)
 
82
{
 
83
  ogg_page * new_og;
 
84
 
 
85
  new_og = malloc (sizeof (*og));
 
86
  new_og->header = malloc (og->header_len);
 
87
  new_og->header_len = og->header_len;
 
88
  memcpy (new_og->header, og->header, og->header_len);
 
89
  new_og->body = malloc (og->body_len);
 
90
  new_og->body_len = og->body_len;
 
91
  memcpy (new_og->body, og->body, og->body_len);
 
92
 
 
93
  return new_og;
 
94
}
 
95
 
 
96
static int
 
97
_ogg_page_free (const ogg_page * og)
 
98
{
 
99
  free (og->header);
 
100
  free (og->body);
 
101
  free ((ogg_page *)og);
 
102
  return 0;
 
103
}
 
104
 
 
105
static void
 
106
ominput_delete (OMInput * input)
 
107
{
 
108
  oggz_close (input->reader);
 
109
 
 
110
  free (input);
 
111
}
 
112
 
 
113
static OMData *
 
114
omdata_new (void)
 
115
{
 
116
  OMData * omdata;
 
117
 
 
118
  omdata = (OMData *) malloc (sizeof (OMData));
 
119
 
 
120
  omdata->inputs = oggz_table_new ();
 
121
 
 
122
  return omdata;
 
123
}
 
124
 
 
125
static void
 
126
omdata_delete (OMData * omdata)
 
127
{
 
128
  OMInput * input;
 
129
  int i, ninputs;
 
130
 
 
131
  ninputs = oggz_table_size (omdata->inputs);
 
132
  for (i = 0; i < ninputs; i++) {
 
133
    input = (OMInput *) oggz_table_nth (omdata->inputs, i, NULL);
 
134
    ominput_delete (input);
 
135
  }
 
136
  oggz_table_delete (omdata->inputs);
 
137
 
 
138
  free (omdata);
 
139
}
 
140
 
 
141
static int
 
142
read_page (OGGZ * oggz, const ogg_page * og, long serialno, void * user_data)
 
143
{
 
144
  OMInput * input = (OMInput *) user_data;
 
145
 
 
146
  input->og = _ogg_page_copy (og);
 
147
 
 
148
  return OGGZ_STOP_OK;
 
149
}
 
150
 
 
151
static int
 
152
omdata_add_input (OMData * omdata, FILE * infile)
 
153
{
 
154
  OMInput * input;
 
155
  int nfiles;
 
156
 
 
157
  input = (OMInput *) malloc (sizeof (OMInput));
 
158
  if (input == NULL) return -1;
 
159
 
 
160
  input->omdata = omdata;
 
161
  input->reader = oggz_open_stdio (infile, OGGZ_READ|OGGZ_AUTO);
 
162
  input->og = NULL;
 
163
 
 
164
  oggz_set_read_page (input->reader, -1, read_page, input);
 
165
 
 
166
  nfiles = oggz_table_size (omdata->inputs);
 
167
  if (!oggz_table_insert (omdata->inputs, nfiles++, input)) {
 
168
    ominput_delete (input);
 
169
    return -1;
 
170
  }
 
171
 
 
172
  return 0;
 
173
}
 
174
 
 
175
static int
 
176
oggz_merge (OMData * omdata, FILE * outfile)
 
177
{
 
178
  OMInput * input;
 
179
  int ninputs, i, min_i;
 
180
  long key, n;
 
181
  ogg_int64_t units, min_units;
 
182
  const ogg_page * og;
 
183
  int active;
 
184
 
 
185
  while ((ninputs = oggz_table_size (omdata->inputs)) > 0) {
 
186
    min_units = -1;
 
187
    min_i = -1;
 
188
    active = 1;
 
189
 
 
190
    /* Reload all pages, and find the min (earliest) */
 
191
    for (i = 0; active && i < oggz_table_size (omdata->inputs); i++) {
 
192
      input = (OMInput *) oggz_table_nth (omdata->inputs, i, &key);
 
193
      if (input != NULL) {
 
194
        if (input->og == NULL) {
 
195
          n = oggz_read (input->reader, READ_SIZE);
 
196
          if (n == 0) {
 
197
            oggz_table_remove (omdata->inputs, key);
 
198
            ominput_delete (input);
 
199
            input = NULL;
 
200
          }
 
201
        }
 
202
        if (input && input->og) {
 
203
          if (ogg_page_bos ((ogg_page *)input->og)) {
 
204
            min_i = i;
 
205
            active = 0;
 
206
          }
 
207
          units = oggz_tell_units (input->reader);
 
208
          if (min_units == -1 || units == 0 ||
 
209
              (units > -1 && units < min_units)) {
 
210
            min_units = units;
 
211
            min_i = i;
 
212
          }
 
213
        }
 
214
      }
 
215
    }
 
216
 
 
217
    /* Write the earliest page */
 
218
    if (min_i != -1) {
 
219
      input = (OMInput *) oggz_table_nth (omdata->inputs, min_i, &key);
 
220
      og = input->og;
 
221
      fwrite (og->header, 1, og->header_len, outfile);
 
222
      fwrite (og->body, 1, og->body_len, outfile);
 
223
 
 
224
      _ogg_page_free (og);
 
225
      input->og = NULL;
 
226
    }
 
227
  }
 
228
 
 
229
  return 0;
 
230
}
 
231
 
 
232
int
 
233
main (int argc, char * argv[])
 
234
{
 
235
  int show_version = 0;
 
236
  int show_help = 0;
 
237
 
 
238
  char * progname;
 
239
  char * infilename = NULL, * outfilename = NULL;
 
240
  FILE * infile = NULL, * outfile = NULL;
 
241
  OMData * omdata;
 
242
  int i;
 
243
 
 
244
  ot_init ();
 
245
 
 
246
  progname = argv[0];
 
247
 
 
248
  if (argc < 2) {
 
249
    usage (progname);
 
250
    return (1);
 
251
  }
 
252
 
 
253
  omdata = omdata_new();
 
254
 
 
255
  while (1) {
 
256
    char * optstring = "hvo:";
 
257
 
 
258
#ifdef HAVE_GETOPT_LONG
 
259
    static struct option long_options[] = {
 
260
      {"help", no_argument, 0, 'h'},
 
261
      {"version", no_argument, 0, 'v'},
 
262
      {"output", required_argument, 0, 'o'},
 
263
      {0,0,0,0}
 
264
    };
 
265
 
 
266
    i = getopt_long (argc, argv, optstring, long_options, NULL);
 
267
#else
 
268
    i = getopt (argc, argv, optstring);
 
269
#endif
 
270
    if (i == -1) break;
 
271
    if (i == ':') {
 
272
      usage (progname);
 
273
      goto exit_err;
 
274
    }
 
275
 
 
276
    switch (i) {
 
277
    case 'h': /* help */
 
278
      show_help = 1;
 
279
      break;
 
280
    case 'v': /* version */
 
281
      show_version = 1;
 
282
      break;
 
283
    case 'o': /* output */
 
284
      outfilename = optarg;
 
285
      break;
 
286
    default:
 
287
      break;
 
288
    }
 
289
  }
 
290
 
 
291
  if (show_version) {
 
292
    printf ("%s version " VERSION "\n", progname);
 
293
  }
 
294
 
 
295
  if (show_help) {
 
296
    usage (progname);
 
297
  }
 
298
 
 
299
  if (show_version || show_help) {
 
300
    goto exit_ok;
 
301
  }
 
302
 
 
303
  if (optind >= argc) {
 
304
    usage (progname);
 
305
    goto exit_err;
 
306
  }
 
307
 
 
308
  if (optind >= argc) {
 
309
    usage (progname);
 
310
    goto exit_err;
 
311
  }
 
312
 
 
313
  while (optind < argc) {
 
314
    infilename = argv[optind++];
 
315
    infile = fopen (infilename, "rb");
 
316
    if (infile == NULL) {
 
317
      fprintf (stderr, "%s: unable to open input file %s\n", progname,
 
318
               infilename);
 
319
    } else {
 
320
      omdata_add_input (omdata, infile);
 
321
    }
 
322
  }
 
323
 
 
324
  if (outfilename == NULL) {
 
325
    outfile = stdout;
 
326
  } else {
 
327
    outfile = fopen (outfilename, "wb");
 
328
    if (outfile == NULL) {
 
329
      fprintf (stderr, "%s: unable to open output file %s\n",
 
330
               progname, outfilename);
 
331
      goto exit_err;
 
332
    }
 
333
  }
 
334
 
 
335
  oggz_merge (omdata, outfile);
 
336
 
 
337
 exit_ok:
 
338
  omdata_delete (omdata);
 
339
  exit (0);
 
340
 
 
341
 exit_err:
 
342
  omdata_delete (omdata);
 
343
  exit (1);
 
344
}