| /* |
| * Copyright © 2010 Mozilla Foundation |
| * |
| * This program is made available under an ISC-style license. See the |
| * accompanying file LICENSE for details. |
| */ |
| #include <assert.h> |
| #include <stdarg.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <stdint.h> |
| #include "nestegg/nestegg.h" |
| |
| #undef DEBUG |
| #define SEEK_TEST |
| |
| static int |
| stdio_read(void * p, size_t length, void * fp) |
| { |
| size_t r; |
| |
| r = fread(p, length, 1, fp); |
| if (r == 0 && feof(fp)) |
| return 0; |
| return r == 0 ? -1 : 1; |
| } |
| |
| static int |
| stdio_seek(int64_t offset, int whence, void * fp) |
| { |
| return fseek(fp, offset, whence); |
| } |
| |
| static int64_t |
| stdio_tell(void * fp) |
| { |
| return ftell(fp); |
| } |
| |
| static void |
| log_callback(nestegg * ctx, unsigned int severity, char const * fmt, ...) |
| { |
| va_list ap; |
| char const * sev = NULL; |
| |
| #ifndef DEBUG |
| if (severity < NESTEGG_LOG_WARNING) |
| return; |
| #endif |
| |
| switch (severity) { |
| case NESTEGG_LOG_DEBUG: |
| sev = "debug: "; |
| break; |
| case NESTEGG_LOG_WARNING: |
| sev = "warning: "; |
| break; |
| case NESTEGG_LOG_CRITICAL: |
| sev = "critical:"; |
| break; |
| default: |
| sev = "unknown: "; |
| } |
| |
| fprintf(stderr, "%p %s ", (void *) ctx, sev); |
| |
| va_start(ap, fmt); |
| vfprintf(stderr, fmt, ap); |
| va_end(ap); |
| |
| fprintf(stderr, "\n"); |
| } |
| |
| int |
| main(int argc, char * argv[]) |
| { |
| FILE * fp; |
| int r, type; |
| nestegg * ctx; |
| nestegg_audio_params aparams; |
| nestegg_packet * pkt; |
| nestegg_video_params vparams; |
| size_t length, size; |
| uint64_t duration, tstamp, pkt_tstamp; |
| unsigned char * codec_data, * ptr; |
| unsigned int cnt, i, j, track, tracks, pkt_cnt, pkt_track; |
| unsigned int data_items = 0; |
| nestegg_io io = { |
| stdio_read, |
| stdio_seek, |
| stdio_tell, |
| NULL |
| }; |
| |
| if (argc != 2) |
| return EXIT_FAILURE; |
| |
| fp = fopen(argv[1], "rb"); |
| if (!fp) |
| return EXIT_FAILURE; |
| |
| io.userdata = fp; |
| |
| ctx = NULL; |
| r = nestegg_init(&ctx, io, log_callback); |
| if (r != 0) |
| return EXIT_FAILURE; |
| |
| nestegg_track_count(ctx, &tracks); |
| nestegg_duration(ctx, &duration); |
| #ifdef DEBUG |
| fprintf(stderr, "media has %u tracks and duration %fs\n", tracks, duration / 1e9); |
| #endif |
| |
| for (i = 0; i < tracks; ++i) { |
| type = nestegg_track_type(ctx, i); |
| #ifdef DEBUG |
| fprintf(stderr, "track %u: type: %d codec: %d", i, |
| type, nestegg_track_codec_id(ctx, i)); |
| #endif |
| nestegg_track_codec_data_count(ctx, i, &data_items); |
| for (j = 0; j < data_items; ++j) { |
| nestegg_track_codec_data(ctx, i, j, &codec_data, &length); |
| #ifdef DEBUG |
| fprintf(stderr, " (%p, %u)", codec_data, (unsigned int) length); |
| #endif |
| } |
| if (type == NESTEGG_TRACK_VIDEO) { |
| nestegg_track_video_params(ctx, i, &vparams); |
| #ifdef DEBUG |
| fprintf(stderr, " video: %ux%u (d: %ux%u %ux%ux%ux%u)", |
| vparams.width, vparams.height, |
| vparams.display_width, vparams.display_height, |
| vparams.crop_top, vparams.crop_left, vparams.crop_bottom, vparams.crop_right); |
| #endif |
| } else if (type == NESTEGG_TRACK_AUDIO) { |
| nestegg_track_audio_params(ctx, i, &aparams); |
| #ifdef DEBUG |
| fprintf(stderr, " audio: %.2fhz %u bit %u channels", |
| aparams.rate, aparams.depth, aparams.channels); |
| #endif |
| } |
| #ifdef DEBUG |
| fprintf(stderr, "\n"); |
| #endif |
| } |
| |
| #ifdef SEEK_TEST |
| #ifdef DEBUG |
| fprintf(stderr, "seek to middle\n"); |
| #endif |
| r = nestegg_track_seek(ctx, 0, duration / 2); |
| if (r == 0) { |
| #ifdef DEBUG |
| fprintf(stderr, "middle "); |
| #endif |
| r = nestegg_read_packet(ctx, &pkt); |
| if (r == 1) { |
| nestegg_packet_track(pkt, &track); |
| nestegg_packet_count(pkt, &cnt); |
| nestegg_packet_tstamp(pkt, &tstamp); |
| #ifdef DEBUG |
| fprintf(stderr, "* t %u pts %f frames %u\n", track, tstamp / 1e9, cnt); |
| #endif |
| nestegg_free_packet(pkt); |
| } else { |
| #ifdef DEBUG |
| fprintf(stderr, "middle seek failed\n"); |
| #endif |
| } |
| } |
| |
| #ifdef DEBUG |
| fprintf(stderr, "seek to ~end\n"); |
| #endif |
| r = nestegg_track_seek(ctx, 0, duration - (duration / 10)); |
| if (r == 0) { |
| #ifdef DEBUG |
| fprintf(stderr, "end "); |
| #endif |
| r = nestegg_read_packet(ctx, &pkt); |
| if (r == 1) { |
| nestegg_packet_track(pkt, &track); |
| nestegg_packet_count(pkt, &cnt); |
| nestegg_packet_tstamp(pkt, &tstamp); |
| #ifdef DEBUG |
| fprintf(stderr, "* t %u pts %f frames %u\n", track, tstamp / 1e9, cnt); |
| #endif |
| nestegg_free_packet(pkt); |
| } else { |
| #ifdef DEBUG |
| fprintf(stderr, "end seek failed\n"); |
| #endif |
| } |
| } |
| |
| #ifdef DEBUG |
| fprintf(stderr, "seek to ~start\n"); |
| #endif |
| r = nestegg_track_seek(ctx, 0, duration / 10); |
| if (r == 0) { |
| #ifdef DEBUG |
| fprintf(stderr, "start "); |
| #endif |
| r = nestegg_read_packet(ctx, &pkt); |
| if (r == 1) { |
| nestegg_packet_track(pkt, &track); |
| nestegg_packet_count(pkt, &cnt); |
| nestegg_packet_tstamp(pkt, &tstamp); |
| #ifdef DEBUG |
| fprintf(stderr, "* t %u pts %f frames %u\n", track, tstamp / 1e9, cnt); |
| #endif |
| nestegg_free_packet(pkt); |
| } else { |
| #ifdef DEBUG |
| fprintf(stderr, "start seek failed\n"); |
| #endif |
| } |
| } |
| #endif |
| |
| while (nestegg_read_packet(ctx, &pkt) > 0) { |
| nestegg_packet_track(pkt, &pkt_track); |
| nestegg_packet_count(pkt, &pkt_cnt); |
| nestegg_packet_tstamp(pkt, &pkt_tstamp); |
| |
| #ifdef DEBUG |
| fprintf(stderr, "t %u pts %f frames %u: ", pkt_track, pkt_tstamp / 1e9, pkt_cnt); |
| #endif |
| |
| for (i = 0; i < pkt_cnt; ++i) { |
| nestegg_packet_data(pkt, i, &ptr, &size); |
| #ifdef DEBUG |
| fprintf(stderr, "%u ", (unsigned int) size); |
| #endif |
| } |
| #ifdef DEBUG |
| fprintf(stderr, "\n"); |
| #endif |
| |
| nestegg_free_packet(pkt); |
| } |
| |
| nestegg_destroy(ctx); |
| fclose(fp); |
| |
| return EXIT_SUCCESS; |
| } |