vpxdec: Relocate WebM input support. - Move it to webmdec.c and webmdec.h. - Also, tidy up obvious style nits in the vicinity of code I was already touching. Change-Id: Ie2898d06e73c1e9030d9c8d465b73ee7edc3c02a
diff --git a/webmdec.c b/webmdec.c new file mode 100644 index 0000000..4bf7c7e --- /dev/null +++ b/webmdec.c
@@ -0,0 +1,193 @@ +/* + * Copyright (c) 2013 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "./webmdec.h" + +#include <stdarg.h> + +#include "nestegg/include/nestegg/nestegg.h" + +static int nestegg_read_cb(void *buffer, size_t length, void *userdata) { + FILE *f = userdata; + + if (fread(buffer, 1, length, f) < length) { + if (ferror(f)) + return -1; + if (feof(f)) + return 0; + } + return 1; +} + +static int nestegg_seek_cb(int64_t offset, int whence, void *userdata) { + switch (whence) { + case NESTEGG_SEEK_SET: + whence = SEEK_SET; + break; + case NESTEGG_SEEK_CUR: + whence = SEEK_CUR; + break; + case NESTEGG_SEEK_END: + whence = SEEK_END; + break; + }; + return fseek(userdata, (int32_t)offset, whence) ? -1 : 0; +} + +static int64_t nestegg_tell_cb(void *userdata) { + return ftell(userdata); +} + +static void nestegg_log_cb(nestegg *context, + unsigned int severity, + char const *format, ...) { + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + +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 webm_read_frame(struct WebmInputContext *webm_ctx, + uint8_t **buffer, + size_t *bytes_in_buffer, + size_t *buffer_size) { + if (webm_ctx->chunk >= webm_ctx->chunks) { + uint32_t track; + + do { + /* End of this packet, get another. */ + if (webm_ctx->pkt) + nestegg_free_packet(webm_ctx->pkt); + + if (nestegg_read_packet(webm_ctx->nestegg_ctx, &webm_ctx->pkt) <= 0 || + nestegg_packet_track(webm_ctx->pkt, &track)) { + return 1; + } + } while (track != webm_ctx->video_track); + + if (nestegg_packet_count(webm_ctx->pkt, &webm_ctx->chunks)) + return 1; + + webm_ctx->chunk = 0; + } + + if (nestegg_packet_data(webm_ctx->pkt, webm_ctx->chunk, + buffer, bytes_in_buffer)) { + return 1; + } + + webm_ctx->chunk++; + return 0; +} + +int webm_guess_framerate(struct WebmInputContext *webm_ctx, + struct VpxInputContext *vpx_ctx) { + uint32_t i; + uint64_t tstamp = 0; + + /* Check to see if we can seek before we parse any data. */ + if (nestegg_track_seek(webm_ctx->nestegg_ctx, webm_ctx->video_track, 0)) { + warn("Failed to guess framerate (no Cues), set to 30fps.\n"); + vpx_ctx->framerate.numerator = 30; + vpx_ctx->framerate.denominator = 1; + return 0; + } + + /* Guess the framerate. Read up to 1 second, or 50 video packets, + * whichever comes first. + */ + for (i = 0; tstamp < 1000000000 && i < 50;) { + nestegg_packet *pkt; + uint32_t track; + + if (nestegg_read_packet(webm_ctx->nestegg_ctx, &pkt) <= 0) + break; + + nestegg_packet_track(pkt, &track); + if (track == webm_ctx->video_track) { + nestegg_packet_tstamp(pkt, &tstamp); + ++i; + } + + nestegg_free_packet(pkt); + } + + if (nestegg_track_seek(webm_ctx->nestegg_ctx, webm_ctx->video_track, 0)) + goto fail; + + vpx_ctx->framerate.numerator = (i - 1) * 1000000; + vpx_ctx->framerate.denominator = (int)(tstamp / 1000); + return 0; + + fail: + nestegg_destroy(webm_ctx->nestegg_ctx); + webm_ctx->nestegg_ctx = NULL; + rewind(vpx_ctx->file); + return 1; +} + +void webm_free(struct WebmInputContext *webm_ctx) { + if (webm_ctx && webm_ctx->nestegg_ctx) + nestegg_destroy(webm_ctx->nestegg_ctx); +}