tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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); }