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, ¶ms)) 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