blob: 30114d0c356a0cd742eb70f37a17ce258e807458 [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
91 if (buffer_message.has_splice_timestamp_usec()) {
92 buffer->set_splice_timestamp(base::TimeDelta::FromMicroseconds(
93 buffer_message.splice_timestamp_usec()));
94 }
95
96 if (buffer_message.has_side_data()) {
97 buffer->CopySideDataFrom(
98 reinterpret_cast<const uint8_t*>(buffer_message.side_data().data()),
99 buffer_message.side_data().size());
100 }
101
102 return buffer;
103}
104
miu9f7788e2017-01-25 00:46:09105void ConvertDecryptConfigToProto(const DecryptConfig& decrypt_config,
erickung1fc58a42016-09-24 03:00:07106 pb::DecryptConfig* config_message) {
107 DCHECK(config_message);
108
109 config_message->set_key_id(decrypt_config.key_id());
110 config_message->set_iv(decrypt_config.iv());
111
112 for (const auto& entry : decrypt_config.subsamples()) {
113 pb::DecryptConfig::SubSample* sub_sample =
114 config_message->add_sub_samples();
115 sub_sample->set_clear_bytes(entry.clear_bytes);
116 sub_sample->set_cypher_bytes(entry.cypher_bytes);
117 }
118}
119
miu9f7788e2017-01-25 00:46:09120void ConvertDecoderBufferToProto(const DecoderBuffer& decoder_buffer,
121 pb::DecoderBuffer* buffer_message) {
122 if (decoder_buffer.end_of_stream()) {
erickung1fc58a42016-09-24 03:00:07123 buffer_message->set_is_eos(true);
124 return;
125 }
126
miu9f7788e2017-01-25 00:46:09127 VLOG(3) << "timestamp:" << decoder_buffer.timestamp().InMicroseconds()
128 << " duration:" << decoder_buffer.duration().InMicroseconds();
erickung1fc58a42016-09-24 03:00:07129 buffer_message->set_timestamp_usec(
miu9f7788e2017-01-25 00:46:09130 decoder_buffer.timestamp().InMicroseconds());
131 buffer_message->set_duration_usec(decoder_buffer.duration().InMicroseconds());
132 buffer_message->set_is_key_frame(decoder_buffer.is_key_frame());
erickung1fc58a42016-09-24 03:00:07133
miu9f7788e2017-01-25 00:46:09134 if (decoder_buffer.decrypt_config()) {
135 ConvertDecryptConfigToProto(*decoder_buffer.decrypt_config(),
erickung1fc58a42016-09-24 03:00:07136 buffer_message->mutable_decrypt_config());
137 }
138
139 buffer_message->set_front_discard_usec(
miu9f7788e2017-01-25 00:46:09140 decoder_buffer.discard_padding().first.InMicroseconds());
erickung1fc58a42016-09-24 03:00:07141 buffer_message->set_back_discard_usec(
miu9f7788e2017-01-25 00:46:09142 decoder_buffer.discard_padding().second.InMicroseconds());
erickung1fc58a42016-09-24 03:00:07143 buffer_message->set_splice_timestamp_usec(
miu9f7788e2017-01-25 00:46:09144 decoder_buffer.splice_timestamp().InMicroseconds());
erickung1fc58a42016-09-24 03:00:07145
miu9f7788e2017-01-25 00:46:09146 if (decoder_buffer.side_data_size()) {
147 buffer_message->set_side_data(decoder_buffer.side_data(),
148 decoder_buffer.side_data_size());
erickung1fc58a42016-09-24 03:00:07149 }
150}
151
152} // namespace
153
miu9f7788e2017-01-25 00:46:09154scoped_refptr<DecoderBuffer> ByteArrayToDecoderBuffer(const uint8_t* data,
155 uint32_t size) {
erickung1fc58a42016-09-24 03:00:07156 base::BigEndianReader reader(reinterpret_cast<const char*>(data), size);
157 uint8_t payload_version = 0;
158 uint16_t proto_size = 0;
159 pb::DecoderBuffer segment;
160 uint32_t buffer_size = 0;
161 if (reader.ReadU8(&payload_version) && payload_version == 0 &&
162 reader.ReadU16(&proto_size) &&
163 static_cast<int>(proto_size) < reader.remaining() &&
164 segment.ParseFromArray(reader.ptr(), proto_size) &&
165 reader.Skip(proto_size) && reader.ReadU32(&buffer_size) &&
166 static_cast<int64_t>(buffer_size) <= reader.remaining()) {
167 // Deserialize proto buffer. It passes the pre allocated DecoderBuffer into
168 // the function because the proto buffer may overwrite DecoderBuffer since
169 // it may be EOS buffer.
miu9f7788e2017-01-25 00:46:09170 scoped_refptr<DecoderBuffer> decoder_buffer = ConvertProtoToDecoderBuffer(
171 segment,
172 DecoderBuffer::CopyFrom(reinterpret_cast<const uint8_t*>(reader.ptr()),
173 buffer_size));
erickung1fc58a42016-09-24 03:00:07174 return decoder_buffer;
175 }
176
erickung1fc58a42016-09-24 03:00:07177 return nullptr;
178}
179
180std::vector<uint8_t> DecoderBufferToByteArray(
miu9f7788e2017-01-25 00:46:09181 const DecoderBuffer& decoder_buffer) {
erickung1fc58a42016-09-24 03:00:07182 pb::DecoderBuffer decoder_buffer_message;
183 ConvertDecoderBufferToProto(decoder_buffer, &decoder_buffer_message);
184
185 size_t decoder_buffer_size =
miu9f7788e2017-01-25 00:46:09186 decoder_buffer.end_of_stream() ? 0 : decoder_buffer.data_size();
erickung1fc58a42016-09-24 03:00:07187 size_t size = kPayloadVersionFieldSize + kProtoBufferHeaderSize +
188 decoder_buffer_message.ByteSize() + kDataBufferHeaderSize +
189 decoder_buffer_size;
190 std::vector<uint8_t> buffer(size);
191 base::BigEndianWriter writer(reinterpret_cast<char*>(buffer.data()),
192 buffer.size());
193 if (writer.WriteU8(0) &&
194 writer.WriteU16(
195 static_cast<uint16_t>(decoder_buffer_message.GetCachedSize())) &&
196 decoder_buffer_message.SerializeToArray(
197 writer.ptr(), decoder_buffer_message.GetCachedSize()) &&
198 writer.Skip(decoder_buffer_message.GetCachedSize()) &&
199 writer.WriteU32(decoder_buffer_size)) {
200 if (decoder_buffer_size) {
201 // DecoderBuffer frame data.
miu9f7788e2017-01-25 00:46:09202 writer.WriteBytes(reinterpret_cast<const void*>(decoder_buffer.data()),
203 decoder_buffer.data_size());
erickung1fc58a42016-09-24 03:00:07204 }
205 return buffer;
206 }
207
miu9f7788e2017-01-25 00:46:09208 NOTREACHED();
erickung1fc58a42016-09-24 03:00:07209 // Reset buffer since serialization of the data failed.
erickung1fc58a42016-09-24 03:00:07210 buffer.clear();
211 return buffer;
212}
213
miu9f7788e2017-01-25 00:46:09214void ConvertEncryptionSchemeToProto(const EncryptionScheme& encryption_scheme,
215 pb::EncryptionScheme* message) {
erickung1fc58a42016-09-24 03:00:07216 DCHECK(message);
217 message->set_mode(
218 ToProtoEncryptionSchemeCipherMode(encryption_scheme.mode()).value());
219 message->set_encrypt_blocks(encryption_scheme.pattern().encrypt_blocks());
220 message->set_skip_blocks(encryption_scheme.pattern().skip_blocks());
221}
222
miu9f7788e2017-01-25 00:46:09223EncryptionScheme ConvertProtoToEncryptionScheme(
erickung1fc58a42016-09-24 03:00:07224 const pb::EncryptionScheme& message) {
miu9f7788e2017-01-25 00:46:09225 return EncryptionScheme(
erickung1fc58a42016-09-24 03:00:07226 ToMediaEncryptionSchemeCipherMode(message.mode()).value(),
miu9f7788e2017-01-25 00:46:09227 EncryptionScheme::Pattern(message.encrypt_blocks(),
228 message.skip_blocks()));
erickung1fc58a42016-09-24 03:00:07229}
230
miu9f7788e2017-01-25 00:46:09231void ConvertAudioDecoderConfigToProto(const AudioDecoderConfig& audio_config,
232 pb::AudioDecoderConfig* audio_message) {
erickung1fc58a42016-09-24 03:00:07233 DCHECK(audio_config.IsValidConfig());
234 DCHECK(audio_message);
235
236 audio_message->set_codec(
237 ToProtoAudioDecoderConfigCodec(audio_config.codec()).value());
238 audio_message->set_sample_format(
239 ToProtoAudioDecoderConfigSampleFormat(audio_config.sample_format())
240 .value());
241 audio_message->set_channel_layout(
242 ToProtoAudioDecoderConfigChannelLayout(audio_config.channel_layout())
243 .value());
244 audio_message->set_samples_per_second(audio_config.samples_per_second());
245 audio_message->set_seek_preroll_usec(
246 audio_config.seek_preroll().InMicroseconds());
247 audio_message->set_codec_delay(audio_config.codec_delay());
248
249 if (!audio_config.extra_data().empty()) {
250 audio_message->set_extra_data(audio_config.extra_data().data(),
251 audio_config.extra_data().size());
252 }
253
254 if (audio_config.is_encrypted()) {
255 pb::EncryptionScheme* encryption_scheme_message =
256 audio_message->mutable_encryption_scheme();
257 ConvertEncryptionSchemeToProto(audio_config.encryption_scheme(),
258 encryption_scheme_message);
259 }
260}
261
262bool ConvertProtoToAudioDecoderConfig(
263 const pb::AudioDecoderConfig& audio_message,
miu9f7788e2017-01-25 00:46:09264 AudioDecoderConfig* audio_config) {
erickung1fc58a42016-09-24 03:00:07265 DCHECK(audio_config);
266 audio_config->Initialize(
267 ToMediaAudioCodec(audio_message.codec()).value(),
268 ToMediaSampleFormat(audio_message.sample_format()).value(),
269 ToMediaChannelLayout(audio_message.channel_layout()).value(),
270 audio_message.samples_per_second(),
271 std::vector<uint8_t>(audio_message.extra_data().begin(),
272 audio_message.extra_data().end()),
273 ConvertProtoToEncryptionScheme(audio_message.encryption_scheme()),
274 base::TimeDelta::FromMicroseconds(audio_message.seek_preroll_usec()),
275 audio_message.codec_delay());
276 return audio_config->IsValidConfig();
277}
278
miu9f7788e2017-01-25 00:46:09279void ConvertVideoDecoderConfigToProto(const VideoDecoderConfig& video_config,
280 pb::VideoDecoderConfig* video_message) {
erickung1fc58a42016-09-24 03:00:07281 DCHECK(video_config.IsValidConfig());
282 DCHECK(video_message);
283
284 video_message->set_codec(
285 ToProtoVideoDecoderConfigCodec(video_config.codec()).value());
286 video_message->set_profile(
287 ToProtoVideoDecoderConfigProfile(video_config.profile()).value());
288 video_message->set_format(
289 ToProtoVideoDecoderConfigFormat(video_config.format()).value());
290 video_message->set_color_space(
291 ToProtoVideoDecoderConfigColorSpace(video_config.color_space()).value());
292
293 pb::Size* coded_size_message = video_message->mutable_coded_size();
294 coded_size_message->set_width(video_config.coded_size().width());
295 coded_size_message->set_height(video_config.coded_size().height());
296
297 pb::Rect* visible_rect_message = video_message->mutable_visible_rect();
298 visible_rect_message->set_x(video_config.visible_rect().x());
299 visible_rect_message->set_y(video_config.visible_rect().y());
300 visible_rect_message->set_width(video_config.visible_rect().width());
301 visible_rect_message->set_height(video_config.visible_rect().height());
302
303 pb::Size* natural_size_message = video_message->mutable_natural_size();
304 natural_size_message->set_width(video_config.natural_size().width());
305 natural_size_message->set_height(video_config.natural_size().height());
306
307 if (!video_config.extra_data().empty()) {
308 video_message->set_extra_data(video_config.extra_data().data(),
309 video_config.extra_data().size());
310 }
311
312 if (video_config.is_encrypted()) {
313 pb::EncryptionScheme* encryption_scheme_message =
314 video_message->mutable_encryption_scheme();
315 ConvertEncryptionSchemeToProto(video_config.encryption_scheme(),
316 encryption_scheme_message);
317 }
318}
319
320bool ConvertProtoToVideoDecoderConfig(
321 const pb::VideoDecoderConfig& video_message,
miu9f7788e2017-01-25 00:46:09322 VideoDecoderConfig* video_config) {
erickung1fc58a42016-09-24 03:00:07323 DCHECK(video_config);
miu9f7788e2017-01-25 00:46:09324 EncryptionScheme encryption_scheme;
erickung1fc58a42016-09-24 03:00:07325 video_config->Initialize(
326 ToMediaVideoCodec(video_message.codec()).value(),
327 ToMediaVideoCodecProfile(video_message.profile()).value(),
328 ToMediaVideoPixelFormat(video_message.format()).value(),
329 ToMediaColorSpace(video_message.color_space()).value(),
330 gfx::Size(video_message.coded_size().width(),
331 video_message.coded_size().height()),
332 gfx::Rect(video_message.visible_rect().x(),
333 video_message.visible_rect().y(),
334 video_message.visible_rect().width(),
335 video_message.visible_rect().height()),
336 gfx::Size(video_message.natural_size().width(),
337 video_message.natural_size().height()),
338 std::vector<uint8_t>(video_message.extra_data().begin(),
339 video_message.extra_data().end()),
340 ConvertProtoToEncryptionScheme(video_message.encryption_scheme()));
341 return video_config->IsValidConfig();
342}
343
miu9f7788e2017-01-25 00:46:09344void ConvertProtoToPipelineStatistics(
345 const pb::PipelineStatistics& stats_message,
346 PipelineStatistics* stats) {
347 stats->audio_bytes_decoded = stats_message.audio_bytes_decoded();
348 stats->video_bytes_decoded = stats_message.video_bytes_decoded();
349 stats->video_frames_decoded = stats_message.video_frames_decoded();
350 stats->video_frames_dropped = stats_message.video_frames_dropped();
351 stats->audio_memory_usage = stats_message.audio_memory_usage();
352 stats->video_memory_usage = stats_message.video_memory_usage();
353 // HACK: Set the following to prevent "disable video when hidden" logic in
354 // media::blink::WebMediaPlayerImpl.
355 stats->video_keyframe_distance_average = base::TimeDelta::Max();
356}
357
erickung1fc58a42016-09-24 03:00:07358void ConvertCdmKeyInfoToProto(
miu9f7788e2017-01-25 00:46:09359 const CdmKeysInfo& keys_information,
erickung1fc58a42016-09-24 03:00:07360 pb::CdmClientOnSessionKeysChange* key_change_message) {
361 for (const auto& info : keys_information) {
362 pb::CdmKeyInformation* key = key_change_message->add_key_information();
363 key->set_key_id(info->key_id.data(), info->key_id.size());
364 key->set_status(ToProtoCdmKeyInformation(info->status).value());
365 key->set_system_code(info->system_code);
366 }
367}
368
369void ConvertProtoToCdmKeyInfo(
370 const pb::CdmClientOnSessionKeysChange keychange_message,
371 CdmKeysInfo* key_information) {
372 DCHECK(key_information);
373 key_information->reserve(keychange_message.key_information_size());
374 for (int i = 0; i < keychange_message.key_information_size(); ++i) {
375 const pb::CdmKeyInformation key_info_msg =
376 keychange_message.key_information(i);
377
miu9f7788e2017-01-25 00:46:09378 std::unique_ptr<CdmKeyInformation> key(new CdmKeyInformation(
379 key_info_msg.key_id(),
380 ToMediaCdmKeyInformationKeyStatus(key_info_msg.status()).value(),
381 key_info_msg.system_code()));
erickung1fc58a42016-09-24 03:00:07382 key_information->push_back(std::move(key));
383 }
384}
385
386void ConvertCdmPromiseToProto(const CdmPromiseResult& result,
387 pb::CdmPromise* promise_message) {
388 promise_message->set_success(result.success());
389 if (!result.success()) {
390 promise_message->set_exception(
xhwang79b193042016-12-13 18:52:43391 ToProtoCdmException(result.exception()).value());
erickung1fc58a42016-09-24 03:00:07392 promise_message->set_system_code(result.system_code());
393 promise_message->set_error_message(result.error_message());
394 }
395}
396
397void ConvertCdmPromiseWithSessionIdToProto(const CdmPromiseResult& result,
398 const std::string& session_id,
399 pb::CdmPromise* promise_message) {
400 ConvertCdmPromiseToProto(result, promise_message);
401 promise_message->set_session_id(session_id);
402}
403
404void 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
411bool 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
miu9f7788e2017-01-25 00:46:09422 CdmPromise::Exception exception = CdmPromise::UNKNOWN_ERROR;
erickung1fc58a42016-09-24 03:00:07423 uint32_t system_code = 0;
424 std::string error_message;
425
corona101f1c7d32016-10-27 17:08:10426 exception = ToCdmPromiseException(promise_message.exception()).value();
erickung1fc58a42016-09-24 03:00:07427 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
433bool 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//==============================================================================
453CdmPromiseResult::CdmPromiseResult()
miu9f7788e2017-01-25 00:46:09454 : CdmPromiseResult(CdmPromise::UNKNOWN_ERROR, 0, "") {}
erickung1fc58a42016-09-24 03:00:07455
miu9f7788e2017-01-25 00:46:09456CdmPromiseResult::CdmPromiseResult(CdmPromise::Exception exception,
erickung1fc58a42016-09-24 03:00:07457 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
464CdmPromiseResult::CdmPromiseResult(const CdmPromiseResult& other) = default;
465
466CdmPromiseResult::~CdmPromiseResult() = default;
467
468CdmPromiseResult CdmPromiseResult::SuccessResult() {
miu9f7788e2017-01-25 00:46:09469 CdmPromiseResult result(static_cast<CdmPromise::Exception>(0), 0, "");
erickung1fc58a42016-09-24 03:00:07470 result.success_ = true;
471 return result;
472}
473
474} // namespace remoting
475} // namespace media