OLD | NEW |
(Empty) | |
| 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 "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)) |
| 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_MASK; |
| 86 } else if (codec_id == NESTEGG_CODEC_VP9) { |
| 87 vpx_ctx->fourcc = VP9_FOURCC_MASK; |
| 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 } |
OLD | NEW |