Home | History | Annotate | Download | only in libvpx
      1 /*
      2  *  Copyright (c) 2013 The WebM project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include "./webmdec.h"
     12 
     13 #include <stdarg.h>
     14 
     15 #include "third_party/nestegg/include/nestegg/nestegg.h"
     16 
     17 static int nestegg_read_cb(void *buffer, size_t length, void *userdata) {
     18   FILE *f = userdata;
     19 
     20   if (fread(buffer, 1, length, f) < length) {
     21     if (ferror(f))
     22       return -1;
     23     if (feof(f))
     24       return 0;
     25   }
     26   return 1;
     27 }
     28 
     29 static int nestegg_seek_cb(int64_t offset, int whence, void *userdata) {
     30   switch (whence) {
     31     case NESTEGG_SEEK_SET:
     32       whence = SEEK_SET;
     33       break;
     34     case NESTEGG_SEEK_CUR:
     35       whence = SEEK_CUR;
     36       break;
     37     case NESTEGG_SEEK_END:
     38       whence = SEEK_END;
     39       break;
     40   };
     41   return fseek(userdata, (int32_t)offset, whence) ? -1 : 0;
     42 }
     43 
     44 static int64_t nestegg_tell_cb(void *userdata) {
     45   return ftell(userdata);
     46 }
     47 
     48 static void nestegg_log_cb(nestegg *context,
     49                            unsigned int severity,
     50                            char const *format, ...) {
     51   va_list ap;
     52   va_start(ap, format);
     53   vfprintf(stderr, format, ap);
     54   fprintf(stderr, "\n");
     55   va_end(ap);
     56 }
     57 
     58 int file_is_webm(struct WebmInputContext *webm_ctx,
     59                  struct VpxInputContext *vpx_ctx) {
     60   uint32_t i, n;
     61   int track_type = -1;
     62   int codec_id;
     63 
     64   nestegg_io io = {nestegg_read_cb, nestegg_seek_cb, nestegg_tell_cb, 0};
     65   nestegg_video_params params;
     66 
     67   io.userdata = vpx_ctx->file;
     68   if (nestegg_init(&webm_ctx->nestegg_ctx, io, NULL, -1))
     69     goto fail;
     70 
     71   if (nestegg_track_count(webm_ctx->nestegg_ctx, &n))
     72     goto fail;
     73 
     74   for (i = 0; i < n; i++) {
     75     track_type = nestegg_track_type(webm_ctx->nestegg_ctx, i);
     76 
     77     if (track_type == NESTEGG_TRACK_VIDEO)
     78       break;
     79     else if (track_type < 0)
     80       goto fail;
     81   }
     82 
     83   codec_id = nestegg_track_codec_id(webm_ctx->nestegg_ctx, i);
     84   if (codec_id == NESTEGG_CODEC_VP8) {
     85     vpx_ctx->fourcc = VP8_FOURCC;
     86   } else if (codec_id == NESTEGG_CODEC_VP9) {
     87     vpx_ctx->fourcc = VP9_FOURCC;
     88   } else {
     89     fatal("Not VPx video, quitting.\n");
     90   }
     91 
     92   webm_ctx->video_track = i;
     93 
     94   if (nestegg_track_video_params(webm_ctx->nestegg_ctx, i, &params))
     95     goto fail;
     96 
     97   vpx_ctx->framerate.denominator = 0;
     98   vpx_ctx->framerate.numerator = 0;
     99   vpx_ctx->width = params.width;
    100   vpx_ctx->height = params.height;
    101 
    102   return 1;
    103 
    104  fail:
    105   webm_ctx->nestegg_ctx = NULL;
    106   rewind(vpx_ctx->file);
    107 
    108   return 0;
    109 }
    110 
    111 int webm_read_frame(struct WebmInputContext *webm_ctx,
    112                     uint8_t **buffer,
    113                     size_t *bytes_in_buffer,
    114                     size_t *buffer_size) {
    115   if (webm_ctx->chunk >= webm_ctx->chunks) {
    116     uint32_t track;
    117 
    118     do {
    119       /* End of this packet, get another. */
    120       if (webm_ctx->pkt) {
    121         nestegg_free_packet(webm_ctx->pkt);
    122         webm_ctx->pkt = NULL;
    123       }
    124 
    125       if (nestegg_read_packet(webm_ctx->nestegg_ctx, &webm_ctx->pkt) <= 0 ||
    126           nestegg_packet_track(webm_ctx->pkt, &track)) {
    127         return 1;
    128       }
    129     } while (track != webm_ctx->video_track);
    130 
    131     if (nestegg_packet_count(webm_ctx->pkt, &webm_ctx->chunks))
    132       return 1;
    133 
    134     webm_ctx->chunk = 0;
    135   }
    136 
    137   if (nestegg_packet_data(webm_ctx->pkt, webm_ctx->chunk,
    138                           buffer, bytes_in_buffer)) {
    139     return 1;
    140   }
    141 
    142   webm_ctx->chunk++;
    143   return 0;
    144 }
    145 
    146 int webm_guess_framerate(struct WebmInputContext *webm_ctx,
    147                          struct VpxInputContext *vpx_ctx) {
    148   uint32_t i;
    149   uint64_t tstamp = 0;
    150 
    151   /* Check to see if we can seek before we parse any data. */
    152   if (nestegg_track_seek(webm_ctx->nestegg_ctx, webm_ctx->video_track, 0)) {
    153     warn("Failed to guess framerate (no Cues), set to 30fps.\n");
    154     vpx_ctx->framerate.numerator = 30;
    155     vpx_ctx->framerate.denominator  = 1;
    156     return 0;
    157   }
    158 
    159   /* Guess the framerate. Read up to 1 second, or 50 video packets,
    160    * whichever comes first.
    161    */
    162   for (i = 0; tstamp < 1000000000 && i < 50;) {
    163     nestegg_packet *pkt;
    164     uint32_t track;
    165 
    166     if (nestegg_read_packet(webm_ctx->nestegg_ctx, &pkt) <= 0)
    167       break;
    168 
    169     nestegg_packet_track(pkt, &track);
    170     if (track == webm_ctx->video_track) {
    171       nestegg_packet_tstamp(pkt, &tstamp);
    172       ++i;
    173     }
    174 
    175     nestegg_free_packet(pkt);
    176   }
    177 
    178   if (nestegg_track_seek(webm_ctx->nestegg_ctx, webm_ctx->video_track, 0))
    179     goto fail;
    180 
    181   vpx_ctx->framerate.numerator = (i - 1) * 1000000;
    182   vpx_ctx->framerate.denominator = (int)(tstamp / 1000);
    183   return 0;
    184 
    185  fail:
    186   nestegg_destroy(webm_ctx->nestegg_ctx);
    187   webm_ctx->nestegg_ctx = NULL;
    188   rewind(vpx_ctx->file);
    189   return 1;
    190 }
    191 
    192 void webm_free(struct WebmInputContext *webm_ctx) {
    193   if (webm_ctx && webm_ctx->nestegg_ctx) {
    194     if (webm_ctx->pkt)
    195       nestegg_free_packet(webm_ctx->pkt);
    196     nestegg_destroy(webm_ctx->nestegg_ctx);
    197   }
    198 }
    199