webmdec.cc (7807B)
1 /* 2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved. 3 * 4 * This source code is subject to the terms of the BSD 2 Clause License and 5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License 6 * was not distributed with this source code in the LICENSE file, you can 7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open 8 * Media Patent License 1.0 was not distributed with this source code in the 9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent. 10 */ 11 12 #include "common/webmdec.h" 13 14 #include <cassert> 15 #include <cstring> 16 #include <cstdio> 17 18 #include "third_party/libwebm/mkvparser/mkvparser.h" 19 #include "third_party/libwebm/mkvparser/mkvreader.h" 20 21 namespace { 22 23 void reset(struct WebmInputContext *const webm_ctx) { 24 if (webm_ctx->reader != NULL) { 25 mkvparser::MkvReader *const reader = 26 reinterpret_cast<mkvparser::MkvReader *>(webm_ctx->reader); 27 delete reader; 28 } 29 if (webm_ctx->segment != NULL) { 30 mkvparser::Segment *const segment = 31 reinterpret_cast<mkvparser::Segment *>(webm_ctx->segment); 32 delete segment; 33 } 34 if (webm_ctx->buffer != NULL) { 35 delete[] webm_ctx->buffer; 36 } 37 webm_ctx->reader = NULL; 38 webm_ctx->segment = NULL; 39 webm_ctx->buffer = NULL; 40 webm_ctx->cluster = NULL; 41 webm_ctx->block_entry = NULL; 42 webm_ctx->block = NULL; 43 webm_ctx->block_frame_index = 0; 44 webm_ctx->video_track_index = 0; 45 webm_ctx->timestamp_ns = 0; 46 webm_ctx->is_key_frame = false; 47 } 48 49 void get_first_cluster(struct WebmInputContext *const webm_ctx) { 50 mkvparser::Segment *const segment = 51 reinterpret_cast<mkvparser::Segment *>(webm_ctx->segment); 52 const mkvparser::Cluster *const cluster = segment->GetFirst(); 53 webm_ctx->cluster = cluster; 54 } 55 56 void rewind_and_reset(struct WebmInputContext *const webm_ctx, 57 struct AvxInputContext *const aom_ctx) { 58 rewind(aom_ctx->file); 59 reset(webm_ctx); 60 } 61 62 } // namespace 63 64 int file_is_webm(struct WebmInputContext *webm_ctx, 65 struct AvxInputContext *aom_ctx) { 66 mkvparser::MkvReader *const reader = new mkvparser::MkvReader(aom_ctx->file); 67 webm_ctx->reader = reader; 68 webm_ctx->reached_eos = 0; 69 70 mkvparser::EBMLHeader header; 71 long long pos = 0; 72 if (header.Parse(reader, pos) < 0) { 73 rewind_and_reset(webm_ctx, aom_ctx); 74 return 0; 75 } 76 77 mkvparser::Segment *segment; 78 if (mkvparser::Segment::CreateInstance(reader, pos, segment)) { 79 rewind_and_reset(webm_ctx, aom_ctx); 80 return 0; 81 } 82 webm_ctx->segment = segment; 83 if (segment->Load() < 0) { 84 rewind_and_reset(webm_ctx, aom_ctx); 85 return 0; 86 } 87 88 const mkvparser::Tracks *const tracks = segment->GetTracks(); 89 const mkvparser::VideoTrack *video_track = NULL; 90 for (unsigned long i = 0; i < tracks->GetTracksCount(); ++i) { 91 const mkvparser::Track *const track = tracks->GetTrackByIndex(i); 92 if (track->GetType() == mkvparser::Track::kVideo) { 93 video_track = static_cast<const mkvparser::VideoTrack *>(track); 94 webm_ctx->video_track_index = static_cast<int>(track->GetNumber()); 95 break; 96 } 97 } 98 99 if (video_track == NULL || video_track->GetCodecId() == NULL) { 100 rewind_and_reset(webm_ctx, aom_ctx); 101 return 0; 102 } 103 104 if (!strncmp(video_track->GetCodecId(), "V_AV1", 5)) { 105 aom_ctx->fourcc = AV1_FOURCC; 106 } else { 107 rewind_and_reset(webm_ctx, aom_ctx); 108 return 0; 109 } 110 111 aom_ctx->framerate.denominator = 0; 112 aom_ctx->framerate.numerator = 0; 113 aom_ctx->width = static_cast<uint32_t>(video_track->GetWidth()); 114 aom_ctx->height = static_cast<uint32_t>(video_track->GetHeight()); 115 116 get_first_cluster(webm_ctx); 117 118 return 1; 119 } 120 121 int webm_read_frame(struct WebmInputContext *webm_ctx, uint8_t **buffer, 122 size_t *bytes_read, size_t *buffer_size) { 123 assert(webm_ctx->buffer == *buffer); 124 // This check is needed for frame parallel decoding, in which case this 125 // function could be called even after it has reached end of input stream. 126 if (webm_ctx->reached_eos) { 127 return 1; 128 } 129 mkvparser::Segment *const segment = 130 reinterpret_cast<mkvparser::Segment *>(webm_ctx->segment); 131 const mkvparser::Cluster *cluster = 132 reinterpret_cast<const mkvparser::Cluster *>(webm_ctx->cluster); 133 const mkvparser::Block *block = 134 reinterpret_cast<const mkvparser::Block *>(webm_ctx->block); 135 const mkvparser::BlockEntry *block_entry = 136 reinterpret_cast<const mkvparser::BlockEntry *>(webm_ctx->block_entry); 137 bool block_entry_eos = false; 138 do { 139 long status = 0; 140 bool get_new_block = false; 141 if (block_entry == NULL && !block_entry_eos) { 142 status = cluster->GetFirst(block_entry); 143 get_new_block = true; 144 } else if (block_entry_eos || block_entry->EOS()) { 145 cluster = segment->GetNext(cluster); 146 if (cluster == NULL || cluster->EOS()) { 147 *bytes_read = 0; 148 webm_ctx->reached_eos = 1; 149 return 1; 150 } 151 status = cluster->GetFirst(block_entry); 152 block_entry_eos = false; 153 get_new_block = true; 154 } else if (block == NULL || 155 webm_ctx->block_frame_index == block->GetFrameCount() || 156 block->GetTrackNumber() != webm_ctx->video_track_index) { 157 status = cluster->GetNext(block_entry, block_entry); 158 if (block_entry == NULL || block_entry->EOS()) { 159 block_entry_eos = true; 160 continue; 161 } 162 get_new_block = true; 163 } 164 if (status || block_entry == NULL) { 165 return -1; 166 } 167 if (get_new_block) { 168 block = block_entry->GetBlock(); 169 if (block == NULL) return -1; 170 webm_ctx->block_frame_index = 0; 171 } 172 } while (block_entry_eos || 173 block->GetTrackNumber() != webm_ctx->video_track_index); 174 175 webm_ctx->cluster = cluster; 176 webm_ctx->block_entry = block_entry; 177 webm_ctx->block = block; 178 179 const mkvparser::Block::Frame &frame = 180 block->GetFrame(webm_ctx->block_frame_index); 181 ++webm_ctx->block_frame_index; 182 if (frame.len > static_cast<long>(*buffer_size)) { 183 delete[] *buffer; 184 *buffer = new uint8_t[frame.len]; 185 webm_ctx->buffer = *buffer; 186 if (*buffer == NULL) { 187 return -1; 188 } 189 *buffer_size = frame.len; 190 } 191 *bytes_read = frame.len; 192 webm_ctx->timestamp_ns = block->GetTime(cluster); 193 webm_ctx->is_key_frame = block->IsKey(); 194 195 mkvparser::MkvReader *const reader = 196 reinterpret_cast<mkvparser::MkvReader *>(webm_ctx->reader); 197 return frame.Read(reader, *buffer) ? -1 : 0; 198 } 199 200 // Calculate the greatest common divisor between two numbers. 201 static int gcd(int a, int b) { 202 int remainder; 203 while (b > 0) { 204 remainder = a % b; 205 a = b; 206 b = remainder; 207 } 208 return a; 209 } 210 211 int webm_guess_framerate(struct WebmInputContext *webm_ctx, 212 struct AvxInputContext *aom_ctx) { 213 uint32_t i = 0; 214 uint8_t *buffer = NULL; 215 size_t buffer_size = 0; 216 size_t bytes_read = 0; 217 assert(webm_ctx->buffer == NULL); 218 while (webm_ctx->timestamp_ns < 1000000000 && i < 50) { 219 if (webm_read_frame(webm_ctx, &buffer, &bytes_read, &buffer_size)) { 220 break; 221 } 222 ++i; 223 } 224 aom_ctx->framerate.numerator = (i - 1) * 1000000; 225 aom_ctx->framerate.denominator = 226 static_cast<int>(webm_ctx->timestamp_ns / 1000); 227 // Fraction might be represented in large numbers, like 49000000/980000 228 // for 50fps. Simplify as much as possible. 229 int g = gcd(aom_ctx->framerate.numerator, aom_ctx->framerate.denominator); 230 if (g != 0) { 231 aom_ctx->framerate.numerator /= g; 232 aom_ctx->framerate.denominator /= g; 233 } 234 235 delete[] buffer; 236 webm_ctx->buffer = NULL; 237 238 get_first_cluster(webm_ctx); 239 webm_ctx->block = NULL; 240 webm_ctx->block_entry = NULL; 241 webm_ctx->block_frame_index = 0; 242 webm_ctx->timestamp_ns = 0; 243 webm_ctx->reached_eos = 0; 244 245 return 0; 246 } 247 248 void webm_free(struct WebmInputContext *webm_ctx) { reset(webm_ctx); }