tor-browser

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

obu_parser.cc (5845B)


      1 /*
      2 * Copyright (c) 2017, 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 #include <string.h>
     12 
     13 #include <cstdio>
     14 #include <string>
     15 
     16 #include "aom/aom_codec.h"
     17 #include "aom/aom_integer.h"
     18 #include "aom_ports/mem_ops.h"
     19 #include "av1/common/obu_util.h"
     20 #include "tools/obu_parser.h"
     21 
     22 namespace aom_tools {
     23 namespace {
     24 
     25 // Basic OBU syntax
     26 // 8 bits: Header
     27 //   7
     28 //     forbidden bit
     29 //   6,5,4,3
     30 //     type bits
     31 //   2
     32 //     extension flag bit
     33 //   1
     34 //     has size field bit
     35 //   0
     36 //     reserved bit
     37 const uint32_t kObuForbiddenBitMask = 0x1;
     38 const uint32_t kObuForbiddenBitShift = 7;
     39 const uint32_t kObuTypeBitsMask = 0xF;
     40 const uint32_t kObuTypeBitsShift = 3;
     41 const uint32_t kObuExtensionFlagBitMask = 0x1;
     42 const uint32_t kObuExtensionFlagBitShift = 2;
     43 const uint32_t kObuHasSizeFieldBitMask = 0x1;
     44 const uint32_t kObuHasSizeFieldBitShift = 1;
     45 
     46 // When extension flag bit is set:
     47 // 8 bits: extension header
     48 // 7,6,5
     49 //   temporal ID
     50 // 4,3
     51 //   spatial ID
     52 // 2,1,0
     53 //   reserved bits
     54 const uint32_t kObuExtTemporalIdBitsMask = 0x7;
     55 const uint32_t kObuExtTemporalIdBitsShift = 5;
     56 const uint32_t kObuExtSpatialIdBitsMask = 0x3;
     57 const uint32_t kObuExtSpatialIdBitsShift = 3;
     58 
     59 bool ValidObuType(int obu_type) {
     60  switch (obu_type) {
     61    case OBU_SEQUENCE_HEADER:
     62    case OBU_TEMPORAL_DELIMITER:
     63    case OBU_FRAME_HEADER:
     64    case OBU_TILE_GROUP:
     65    case OBU_METADATA:
     66    case OBU_FRAME:
     67    case OBU_REDUNDANT_FRAME_HEADER:
     68    case OBU_TILE_LIST:
     69    case OBU_PADDING: return true;
     70  }
     71  return false;
     72 }
     73 
     74 bool ParseObuHeader(uint8_t obu_header_byte, ObuHeader *obu_header) {
     75  const int forbidden_bit =
     76      (obu_header_byte >> kObuForbiddenBitShift) & kObuForbiddenBitMask;
     77  if (forbidden_bit) {
     78    fprintf(stderr, "Invalid OBU, forbidden bit set.\n");
     79    return false;
     80  }
     81 
     82  obu_header->type = static_cast<OBU_TYPE>(
     83      (obu_header_byte >> kObuTypeBitsShift) & kObuTypeBitsMask);
     84  if (!ValidObuType(obu_header->type)) {
     85    fprintf(stderr, "Invalid OBU type: %d.\n", obu_header->type);
     86    return false;
     87  }
     88 
     89  obu_header->has_extension =
     90      (obu_header_byte >> kObuExtensionFlagBitShift) & kObuExtensionFlagBitMask;
     91  obu_header->has_size_field =
     92      (obu_header_byte >> kObuHasSizeFieldBitShift) & kObuHasSizeFieldBitMask;
     93  return true;
     94 }
     95 
     96 bool ParseObuExtensionHeader(uint8_t ext_header_byte, ObuHeader *obu_header) {
     97  obu_header->temporal_layer_id =
     98      (ext_header_byte >> kObuExtTemporalIdBitsShift) &
     99      kObuExtTemporalIdBitsMask;
    100  obu_header->spatial_layer_id =
    101      (ext_header_byte >> kObuExtSpatialIdBitsShift) & kObuExtSpatialIdBitsMask;
    102 
    103  return true;
    104 }
    105 
    106 void PrintObuHeader(const ObuHeader *header) {
    107  printf(
    108      "  OBU type:        %s\n"
    109      "      extension:   %s\n",
    110      aom_obu_type_to_string(static_cast<OBU_TYPE>(header->type)),
    111      header->has_extension ? "yes" : "no");
    112  if (header->has_extension) {
    113    printf(
    114        "      temporal_id: %d\n"
    115        "      spatial_id:  %d\n",
    116        header->temporal_layer_id, header->spatial_layer_id);
    117  }
    118 }
    119 
    120 }  // namespace
    121 
    122 bool DumpObu(const uint8_t *data, int length, int *obu_overhead_bytes) {
    123  const int kObuHeaderSizeBytes = 1;
    124  const int kMinimumBytesRequired = 1 + kObuHeaderSizeBytes;
    125  int consumed = 0;
    126  int obu_overhead = 0;
    127  ObuHeader obu_header;
    128  while (consumed < length) {
    129    const int remaining = length - consumed;
    130    if (remaining < kMinimumBytesRequired) {
    131      fprintf(stderr,
    132              "OBU parse error. Did not consume all data, %d bytes remain.\n",
    133              remaining);
    134      return false;
    135    }
    136 
    137    int obu_header_size = 0;
    138 
    139    memset(&obu_header, 0, sizeof(obu_header));
    140    const uint8_t obu_header_byte = *(data + consumed);
    141    if (!ParseObuHeader(obu_header_byte, &obu_header)) {
    142      fprintf(stderr, "OBU parsing failed at offset %d.\n", consumed);
    143      return false;
    144    }
    145 
    146    ++obu_overhead;
    147    ++obu_header_size;
    148 
    149    if (obu_header.has_extension) {
    150      const uint8_t obu_ext_header_byte =
    151          *(data + consumed + kObuHeaderSizeBytes);
    152      if (!ParseObuExtensionHeader(obu_ext_header_byte, &obu_header)) {
    153        fprintf(stderr, "OBU extension parsing failed at offset %d.\n",
    154                consumed + kObuHeaderSizeBytes);
    155        return false;
    156      }
    157 
    158      ++obu_overhead;
    159      ++obu_header_size;
    160    }
    161 
    162    PrintObuHeader(&obu_header);
    163 
    164    uint64_t obu_size = 0;
    165    size_t length_field_size = 0;
    166    if (aom_uleb_decode(data + consumed + obu_header_size,
    167                        remaining - obu_header_size, &obu_size,
    168                        &length_field_size) != 0) {
    169      fprintf(stderr, "OBU size parsing failed at offset %d.\n",
    170              consumed + obu_header_size);
    171      return false;
    172    }
    173    int current_obu_length = static_cast<int>(obu_size);
    174    if (obu_header_size + static_cast<int>(length_field_size) +
    175            current_obu_length >
    176        remaining) {
    177      fprintf(stderr, "OBU parsing failed: not enough OBU data.\n");
    178      return false;
    179    }
    180    consumed += obu_header_size + static_cast<int>(length_field_size) +
    181                current_obu_length;
    182    printf("      length:      %d\n",
    183           static_cast<int>(obu_header_size + length_field_size +
    184                            current_obu_length));
    185  }
    186 
    187  if (obu_overhead_bytes != nullptr) *obu_overhead_bytes = obu_overhead;
    188  printf("  TU size: %d\n", consumed);
    189 
    190  return true;
    191 }
    192 
    193 }  // namespace aom_tools