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