int file_is_webm(struct WebmInputContext *webm_ctx, struct VpxInputContext *vpx_ctx) { uint32_t i, n; int track_type = -1; int codec_id; nestegg_io io = {nestegg_read_cb, nestegg_seek_cb, nestegg_tell_cb, 0}; nestegg_video_params params; io.userdata = vpx_ctx->file; if (nestegg_init(&webm_ctx->nestegg_ctx, io, NULL)) goto fail; if (nestegg_track_count(webm_ctx->nestegg_ctx, &n)) goto fail; for (i = 0; i < n; i++) { track_type = nestegg_track_type(webm_ctx->nestegg_ctx, i); if (track_type == NESTEGG_TRACK_VIDEO) break; else if (track_type < 0) goto fail; } codec_id = nestegg_track_codec_id(webm_ctx->nestegg_ctx, i); if (codec_id == NESTEGG_CODEC_VP8) { vpx_ctx->fourcc = VP8_FOURCC_MASK; } else if (codec_id == NESTEGG_CODEC_VP9) { vpx_ctx->fourcc = VP9_FOURCC_MASK; } else { fatal("Not VPx video, quitting.\n"); } webm_ctx->video_track = i; if (nestegg_track_video_params(webm_ctx->nestegg_ctx, i, ¶ms)) goto fail; vpx_ctx->framerate.denominator = 0; vpx_ctx->framerate.numerator = 0; vpx_ctx->width = params.width; vpx_ctx->height = params.height; return 1; fail: webm_ctx->nestegg_ctx = NULL; rewind(vpx_ctx->file); return 0; }
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, -1); if (r != 0) return EXIT_FAILURE; nestegg_track_count(ctx, &tracks); r = nestegg_duration(ctx, &duration); if (r == 0) { #if defined(DEBUG) fprintf(stderr, "media has %u tracks and duration %fs\n", tracks, duration / 1e9); #endif } else { #if defined(DEBUG) fprintf(stderr, "media has %u tracks and unknown duration, using 10s default\n", tracks); #endif duration = 10000000000; } for (i = 0; i < tracks; ++i) { type = nestegg_track_type(ctx, i); #if defined(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); #if defined(DEBUG) fprintf(stderr, " (%p, %u)", codec_data, (unsigned int) length); #endif } if (type == NESTEGG_TRACK_VIDEO) { nestegg_track_video_params(ctx, i, &vparams); #if defined(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); #if defined(DEBUG) fprintf(stderr, " audio: %.2fhz %u bit %u channels", aparams.rate, aparams.depth, aparams.channels); #endif } #if defined(DEBUG) fprintf(stderr, "\n"); #endif } #if defined(SEEK_TEST) #if defined(DEBUG) fprintf(stderr, "seek to middle\n"); #endif r = nestegg_track_seek(ctx, 0, duration / 2); if (r == 0) { #if defined(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); #if defined(DEBUG) fprintf(stderr, "* t %u pts %f frames %u\n", track, tstamp / 1e9, cnt); #endif nestegg_free_packet(pkt); } else { #if defined(DEBUG) fprintf(stderr, "middle seek failed\n"); #endif } } #if defined(DEBUG) fprintf(stderr, "seek to ~end\n"); #endif r = nestegg_track_seek(ctx, 0, duration - (duration / 10)); if (r == 0) { #if defined(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); #if defined(DEBUG) fprintf(stderr, "* t %u pts %f frames %u\n", track, tstamp / 1e9, cnt); #endif nestegg_free_packet(pkt); } else { #if defined(DEBUG) fprintf(stderr, "end seek failed\n"); #endif } } #if defined(DEBUG) fprintf(stderr, "seek to ~start\n"); #endif r = nestegg_track_seek(ctx, 0, duration / 10); if (r == 0) { #if defined(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); #if defined(DEBUG) fprintf(stderr, "* t %u pts %f frames %u\n", track, tstamp / 1e9, cnt); #endif nestegg_free_packet(pkt); } else { #if defined(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); #if defined(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); #if defined(DEBUG) fprintf(stderr, "%u ", (unsigned int) size); #endif } #if defined(DEBUG) fprintf(stderr, "\n"); #endif nestegg_free_packet(pkt); } nestegg_destroy(ctx); fclose(fp); return EXIT_SUCCESS; }
webm_context *webm_start_playback(const char *path, int volume) { webm_context *ctx; nestegg_io io; int video_track = -1, audio_track = -1; quit_video = 0; ctx = malloc(sizeof(*ctx)); if(!ctx) return NULL; memset(ctx, 0, sizeof(*ctx)); // set up I/O callbacks io.read = webm_read; io.seek = webm_seek; io.tell = webm_tell; // open video file ctx->packhandle = openpackfile(path, packfile); if(ctx->packhandle < 0) { printf("Error: Unable to open file %s for playback\n", path); goto error1; } io.userdata = (void*)ctx->packhandle; if(nestegg_init(&(ctx->nestegg_ctx), io, NULL, -1) < 0) goto error2; // get number of tracks unsigned int num_tracks, i; if(nestegg_track_count(ctx->nestegg_ctx, &num_tracks) < 0) goto error3; // find the first video and audio tracks for (i = 0; i < num_tracks; i++) { int track_type = nestegg_track_type(ctx->nestegg_ctx, i); int codec = nestegg_track_codec_id(ctx->nestegg_ctx, i); if (track_type == NESTEGG_TRACK_VIDEO) { if(codec != NESTEGG_CODEC_VP8) { printf("Error: unsupported video codec; only VP8 is supported\n"); goto error3; } video_track = i; } else if (track_type == NESTEGG_TRACK_AUDIO) { if(codec != NESTEGG_CODEC_VORBIS) { printf("Error: unsupported audio codec; only Vorbis is supported\n"); goto error3; } audio_track = i; } } // set up video ctx->video_track = video_track; init_video(ctx->nestegg_ctx, ctx->video_track, &(ctx->video_ctx)); ctx->the_video_thread = thread_create(video_thread, "video", &(ctx->video_ctx)); assert(ctx->the_video_thread); // set up audio, if applicable ctx->audio_track = audio_track; if (audio_track >= 0) { // use the audio track of this file init_audio(ctx->nestegg_ctx, ctx->audio_track, &(ctx->audio_ctx), volume); ctx->the_audio_thread = thread_create(audio_thread, "audio", &(ctx->audio_ctx)); assert(ctx->the_audio_thread); } else if (sound_query_music(NULL, NULL)) { // continue to play the BGM that's already playing ctx->the_audio_thread = thread_create(bgm_update_thread, "bgm", NULL); assert(ctx->the_audio_thread); } // finally, start the demuxing thread ctx->the_demux_thread = thread_create(demux_thread, "demux", ctx); assert(ctx->the_demux_thread); return ctx; error3: nestegg_destroy(ctx->nestegg_ctx); error2: closepackfile(ctx->packhandle); error1: free(ctx); return NULL; }