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