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