| posciak | 3e644c79 | 2015-01-11 03:45:06 | [diff] [blame] | 1 | // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | // |
| 5 | // This file contains an implementation of a VP8 raw stream parser, |
| 6 | // as defined in RFC 6386. |
| 7 | |
| Gil Dekel | bf30863 | 2019-05-28 22:24:17 | [diff] [blame] | 8 | #ifndef MEDIA_PARSERS_VP8_PARSER_H_ |
| 9 | #define MEDIA_PARSERS_VP8_PARSER_H_ |
| posciak | 3e644c79 | 2015-01-11 03:45:06 | [diff] [blame] | 10 | |
| avi | 1323b9c2 | 2015-12-23 06:22:36 | [diff] [blame] | 11 | #include <stddef.h> |
| 12 | #include <stdint.h> |
| 13 | |
| avi | a82b9b5 | 2015-12-19 04:27:08 | [diff] [blame] | 14 | #include "base/macros.h" |
| Gil Dekel | bf30863 | 2019-05-28 22:24:17 | [diff] [blame] | 15 | #include "media/parsers/media_parsers_export.h" |
| 16 | #include "media/parsers/vp8_bool_decoder.h" |
| posciak | 3e644c79 | 2015-01-11 03:45:06 | [diff] [blame] | 17 | |
| 18 | namespace media { |
| 19 | |
| 20 | // See spec for definitions of values/fields. |
| 21 | const size_t kMaxMBSegments = 4; |
| 22 | const size_t kNumMBFeatureTreeProbs = 3; |
| 23 | |
| 24 | // Member of Vp8FrameHeader and will be 0-initialized |
| 25 | // in Vp8FrameHeader's constructor. |
| Gil Dekel | bf30863 | 2019-05-28 22:24:17 | [diff] [blame] | 26 | struct Vp8SegmentationHeader { |
| posciak | 3e644c79 | 2015-01-11 03:45:06 | [diff] [blame] | 27 | enum SegmentFeatureMode { FEATURE_MODE_DELTA = 0, FEATURE_MODE_ABSOLUTE = 1 }; |
| 28 | |
| 29 | bool segmentation_enabled; |
| 30 | bool update_mb_segmentation_map; |
| 31 | bool update_segment_feature_data; |
| 32 | SegmentFeatureMode segment_feature_mode; |
| 33 | |
| 34 | int8_t quantizer_update_value[kMaxMBSegments]; |
| 35 | int8_t lf_update_value[kMaxMBSegments]; |
| 36 | static const int kDefaultSegmentProb = 255; |
| 37 | uint8_t segment_prob[kNumMBFeatureTreeProbs]; |
| 38 | }; |
| 39 | |
| 40 | const size_t kNumBlockContexts = 4; |
| 41 | |
| 42 | // Member of Vp8FrameHeader and will be 0-initialized |
| 43 | // in Vp8FrameHeader's constructor. |
| Gil Dekel | bf30863 | 2019-05-28 22:24:17 | [diff] [blame] | 44 | struct Vp8LoopFilterHeader { |
| posciak | 3e644c79 | 2015-01-11 03:45:06 | [diff] [blame] | 45 | enum Type { LOOP_FILTER_TYPE_NORMAL = 0, LOOP_FILTER_TYPE_SIMPLE = 1 }; |
| 46 | Type type; |
| 47 | uint8_t level; |
| 48 | uint8_t sharpness_level; |
| 49 | bool loop_filter_adj_enable; |
| 50 | bool mode_ref_lf_delta_update; |
| 51 | |
| 52 | int8_t ref_frame_delta[kNumBlockContexts]; |
| 53 | int8_t mb_mode_delta[kNumBlockContexts]; |
| 54 | }; |
| 55 | |
| 56 | // Member of Vp8FrameHeader and will be 0-initialized |
| 57 | // in Vp8FrameHeader's constructor. |
| Gil Dekel | bf30863 | 2019-05-28 22:24:17 | [diff] [blame] | 58 | struct Vp8QuantizationHeader { |
| posciak | 3e644c79 | 2015-01-11 03:45:06 | [diff] [blame] | 59 | uint8_t y_ac_qi; |
| 60 | int8_t y_dc_delta; |
| 61 | int8_t y2_dc_delta; |
| 62 | int8_t y2_ac_delta; |
| 63 | int8_t uv_dc_delta; |
| 64 | int8_t uv_ac_delta; |
| 65 | }; |
| 66 | |
| 67 | const size_t kNumBlockTypes = 4; |
| 68 | const size_t kNumCoeffBands = 8; |
| 69 | const size_t kNumPrevCoeffContexts = 3; |
| 70 | const size_t kNumEntropyNodes = 11; |
| 71 | |
| 72 | const size_t kNumMVContexts = 2; |
| 73 | const size_t kNumMVProbs = 19; |
| 74 | |
| 75 | const size_t kNumYModeProbs = 4; |
| 76 | const size_t kNumUVModeProbs = 3; |
| 77 | |
| 78 | // Member of Vp8FrameHeader and will be 0-initialized |
| 79 | // in Vp8FrameHeader's constructor. |
| 80 | struct Vp8EntropyHeader { |
| 81 | uint8_t coeff_probs[kNumBlockTypes][kNumCoeffBands][kNumPrevCoeffContexts] |
| 82 | [kNumEntropyNodes]; |
| 83 | |
| 84 | uint8_t y_mode_probs[kNumYModeProbs]; |
| 85 | uint8_t uv_mode_probs[kNumUVModeProbs]; |
| 86 | |
| 87 | uint8_t mv_probs[kNumMVContexts][kNumMVProbs]; |
| 88 | }; |
| 89 | |
| 90 | const size_t kMaxDCTPartitions = 8; |
| Pawel Osciak | 13de15a | 2018-05-21 05:48:25 | [diff] [blame] | 91 | const size_t kNumVp8ReferenceBuffers = 3; |
| 92 | |
| 93 | enum Vp8RefType : size_t { |
| 94 | VP8_FRAME_LAST = 0, |
| 95 | VP8_FRAME_GOLDEN = 1, |
| 96 | VP8_FRAME_ALTREF = 2, |
| 97 | }; |
| posciak | 3e644c79 | 2015-01-11 03:45:06 | [diff] [blame] | 98 | |
| Gil Dekel | bf30863 | 2019-05-28 22:24:17 | [diff] [blame] | 99 | struct MEDIA_PARSERS_EXPORT Vp8FrameHeader { |
| posciak | 3e644c79 | 2015-01-11 03:45:06 | [diff] [blame] | 100 | Vp8FrameHeader(); |
| 101 | |
| 102 | enum FrameType { KEYFRAME = 0, INTERFRAME = 1 }; |
| Pawel Osciak | 13de15a | 2018-05-21 05:48:25 | [diff] [blame] | 103 | bool IsKeyframe() const { return frame_type == KEYFRAME; } |
| posciak | 3e644c79 | 2015-01-11 03:45:06 | [diff] [blame] | 104 | |
| 105 | enum GoldenRefreshMode { |
| Pawel Osciak | 13de15a | 2018-05-21 05:48:25 | [diff] [blame] | 106 | NO_GOLDEN_REFRESH = 0, |
| posciak | a86e8af | 2015-01-15 14:06:00 | [diff] [blame] | 107 | COPY_LAST_TO_GOLDEN = 1, |
| 108 | COPY_ALT_TO_GOLDEN = 2, |
| posciak | 3e644c79 | 2015-01-11 03:45:06 | [diff] [blame] | 109 | }; |
| 110 | |
| 111 | enum AltRefreshMode { |
| Pawel Osciak | 13de15a | 2018-05-21 05:48:25 | [diff] [blame] | 112 | NO_ALT_REFRESH = 0, |
| posciak | a86e8af | 2015-01-15 14:06:00 | [diff] [blame] | 113 | COPY_LAST_TO_ALT = 1, |
| 114 | COPY_GOLDEN_TO_ALT = 2, |
| posciak | 3e644c79 | 2015-01-11 03:45:06 | [diff] [blame] | 115 | }; |
| 116 | |
| Pawel Osciak | 13de15a | 2018-05-21 05:48:25 | [diff] [blame] | 117 | FrameType frame_type; |
| posciak | 3e644c79 | 2015-01-11 03:45:06 | [diff] [blame] | 118 | uint8_t version; |
| 119 | bool is_experimental; |
| 120 | bool show_frame; |
| 121 | size_t first_part_size; |
| 122 | |
| 123 | uint16_t width; |
| 124 | uint8_t horizontal_scale; |
| 125 | uint16_t height; |
| 126 | uint8_t vertical_scale; |
| 127 | |
| 128 | Vp8SegmentationHeader segmentation_hdr; |
| 129 | Vp8LoopFilterHeader loopfilter_hdr; |
| 130 | Vp8QuantizationHeader quantization_hdr; |
| 131 | |
| 132 | size_t num_of_dct_partitions; |
| 133 | |
| 134 | Vp8EntropyHeader entropy_hdr; |
| 135 | |
| 136 | bool refresh_entropy_probs; |
| 137 | bool refresh_golden_frame; |
| 138 | bool refresh_alternate_frame; |
| 139 | GoldenRefreshMode copy_buffer_to_golden; |
| 140 | AltRefreshMode copy_buffer_to_alternate; |
| 141 | uint8_t sign_bias_golden; |
| 142 | uint8_t sign_bias_alternate; |
| 143 | bool refresh_last; |
| 144 | |
| 145 | bool mb_no_skip_coeff; |
| 146 | uint8_t prob_skip_false; |
| 147 | uint8_t prob_intra; |
| 148 | uint8_t prob_last; |
| 149 | uint8_t prob_gf; |
| 150 | |
| 151 | const uint8_t* data; |
| 152 | size_t frame_size; |
| 153 | |
| 154 | size_t dct_partition_sizes[kMaxDCTPartitions]; |
| 155 | // Offset in bytes from data. |
| 156 | off_t first_part_offset; |
| 157 | // Offset in bits from first_part_offset. |
| 158 | off_t macroblock_bit_offset; |
| 159 | |
| 160 | // Bool decoder state |
| 161 | uint8_t bool_dec_range; |
| 162 | uint8_t bool_dec_value; |
| 163 | uint8_t bool_dec_count; |
| 164 | }; |
| 165 | |
| 166 | // A parser for raw VP8 streams as specified in RFC 6386. |
| Gil Dekel | bf30863 | 2019-05-28 22:24:17 | [diff] [blame] | 167 | class MEDIA_PARSERS_EXPORT Vp8Parser { |
| posciak | 3e644c79 | 2015-01-11 03:45:06 | [diff] [blame] | 168 | public: |
| 169 | Vp8Parser(); |
| 170 | ~Vp8Parser(); |
| 171 | |
| 172 | // Try to parse exactly one VP8 frame starting at |ptr| and of size |size|, |
| 173 | // filling the parsed data in |fhdr|. Return true on success. |
| 174 | // Size has to be exactly the size of the frame and coming from the caller, |
| 175 | // who needs to acquire it from elsewhere (normally from a container). |
| 176 | bool ParseFrame(const uint8_t* ptr, size_t size, Vp8FrameHeader* fhdr); |
| 177 | |
| 178 | private: |
| 179 | bool ParseFrameTag(Vp8FrameHeader* fhdr); |
| 180 | bool ParseFrameHeader(Vp8FrameHeader* fhdr); |
| 181 | |
| 182 | bool ParseSegmentationHeader(bool keyframe); |
| 183 | bool ParseLoopFilterHeader(bool keyframe); |
| 184 | bool ParseQuantizationHeader(Vp8QuantizationHeader* qhdr); |
| 185 | bool ParseTokenProbs(Vp8EntropyHeader* ehdr, bool update_curr_probs); |
| posciak | e8812c6 | 2015-05-06 05:42:17 | [diff] [blame] | 186 | bool ParseIntraProbs(Vp8EntropyHeader* ehdr, |
| 187 | bool update_curr_probs, |
| 188 | bool keyframe); |
| posciak | 3e644c79 | 2015-01-11 03:45:06 | [diff] [blame] | 189 | bool ParseMVProbs(Vp8EntropyHeader* ehdr, bool update_curr_probs); |
| 190 | bool ParsePartitions(Vp8FrameHeader* fhdr); |
| posciak | e8812c6 | 2015-05-06 05:42:17 | [diff] [blame] | 191 | void ResetProbs(); |
| posciak | 3e644c79 | 2015-01-11 03:45:06 | [diff] [blame] | 192 | |
| 193 | // These persist across calls to ParseFrame() and may be used and/or updated |
| 194 | // for subsequent frames if the stream instructs us to do so. |
| 195 | Vp8SegmentationHeader curr_segmentation_hdr_; |
| 196 | Vp8LoopFilterHeader curr_loopfilter_hdr_; |
| 197 | Vp8EntropyHeader curr_entropy_hdr_; |
| 198 | |
| 199 | const uint8_t* stream_; |
| 200 | size_t bytes_left_; |
| 201 | Vp8BoolDecoder bd_; |
| 202 | |
| 203 | DISALLOW_COPY_AND_ASSIGN(Vp8Parser); |
| 204 | }; |
| 205 | |
| 206 | } // namespace media |
| 207 | |
| Gil Dekel | bf30863 | 2019-05-28 22:24:17 | [diff] [blame] | 208 | #endif // MEDIA_PARSERS_VP8_PARSER_H_ |