1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217

media / parsers / vp8_parser.h [blame]

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// This file contains an implementation of a VP8 raw stream parser,
// as defined in RFC 6386.

#ifndef MEDIA_PARSERS_VP8_PARSER_H_
#define MEDIA_PARSERS_VP8_PARSER_H_

#include <stddef.h>
#include <stdint.h>

#include "base/memory/raw_ptr.h"
#include "media/base/media_export.h"
#include "media/parsers/vp8_bool_decoder.h"

namespace media {

// See spec for definitions of values/fields.
const size_t kMaxMBSegments = 4;
const size_t kNumMBFeatureTreeProbs = 3;

// Member of Vp8FrameHeader and will be 0-initialized
// in Vp8FrameHeader's constructor.
struct Vp8SegmentationHeader {
  enum SegmentFeatureMode { FEATURE_MODE_DELTA = 0, FEATURE_MODE_ABSOLUTE = 1 };

  bool segmentation_enabled;
  bool update_mb_segmentation_map;
  bool update_segment_feature_data;
  SegmentFeatureMode segment_feature_mode;

  int8_t quantizer_update_value[kMaxMBSegments];
  int8_t lf_update_value[kMaxMBSegments];
  static const int kDefaultSegmentProb = 255;
  uint8_t segment_prob[kNumMBFeatureTreeProbs];
};

const size_t kNumBlockContexts = 4;

// Member of Vp8FrameHeader and will be 0-initialized
// in Vp8FrameHeader's constructor.
struct Vp8LoopFilterHeader {
  enum Type { LOOP_FILTER_TYPE_NORMAL = 0, LOOP_FILTER_TYPE_SIMPLE = 1 };
  Type type;
  uint8_t level;
  uint8_t sharpness_level;
  bool loop_filter_adj_enable;
  bool mode_ref_lf_delta_update;

  int8_t ref_frame_delta[kNumBlockContexts];
  int8_t mb_mode_delta[kNumBlockContexts];
};

// Member of Vp8FrameHeader and will be 0-initialized
// in Vp8FrameHeader's constructor.
struct Vp8QuantizationHeader {
  uint8_t y_ac_qi;
  int8_t y_dc_delta;
  int8_t y2_dc_delta;
  int8_t y2_ac_delta;
  int8_t uv_dc_delta;
  int8_t uv_ac_delta;
};

const size_t kNumBlockTypes = 4;
const size_t kNumCoeffBands = 8;
const size_t kNumPrevCoeffContexts = 3;
const size_t kNumEntropyNodes = 11;

const size_t kNumMVContexts = 2;
const size_t kNumMVProbs = 19;

const size_t kNumYModeProbs = 4;
const size_t kNumUVModeProbs = 3;

// Member of Vp8FrameHeader and will be 0-initialized
// in Vp8FrameHeader's constructor.
struct Vp8EntropyHeader {
  uint8_t coeff_probs[kNumBlockTypes][kNumCoeffBands][kNumPrevCoeffContexts]
                     [kNumEntropyNodes];

  uint8_t y_mode_probs[kNumYModeProbs];
  uint8_t uv_mode_probs[kNumUVModeProbs];

  uint8_t mv_probs[kNumMVContexts][kNumMVProbs];
};

const size_t kMaxDCTPartitions = 8;
const size_t kNumVp8ReferenceBuffers = 3;

enum Vp8RefType : size_t {
  VP8_FRAME_LAST = 0,
  VP8_FRAME_GOLDEN = 1,
  VP8_FRAME_ALTREF = 2,
};

struct MEDIA_EXPORT Vp8FrameHeader {
  Vp8FrameHeader();
  ~Vp8FrameHeader();
  Vp8FrameHeader& operator=(const Vp8FrameHeader&);
  Vp8FrameHeader(const Vp8FrameHeader&);

  enum FrameType { KEYFRAME = 0, INTERFRAME = 1 };
  bool IsKeyframe() const { return frame_type == KEYFRAME; }

  enum GoldenRefreshMode {
    NO_GOLDEN_REFRESH = 0,
    COPY_LAST_TO_GOLDEN = 1,
    COPY_ALT_TO_GOLDEN = 2,
  };

