xref: /aosp_15_r20/external/libwebm/webm_parser/src/block_parser.cc (revision 103e46e4cd4b6efcf6001f23fa8665fb110abf8d)
1*103e46e4SHarish Mahendrakar // Copyright (c) 2016 The WebM project authors. All Rights Reserved.
2*103e46e4SHarish Mahendrakar //
3*103e46e4SHarish Mahendrakar // Use of this source code is governed by a BSD-style license
4*103e46e4SHarish Mahendrakar // that can be found in the LICENSE file in the root of the source
5*103e46e4SHarish Mahendrakar // tree. An additional intellectual property rights grant can be found
6*103e46e4SHarish Mahendrakar // in the file PATENTS.  All contributing project authors may
7*103e46e4SHarish Mahendrakar // be found in the AUTHORS file in the root of the source tree.
8*103e46e4SHarish Mahendrakar #include "src/block_parser.h"
9*103e46e4SHarish Mahendrakar 
10*103e46e4SHarish Mahendrakar #include <cassert>
11*103e46e4SHarish Mahendrakar #include <cstdint>
12*103e46e4SHarish Mahendrakar #include <numeric>
13*103e46e4SHarish Mahendrakar #include <type_traits>
14*103e46e4SHarish Mahendrakar #include <vector>
15*103e46e4SHarish Mahendrakar 
16*103e46e4SHarish Mahendrakar #include "src/parser_utils.h"
17*103e46e4SHarish Mahendrakar #include "webm/element.h"
18*103e46e4SHarish Mahendrakar 
19*103e46e4SHarish Mahendrakar namespace webm {
20*103e46e4SHarish Mahendrakar 
21*103e46e4SHarish Mahendrakar namespace {
22*103e46e4SHarish Mahendrakar 
23*103e46e4SHarish Mahendrakar // The ParseBasicBlockFlags functions parse extra flag bits into the block,
24*103e46e4SHarish Mahendrakar // depending on the type of block that is being parsed.
ParseBasicBlockFlags(std::uint8_t,Block *)25*103e46e4SHarish Mahendrakar void ParseBasicBlockFlags(std::uint8_t /* flags */, Block* /* block */) {
26*103e46e4SHarish Mahendrakar   // Block has no extra flags that aren't already handled.
27*103e46e4SHarish Mahendrakar }
28*103e46e4SHarish Mahendrakar 
ParseBasicBlockFlags(std::uint8_t flags,SimpleBlock * block)29*103e46e4SHarish Mahendrakar void ParseBasicBlockFlags(std::uint8_t flags, SimpleBlock* block) {
30*103e46e4SHarish Mahendrakar   block->is_key_frame = (0x80 & flags) != 0;
31*103e46e4SHarish Mahendrakar   block->is_discardable = (0x01 & flags) != 0;
32*103e46e4SHarish Mahendrakar }
33*103e46e4SHarish Mahendrakar 
34*103e46e4SHarish Mahendrakar // The BasicBlockBegin functions call the Callback event handler and get the
35*103e46e4SHarish Mahendrakar // correct action for the parser, depending on the type of block that is being
36*103e46e4SHarish Mahendrakar // parsed.
BasicBlockBegin(const ElementMetadata & metadata,const Block & block,Callback * callback,Action * action)37*103e46e4SHarish Mahendrakar Status BasicBlockBegin(const ElementMetadata& metadata, const Block& block,
38*103e46e4SHarish Mahendrakar                        Callback* callback, Action* action) {
39*103e46e4SHarish Mahendrakar   return callback->OnBlockBegin(metadata, block, action);
40*103e46e4SHarish Mahendrakar }
41*103e46e4SHarish Mahendrakar 
BasicBlockBegin(const ElementMetadata & metadata,const SimpleBlock & block,Callback * callback,Action * action)42*103e46e4SHarish Mahendrakar Status BasicBlockBegin(const ElementMetadata& metadata,
43*103e46e4SHarish Mahendrakar                        const SimpleBlock& block, Callback* callback,
44*103e46e4SHarish Mahendrakar                        Action* action) {
45*103e46e4SHarish Mahendrakar   return callback->OnSimpleBlockBegin(metadata, block, action);
46*103e46e4SHarish Mahendrakar }
47*103e46e4SHarish Mahendrakar 
48*103e46e4SHarish Mahendrakar // The BasicBlockEnd functions call the Callback event handler depending on the
49*103e46e4SHarish Mahendrakar // type of block that is being parsed.
BasicBlockEnd(const ElementMetadata & metadata,const Block & block,Callback * callback)50*103e46e4SHarish Mahendrakar Status BasicBlockEnd(const ElementMetadata& metadata, const Block& block,
51*103e46e4SHarish Mahendrakar                      Callback* callback) {
52*103e46e4SHarish Mahendrakar   return callback->OnBlockEnd(metadata, block);
53*103e46e4SHarish Mahendrakar }
54*103e46e4SHarish Mahendrakar 
BasicBlockEnd(const ElementMetadata & metadata,const SimpleBlock & block,Callback * callback)55*103e46e4SHarish Mahendrakar Status BasicBlockEnd(const ElementMetadata& metadata, const SimpleBlock& block,
56*103e46e4SHarish Mahendrakar                      Callback* callback) {
57*103e46e4SHarish Mahendrakar   return callback->OnSimpleBlockEnd(metadata, block);
58*103e46e4SHarish Mahendrakar }
59*103e46e4SHarish Mahendrakar 
60*103e46e4SHarish Mahendrakar }  // namespace
61*103e46e4SHarish Mahendrakar 
62*103e46e4SHarish Mahendrakar template <typename T>
Init(const ElementMetadata & metadata,std::uint64_t max_size)63*103e46e4SHarish Mahendrakar Status BasicBlockParser<T>::Init(const ElementMetadata& metadata,
64*103e46e4SHarish Mahendrakar                                  std::uint64_t max_size) {
65*103e46e4SHarish Mahendrakar   assert(metadata.size == kUnknownElementSize || metadata.size <= max_size);
66*103e46e4SHarish Mahendrakar 
67*103e46e4SHarish Mahendrakar   if (metadata.size == kUnknownElementSize || metadata.size < 5) {
68*103e46e4SHarish Mahendrakar     return Status(Status::kInvalidElementSize);
69*103e46e4SHarish Mahendrakar   }
70*103e46e4SHarish Mahendrakar 
71*103e46e4SHarish Mahendrakar   *this = {};
72*103e46e4SHarish Mahendrakar   frame_metadata_.parent_element = metadata;
73*103e46e4SHarish Mahendrakar 
74*103e46e4SHarish Mahendrakar   return Status(Status::kOkCompleted);
75*103e46e4SHarish Mahendrakar }
76*103e46e4SHarish Mahendrakar 
77*103e46e4SHarish Mahendrakar template <typename T>
Feed(Callback * callback,Reader * reader,std::uint64_t * num_bytes_read)78*103e46e4SHarish Mahendrakar Status BasicBlockParser<T>::Feed(Callback* callback, Reader* reader,
79*103e46e4SHarish Mahendrakar                                  std::uint64_t* num_bytes_read) {
80*103e46e4SHarish Mahendrakar   assert(callback != nullptr);
81*103e46e4SHarish Mahendrakar   assert(reader != nullptr);
82*103e46e4SHarish Mahendrakar   assert(num_bytes_read != nullptr);
83*103e46e4SHarish Mahendrakar 
84*103e46e4SHarish Mahendrakar   *num_bytes_read = 0;
85*103e46e4SHarish Mahendrakar 
86*103e46e4SHarish Mahendrakar   Status status;
87*103e46e4SHarish Mahendrakar   std::uint64_t local_num_bytes_read;
88*103e46e4SHarish Mahendrakar 
89*103e46e4SHarish Mahendrakar   while (true) {
90*103e46e4SHarish Mahendrakar     switch (state_) {
91*103e46e4SHarish Mahendrakar       case State::kReadingHeader: {
92*103e46e4SHarish Mahendrakar         status = header_parser_.Feed(callback, reader, &local_num_bytes_read);
93*103e46e4SHarish Mahendrakar         *num_bytes_read += local_num_bytes_read;
94*103e46e4SHarish Mahendrakar         header_bytes_read_ += local_num_bytes_read;
95*103e46e4SHarish Mahendrakar         if (!status.completed_ok()) {
96*103e46e4SHarish Mahendrakar           return status;
97*103e46e4SHarish Mahendrakar         }
98*103e46e4SHarish Mahendrakar         value_.track_number = header_parser_.value().track_number;
99*103e46e4SHarish Mahendrakar         value_.timecode = header_parser_.value().timecode;
100*103e46e4SHarish Mahendrakar 
101*103e46e4SHarish Mahendrakar         std::uint8_t flags = header_parser_.value().flags;
102*103e46e4SHarish Mahendrakar         value_.is_visible = (0x08 & flags) == 0;
103*103e46e4SHarish Mahendrakar         value_.lacing = static_cast<Lacing>(flags & 0x06);
104*103e46e4SHarish Mahendrakar         ParseBasicBlockFlags(flags, &value_);
105*103e46e4SHarish Mahendrakar 
106*103e46e4SHarish Mahendrakar         if (value_.lacing == Lacing::kNone) {
107*103e46e4SHarish Mahendrakar           value_.num_frames = 1;
108*103e46e4SHarish Mahendrakar           state_ = State::kGettingAction;
109*103e46e4SHarish Mahendrakar         } else {
110*103e46e4SHarish Mahendrakar           state_ = State::kReadingLaceCount;
111*103e46e4SHarish Mahendrakar         }
112*103e46e4SHarish Mahendrakar         continue;
113*103e46e4SHarish Mahendrakar       }
114*103e46e4SHarish Mahendrakar 
115*103e46e4SHarish Mahendrakar       case State::kReadingLaceCount: {
116*103e46e4SHarish Mahendrakar         assert(lace_sizes_.empty());
117*103e46e4SHarish Mahendrakar         std::uint8_t lace_count;
118*103e46e4SHarish Mahendrakar         status = ReadByte(reader, &lace_count);
119*103e46e4SHarish Mahendrakar         if (!status.completed_ok()) {
120*103e46e4SHarish Mahendrakar           return status;
121*103e46e4SHarish Mahendrakar         }
122*103e46e4SHarish Mahendrakar         ++*num_bytes_read;
123*103e46e4SHarish Mahendrakar         ++header_bytes_read_;
124*103e46e4SHarish Mahendrakar         // Lace count is stored as (count - 1).
125*103e46e4SHarish Mahendrakar         value_.num_frames = lace_count + 1;
126*103e46e4SHarish Mahendrakar         state_ = State::kGettingAction;
127*103e46e4SHarish Mahendrakar         continue;
128*103e46e4SHarish Mahendrakar       }
129*103e46e4SHarish Mahendrakar 
130*103e46e4SHarish Mahendrakar       case State::kGettingAction: {
131*103e46e4SHarish Mahendrakar         Action action = Action::kRead;
132*103e46e4SHarish Mahendrakar         status = BasicBlockBegin(frame_metadata_.parent_element, value_,
133*103e46e4SHarish Mahendrakar                                  callback, &action);
134*103e46e4SHarish Mahendrakar         if (!status.completed_ok()) {
135*103e46e4SHarish Mahendrakar           return status;
136*103e46e4SHarish Mahendrakar         }
137*103e46e4SHarish Mahendrakar         if (action == Action::kSkip) {
138*103e46e4SHarish Mahendrakar           state_ = State::kSkipping;
139*103e46e4SHarish Mahendrakar         } else if (value_.lacing == Lacing::kNone || value_.num_frames == 1) {
140*103e46e4SHarish Mahendrakar           state_ = State::kValidatingSize;
141*103e46e4SHarish Mahendrakar         } else if (value_.lacing == Lacing::kXiph) {
142*103e46e4SHarish Mahendrakar           state_ = State::kReadingXiphLaceSizes;
143*103e46e4SHarish Mahendrakar         } else if (value_.lacing == Lacing::kEbml) {
144*103e46e4SHarish Mahendrakar           state_ = State::kReadingFirstEbmlLaceSize;
145*103e46e4SHarish Mahendrakar         } else {
146*103e46e4SHarish Mahendrakar           state_ = State::kCalculatingFixedLaceSizes;
147*103e46e4SHarish Mahendrakar         }
148*103e46e4SHarish Mahendrakar         continue;
149*103e46e4SHarish Mahendrakar       }
150*103e46e4SHarish Mahendrakar 
151*103e46e4SHarish Mahendrakar       case State::kReadingXiphLaceSizes:
152*103e46e4SHarish Mahendrakar         assert(value_.num_frames > 0);
153*103e46e4SHarish Mahendrakar         while (static_cast<int>(lace_sizes_.size()) < value_.num_frames - 1) {
154*103e46e4SHarish Mahendrakar           std::uint8_t byte;
155*103e46e4SHarish Mahendrakar           do {
156*103e46e4SHarish Mahendrakar             status = ReadByte(reader, &byte);
157*103e46e4SHarish Mahendrakar             if (!status.completed_ok()) {
158*103e46e4SHarish Mahendrakar               return status;
159*103e46e4SHarish Mahendrakar             }
160*103e46e4SHarish Mahendrakar             ++*num_bytes_read;
161*103e46e4SHarish Mahendrakar             ++header_bytes_read_;
162*103e46e4SHarish Mahendrakar             xiph_lace_size_ += byte;
163*103e46e4SHarish Mahendrakar           } while (byte == 255);
164*103e46e4SHarish Mahendrakar 
165*103e46e4SHarish Mahendrakar           lace_sizes_.push_back(xiph_lace_size_);
166*103e46e4SHarish Mahendrakar           xiph_lace_size_ = 0;
167*103e46e4SHarish Mahendrakar         }
168*103e46e4SHarish Mahendrakar         state_ = State::kValidatingSize;
169*103e46e4SHarish Mahendrakar         continue;
170*103e46e4SHarish Mahendrakar 
171*103e46e4SHarish Mahendrakar       case State::kReadingFirstEbmlLaceSize:
172*103e46e4SHarish Mahendrakar         assert(value_.num_frames > 0);
173*103e46e4SHarish Mahendrakar         assert(lace_sizes_.empty());
174*103e46e4SHarish Mahendrakar         status = uint_parser_.Feed(callback, reader, &local_num_bytes_read);
175*103e46e4SHarish Mahendrakar         *num_bytes_read += local_num_bytes_read;
176*103e46e4SHarish Mahendrakar         header_bytes_read_ += local_num_bytes_read;
177*103e46e4SHarish Mahendrakar         if (!status.completed_ok()) {
178*103e46e4SHarish Mahendrakar           return status;
179*103e46e4SHarish Mahendrakar         }
180*103e46e4SHarish Mahendrakar         lace_sizes_.push_back(uint_parser_.value());
181*103e46e4SHarish Mahendrakar         uint_parser_ = {};
182*103e46e4SHarish Mahendrakar         state_ = State::kReadingEbmlLaceSizes;
183*103e46e4SHarish Mahendrakar         continue;
184*103e46e4SHarish Mahendrakar 
185*103e46e4SHarish Mahendrakar       case State::kReadingEbmlLaceSizes:
186*103e46e4SHarish Mahendrakar         assert(value_.num_frames > 0);
187*103e46e4SHarish Mahendrakar         assert(!lace_sizes_.empty());
188*103e46e4SHarish Mahendrakar         while (static_cast<int>(lace_sizes_.size()) < value_.num_frames - 1) {
189*103e46e4SHarish Mahendrakar           status = uint_parser_.Feed(callback, reader, &local_num_bytes_read);
190*103e46e4SHarish Mahendrakar           *num_bytes_read += local_num_bytes_read;
191*103e46e4SHarish Mahendrakar           header_bytes_read_ += local_num_bytes_read;
192*103e46e4SHarish Mahendrakar           if (!status.completed_ok()) {
193*103e46e4SHarish Mahendrakar             return status;
194*103e46e4SHarish Mahendrakar           }
195*103e46e4SHarish Mahendrakar           constexpr std::uint64_t one = 1;  // Prettier than a static_cast.
196*103e46e4SHarish Mahendrakar           std::uint64_t offset =
197*103e46e4SHarish Mahendrakar               (one << (uint_parser_.encoded_length() * 7 - 1)) - 1;
198*103e46e4SHarish Mahendrakar           lace_sizes_.push_back(lace_sizes_.back() + uint_parser_.value() -
199*103e46e4SHarish Mahendrakar                                 offset);
200*103e46e4SHarish Mahendrakar           uint_parser_ = {};
201*103e46e4SHarish Mahendrakar         }
202*103e46e4SHarish Mahendrakar         state_ = State::kValidatingSize;
203*103e46e4SHarish Mahendrakar         continue;
204*103e46e4SHarish Mahendrakar 
205*103e46e4SHarish Mahendrakar       case State::kCalculatingFixedLaceSizes: {
206*103e46e4SHarish Mahendrakar         assert(value_.num_frames > 0);
207*103e46e4SHarish Mahendrakar         assert(lace_sizes_.empty());
208*103e46e4SHarish Mahendrakar         if (header_bytes_read_ >= frame_metadata_.parent_element.size) {
209*103e46e4SHarish Mahendrakar           return Status(Status::kInvalidElementValue);
210*103e46e4SHarish Mahendrakar         }
211*103e46e4SHarish Mahendrakar         std::uint64_t laced_data_size =
212*103e46e4SHarish Mahendrakar             frame_metadata_.parent_element.size - header_bytes_read_;
213*103e46e4SHarish Mahendrakar         std::uint64_t frame_size = laced_data_size / value_.num_frames;
214*103e46e4SHarish Mahendrakar         if (laced_data_size % value_.num_frames != 0) {
215*103e46e4SHarish Mahendrakar           return Status(Status::kInvalidElementValue);
216*103e46e4SHarish Mahendrakar         }
217*103e46e4SHarish Mahendrakar         lace_sizes_.resize(value_.num_frames, frame_size);
218*103e46e4SHarish Mahendrakar         frame_metadata_.position =
219*103e46e4SHarish Mahendrakar             frame_metadata_.parent_element.position + header_bytes_read_;
220*103e46e4SHarish Mahendrakar         frame_metadata_.size = frame_size;
221*103e46e4SHarish Mahendrakar         state_ = State::kReadingFrames;
222*103e46e4SHarish Mahendrakar         continue;
223*103e46e4SHarish Mahendrakar       }
224*103e46e4SHarish Mahendrakar 
225*103e46e4SHarish Mahendrakar       case State::kValidatingSize: {
226*103e46e4SHarish Mahendrakar         std::uint64_t sum = std::accumulate(
227*103e46e4SHarish Mahendrakar             lace_sizes_.begin(), lace_sizes_.end(), header_bytes_read_);
228*103e46e4SHarish Mahendrakar         if (sum >= frame_metadata_.parent_element.size) {
229*103e46e4SHarish Mahendrakar           return Status(Status::kInvalidElementValue);
230*103e46e4SHarish Mahendrakar         }
231*103e46e4SHarish Mahendrakar         lace_sizes_.push_back(frame_metadata_.parent_element.size - sum);
232*103e46e4SHarish Mahendrakar         frame_metadata_.position = frame_metadata_.parent_element.position +
233*103e46e4SHarish Mahendrakar                                    frame_metadata_.parent_element.header_size +
234*103e46e4SHarish Mahendrakar                                    header_bytes_read_;
235*103e46e4SHarish Mahendrakar         frame_metadata_.size = lace_sizes_[0];
236*103e46e4SHarish Mahendrakar         state_ = State::kReadingFrames;
237*103e46e4SHarish Mahendrakar         continue;
238*103e46e4SHarish Mahendrakar       }
239*103e46e4SHarish Mahendrakar 
240*103e46e4SHarish Mahendrakar       case State::kSkipping:
241*103e46e4SHarish Mahendrakar         do {
242*103e46e4SHarish Mahendrakar           // Skip the remaining part of the header and all of the frames.
243*103e46e4SHarish Mahendrakar           status = reader->Skip(
244*103e46e4SHarish Mahendrakar               frame_metadata_.parent_element.size - header_bytes_read_,
245*103e46e4SHarish Mahendrakar               &local_num_bytes_read);
246*103e46e4SHarish Mahendrakar           *num_bytes_read += local_num_bytes_read;
247*103e46e4SHarish Mahendrakar           header_bytes_read_ += local_num_bytes_read;
248*103e46e4SHarish Mahendrakar         } while (status.code == Status::kOkPartial);
249*103e46e4SHarish Mahendrakar         return status;
250*103e46e4SHarish Mahendrakar 
251*103e46e4SHarish Mahendrakar       case State::kReadingFrames:
252*103e46e4SHarish Mahendrakar         assert(value_.num_frames > 0);
253*103e46e4SHarish Mahendrakar         assert(static_cast<int>(lace_sizes_.size()) == value_.num_frames);
254*103e46e4SHarish Mahendrakar         for (; current_lace_ < lace_sizes_.size(); ++current_lace_) {
255*103e46e4SHarish Mahendrakar           const std::uint64_t original = lace_sizes_[current_lace_];
256*103e46e4SHarish Mahendrakar           status = callback->OnFrame(frame_metadata_, reader,
257*103e46e4SHarish Mahendrakar                                      &lace_sizes_[current_lace_]);
258*103e46e4SHarish Mahendrakar           *num_bytes_read += original - lace_sizes_[current_lace_];
259*103e46e4SHarish Mahendrakar           if (!status.completed_ok()) {
260*103e46e4SHarish Mahendrakar             return status;
261*103e46e4SHarish Mahendrakar           }
262*103e46e4SHarish Mahendrakar           assert(lace_sizes_[current_lace_] == 0);
263*103e46e4SHarish Mahendrakar           if (current_lace_ + 1 < lace_sizes_.size()) {
264*103e46e4SHarish Mahendrakar             frame_metadata_.position += frame_metadata_.size;
265*103e46e4SHarish Mahendrakar             frame_metadata_.size = lace_sizes_[current_lace_ + 1];
266*103e46e4SHarish Mahendrakar           }
267*103e46e4SHarish Mahendrakar         }
268*103e46e4SHarish Mahendrakar         state_ = State::kDone;
269*103e46e4SHarish Mahendrakar         continue;
270*103e46e4SHarish Mahendrakar 
271*103e46e4SHarish Mahendrakar       case State::kDone:
272*103e46e4SHarish Mahendrakar         return BasicBlockEnd(frame_metadata_.parent_element, value_, callback);
273*103e46e4SHarish Mahendrakar     }
274*103e46e4SHarish Mahendrakar   }
275*103e46e4SHarish Mahendrakar }
276*103e46e4SHarish Mahendrakar 
277*103e46e4SHarish Mahendrakar template <typename T>
WasSkipped() const278*103e46e4SHarish Mahendrakar bool BasicBlockParser<T>::WasSkipped() const {
279*103e46e4SHarish Mahendrakar   return state_ == State::kSkipping;
280*103e46e4SHarish Mahendrakar }
281*103e46e4SHarish Mahendrakar 
282*103e46e4SHarish Mahendrakar template class BasicBlockParser<Block>;
283*103e46e4SHarish Mahendrakar template class BasicBlockParser<SimpleBlock>;
284*103e46e4SHarish Mahendrakar 
285*103e46e4SHarish Mahendrakar }  // namespace webm
286