Shaka Packager SDK
webm_content_encodings_client.cc
1 // Copyright 2014 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 #include <packager/media/formats/webm/webm_content_encodings_client.h>
6 
7 #include <absl/log/check.h>
8 #include <absl/log/log.h>
9 
10 #include <packager/media/formats/webm/webm_constants.h>
11 
12 namespace shaka {
13 namespace media {
14 
15 WebMContentEncodingsClient::WebMContentEncodingsClient()
16  : content_encryption_encountered_(false), content_encodings_ready_(false) {}
17 
18 WebMContentEncodingsClient::~WebMContentEncodingsClient() {}
19 
20 const ContentEncodings& WebMContentEncodingsClient::content_encodings() const {
21  DCHECK(content_encodings_ready_);
22  return content_encodings_;
23 }
24 
25 WebMParserClient* WebMContentEncodingsClient::OnListStart(int id) {
26  if (id == kWebMIdContentEncodings) {
27  DCHECK(!cur_content_encoding_.get());
28  DCHECK(!content_encryption_encountered_);
29  content_encodings_.clear();
30  content_encodings_ready_ = false;
31  return this;
32  }
33 
34  if (id == kWebMIdContentEncoding) {
35  DCHECK(!cur_content_encoding_.get());
36  DCHECK(!content_encryption_encountered_);
37  cur_content_encoding_.reset(new ContentEncoding());
38  return this;
39  }
40 
41  if (id == kWebMIdContentEncryption) {
42  DCHECK(cur_content_encoding_.get());
43  if (content_encryption_encountered_) {
44  LOG(ERROR) << "Unexpected multiple ContentEncryption.";
45  return NULL;
46  }
47  content_encryption_encountered_ = true;
48  return this;
49  }
50 
51  if (id == kWebMIdContentEncAESSettings) {
52  DCHECK(cur_content_encoding_.get());
53  return this;
54  }
55 
56  // This should not happen if WebMListParser is working properly.
57  DCHECK(false);
58  return NULL;
59 }
60 
61 // Mandatory occurrence restriction is checked in this function. Multiple
62 // occurrence restriction is checked in OnUInt and OnBinary.
63 bool WebMContentEncodingsClient::OnListEnd(int id) {
64  if (id == kWebMIdContentEncodings) {
65  // ContentEncoding element is mandatory. Check this!
66  if (content_encodings_.empty()) {
67  LOG(ERROR) << "Missing ContentEncoding.";
68  return false;
69  }
70  content_encodings_ready_ = true;
71  return true;
72  }
73 
74  if (id == kWebMIdContentEncoding) {
75  DCHECK(cur_content_encoding_.get());
76 
77  //
78  // Specify default values to missing mandatory elements.
79  //
80 
81  if (cur_content_encoding_->order() == ContentEncoding::kOrderInvalid) {
82  // Default value of encoding order is 0, which should only be used on the
83  // first ContentEncoding.
84  if (!content_encodings_.empty()) {
85  LOG(ERROR) << "Missing ContentEncodingOrder.";
86  return false;
87  }
88  cur_content_encoding_->set_order(0);
89  }
90 
91  if (cur_content_encoding_->scope() == ContentEncoding::kScopeInvalid)
92  cur_content_encoding_->set_scope(ContentEncoding::kScopeAllFrameContents);
93 
94  if (cur_content_encoding_->type() == ContentEncoding::kTypeInvalid)
95  cur_content_encoding_->set_type(ContentEncoding::kTypeCompression);
96 
97  // Check for elements valid in spec but not supported for now.
98  if (cur_content_encoding_->type() == ContentEncoding::kTypeCompression) {
99  LOG(ERROR) << "ContentCompression not supported.";
100  return false;
101  }
102 
103  // Enforce mandatory elements without default values.
104  DCHECK_EQ(cur_content_encoding_->type(), ContentEncoding::kTypeEncryption);
105  if (!content_encryption_encountered_) {
106  LOG(ERROR) << "ContentEncodingType is encryption but"
107  << " ContentEncryption is missing.";
108  return false;
109  }
110 
111  content_encodings_.push_back(std::move(cur_content_encoding_));
112  content_encryption_encountered_ = false;
113  return true;
114  }
115 
116  if (id == kWebMIdContentEncryption) {
117  DCHECK(cur_content_encoding_.get());
118  // Specify default value for elements that are not present.
119  if (cur_content_encoding_->encryption_algo() ==
120  ContentEncoding::kEncAlgoInvalid) {
121  cur_content_encoding_->set_encryption_algo(
122  ContentEncoding::kEncAlgoNotEncrypted);
123  }
124  return true;
125  }
126 
127  if (id == kWebMIdContentEncAESSettings) {
128  if (cur_content_encoding_->cipher_mode() ==
129  ContentEncoding::kCipherModeInvalid)
130  cur_content_encoding_->set_cipher_mode(ContentEncoding::kCipherModeCtr);
131  return true;
132  }
133 
134  // This should not happen if WebMListParser is working properly.
135  DCHECK(false);
136  return false;
137 }
138 
139 // Multiple occurrence restriction and range are checked in this function.
140 // Mandatory occurrence restriction is checked in OnListEnd.
141 bool WebMContentEncodingsClient::OnUInt(int id, int64_t val) {
142  DCHECK(cur_content_encoding_.get());
143 
144  if (id == kWebMIdContentEncodingOrder) {
145  if (cur_content_encoding_->order() != ContentEncoding::kOrderInvalid) {
146  LOG(ERROR) << "Unexpected multiple ContentEncodingOrder.";
147  return false;
148  }
149 
150  if (val != static_cast<int64_t>(content_encodings_.size())) {
151  // According to the spec, encoding order starts with 0 and counts upwards.
152  LOG(ERROR) << "Unexpected ContentEncodingOrder.";
153  return false;
154  }
155 
156  cur_content_encoding_->set_order(val);
157  return true;
158  }
159 
160  if (id == kWebMIdContentEncodingScope) {
161  if (cur_content_encoding_->scope() != ContentEncoding::kScopeInvalid) {
162  LOG(ERROR) << "Unexpected multiple ContentEncodingScope.";
163  return false;
164  }
165 
166  if (val == ContentEncoding::kScopeInvalid ||
167  val > ContentEncoding::kScopeMax) {
168  LOG(ERROR) << "Unexpected ContentEncodingScope.";
169  return false;
170  }
171 
172  if (val & ContentEncoding::kScopeNextContentEncodingData) {
173  LOG(ERROR) << "Encoded next ContentEncoding is not "
174  "supported.";
175  return false;
176  }
177 
178  cur_content_encoding_->set_scope(static_cast<ContentEncoding::Scope>(val));
179  return true;
180  }
181 
182  if (id == kWebMIdContentEncodingType) {
183  if (cur_content_encoding_->type() != ContentEncoding::kTypeInvalid) {
184  LOG(ERROR) << "Unexpected multiple ContentEncodingType.";
185  return false;
186  }
187 
188  if (val == ContentEncoding::kTypeCompression) {
189  LOG(ERROR) << "ContentCompression not supported.";
190  return false;
191  }
192 
193  if (val != ContentEncoding::kTypeEncryption) {
194  LOG(ERROR) << "Unexpected ContentEncodingType " << val << ".";
195  return false;
196  }
197 
198  cur_content_encoding_->set_type(static_cast<ContentEncoding::Type>(val));
199  return true;
200  }
201 
202  if (id == kWebMIdContentEncAlgo) {
203  if (cur_content_encoding_->encryption_algo() !=
204  ContentEncoding::kEncAlgoInvalid) {
205  LOG(ERROR) << "Unexpected multiple ContentEncAlgo.";
206  return false;
207  }
208 
209  if (val < ContentEncoding::kEncAlgoNotEncrypted ||
210  val > ContentEncoding::kEncAlgoAes) {
211  LOG(ERROR) << "Unexpected ContentEncAlgo " << val << ".";
212  return false;
213  }
214 
215  cur_content_encoding_->set_encryption_algo(
216  static_cast<ContentEncoding::EncryptionAlgo>(val));
217  return true;
218  }
219 
220  if (id == kWebMIdAESSettingsCipherMode) {
221  if (cur_content_encoding_->cipher_mode() !=
222  ContentEncoding::kCipherModeInvalid) {
223  LOG(ERROR) << "Unexpected multiple AESSettingsCipherMode.";
224  return false;
225  }
226 
227  if (val != ContentEncoding::kCipherModeCtr) {
228  LOG(ERROR) << "Unexpected AESSettingsCipherMode " << val << ".";
229  return false;
230  }
231 
232  cur_content_encoding_->set_cipher_mode(
233  static_cast<ContentEncoding::CipherMode>(val));
234  return true;
235  }
236 
237  // This should not happen if WebMListParser is working properly.
238  DCHECK(false);
239  return false;
240 }
241 
242 // Multiple occurrence restriction is checked in this function. Mandatory
243 // restriction is checked in OnListEnd.
244 bool WebMContentEncodingsClient::OnBinary(int id,
245  const uint8_t* data,
246  int size) {
247  DCHECK(cur_content_encoding_.get());
248  DCHECK(data);
249  DCHECK_GT(size, 0);
250 
251  if (id == kWebMIdContentEncKeyID) {
252  if (!cur_content_encoding_->encryption_key_id().empty()) {
253  LOG(ERROR) << "Unexpected multiple ContentEncKeyID";
254  return false;
255  }
256  cur_content_encoding_->SetEncryptionKeyId(data, size);
257  return true;
258  }
259 
260  // This should not happen if WebMListParser is working properly.
261  DCHECK(false);
262  return false;
263 }
264 
265 } // namespace media
266 } // namespace shaka
All the methods that are virtual are virtual for mocking.
Definition: crypto_flags.cc:66