blob: 55e1ab5704e0cc255171e8a07df61c8d3417849e [file] [log] [blame]
erickung1fc58a42016-09-24 03:00:071// 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
miu9f7788e2017-01-25 00:46:095#include "media/remoting/proto_utils.h"
erickung1fc58a42016-09-24 03:00:076
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"
miu9f7788e2017-01-25 00:46:0914#include "media/remoting/proto_enum_utils.h"
erickung1fc58a42016-09-24 03:00:0715
16namespace media {
17namespace remoting {
18
19namespace {
20
21constexpr size_t kPayloadVersionFieldSize = sizeof(uint8_t);
22constexpr size_t kProtoBufferHeaderSize = sizeof(uint16_t);
23constexpr size_t kDataBufferHeaderSize = sizeof(uint32_t);
24
miu9f7788e2017-01-25 00:46:0925std::unique_ptr<DecryptConfig> ConvertProtoToDecryptConfig(
erickung1fc58a42016-09-24 03:00:0726 const pb::DecryptConfig& config_message) {
27 if (!config_message.has_key_id())
28 return nullptr;
29 if (!config_message.has_iv())
30 return nullptr;
31
miu9f7788e2017-01-25 00:46:0932 std::vector<SubsampleEntry> entries(config_message.sub_samples_size());
erickung1fc58a42016-09-24 03:00:0733 for (int i = 0; i < config_message.sub_samples_size(); ++i) {
34 entries.push_back(
miu9f7788e2017-01-25 00:46:0935 SubsampleEntry(config_message.sub_samples(i).clear_bytes(),
36 config_message.sub_samples(i).cypher_bytes()));
erickung1fc58a42016-09-24 03:00:0737 }
38
miu9f7788e2017-01-25 00:46:0939 std::unique_ptr<DecryptConfig> decrypt_config(
40 new DecryptConfig(config_message.key_id(), config_message.iv(), entries));
erickung1fc58a42016-09-24 03:00:0741 return decrypt_config;
42}
43
miu9f7788e2017-01-25 00:46:0944scoped_refptr<DecoderBuffer> ConvertProtoToDecoderBuffer(
erickung1fc58a42016-09-24 03:00:0745 const pb::DecoderBuffer& buffer_message,
miu9f7788e2017-01-25 00:46:0946 scoped_refptr<DecoderBuffer> buffer) {
erickung1fc58a42016-09-24 03:00:0747 if (buffer_message.is_eos()) {
48 VLOG(1) << "EOS data";
miu9f7788e2017-01-25 00:46:0949 return DecoderBuffer::CreateEOSBuffer();
erickung1fc58a42016-09-24 03:00:0750 }
51
52 if (buffer_message.has_timestamp_usec()) {
53 buffer->set_timestamp(
54 base::TimeDelta::FromMicroseconds(buffer_message.timestamp_usec()));
55 }
56
57 if (buffer_message.has_duration_usec()) {
58 buffer->set_duration(
59 base::TimeDelta::FromMicroseconds(buffer_message.duration_usec()));
60 }
61 VLOG(3) << "timestamp:" << buffer_message.timestamp_usec()
62 << " duration:" << buffer_message.duration_usec();
63
64 if (buffer_message.has_is_key_frame())
65 buffer->set_is_key_frame(buffer_message.is_key_frame());
66
67 if (buffer_message.has_decrypt_config()) {
68 buffer->set_decrypt_config(
69 ConvertProtoToDecryptConfig(buffer_message.decrypt_config()));
70 }
71
72 bool has_discard = false;
73 base::TimeDelta front_discard;
74 if (buffer_message.has_front_discard_usec()) {
75 has_discard = true;
76 front_discard =
77 base::TimeDelta::FromMicroseconds(buffer_message.front_discard_usec());
78 }
79 base::TimeDelta back_discard;
80 if (buffer_message.has_back_discard_usec()) {
81 has_discard = true;
82 back_discard =
83 base::TimeDelta::FromMicroseconds(buffer_message.back_discard_usec());
84 }
85
86 if (has_discard) {
87 buffer->set_discard_padding(
miu9f7788e2017-01-25 00:46:0988 DecoderBuffer::DiscardPadding(front_discard, back_discard));
erickung1fc58a42016-09-24 03:00:0789 }
90
erickung1fc58a42016-09-24 03:00:0791 if (buffer_message.has_side_data()) {
92 buffer->CopySideDataFrom(
93 reinterpret_cast<const uint8_t*>(buffer_message.side_data().data()),
94 buffer_message.side_data().size());
95 }
96
97 return buffer;
98}
99
miu9f7788e2017-01-25 00:46:09100void ConvertDecryptConfigToProto(const DecryptConfig& decrypt_config,
erickung1fc58a42016-09-24 03:00:07101 pb::DecryptConfig* config_message) {
102 DCHECK(config_message);
103
104 config_message->set_key_id(decrypt_config.key_id());
105 config_message->set_iv(decrypt_config.iv());
106
107 for (const auto& entry : decrypt_config.subsamples()) {
108 pb::DecryptConfig::SubSample* sub_sample =
109 config_message->add_sub_samples();
110 sub_sample->set_clear_bytes(entry.clear_bytes);
111 sub_sample->set_cypher_bytes(entry.cypher_bytes);
112 }
113}
114
miu9f7788e2017-01-25 00:46:09115void ConvertDecoderBufferToProto(const DecoderBuffer& decoder_buffer,
116 pb::DecoderBuffer* buffer_message) {
117 if (decoder_buffer.end_of_stream()) {
erickung1fc58a42016-09-24 03:00:07118 buffer_message->set_is_eos(true);
119 return;
120 }
121
miu9f7788e2017-01-25 00:46:09122 VLOG(3) << "timestamp:" << decoder_buffer.timestamp().InMicroseconds()
123 << " duration:" << decoder_buffer.duration().InMicroseconds();
erickung1fc58a42016-09-24 03:00:07124 buffer_message->set_timestamp_usec(
miu9f7788e2017-01-25 00:46:09125 decoder_buffer.timestamp().InMicroseconds());
126 buffer_message->set_duration_usec(decoder_buffer.duration().InMicroseconds());
127 buffer_message->set_is_key_frame(decoder_buffer.is_key_frame());
erickung1fc58a42016-09-24 03:00:07128
miu9f7788e2017-01-25 00:46:09129 if (decoder_buffer.decrypt_config()) {
130 ConvertDecryptConfigToProto(*decoder_buffer.decrypt_config(),
erickung1fc58a42016-09-24 03:00:07131 buffer_message->mutable_decrypt_config());
132 }
133
134 buffer_message->set_front_discard_usec(
miu9f7788e2017-01-25 00:46:09135 decoder_buffer.discard_padding().first.InMicroseconds());
erickung1fc58a42016-09-24 03:00:07136 buffer_message->set_back_discard_usec(
miu9f7788e2017-01-25 00:46:09137 decoder_buffer.discard_padding().second.InMicroseconds());
erickung1fc58a42016-09-24 03:00:07138
miu9f7788e2017-01-25 00:46:09139 if (decoder_buffer.side_data_size()) {
140 buffer_message->set_side_data(decoder_buffer.side_data(),
141 decoder_buffer.side_data_size());
erickung1fc58a42016-09-24 03:00:07142 }
143}
144
145} // namespace
146
miu9f7788e2017-01-25 00:46:09147scoped_refptr<DecoderBuffer> ByteArrayToDecoderBuffer(const uint8_t* data,
148 uint32_t size) {
erickung1fc58a42016-09-24 03:00:07149 base::BigEndianReader reader(reinterpret_cast<const char*>(data), size);
150 uint8_t payload_version = 0;
151 uint16_t proto_size = 0;
152 pb::DecoderBuffer segment;
153 uint32_t buffer_size = 0;
154 if (reader.ReadU8(&payload_version) && payload_version == 0 &&
155 reader.ReadU16(&proto_size) &&
156 static_cast<int>(proto_size) < reader.remaining() &&
157 segment.ParseFromArray(reader.ptr(), proto_size) &&
158 reader.Skip(proto_size) && reader.ReadU32(&buffer_size) &&
159 static_cast<int64_t>(buffer_size) <= reader.remaining()) {
160 // Deserialize proto buffer. It passes the pre allocated DecoderBuffer into
161 // the function because the proto buffer may overwrite DecoderBuffer since
162 // it may be EOS buffer.
miu9f7788e2017-01-25 00:46:09163 scoped_refptr<DecoderBuffer> decoder_buffer = ConvertProtoToDecoderBuffer(
164 segment,
165 DecoderBuffer::CopyFrom(reinterpret_cast<const uint8_t*>(reader.ptr()),
166 buffer_size));
erickung1fc58a42016-09-24 03:00:07167 return decoder_buffer;
168 }
169
erickung1fc58a42016-09-24 03:00:07170 return nullptr;
171}
172
173std::vector<uint8_t> DecoderBufferToByteArray(
miu9f7788e2017-01-25 00:46:09174 const DecoderBuffer& decoder_buffer) {
erickung1fc58a42016-09-24 03:00:07175 pb::DecoderBuffer decoder_buffer_message;
176 ConvertDecoderBufferToProto(decoder_buffer, &decoder_buffer_message);
177
178 size_t decoder_buffer_size =
miu9f7788e2017-01-25 00:46:09179 decoder_buffer.end_of_stream() ? 0 : decoder_buffer.data_size();
erickung1fc58a42016-09-24 03:00:07180 size_t size = kPayloadVersionFieldSize + kProtoBufferHeaderSize +
181 decoder_buffer_message.ByteSize() + kDataBufferHeaderSize +
182 decoder_buffer_size;
183 std::vector<uint8_t> buffer(size);
184 base::BigEndianWriter writer(reinterpret_cast<char*>(buffer.data()),
185 buffer.size());
186 if (writer.WriteU8(0) &&
187 writer.WriteU16(
188 static_cast<uint16_t>(decoder_buffer_message.GetCachedSize())) &&
189 decoder_buffer_message.SerializeToArray(
190 writer.ptr(), decoder_buffer_message.GetCachedSize()) &&
191 writer.Skip(decoder_buffer_message.GetCachedSize()) &&
192 writer.WriteU32(decoder_buffer_size)) {
193 if (decoder_buffer_size) {
194 // DecoderBuffer frame data.
miu9f7788e2017-01-25 00:46:09195 writer.WriteBytes(reinterpret_cast<const void*>(decoder_buffer.data()),
196 decoder_buffer.data_size());
erickung1fc58a42016-09-24 03:00:07197 }
198 return buffer;
199 }
200
miu9f7788e2017-01-25 00:46:09201 NOTREACHED();
erickung1fc58a42016-09-24 03:00:07202 // Reset buffer since serialization of the data failed.
erickung1fc58a42016-09-24 03:00:07203 buffer.clear();
204 return buffer;
205}
206
miu9f7788e2017-01-25 00:46:09207void ConvertEncryptionSchemeToProto(const EncryptionScheme& encryption_scheme,
208 pb::EncryptionScheme* message) {
erickung1fc58a42016-09-24 03:00:07209 DCHECK(message);
210 message->set_mode(
211 ToProtoEncryptionSchemeCipherMode(encryption_scheme.mode()).value());
212 message->set_encrypt_blocks(encryption_scheme.pattern().encrypt_blocks());
213 message->set_skip_blocks(encryption_scheme.pattern().skip_blocks());
214}
215
miu9f7788e2017-01-25 00:46:09216EncryptionScheme ConvertProtoToEncryptionScheme(
erickung1fc58a42016-09-24 03:00:07217 const pb::EncryptionScheme& message) {
miu9f7788e2017-01-25 00:46:09218 return EncryptionScheme(
erickung1fc58a42016-09-24 03:00:07219 ToMediaEncryptionSchemeCipherMode(message.mode()).value(),
miu9f7788e2017-01-25 00:46:09220 EncryptionScheme::Pattern(message.encrypt_blocks(),
221 message.skip_blocks()));
erickung1fc58a42016-09-24 03:00:07222}
223
miu9f7788e2017-01-25 00:46:09224void ConvertAudioDecoderConfigToProto(const AudioDecoderConfig& audio_config,
225 pb::AudioDecoderConfig* audio_message) {
erickung1fc58a42016-09-24 03:00:07226 DCHECK(audio_config.IsValidConfig());
227 DCHECK(audio_message);
228
229 audio_message->set_codec(
230 ToProtoAudioDecoderConfigCodec(audio_config.codec()).value());
231 audio_message->set_sample_format(
232 ToProtoAudioDecoderConfigSampleFormat(audio_config.sample_format())
233 .value());
234 audio_message->set_channel_layout(
235 ToProtoAudioDecoderConfigChannelLayout(audio_config.channel_layout())
236 .value());
237 audio_message->set_samples_per_second(audio_config.samples_per_second());
238 audio_message->set_seek_preroll_usec(
239 audio_config.seek_preroll().InMicroseconds());
240 audio_message->set_codec_delay(audio_config.codec_delay());
241
242 if (!audio_config.extra_data().empty()) {
243 audio_message->set_extra_data(audio_config.extra_data().data(),
244 audio_config.extra_data().size());
245 }
246
247 if (audio_config.is_encrypted()) {
248 pb::EncryptionScheme* encryption_scheme_message =
249 audio_message->mutable_encryption_scheme();
250 ConvertEncryptionSchemeToProto(audio_config.encryption_scheme(),
251 encryption_scheme_message);
252 }
253}
254
255bool ConvertProtoToAudioDecoderConfig(
256 const pb::AudioDecoderConfig& audio_message,
miu9f7788e2017-01-25 00:46:09257 AudioDecoderConfig* audio_config) {
erickung1fc58a42016-09-24 03:00:07258 DCHECK(audio_config);
259 audio_config->Initialize(
260 ToMediaAudioCodec(audio_message.codec()).value(),
261 ToMediaSampleFormat(audio_message.sample_format()).value(),
262 ToMediaChannelLayout(audio_message.channel_layout()).value(),
263 audio_message.samples_per_second(),
264 std::vector<uint8_t>(audio_message.extra_data().begin(),
265 audio_message.extra_data().end()),
266 ConvertProtoToEncryptionScheme(audio_message.encryption_scheme()),
267 base::TimeDelta::FromMicroseconds(audio_message.seek_preroll_usec()),
268 audio_message.codec_delay());
269 return audio_config->IsValidConfig();
270}
271
miu9f7788e2017-01-25 00:46:09272void ConvertVideoDecoderConfigToProto(const VideoDecoderConfig& video_config,
273 pb::VideoDecoderConfig* video_message) {
erickung1fc58a42016-09-24 03:00:07274 DCHECK(video_config.IsValidConfig());
275 DCHECK(video_message);
276
277 video_message->set_codec(
278 ToProtoVideoDecoderConfigCodec(video_config.codec()).value());
279 video_message->set_profile(
280 ToProtoVideoDecoderConfigProfile(video_config.profile()).value());
281 video_message->set_format(
282 ToProtoVideoDecoderConfigFormat(video_config.format()).value());
283 video_message->set_color_space(
284 ToProtoVideoDecoderConfigColorSpace(video_config.color_space()).value());
285
286 pb::Size* coded_size_message = video_message->mutable_coded_size();
287 coded_size_message->set_width(video_config.coded_size().width());
288 coded_size_message->set_height(video_config.coded_size().height());
289
290 pb::Rect* visible_rect_message = video_message->mutable_visible_rect();
291 visible_rect_message->set_x(video_config.visible_rect().x());
292 visible_rect_message->set_y(video_config.visible_rect().y());
293 visible_rect_message->set_width(video_config.visible_rect().width());
294 visible_rect_message->set_height(video_config.visible_rect().height());
295
296 pb::Size* natural_size_message = video_message->mutable_natural_size();
297 natural_size_message->set_width(video_config.natural_size().width());
298 natural_size_message->set_height(video_config.natural_size().height());
299
300 if (!video_config.extra_data().empty()) {
301 video_message->set_extra_data(video_config.extra_data().data(),
302 video_config.extra_data().size());
303 }
304
305 if (video_config.is_encrypted()) {
306 pb::EncryptionScheme* encryption_scheme_message =
307 video_message->mutable_encryption_scheme();
308 ConvertEncryptionSchemeToProto(video_config.encryption_scheme(),
309 encryption_scheme_message);
310 }
311}
312
313bool ConvertProtoToVideoDecoderConfig(
314 const pb::VideoDecoderConfig& video_message,
miu9f7788e2017-01-25 00:46:09315 VideoDecoderConfig* video_config) {
erickung1fc58a42016-09-24 03:00:07316 DCHECK(video_config);
miu9f7788e2017-01-25 00:46:09317 EncryptionScheme encryption_scheme;
erickung1fc58a42016-09-24 03:00:07318 video_config->Initialize(
319 ToMediaVideoCodec(video_message.codec()).value(),
320 ToMediaVideoCodecProfile(video_message.profile()).value(),
321 ToMediaVideoPixelFormat(video_message.format()).value(),
322 ToMediaColorSpace(video_message.color_space()).value(),
323 gfx::Size(video_message.coded_size().width(),
324 video_message.coded_size().height()),
325 gfx::Rect(video_message.visible_rect().x(),
326 video_message.visible_rect().y(),
327 video_message.visible_rect().width(),
328 video_message.visible_rect().height()),
329 gfx::Size(video_message.natural_size().width(),
330 video_message.natural_size().height()),
331 std::vector<uint8_t>(video_message.extra_data().begin(),
332 video_message.extra_data().end()),
333 ConvertProtoToEncryptionScheme(video_message.encryption_scheme()));
334 return video_config->IsValidConfig();
335}
336
miu9f7788e2017-01-25 00:46:09337void ConvertProtoToPipelineStatistics(
338 const pb::PipelineStatistics& stats_message,
339 PipelineStatistics* stats) {
340 stats->audio_bytes_decoded = stats_message.audio_bytes_decoded();
341 stats->video_bytes_decoded = stats_message.video_bytes_decoded();
342 stats->video_frames_decoded = stats_message.video_frames_decoded();
343 stats->video_frames_dropped = stats_message.video_frames_dropped();
344 stats->audio_memory_usage = stats_message.audio_memory_usage();
345 stats->video_memory_usage = stats_message.video_memory_usage();
346 // HACK: Set the following to prevent "disable video when hidden" logic in
347 // media::blink::WebMediaPlayerImpl.
348 stats->video_keyframe_distance_average = base::TimeDelta::Max();
349}
350
erickung1fc58a42016-09-24 03:00:07351void ConvertCdmKeyInfoToProto(
miu9f7788e2017-01-25 00:46:09352 const CdmKeysInfo& keys_information,
erickung1fc58a42016-09-24 03:00:07353 pb::CdmClientOnSessionKeysChange* key_change_message) {
xiaofeng.zhang8235be22017-05-21 11:39:34354 for (auto& info : keys_information) {
erickung1fc58a42016-09-24 03:00:07355 pb::CdmKeyInformation* key = key_change_message->add_key_information();
356 key->set_key_id(info->key_id.data(), info->key_id.size());
357 key->set_status(ToProtoCdmKeyInformation(info->status).value());
358 key->set_system_code(info->system_code);
359 }
360}
361
362void ConvertProtoToCdmKeyInfo(
363 const pb::CdmClientOnSessionKeysChange keychange_message,
364 CdmKeysInfo* key_information) {
365 DCHECK(key_information);
366 key_information->reserve(keychange_message.key_information_size());
367 for (int i = 0; i < keychange_message.key_information_size(); ++i) {
368 const pb::CdmKeyInformation key_info_msg =
369 keychange_message.key_information(i);
370
miu9f7788e2017-01-25 00:46:09371 std::unique_ptr<CdmKeyInformation> key(new CdmKeyInformation(
372 key_info_msg.key_id(),
373 ToMediaCdmKeyInformationKeyStatus(key_info_msg.status()).value(),
374 key_info_msg.system_code()));
erickung1fc58a42016-09-24 03:00:07375 key_information->push_back(std::move(key));
376 }
377}
378
379void ConvertCdmPromiseToProto(const CdmPromiseResult& result,
380 pb::CdmPromise* promise_message) {
381 promise_message->set_success(result.success());
382 if (!result.success()) {
383 promise_message->set_exception(
xhwang79b193042016-12-13 18:52:43384 ToProtoCdmException(result.exception()).value());
erickung1fc58a42016-09-24 03:00:07385 promise_message->set_system_code(result.system_code());
386 promise_message->set_error_message(result.error_message());
387 }
388}
389
390void ConvertCdmPromiseWithSessionIdToProto(const CdmPromiseResult& result,
391 const std::string& session_id,
392 pb::CdmPromise* promise_message) {
393 ConvertCdmPromiseToProto(result, promise_message);
394 promise_message->set_session_id(session_id);
395}
396
397void ConvertCdmPromiseWithCdmIdToProto(const CdmPromiseResult& result,
398 int cdm_id,
399 pb::CdmPromise* promise_message) {
400 ConvertCdmPromiseToProto(result, promise_message);
401 promise_message->set_cdm_id(cdm_id);
402}
403
404bool ConvertProtoToCdmPromise(const pb::CdmPromise& promise_message,
405 CdmPromiseResult* result) {
406 if (!promise_message.has_success())
407 return false;
408
409 bool success = promise_message.success();
410 if (success) {
411 *result = CdmPromiseResult::SuccessResult();
412 return true;
413 }
414
miu9f7788e2017-01-25 00:46:09415 CdmPromise::Exception exception = CdmPromise::UNKNOWN_ERROR;
erickung1fc58a42016-09-24 03:00:07416 uint32_t system_code = 0;
417 std::string error_message;
418
corona101f1c7d32016-10-27 17:08:10419 exception = ToCdmPromiseException(promise_message.exception()).value();
erickung1fc58a42016-09-24 03:00:07420 system_code = promise_message.system_code();
421 error_message = promise_message.error_message();
422 *result = CdmPromiseResult(exception, system_code, error_message);
423 return true;
424}
425
426bool ConvertProtoToCdmPromiseWithCdmIdSessionId(const pb::RpcMessage& message,
427 CdmPromiseResult* result,
428 int* cdm_id,
429 std::string* session_id) {
430 if (!message.has_cdm_promise_rpc())
431 return false;
432
433 const auto& promise_message = message.cdm_promise_rpc();
434 if (!ConvertProtoToCdmPromise(promise_message, result))
435 return false;
436
437 if (cdm_id)
438 *cdm_id = promise_message.cdm_id();
439 if (session_id)
440 *session_id = promise_message.session_id();
441
442 return true;
443}
444
445//==============================================================================
446CdmPromiseResult::CdmPromiseResult()
miu9f7788e2017-01-25 00:46:09447 : CdmPromiseResult(CdmPromise::UNKNOWN_ERROR, 0, "") {}
erickung1fc58a42016-09-24 03:00:07448
miu9f7788e2017-01-25 00:46:09449CdmPromiseResult::CdmPromiseResult(CdmPromise::Exception exception,
erickung1fc58a42016-09-24 03:00:07450 uint32_t system_code,
451 std::string error_message)
452 : success_(false),
453 exception_(exception),
454 system_code_(system_code),
455 error_message_(error_message) {}
456
457CdmPromiseResult::CdmPromiseResult(const CdmPromiseResult& other) = default;
458
459CdmPromiseResult::~CdmPromiseResult() = default;
460
461CdmPromiseResult CdmPromiseResult::SuccessResult() {
miu9f7788e2017-01-25 00:46:09462 CdmPromiseResult result(static_cast<CdmPromise::Exception>(0), 0, "");
erickung1fc58a42016-09-24 03:00:07463 result.success_ = true;
464 return result;
465}
466
467} // namespace remoting
468} // namespace media