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 <cstring> 14#include <cstdio> 15 16#include "third_party/libwebm/mkvparser.hpp" 17#include "third_party/libwebm/mkvreader.hpp" 18 19namespace { 20 21void reset(struct WebmInputContext *const webm_ctx) { 22 if (webm_ctx->reader != NULL) { 23 mkvparser::MkvReader *const reader = 24 reinterpret_cast<mkvparser::MkvReader*>(webm_ctx->reader); 25 delete reader; 26 } 27 if (webm_ctx->segment != NULL) { 28 mkvparser::Segment *const segment = 29 reinterpret_cast<mkvparser::Segment*>(webm_ctx->segment); 30 delete segment; 31 } 32 if (webm_ctx->buffer != NULL) { 33 delete[] webm_ctx->buffer; 34 } 35 webm_ctx->reader = NULL; 36 webm_ctx->segment = NULL; 37 webm_ctx->buffer = NULL; 38 webm_ctx->cluster = NULL; 39 webm_ctx->block_entry = NULL; 40 webm_ctx->block = NULL; 41 webm_ctx->block_frame_index = 0; 42 webm_ctx->video_track_index = 0; 43 webm_ctx->timestamp_ns = 0; 44} 45 46void get_first_cluster(struct WebmInputContext *const webm_ctx) { 47 mkvparser::Segment *const segment = 48 reinterpret_cast<mkvparser::Segment*>(webm_ctx->segment); 49 const mkvparser::Cluster *const cluster = segment->GetFirst(); 50 webm_ctx->cluster = cluster; 51} 52 53void rewind_and_reset(struct WebmInputContext *const webm_ctx, 54 struct VpxInputContext *const vpx_ctx) { 55 rewind(vpx_ctx->file); 56 reset(webm_ctx); 57} 58 59} // namespace 60 61int file_is_webm(struct WebmInputContext *webm_ctx, 62 struct VpxInputContext *vpx_ctx) { 63 mkvparser::MkvReader *const reader = new mkvparser::MkvReader(vpx_ctx->file); 64 webm_ctx->reader = reader; 65 66 mkvparser::EBMLHeader header; 67 long long pos = 0; 68 if (header.Parse(reader, pos) < 0) { 69 rewind_and_reset(webm_ctx, vpx_ctx); 70 return 0; 71 } 72 73 mkvparser::Segment* segment; 74 if (mkvparser::Segment::CreateInstance(reader, pos, segment)) { 75 rewind_and_reset(webm_ctx, vpx_ctx); 76 return 0; 77 } 78 webm_ctx->segment = segment; 79 if (segment->Load() < 0) { 80 rewind_and_reset(webm_ctx, vpx_ctx); 81 return 0; 82 } 83 84 const mkvparser::Tracks *const tracks = segment->GetTracks(); 85 const mkvparser::VideoTrack* video_track = NULL; 86 for (unsigned long i = 0; i < tracks->GetTracksCount(); ++i) { 87 const mkvparser::Track* const track = tracks->GetTrackByIndex(i); 88 if (track->GetType() == mkvparser::Track::kVideo) { 89 video_track = static_cast<const mkvparser::VideoTrack*>(track); 90 webm_ctx->video_track_index = track->GetNumber(); 91 break; 92 } 93 } 94 95 if (video_track == NULL) { 96 rewind_and_reset(webm_ctx, vpx_ctx); 97 return 0; 98 } 99 100 if (!strncmp(video_track->GetCodecId(), "V_VP8", 5)) { 101 vpx_ctx->fourcc = VP8_FOURCC; 102 } else if (!strncmp(video_track->GetCodecId(), "V_VP9", 5)) { 103 vpx_ctx->fourcc = VP9_FOURCC; 104 } else { 105 rewind_and_reset(webm_ctx, vpx_ctx); 106 return 0; 107 } 108 109 vpx_ctx->framerate.denominator = 0; 110 vpx_ctx->framerate.numerator = 0; 111 vpx_ctx->width = static_cast<uint32_t>(video_track->GetWidth()); 112 vpx_ctx->height = static_cast<uint32_t>(video_track->GetHeight()); 113 114 get_first_cluster(webm_ctx); 115 116 return 1; 117} 118 119int webm_read_frame(struct WebmInputContext *webm_ctx, 120 uint8_t **buffer, 121 size_t *bytes_in_buffer, 122 size_t *buffer_size) { 123 mkvparser::Segment *const segment = 124 reinterpret_cast<mkvparser::Segment*>(webm_ctx->segment); 125 const mkvparser::Cluster* cluster = 126 reinterpret_cast<const mkvparser::Cluster*>(webm_ctx->cluster); 127 const mkvparser::Block *block = 128 reinterpret_cast<const mkvparser::Block*>(webm_ctx->block); 129 const mkvparser::BlockEntry *block_entry = 130 reinterpret_cast<const mkvparser::BlockEntry*>(webm_ctx->block_entry); 131 bool block_entry_eos = false; 132 do { 133 long status = 0; 134 bool get_new_block = false; 135 if (block_entry == NULL && !block_entry_eos) { 136 status = cluster->GetFirst(block_entry); 137 get_new_block = true; 138 } else if (block_entry_eos || block_entry->EOS()) { 139 cluster = segment->GetNext(cluster); 140 if (cluster == NULL || cluster->EOS()) { 141 *bytes_in_buffer = 0; 142 return 1; 143 } 144 status = cluster->GetFirst(block_entry); 145 block_entry_eos = false; 146 get_new_block = true; 147 } else if (block == NULL || 148 webm_ctx->block_frame_index == block->GetFrameCount() || 149 block->GetTrackNumber() != webm_ctx->video_track_index) { 150 status = cluster->GetNext(block_entry, block_entry); 151 if (block_entry == NULL || block_entry->EOS()) { 152 block_entry_eos = true; 153 continue; 154 } 155 get_new_block = true; 156 } 157 if (status) { 158 return -1; 159 } 160 if (get_new_block) { 161 block = block_entry->GetBlock(); 162 webm_ctx->block_frame_index = 0; 163 } 164 } while (block->GetTrackNumber() != webm_ctx->video_track_index || 165 block_entry_eos); 166 167 webm_ctx->cluster = cluster; 168 webm_ctx->block_entry = block_entry; 169 webm_ctx->block = block; 170 171 const mkvparser::Block::Frame& frame = 172 block->GetFrame(webm_ctx->block_frame_index); 173 ++webm_ctx->block_frame_index; 174 if (frame.len > static_cast<long>(*buffer_size)) { 175 delete[] *buffer; 176 *buffer = new uint8_t[frame.len]; 177 if (*buffer == NULL) { 178 return -1; 179 } 180 *buffer_size = frame.len; 181 webm_ctx->buffer = *buffer; 182 } 183 *bytes_in_buffer = frame.len; 184 webm_ctx->timestamp_ns = block->GetTime(cluster); 185 186 mkvparser::MkvReader *const reader = 187 reinterpret_cast<mkvparser::MkvReader*>(webm_ctx->reader); 188 return frame.Read(reader, *buffer) ? -1 : 0; 189} 190 191int webm_guess_framerate(struct WebmInputContext *webm_ctx, 192 struct VpxInputContext *vpx_ctx) { 193 uint32_t i = 0; 194 uint8_t *buffer = NULL; 195 size_t bytes_in_buffer = 0; 196 size_t buffer_size = 0; 197 while (webm_ctx->timestamp_ns < 1000000000 && i < 50) { 198 if (webm_read_frame(webm_ctx, &buffer, &bytes_in_buffer, &buffer_size)) { 199 break; 200 } 201 ++i; 202 } 203 vpx_ctx->framerate.numerator = (i - 1) * 1000000; 204 vpx_ctx->framerate.denominator = 205 static_cast<int>(webm_ctx->timestamp_ns / 1000); 206 delete[] buffer; 207 208 get_first_cluster(webm_ctx); 209 webm_ctx->block = NULL; 210 webm_ctx->block_entry = NULL; 211 webm_ctx->block_frame_index = 0; 212 webm_ctx->timestamp_ns = 0; 213 214 return 0; 215} 216 217void webm_free(struct WebmInputContext *webm_ctx) { 218 reset(webm_ctx); 219} 220