OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 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 "media/remoting/rpc/proto_utils.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/big_endian.h" | |
10 #include "base/logging.h" | |
11 #include "base/time/time.h" | |
12 #include "base/values.h" | |
13 #include "media/base/encryption_scheme.h" | |
14 #include "media/remoting/rpc/proto_enum_utils.h" | |
15 | |
16 namespace media { | |
17 namespace remoting { | |
18 | |
19 const int kInvalidHandle = -1; | |
20 const int kReceiverHandle = 0; | |
21 | |
22 namespace { | |
23 | |
24 const int kPayloadVersionFieldSize = 1; | |
miu
2016/09/16 18:14:13
For these three constants:
1. s/const/constexpr/
erickung1
2016/09/19 17:04:35
Done.
| |
25 const int kProtoBufferHeaderSize = 2; | |
26 const int kDataBufferHeaderSize = 4; | |
27 | |
28 std::unique_ptr<::media::DecryptConfig> ConvertProtoToDecryptConfig( | |
29 const pb::DecryptConfig& config_message) { | |
30 std::vector<::media::SubsampleEntry> entries; | |
miu
2016/09/16 18:14:13
nit: Please move declaration down to where this is
erickung1
2016/09/19 17:04:34
Done.
| |
31 | |
32 if (!config_message.has_key_id()) | |
33 return nullptr; | |
34 if (!config_message.has_iv()) | |
35 return nullptr; | |
36 | |
37 for (int i = 0; i < config_message.sub_samples_size(); ++i) { | |
38 entries.push_back( | |
39 ::media::SubsampleEntry(config_message.sub_samples(i).clear_bytes(), | |
40 config_message.sub_samples(i).cypher_bytes())); | |
41 } | |
42 | |
43 std::unique_ptr<::media::DecryptConfig> decrypt_config( | |
44 new ::media::DecryptConfig(config_message.key_id(), config_message.iv(), | |
45 entries)); | |
46 return decrypt_config; | |
47 } | |
48 | |
49 scoped_refptr<::media::DecoderBuffer> ConvertProtoToDecoderBuffer( | |
50 const pb::DecoderBuffer& buffer_message, | |
51 scoped_refptr<::media::DecoderBuffer> buffer) { | |
52 if (buffer_message.is_eos()) { | |
53 VLOG(1) << "EOS data"; | |
54 return ::media::DecoderBuffer::CreateEOSBuffer(); | |
55 } | |
56 | |
57 if (buffer_message.has_timestamp_usec()) { | |
58 buffer->set_timestamp( | |
59 base::TimeDelta::FromMicroseconds(buffer_message.timestamp_usec())); | |
60 } | |
61 | |
62 if (buffer_message.has_duration_usec()) { | |
63 buffer->set_duration( | |
64 base::TimeDelta::FromMicroseconds(buffer_message.duration_usec())); | |
65 } | |
66 VLOG(2) << "timestamp:" << buffer_message.timestamp_usec() | |
67 << " duration:" << buffer_message.duration_usec(); | |
68 | |
69 if (buffer_message.has_is_key_frame()) | |
70 buffer->set_is_key_frame(buffer_message.is_key_frame()); | |
71 | |
72 if (buffer_message.has_decrypt_config()) { | |
73 buffer->set_decrypt_config( | |
74 ConvertProtoToDecryptConfig(buffer_message.decrypt_config())); | |
75 } | |
76 | |
77 bool has_discard = false; | |
78 base::TimeDelta front_discard; | |
79 if (buffer_message.has_front_discard_usec()) { | |
80 has_discard = true; | |
81 front_discard = | |
82 base::TimeDelta::FromMicroseconds(buffer_message.front_discard_usec()); | |
83 } | |
84 base::TimeDelta back_discard; | |
85 if (buffer_message.has_back_discard_usec()) { | |
86 has_discard = true; | |
87 back_discard = | |
88 base::TimeDelta::FromMicroseconds(buffer_message.back_discard_usec()); | |
89 } | |
90 | |
91 if (has_discard) { | |
92 buffer->set_discard_padding( | |
93 ::media::DecoderBuffer::DiscardPadding(front_discard, back_discard)); | |
94 } | |
95 | |
96 if (buffer_message.has_splice_timestamp_usec()) { | |
97 buffer->set_splice_timestamp(base::TimeDelta::FromMicroseconds( | |
98 buffer_message.splice_timestamp_usec())); | |
99 } | |
100 | |
101 if (buffer_message.has_side_data()) { | |
102 buffer->CopySideDataFrom( | |
103 reinterpret_cast<const uint8_t*>(buffer_message.side_data().data()), | |
104 buffer_message.side_data().size()); | |
105 } | |
106 | |
107 return buffer; | |
108 } | |
109 | |
110 void ConvertDecryptConfigToProto(const ::media::DecryptConfig& decrypt_config, | |
111 pb::DecryptConfig* config_message) { | |
112 DCHECK(config_message); | |
113 | |
114 config_message->set_key_id(decrypt_config.key_id()); | |
115 config_message->set_iv(decrypt_config.iv()); | |
116 | |
117 for (const auto& entry : decrypt_config.subsamples()) { | |
118 pb::DecryptConfig::SubSample* sub_sample = | |
119 config_message->add_sub_samples(); | |
120 sub_sample->set_clear_bytes(entry.clear_bytes); | |
121 sub_sample->set_cypher_bytes(entry.cypher_bytes); | |
122 } | |
123 } | |
124 | |
125 void ConvertDecoderBufferToProto( | |
126 const scoped_refptr<::media::DecoderBuffer>& decoder_buffer, | |
127 pb::DecoderBuffer* buffer_message) { | |
128 if (decoder_buffer->end_of_stream()) { | |
129 buffer_message->set_is_eos(true); | |
130 return; | |
131 } | |
132 | |
133 VLOG(2) << "timestamp:" << decoder_buffer->timestamp().InMicroseconds() | |
134 << " duration:" << decoder_buffer->duration().InMicroseconds(); | |
135 buffer_message->set_timestamp_usec( | |
136 decoder_buffer->timestamp().InMicroseconds()); | |
137 buffer_message->set_duration_usec( | |
138 decoder_buffer->duration().InMicroseconds()); | |
139 buffer_message->set_is_key_frame(decoder_buffer->is_key_frame()); | |
140 | |
141 if (decoder_buffer->decrypt_config()) { | |
142 ConvertDecryptConfigToProto(*decoder_buffer->decrypt_config(), | |
143 buffer_message->mutable_decrypt_config()); | |
144 } | |
145 | |
146 buffer_message->set_front_discard_usec( | |
147 decoder_buffer->discard_padding().first.InMicroseconds()); | |
148 buffer_message->set_back_discard_usec( | |
149 decoder_buffer->discard_padding().second.InMicroseconds()); | |
150 buffer_message->set_splice_timestamp_usec( | |
151 decoder_buffer->splice_timestamp().InMicroseconds()); | |
152 | |
153 if (decoder_buffer->side_data_size()) { | |
154 buffer_message->set_side_data(decoder_buffer->side_data(), | |
155 decoder_buffer->side_data_size()); | |
156 } | |
157 } | |
158 | |
159 } // namespace | |
160 | |
161 scoped_refptr<::media::DecoderBuffer> ByteArrayToDecoderBuffer( | |
162 const uint8_t* data, | |
163 uint32_t size) { | |
164 base::BigEndianReader reader(reinterpret_cast<const char*>(data), size); | |
165 uint8_t payload_version = 0; | |
166 uint16_t proto_size = 0; | |
167 pb::DecoderBuffer segment; | |
168 uint32_t buffer_size = 0; | |
169 if (reader.ReadU8(&payload_version) && payload_version == 0 && | |
170 reader.ReadU16(&proto_size) && | |
171 static_cast<int>(proto_size) < reader.remaining() && | |
172 segment.ParseFromArray(reader.ptr(), proto_size) && | |
173 reader.Skip(proto_size) && reader.ReadU32(&buffer_size) && | |
174 static_cast<int64_t>(buffer_size) <= reader.remaining()) { | |
175 // Deserialize proto buffer. It passes the pre allocated DecoderBuffer into | |
176 // the function because the proto buffer may overwrite DecoderBuffer since | |
177 // it may be EOS buffer. | |
178 scoped_refptr<media::DecoderBuffer> decoder_buffer = | |
179 ConvertProtoToDecoderBuffer( | |
180 segment, | |
181 DecoderBuffer::CopyFrom( | |
182 reinterpret_cast<const uint8_t*>(reader.ptr()), buffer_size)); | |
183 return decoder_buffer; | |
184 } | |
185 | |
186 LOG(ERROR) << "Not able to convert byte array to ::media::DecoderBuffer"; | |
187 return nullptr; | |
188 } | |
189 | |
190 std::vector<uint8_t> DecoderBufferToByteArray( | |
191 const scoped_refptr<::media::DecoderBuffer>& decoder_buffer) { | |
192 pb::DecoderBuffer decoder_buffer_message; | |
193 ConvertDecoderBufferToProto(decoder_buffer, &decoder_buffer_message); | |
194 | |
195 size_t decoder_buffer_size = | |
196 decoder_buffer->end_of_stream() ? 0 : decoder_buffer->data_size(); | |
197 size_t size = kPayloadVersionFieldSize + kProtoBufferHeaderSize + | |
198 decoder_buffer_message.ByteSize() + kDataBufferHeaderSize + | |
199 decoder_buffer_size; | |
200 std::vector<uint8_t> buffer(size); | |
201 base::BigEndianWriter writer(reinterpret_cast<char*>(buffer.data()), | |
202 buffer.size()); | |
203 if (writer.WriteU8(0) && | |
204 writer.WriteU16( | |
205 static_cast<uint16_t>(decoder_buffer_message.GetCachedSize())) && | |
206 decoder_buffer_message.SerializeToArray( | |
207 writer.ptr(), decoder_buffer_message.GetCachedSize()) && | |
208 writer.Skip(decoder_buffer_message.GetCachedSize()) && | |
209 writer.WriteU32(decoder_buffer_size)) { | |
210 if (decoder_buffer_size) { | |
211 // DecoderBuffer frame data. | |
212 writer.WriteBytes(reinterpret_cast<const void*>(decoder_buffer->data()), | |
213 decoder_buffer->data_size()); | |
214 } | |
215 return buffer; | |
216 } | |
217 | |
218 // Reset buffer since serialization of the data failed. | |
219 LOG(ERROR) << "Not able to convert ::media::DecoderBuffer to byte array"; | |
220 buffer.clear(); | |
221 return buffer; | |
222 } | |
223 | |
224 void ConvertEncryptionSchemeToProto( | |
225 const ::media::EncryptionScheme& encryption_scheme, | |
226 pb::EncryptionScheme* message) { | |
227 DCHECK(message); | |
228 message->set_mode( | |
229 ToProtoEncryptionSchemeCipherMode(encryption_scheme.mode()).value()); | |
230 message->set_encrypt_blocks(encryption_scheme.pattern().encrypt_blocks()); | |
231 message->set_skip_blocks(encryption_scheme.pattern().skip_blocks()); | |
232 } | |
233 | |
234 ::media::EncryptionScheme ConvertProtoToEncryptionScheme( | |
235 const pb::EncryptionScheme& message) { | |
236 return ::media::EncryptionScheme( | |
237 ToMediaEncryptionSchemeCipherMode(message.mode()).value(), | |
238 ::media::EncryptionScheme::Pattern(message.encrypt_blocks(), | |
239 message.skip_blocks())); | |
240 } | |
241 | |
242 void ConvertAudioDecoderConfigToProto( | |
243 const ::media::AudioDecoderConfig& audio_config, | |
244 pb::AudioDecoderConfig* audio_message) { | |
245 DCHECK(audio_config.IsValidConfig()); | |
246 DCHECK(audio_message); | |
247 | |
248 audio_message->set_codec( | |
249 ToProtoAudioDecoderConfigCodec(audio_config.codec()).value()); | |
250 audio_message->set_sample_format( | |
251 ToProtoAudioDecoderConfigSampleFormat(audio_config.sample_format()) | |
252 .value()); | |
253 audio_message->set_channel_layout( | |
254 ToProtoAudioDecoderConfigChannelLayout(audio_config.channel_layout()) | |
255 .value()); | |
256 audio_message->set_samples_per_second(audio_config.samples_per_second()); | |
257 audio_message->set_seek_preroll_usec( | |
258 audio_config.seek_preroll().InMicroseconds()); | |
259 audio_message->set_codec_delay(audio_config.codec_delay()); | |
260 | |
261 if (!audio_config.extra_data().empty()) { | |
262 audio_message->set_extra_data(audio_config.extra_data().data(), | |
263 audio_config.extra_data().size()); | |
264 } | |
265 | |
266 if (audio_config.is_encrypted()) { | |
267 pb::EncryptionScheme* encryption_scheme_message = | |
268 audio_message->mutable_encryption_scheme(); | |
269 ConvertEncryptionSchemeToProto(audio_config.encryption_scheme(), | |
270 encryption_scheme_message); | |
271 } | |
272 } | |
273 | |
274 bool ConvertProtoToAudioDecoderConfig( | |
275 const pb::AudioDecoderConfig& audio_message, | |
276 ::media::AudioDecoderConfig* audio_config) { | |
277 DCHECK(audio_config); | |
278 audio_config->Initialize( | |
279 ToMediaAudioCodec(audio_message.codec()).value(), | |
280 ToMediaSampleFormat(audio_message.sample_format()).value(), | |
281 ToMediaChannelLayout(audio_message.channel_layout()).value(), | |
282 audio_message.samples_per_second(), | |
283 std::vector<uint8_t>(audio_message.extra_data().begin(), | |
284 audio_message.extra_data().end()), | |
285 ConvertProtoToEncryptionScheme(audio_message.encryption_scheme()), | |
286 base::TimeDelta::FromMicroseconds(audio_message.seek_preroll_usec()), | |
287 audio_message.codec_delay()); | |
288 return audio_config->IsValidConfig(); | |
289 } | |
290 | |
291 void ConvertVideoDecoderConfigToProto( | |
292 const ::media::VideoDecoderConfig& video_config, | |
293 pb::VideoDecoderConfig* video_message) { | |
294 DCHECK(video_config.IsValidConfig()); | |
295 DCHECK(video_message); | |
296 | |
297 video_message->set_codec( | |
298 ToProtoVideoDecoderConfigCodec(video_config.codec()).value()); | |
299 video_message->set_profile( | |
300 ToProtoVideoDecoderConfigProfile(video_config.profile()).value()); | |
301 video_message->set_format( | |
302 ToProtoVideoDecoderConfigFormat(video_config.format()).value()); | |
303 video_message->set_color_space( | |
304 ToProtoVideoDecoderConfigColorSpace(video_config.color_space()).value()); | |
305 | |
306 pb::Size* coded_size_message = video_message->mutable_coded_size(); | |
307 coded_size_message->set_width(video_config.coded_size().width()); | |
308 coded_size_message->set_height(video_config.coded_size().height()); | |
309 | |
310 pb::Rect* visible_rect_message = video_message->mutable_visible_rect(); | |
311 visible_rect_message->set_x(video_config.visible_rect().x()); | |
312 visible_rect_message->set_y(video_config.visible_rect().y()); | |
313 visible_rect_message->set_width(video_config.visible_rect().width()); | |
314 visible_rect_message->set_height(video_config.visible_rect().height()); | |
315 | |
316 pb::Size* natural_size_message = video_message->mutable_natural_size(); | |
317 natural_size_message->set_width(video_config.natural_size().width()); | |
318 natural_size_message->set_height(video_config.natural_size().height()); | |
319 | |
320 if (!video_config.extra_data().empty()) { | |
321 video_message->set_extra_data(video_config.extra_data().data(), | |
322 video_config.extra_data().size()); | |
323 } | |
324 | |
325 if (video_config.is_encrypted()) { | |
326 pb::EncryptionScheme* encryption_scheme_message = | |
327 video_message->mutable_encryption_scheme(); | |
328 ConvertEncryptionSchemeToProto(video_config.encryption_scheme(), | |
329 encryption_scheme_message); | |
330 } | |
331 } | |
332 | |
333 bool ConvertProtoToVideoDecoderConfig( | |
334 const pb::VideoDecoderConfig& video_message, | |
335 ::media::VideoDecoderConfig* video_config) { | |
336 DCHECK(video_config); | |
337 ::media::EncryptionScheme encryption_scheme; | |
338 video_config->Initialize( | |
339 ToMediaVideoCodec(video_message.codec()).value(), | |
340 ToMediaVideoCodecProfile(video_message.profile()).value(), | |
341 ToMediaVideoPixelFormat(video_message.format()).value(), | |
342 ToMediaColorSpace(video_message.color_space()).value(), | |
343 gfx::Size(video_message.coded_size().width(), | |
344 video_message.coded_size().height()), | |
345 gfx::Rect(video_message.visible_rect().x(), | |
346 video_message.visible_rect().y(), | |
347 video_message.visible_rect().width(), | |
348 video_message.visible_rect().height()), | |
349 gfx::Size(video_message.natural_size().width(), | |
350 video_message.natural_size().height()), | |
351 std::vector<uint8_t>(video_message.extra_data().begin(), | |
352 video_message.extra_data().end()), | |
353 ConvertProtoToEncryptionScheme(video_message.encryption_scheme())); | |
354 return video_config->IsValidConfig(); | |
355 } | |
356 | |
357 void ConvertCdmKeyInfoToProto( | |
358 const ::media::CdmKeysInfo& keys_information, | |
359 pb::CdmClientOnSessionKeysChange* key_change_message) { | |
360 for (const auto& info : keys_information) { | |
361 pb::CdmKeyInformation* key = key_change_message->add_key_information(); | |
362 key->set_key_id(info->key_id.data(), info->key_id.size()); | |
363 key->set_status(ToProtoCdmKeyInformation(info->status).value()); | |
364 key->set_system_code(info->system_code); | |
365 } | |
366 } | |
367 | |
368 void ConvertProtoToCdmKeyInfo( | |
369 const pb::CdmClientOnSessionKeysChange keychange_message, | |
370 CdmKeysInfo* key_information) { | |
371 DCHECK(key_information); | |
372 for (int i = 0; i < keychange_message.key_information_size(); ++i) { | |
miu
2016/09/16 18:14:13
nit: Please add: key_information->reserve(keychang
erickung1
2016/09/19 17:04:35
Done.
| |
373 const pb::CdmKeyInformation key_info_msg = | |
374 keychange_message.key_information(i); | |
375 | |
376 std::unique_ptr<::media::CdmKeyInformation> key( | |
377 new ::media::CdmKeyInformation( | |
378 key_info_msg.key_id(), | |
379 ToMediaCdmKeyInformationKeyStatus(key_info_msg.status()).value(), | |
380 key_info_msg.system_code())); | |
381 key_information->push_back(std::move(key)); | |
382 } | |
383 } | |
384 | |
385 void ConvertCdmPromiseToProto(const CdmPromiseResult& result, | |
386 pb::CdmPromise* promise_message) { | |
387 promise_message->set_success(result.success()); | |
388 if (!result.success()) { | |
389 promise_message->set_exception( | |
390 ToProtoMediaKeysException(result.exception()).value()); | |
391 promise_message->set_system_code(result.system_code()); | |
392 promise_message->set_error_message(result.error_message()); | |
393 } | |
394 } | |
395 | |
396 void ConvertCdmPromiseWithSessionIdToProto(const CdmPromiseResult& result, | |
397 const std::string& session_id, | |
398 pb::CdmPromise* promise_message) { | |
399 ConvertCdmPromiseToProto(result, promise_message); | |
400 if (!session_id.empty()) | |
miu
2016/09/16 18:14:13
Is an empty |session_id| valid? If that would indi
erickung1
2016/09/19 17:04:35
Done. I decided to remove the if condition, since
| |
401 promise_message->set_session_id(session_id); | |
402 } | |
403 | |
404 void ConvertCdmPromiseWithCdmIdToProto(const CdmPromiseResult& result, | |
405 int cdm_id, | |
406 pb::CdmPromise* promise_message) { | |
407 ConvertCdmPromiseToProto(result, promise_message); | |
408 promise_message->set_cdm_id(cdm_id); | |
409 } | |
410 | |
411 bool ConvertProtoToCdmPromise(const pb::CdmPromise& promise_message, | |
412 CdmPromiseResult* result) { | |
413 if (!promise_message.has_success()) | |
414 return false; | |
415 | |
416 bool success = promise_message.success(); | |
417 if (success) { | |
418 *result = CdmPromiseResult::SuccessResult(); | |
419 return true; | |
420 } | |
421 | |
422 ::media::MediaKeys::Exception exception = ::media::MediaKeys::UNKNOWN_ERROR; | |
423 uint32_t system_code = 0; | |
424 std::string error_message; | |
425 | |
426 exception = ToMediaMediaKeysException(promise_message.exception()).value(); | |
427 system_code = promise_message.system_code(); | |
428 error_message = promise_message.error_message(); | |
429 *result = CdmPromiseResult(exception, system_code, error_message); | |
430 return true; | |
431 } | |
432 | |
433 bool ConvertProtoToCdmPromiseWithCdmIdSessionId(const pb::RpcMessage& message, | |
434 CdmPromiseResult* result, | |
435 int* cdm_id, | |
436 std::string* session_id) { | |
437 if (!message.has_cdm_promise_rpc()) | |
438 return false; | |
439 | |
440 const auto& promise_message = message.cdm_promise_rpc(); | |
441 if (!ConvertProtoToCdmPromise(promise_message, result)) | |
442 return false; | |
443 | |
444 if (cdm_id) | |
445 *cdm_id = promise_message.cdm_id(); | |
446 if (session_id) | |
447 *session_id = promise_message.session_id(); | |
448 | |
449 return true; | |
450 } | |
451 | |
452 //============================================================================== | |
453 CdmPromiseResult::CdmPromiseResult() | |
454 : CdmPromiseResult(::media::MediaKeys::UNKNOWN_ERROR, 0, "") {} | |
455 | |
456 CdmPromiseResult::CdmPromiseResult(::media::MediaKeys::Exception exception, | |
457 uint32_t system_code, | |
458 std::string error_message) | |
459 : success_(false), | |
460 exception_(exception), | |
461 system_code_(system_code), | |
462 error_message_(error_message) {} | |
463 | |
464 CdmPromiseResult::CdmPromiseResult(const CdmPromiseResult& other) = default; | |
465 | |
466 CdmPromiseResult::~CdmPromiseResult() = default; | |
467 | |
468 CdmPromiseResult CdmPromiseResult::SuccessResult() { | |
469 CdmPromiseResult result(static_cast<::media::MediaKeys::Exception>(0), 0, ""); | |
470 result.success_ = true; | |
471 return result; | |
472 } | |
473 | |
474 } // namespace remoting | |
475 } // namespace media | |
OLD | NEW |