1/*
2 * Copyright © 2010 Mozilla Foundation
3 *
4 * This program is made available under an ISC-style license.  See the
5 * accompanying file LICENSE for details.
6 */
7#include <assert.h>
8#include <stdarg.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <stdint.h>
12#include "nestegg/nestegg.h"
13
14#undef DEBUG
15#define SEEK_TEST
16
17static int
18stdio_read(void * p, size_t length, void * file)
19{
20  size_t r;
21  FILE * fp = file;
22
23  r = fread(p, length, 1, fp);
24  if (r == 0 && feof(fp))
25    return 0;
26  return r == 0 ? -1 : 1;
27}
28
29static int
30stdio_seek(int64_t offset, int whence, void * file)
31{
32  FILE * fp = file;
33  return fseek(fp, offset, whence);
34}
35
36static int64_t
37stdio_tell(void * fp)
38{
39  return ftell(fp);
40}
41
42static void
43log_callback(nestegg * ctx, unsigned int severity, char const * fmt, ...)
44{
45  va_list ap;
46  char const * sev = NULL;
47
48#if !defined(DEBUG)
49  if (severity < NESTEGG_LOG_WARNING)
50    return;
51#endif
52
53  switch (severity) {
54  case NESTEGG_LOG_DEBUG:
55    sev = "debug:   ";
56    break;
57  case NESTEGG_LOG_WARNING:
58    sev = "warning: ";
59    break;
60  case NESTEGG_LOG_CRITICAL:
61    sev = "critical:";
62    break;
63  default:
64    sev = "unknown: ";
65  }
66
67  fprintf(stderr, "%p %s ", (void *) ctx, sev);
68
69  va_start(ap, fmt);
70  vfprintf(stderr, fmt, ap);
71  va_end(ap);
72
73  fprintf(stderr, "\n");
74}
75
76int
77main(int argc, char * argv[])
78{
79  FILE * fp;
80  int r, type;
81  nestegg * ctx;
82  nestegg_audio_params aparams;
83  nestegg_packet * pkt;
84  nestegg_video_params vparams;
85  size_t length, size;
86  uint64_t duration, tstamp, pkt_tstamp;
87  unsigned char * codec_data, * ptr;
88  unsigned int cnt, i, j, track, tracks, pkt_cnt, pkt_track;
89  unsigned int data_items = 0;
90  nestegg_io io = {
91    stdio_read,
92    stdio_seek,
93    stdio_tell,
94    NULL
95  };
96
97  if (argc != 2)
98    return EXIT_FAILURE;
99
100  fp = fopen(argv[1], "rb");
101  if (!fp)
102    return EXIT_FAILURE;
103
104  io.userdata = fp;
105
106  ctx = NULL;
107  r = nestegg_init(&ctx, io, log_callback, -1);
108  if (r != 0)
109    return EXIT_FAILURE;
110
111  nestegg_track_count(ctx, &tracks);
112  nestegg_duration(ctx, &duration);
113#if defined(DEBUG)
114  fprintf(stderr, "media has %u tracks and duration %fs\n", tracks, duration / 1e9);
115#endif
116
117  for (i = 0; i < tracks; ++i) {
118    type = nestegg_track_type(ctx, i);
119#if defined(DEBUG)
120    fprintf(stderr, "track %u: type: %d codec: %d", i,
121            type, nestegg_track_codec_id(ctx, i));
122#endif
123    nestegg_track_codec_data_count(ctx, i, &data_items);
124    for (j = 0; j < data_items; ++j) {
125      nestegg_track_codec_data(ctx, i, j, &codec_data, &length);
126#if defined(DEBUG)
127      fprintf(stderr, " (%p, %u)", codec_data, (unsigned int) length);
128#endif
129    }
130    if (type == NESTEGG_TRACK_VIDEO) {
131      nestegg_track_video_params(ctx, i, &vparams);
132#if defined(DEBUG)
133      fprintf(stderr, " video: %ux%u (d: %ux%u %ux%ux%ux%u)",
134              vparams.width, vparams.height,
135              vparams.display_width, vparams.display_height,
136              vparams.crop_top, vparams.crop_left, vparams.crop_bottom, vparams.crop_right);
137#endif
138    } else if (type == NESTEGG_TRACK_AUDIO) {
139      nestegg_track_audio_params(ctx, i, &aparams);
140#if defined(DEBUG)
141      fprintf(stderr, " audio: %.2fhz %u bit %u channels",
142              aparams.rate, aparams.depth, aparams.channels);
143#endif
144    }
145#if defined(DEBUG)
146    fprintf(stderr, "\n");
147#endif
148  }
149
150#if defined(SEEK_TEST)
151#if defined(DEBUG)
152  fprintf(stderr, "seek to middle\n");
153#endif
154  r = nestegg_track_seek(ctx, 0, duration / 2);
155  if (r == 0) {
156#if defined(DEBUG)
157    fprintf(stderr, "middle ");
158#endif
159    r = nestegg_read_packet(ctx, &pkt);
160    if (r == 1) {
161      nestegg_packet_track(pkt, &track);
162      nestegg_packet_count(pkt, &cnt);
163      nestegg_packet_tstamp(pkt, &tstamp);
164#if defined(DEBUG)
165      fprintf(stderr, "* t %u pts %f frames %u\n", track, tstamp / 1e9, cnt);
166#endif
167      nestegg_free_packet(pkt);
168    } else {
169#if defined(DEBUG)
170      fprintf(stderr, "middle seek failed\n");
171#endif
172    }
173  }
174
175#if defined(DEBUG)
176  fprintf(stderr, "seek to ~end\n");
177#endif
178  r = nestegg_track_seek(ctx, 0, duration - (duration / 10));
179  if (r == 0) {
180#if defined(DEBUG)
181    fprintf(stderr, "end ");
182#endif
183    r = nestegg_read_packet(ctx, &pkt);
184    if (r == 1) {
185      nestegg_packet_track(pkt, &track);
186      nestegg_packet_count(pkt, &cnt);
187      nestegg_packet_tstamp(pkt, &tstamp);
188#if defined(DEBUG)
189      fprintf(stderr, "* t %u pts %f frames %u\n", track, tstamp / 1e9, cnt);
190#endif
191      nestegg_free_packet(pkt);
192    } else {
193#if defined(DEBUG)
194      fprintf(stderr, "end seek failed\n");
195#endif
196    }
197  }
198
199#if defined(DEBUG)
200  fprintf(stderr, "seek to ~start\n");
201#endif
202  r = nestegg_track_seek(ctx, 0, duration / 10);
203  if (r == 0) {
204#if defined(DEBUG)
205    fprintf(stderr, "start ");
206#endif
207    r = nestegg_read_packet(ctx, &pkt);
208    if (r == 1) {
209      nestegg_packet_track(pkt, &track);
210      nestegg_packet_count(pkt, &cnt);
211      nestegg_packet_tstamp(pkt, &tstamp);
212#if defined(DEBUG)
213      fprintf(stderr, "* t %u pts %f frames %u\n", track, tstamp / 1e9, cnt);
214#endif
215      nestegg_free_packet(pkt);
216    } else {
217#if defined(DEBUG)
218      fprintf(stderr, "start seek failed\n");
219#endif
220    }
221  }
222#endif
223
224  while (nestegg_read_packet(ctx, &pkt) > 0) {
225    nestegg_packet_track(pkt, &pkt_track);
226    nestegg_packet_count(pkt, &pkt_cnt);
227    nestegg_packet_tstamp(pkt, &pkt_tstamp);
228
229#if defined(DEBUG)
230    fprintf(stderr, "t %u pts %f frames %u: ", pkt_track, pkt_tstamp / 1e9, pkt_cnt);
231#endif
232
233    for (i = 0; i < pkt_cnt; ++i) {
234      nestegg_packet_data(pkt, i, &ptr, &size);
235#if defined(DEBUG)
236      fprintf(stderr, "%u ", (unsigned int) size);
237#endif
238    }
239#if defined(DEBUG)
240    fprintf(stderr, "\n");
241#endif
242
243    nestegg_free_packet(pkt);
244  }
245
246  nestegg_destroy(ctx);
247  fclose(fp);
248
249  return EXIT_SUCCESS;
250}
251