  enum AltRefreshMode {
    NO_ALT_REFRESH = 0,
    COPY_LAST_TO_ALT = 1,
    COPY_GOLDEN_TO_ALT = 2,
  };

  FrameType frame_type = FrameType::KEYFRAME;
  uint8_t version = 0;
  bool is_experimental = false;
  bool show_frame = false;
  size_t first_part_size = 0;

  uint16_t width = 0;
  uint8_t horizontal_scale = 0;
  uint16_t height = 0;
  uint8_t vertical_scale = 0;

  Vp8SegmentationHeader segmentation_hdr{};
  Vp8LoopFilterHeader loopfilter_hdr{};
  Vp8QuantizationHeader quantization_hdr{};

  size_t num_of_dct_partitions = 0;

  Vp8EntropyHeader entropy_hdr{};

  bool refresh_entropy_probs = false;
  bool refresh_golden_frame = false;
  bool refresh_alternate_frame = false;
  GoldenRefreshMode copy_buffer_to_golden =
      GoldenRefreshMode::NO_GOLDEN_REFRESH;
  AltRefreshMode copy_buffer_to_alternate = AltRefreshMode::NO_ALT_REFRESH;
  uint8_t sign_bias_golden = 0;
  uint8_t sign_bias_alternate = 0;
  bool refresh_last = false;

  bool mb_no_skip_coeff = false;
  uint8_t prob_skip_false = 0;
  uint8_t prob_intra = 0;
  uint8_t prob_last = 0;
  uint8_t prob_gf = 0;

  raw_ptr<const uint8_t, AllowPtrArithmetic | DanglingUntriaged> data = nullptr;
  size_t frame_size = 0;

  size_t dct_partition_sizes[kMaxDCTPartitions] = {};
  // Offset in bytes from data.
  off_t first_part_offset = 0;
  // Offset in bits from first_part_offset.
  off_t macroblock_bit_offset = 0;

  // Bool decoder state
  uint8_t bool_dec_range = 0;
  uint8_t bool_dec_value = 0;
  uint8_t bool_dec_count = 0;

  // Color range information.
  bool is_full_range = false;
};

// A parser for raw VP8 streams as specified in RFC 6386.
class MEDIA_EXPORT Vp8Parser {
 public:
  Vp8Parser();

  Vp8Parser(const Vp8Parser&) = delete;
  Vp8Parser& operator=(const Vp8Parser&) = delete;

  ~Vp8Parser();

  // Try to parse exactly one VP8 frame starting at |ptr| and of size |size|,
  // filling the parsed data in |fhdr|. Return true on success.
  // Size has to be exactly the size of the frame and coming from the caller,
  // who needs to acquire it from elsewhere (normally from a container).
  bool ParseFrame(const uint8_t* ptr, size_t size, Vp8FrameHeader* fhdr);

 private:
  bool ParseFrameTag(Vp8FrameHeader* fhdr);
  bool ParseFrameHeader(Vp8FrameHeader* fhdr);

  bool ParseSegmentationHeader(bool keyframe);
  bool ParseLoopFilterHeader(bool keyframe);
  bool ParseQuantizationHeader(Vp8QuantizationHeader* qhdr);
  bool ParseTokenProbs(Vp8EntropyHeader* ehdr, bool update_curr_probs);
  bool ParseIntraProbs(Vp8EntropyHeader* ehdr,
                       bool update_curr_probs,
                       bool keyframe);
  bool ParseMVProbs(Vp8EntropyHeader* ehdr, bool update_curr_probs);
  bool ParsePartitions(Vp8FrameHeader* fhdr);
  void ResetProbs();

  // These persist across calls to ParseFrame() and may be used and/or updated
  // for subsequent frames if the stream instructs us to do so.
  Vp8SegmentationHeader curr_segmentation_hdr_;
  Vp8LoopFilterHeader curr_loopfilter_hdr_;
  Vp8EntropyHeader curr_entropy_hdr_;

  raw_ptr<const uint8_t, AllowPtrArithmetic | DanglingUntriaged> stream_;
  size_t bytes_left_;
  Vp8BoolDecoder bd_;
};

}  // namespace media

#endif  // MEDIA_PARSERS_VP8_PARSER_H_