xref: /aosp_15_r20/external/libwebm/common/vp9_header_parser.cc (revision 103e46e4cd4b6efcf6001f23fa8665fb110abf8d)
1 // Copyright (c) 2016 The WebM project authors. All Rights Reserved.
2 //
3 // Use of this source code is governed by a BSD-style license
4 // that can be found in the LICENSE file in the root of the source
5 // tree. An additional intellectual property rights grant can be found
6 // in the file PATENTS.  All contributing project authors may
7 // be found in the AUTHORS file in the root of the source tree.
8 #include "common/vp9_header_parser.h"
9 
10 #include <stdio.h>
11 
12 namespace vp9_parser {
13 
SetFrame(const uint8_t * frame,size_t length)14 bool Vp9HeaderParser::SetFrame(const uint8_t* frame, size_t length) {
15   if (!frame || length == 0)
16     return false;
17 
18   frame_ = frame;
19   frame_size_ = length;
20   bit_offset_ = 0;
21   profile_ = -1;
22   show_existing_frame_ = 0;
23   key_ = 0;
24   altref_ = 0;
25   error_resilient_mode_ = 0;
26   intra_only_ = 0;
27   reset_frame_context_ = 0;
28   color_space_ = 0;
29   color_range_ = 0;
30   subsampling_x_ = 0;
31   subsampling_y_ = 0;
32   refresh_frame_flags_ = 0;
33   return true;
34 }
35 
ParseUncompressedHeader(const uint8_t * frame,size_t length)36 bool Vp9HeaderParser::ParseUncompressedHeader(const uint8_t* frame,
37                                               size_t length) {
38   if (!SetFrame(frame, length))
39     return false;
40   const int frame_marker = VpxReadLiteral(2);
41   if (frame_marker != kVp9FrameMarker) {
42     fprintf(stderr, "Invalid VP9 frame_marker:%d\n", frame_marker);
43     return false;
44   }
45 
46   profile_ = ReadBit();
47   profile_ |= ReadBit() << 1;
48   if (profile_ > 2)
49     profile_ += ReadBit();
50 
51   // TODO(fgalligan): Decide how to handle show existing frames.
52   show_existing_frame_ = ReadBit();
53   if (show_existing_frame_)
54     return true;
55 
56   key_ = !ReadBit();
57   altref_ = !ReadBit();
58   error_resilient_mode_ = ReadBit();
59   if (key_) {
60     if (!ValidateVp9SyncCode()) {
61       fprintf(stderr, "Invalid Sync code!\n");
62       return false;
63     }
64 
65     ParseColorSpace();
66     ParseFrameResolution();
67     ParseFrameParallelMode();
68     ParseTileInfo();
69   } else {
70     intra_only_ = altref_ ? ReadBit() : 0;
71     reset_frame_context_ = error_resilient_mode_ ? 0 : VpxReadLiteral(2);
72     if (intra_only_) {
73       if (!ValidateVp9SyncCode()) {
74         fprintf(stderr, "Invalid Sync code!\n");
75         return false;
76       }
77 
78       if (profile_ > 0) {
79         ParseColorSpace();
80       } else {
81         // NOTE: The intra-only frame header does not include the specification
82         // of either the color format or color sub-sampling in profile 0. VP9
83         // specifies that the default color format should be YUV 4:2:0 in this
84         // case (normative).
85         color_space_ = kVpxCsBt601;
86         color_range_ = kVpxCrStudioRange;
87         subsampling_y_ = subsampling_x_ = 1;
88         bit_depth_ = 8;
89       }
90 
91       refresh_frame_flags_ = VpxReadLiteral(kRefFrames);
92       ParseFrameResolution();
93     } else {
94       refresh_frame_flags_ = VpxReadLiteral(kRefFrames);
95       for (int i = 0; i < kRefsPerFrame; ++i) {
96         VpxReadLiteral(kRefFrames_LOG2);  // Consume ref.
97         ReadBit();  // Consume ref sign bias.
98       }
99 
100       bool found = false;
101       for (int i = 0; i < kRefsPerFrame; ++i) {
102         if (ReadBit()) {
103           // Found previous reference, width and height did not change since
104           // last frame.
105           found = true;
106           break;
107         }
108       }
109 
110       if (!found)
111         ParseFrameResolution();
112     }
113   }
114   return true;
115 }
116 
ReadBit()117 int Vp9HeaderParser::ReadBit() {
118   const size_t off = bit_offset_;
119   const size_t byte_offset = off >> 3;
120   const int bit_shift = 7 - static_cast<int>(off & 0x7);
121   if (byte_offset < frame_size_) {
122     const int bit = (frame_[byte_offset] >> bit_shift) & 1;
123     bit_offset_++;
124     return bit;
125   } else {
126     return 0;
127   }
128 }
129 
VpxReadLiteral(int bits)130 int Vp9HeaderParser::VpxReadLiteral(int bits) {
131   int value = 0;
132   for (int bit = bits - 1; bit >= 0; --bit)
133     value |= ReadBit() << bit;
134   return value;
135 }
136 
ValidateVp9SyncCode()137 bool Vp9HeaderParser::ValidateVp9SyncCode() {
138   const int sync_code_0 = VpxReadLiteral(8);
139   const int sync_code_1 = VpxReadLiteral(8);
140   const int sync_code_2 = VpxReadLiteral(8);
141   return (sync_code_0 == 0x49 && sync_code_1 == 0x83 && sync_code_2 == 0x42);
142 }
143 
ParseColorSpace()144 void Vp9HeaderParser::ParseColorSpace() {
145   bit_depth_ = 0;
146   if (profile_ >= 2)
147     bit_depth_ = ReadBit() ? 12 : 10;
148   else
149     bit_depth_ = 8;
150   color_space_ = VpxReadLiteral(3);
151   if (color_space_ != kVpxCsSrgb) {
152     color_range_ = ReadBit();
153     if (profile_ == 1 || profile_ == 3) {
154       subsampling_x_ = ReadBit();
155       subsampling_y_ = ReadBit();
156       ReadBit();
157     } else {
158       subsampling_y_ = subsampling_x_ = 1;
159     }
160   } else {
161     color_range_ = kVpxCrFullRange;
162     if (profile_ == 1 || profile_ == 3) {
163       subsampling_y_ = subsampling_x_ = 0;
164       ReadBit();
165     }
166   }
167 }
168 
ParseFrameResolution()169 void Vp9HeaderParser::ParseFrameResolution() {
170   width_ = VpxReadLiteral(16) + 1;
171   height_ = VpxReadLiteral(16) + 1;
172   if (ReadBit()) {
173     display_width_ = VpxReadLiteral(16) + 1;
174     display_height_ = VpxReadLiteral(16) + 1;
175   } else {
176     display_width_ = width_;
177     display_height_ = height_;
178   }
179 }
180 
ParseFrameParallelMode()181 void Vp9HeaderParser::ParseFrameParallelMode() {
182   if (!error_resilient_mode_) {
183     ReadBit();  // Consume refresh frame context
184     frame_parallel_mode_ = ReadBit();
185   } else {
186     frame_parallel_mode_ = 1;
187   }
188 }
189 
ParseTileInfo()190 void Vp9HeaderParser::ParseTileInfo() {
191   VpxReadLiteral(2);  // Consume frame context index
192 
193   // loopfilter
194   VpxReadLiteral(6);  // Consume filter level
195   VpxReadLiteral(3);  // Consume sharpness level
196 
197   const bool mode_ref_delta_enabled = ReadBit();
198   if (mode_ref_delta_enabled) {
199     const bool mode_ref_delta_update = ReadBit();
200     if (mode_ref_delta_update) {
201       const int kMaxRefLFDeltas = 4;
202       for (int i = 0; i < kMaxRefLFDeltas; ++i) {
203         if (ReadBit())
204           VpxReadLiteral(7);  // Consume ref_deltas + sign
205       }
206 
207       const int kMaxModeDeltas = 2;
208       for (int i = 0; i < kMaxModeDeltas; ++i) {
209         if (ReadBit())
210           VpxReadLiteral(7);  // Consume mode_delta + sign
211       }
212     }
213   }
214 
215   // quantization
216   VpxReadLiteral(8);  // Consume base_q
217   SkipDeltaQ();  // y dc
218   SkipDeltaQ();  // uv ac
219   SkipDeltaQ();  // uv dc
220 
221   // segmentation
222   const bool segmentation_enabled = ReadBit();
223   if (!segmentation_enabled) {
224     const int aligned_width = AlignPowerOfTwo(width_, kMiSizeLog2);
225     const int mi_cols = aligned_width >> kMiSizeLog2;
226     const int aligned_mi_cols = AlignPowerOfTwo(mi_cols, kMiSizeLog2);
227     const int sb_cols = aligned_mi_cols >> 3;  // to_sbs(mi_cols);
228     int min_log2_n_tiles, max_log2_n_tiles;
229 
230     for (max_log2_n_tiles = 0;
231          (sb_cols >> max_log2_n_tiles) >= kMinTileWidthB64;
232          max_log2_n_tiles++) {
233     }
234     max_log2_n_tiles--;
235     if (max_log2_n_tiles < 0)
236       max_log2_n_tiles = 0;
237 
238     for (min_log2_n_tiles = 0; (kMaxTileWidthB64 << min_log2_n_tiles) < sb_cols;
239          min_log2_n_tiles++) {
240     }
241 
242     // columns
243     const int max_log2_tile_cols = max_log2_n_tiles;
244     const int min_log2_tile_cols = min_log2_n_tiles;
245     int max_ones = max_log2_tile_cols - min_log2_tile_cols;
246     int log2_tile_cols = min_log2_tile_cols;
247     while (max_ones-- && ReadBit())
248       log2_tile_cols++;
249 
250     // rows
251     int log2_tile_rows = ReadBit();
252     if (log2_tile_rows)
253       log2_tile_rows += ReadBit();
254 
255     row_tiles_ = 1 << log2_tile_rows;
256     column_tiles_ = 1 << log2_tile_cols;
257   }
258 }
259 
SkipDeltaQ()260 void Vp9HeaderParser::SkipDeltaQ() {
261   if (ReadBit())
262     VpxReadLiteral(4);
263 }
264 
AlignPowerOfTwo(int value,int n)265 int Vp9HeaderParser::AlignPowerOfTwo(int value, int n) {
266   return (((value) + ((1 << (n)) - 1)) & ~((1 << (n)) - 1));
267 }
268 
269 }  // namespace vp9_parser
270