Chromium Code Reviews| Index: media/remoting/rpc/decoder_buffer_segment.cc |
| diff --git a/media/remoting/rpc/decoder_buffer_segment.cc b/media/remoting/rpc/decoder_buffer_segment.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..1060c6ff309d415a7c1cb55797ec6eb6043b150c |
| --- /dev/null |
| +++ b/media/remoting/rpc/decoder_buffer_segment.cc |
| @@ -0,0 +1,239 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "media/remoting/rpc/decoder_buffer_segment.h" |
| + |
| +#include <algorithm> |
| +#include <memory> |
| +#include <utility> |
| +#include <vector> |
| + |
| +#include "base/logging.h" |
| +#include "base/values.h" |
| +#include "media/base/decrypt_config.h" |
| + |
| +namespace media { |
| +namespace remoting { |
| + |
| +namespace { |
| + |
| +const int kPayloadVersionFieldSize = 1; |
| +const int kProtoBufferHeaderSize = 2; |
| +const int kDataBufferHeaderSize = 4; |
| + |
| +std::unique_ptr<::media::DecryptConfig> DeserializeDecryptConfig( |
| + const pb::DecryptConfig& config_message) { |
| + std::vector<::media::SubsampleEntry> entries; |
| + |
| + DCHECK(config_message.has_key_id()); |
|
miu
2016/09/08 01:07:34
These DCHECKs suggest the fields should not have b
erickung1
2016/09/13 03:52:52
After the discussion, the field in proto buffer wi
miu
2016/09/13 05:40:57
Should we keep these checks? If they are needed, a
erickung1
2016/09/15 02:13:32
Done.
|
| + DCHECK(config_message.has_iv()); |
| + |
| + for (int i = 0; i < config_message.sub_samples_size(); ++i) { |
| + entries.push_back( |
| + ::media::SubsampleEntry(config_message.sub_samples(i).clear_bytes(), |
| + config_message.sub_samples(i).cypher_bytes())); |
| + } |
| + |
| + std::unique_ptr<::media::DecryptConfig> decrypt_config( |
| + new ::media::DecryptConfig(config_message.key_id(), config_message.iv(), |
| + entries)); |
| + return decrypt_config; |
| +} |
| + |
| +scoped_refptr<::media::DecoderBuffer> DeserializeDecoderBuffer( |
| + const pb::DecoderBuffer& buffer_message, |
| + scoped_refptr<::media::DecoderBuffer> buffer) { |
| + std::unique_ptr<::media::DecryptConfig> decrypt_config; |
| + base::TimeDelta front_discard; |
| + base::TimeDelta back_discard; |
| + bool has_discard = true; |
| + |
| + if (buffer_message.is_eos()) { |
| + VLOG(1) << "EOS data"; |
| + return ::media::DecoderBuffer::CreateEOSBuffer(); |
| + } |
| + |
| + if (buffer_message.has_timestamp_usec()) { |
| + buffer->set_timestamp( |
| + base::TimeDelta::FromMicroseconds(buffer_message.timestamp_usec())); |
| + } |
| + |
| + if (buffer_message.has_duration_usec()) { |
| + buffer->set_duration( |
| + base::TimeDelta::FromMicroseconds(buffer_message.duration_usec())); |
| + } |
| + VLOG(2) << "timestamp:" << buffer_message.timestamp_usec() |
| + << " duration:" << buffer_message.duration_usec(); |
| + |
| + if (buffer_message.has_is_key_frame()) |
| + buffer->set_is_key_frame(buffer_message.is_key_frame()); |
| + |
| + if (buffer_message.has_decrypt_config()) { |
| + const pb::DecryptConfig config_message = buffer_message.decrypt_config(); |
| + decrypt_config = DeserializeDecryptConfig(config_message); |
| + buffer->set_decrypt_config(std::move(decrypt_config)); |
|
miu
2016/09/08 01:07:34
You can simplify here and eliminate the local vari
erickung1
2016/09/13 03:52:53
Done.
|
| + } |
| + |
| + if (buffer_message.has_front_discard_usec()) { |
| + has_discard = true; |
| + front_discard = |
| + base::TimeDelta::FromMicroseconds(buffer_message.front_discard_usec()); |
| + } |
| + if (buffer_message.has_back_discard_usec()) { |
| + has_discard = true; |
| + back_discard = |
| + base::TimeDelta::FromMicroseconds(buffer_message.back_discard_usec()); |
| + } |
| + |
| + if (has_discard) { |
| + buffer->set_discard_padding( |
| + ::media::DecoderBuffer::DiscardPadding(front_discard, back_discard)); |
| + } |
| + |
| + if (buffer_message.has_splice_timestamp_usec()) { |
| + buffer->set_splice_timestamp(base::TimeDelta::FromMicroseconds( |
| + buffer_message.splice_timestamp_usec())); |
| + } |
| + |
| + if (buffer_message.has_side_data()) { |
| + buffer->CopySideDataFrom( |
| + reinterpret_cast<const uint8_t*>(buffer_message.side_data().c_str()), |
|
miu
2016/09/08 01:07:34
Don't use c_str() here. Use data() instead.
erickung1
2016/09/13 03:52:52
Done.
|
| + buffer_message.side_data().size()); |
| + } |
| + |
| + return buffer; |
| +} |
| + |
| +void SerializeDecryptConfig(const ::media::DecryptConfig* decrypt_config, |
|
miu
2016/09/08 01:07:34
nit: Please pass by const-reference instead of con
erickung1
2016/09/13 03:52:53
Done.
|
| + pb::DecryptConfig* config_message) { |
| + DCHECK(config_message); |
| + |
| + config_message->set_key_id(decrypt_config->key_id()); |
| + config_message->set_iv(decrypt_config->iv()); |
| + |
| + for (const auto& entry : decrypt_config->subsamples()) { |
| + pb::DecryptConfig::SubSample* sub_sample = |
| + config_message->add_sub_samples(); |
| + sub_sample->set_clear_bytes(entry.clear_bytes); |
| + sub_sample->set_cypher_bytes(entry.cypher_bytes); |
| + } |
| +} |
| + |
| +void SerializeDecoderBuffer( |
| + const scoped_refptr<::media::DecoderBuffer>& decoder_buffer, |
| + pb::DecoderBuffer* buffer_message) { |
| + if (decoder_buffer->end_of_stream()) { |
| + buffer_message->set_is_eos(true); |
| + return; |
| + } |
| + |
| + VLOG(2) << "timestamp:" << decoder_buffer->timestamp().InMicroseconds() |
| + << " duration:" << decoder_buffer->duration().InMicroseconds(); |
| + buffer_message->set_timestamp_usec( |
| + decoder_buffer->timestamp().InMicroseconds()); |
| + buffer_message->set_duration_usec( |
| + decoder_buffer->duration().InMicroseconds()); |
| + buffer_message->set_is_key_frame(decoder_buffer->is_key_frame()); |
| + |
| + if (decoder_buffer->decrypt_config()) { |
| + SerializeDecryptConfig(decoder_buffer->decrypt_config(), |
| + buffer_message->mutable_decrypt_config()); |
| + } |
| + |
| + buffer_message->set_front_discard_usec( |
| + decoder_buffer->discard_padding().first.InMicroseconds()); |
| + buffer_message->set_back_discard_usec( |
| + decoder_buffer->discard_padding().second.InMicroseconds()); |
| + buffer_message->set_splice_timestamp_usec( |
| + decoder_buffer->splice_timestamp().InMicroseconds()); |
| + |
| + if (decoder_buffer->side_data_size()) { |
| + buffer_message->set_side_data(decoder_buffer->side_data(), |
| + decoder_buffer->side_data_size()); |
| + } |
| +} |
| + |
| +} // namespace |
| + |
| +DecoderBufferSegment::DecoderBufferSegment( |
| + const scoped_refptr<::media::DecoderBuffer>& decoder_buffer) |
| + : decoder_buffer_(decoder_buffer) {} |
| + |
| +DecoderBufferSegment::~DecoderBufferSegment() = default; |
| + |
| +// static |
| +scoped_refptr<DecoderBufferSegment> DecoderBufferSegment::FromBuffer( |
| + const uint8_t* data, |
| + uint32_t size) { |
| + uint32_t pos = 0; |
| + |
| + int payload_version = data[pos++]; |
|
miu
2016/09/08 01:07:34
In Chrome, please use base::BigEndianReader instea
erickung1
2016/09/13 03:52:52
Done.
|
| + DCHECK_EQ(payload_version, 0); |
| + |
| + DCHECK(size > pos + kProtoBufferHeaderSize); |
| + uint32_t proto_size = (data[pos] << 8) | data[pos + 1]; |
| + pos += kProtoBufferHeaderSize; |
| + |
| + DCHECK(size > pos + proto_size); |
| + pb::DecoderBuffer segment; |
| + if (!segment.ParseFromArray(data + pos, proto_size)) { |
| + LOG(ERROR) << "Bad proto buffer"; |
| + return nullptr; |
| + } |
| + pos += proto_size; |
| + |
| + DCHECK(size >= pos + kDataBufferHeaderSize); |
| + uint32_t buffer_size = (data[pos] << 24) | (data[pos + 1] << 16) | |
| + (data[pos + 2] << 8) | data[pos + 3]; |
| + pos += kDataBufferHeaderSize; |
| + |
| + DCHECK(size == pos + buffer_size); |
| + // Create DecoderBuffer first to allocate buffer. |
| + scoped_refptr<DecoderBuffer> decoder_buffer = |
| + DecoderBuffer::CopyFrom(data + pos, buffer_size); |
| + // Deserialize proto buffer. It passes the pre allocated DecoderBuffer into |
| + // the function because the proto buffer may overwrite DecoderBuffer since it |
| + // may be EOS buffer. |
| + decoder_buffer = DeserializeDecoderBuffer(segment, std::move(decoder_buffer)); |
| + |
| + return new DecoderBufferSegment(decoder_buffer); |
| +} |
| + |
| +uint32_t DecoderBufferSegment::ToBuffer(std::vector<uint8_t>* buffer) { |
| + DCHECK(buffer); |
| + pb::DecoderBuffer decoder_buffer_data; |
|
miu
2016/09/08 01:07:34
naming nit: How about decoder_buffer_message?
erickung1
2016/09/13 03:52:53
Done.
|
| + SerializeDecoderBuffer(decoder_buffer_, &decoder_buffer_data); |
| + |
| + size_t decoder_buffer_size = |
| + decoder_buffer_->end_of_stream() ? 0 : decoder_buffer_->data_size(); |
| + size_t size = kPayloadVersionFieldSize + kProtoBufferHeaderSize + |
| + decoder_buffer_data.ByteSize() + kDataBufferHeaderSize + |
| + decoder_buffer_size; |
| + buffer->resize(size); |
| + int pos = 0; |
|
miu
2016/09/08 01:07:34
Like above, please use base::BigEndianWriter here:
erickung1
2016/09/13 03:52:52
Done.
|
| + // payload_version, default is 0. |
| + (*buffer)[pos++] = 0; |
| + // Length of protobuf-encoded segment. |
| + (*buffer)[pos++] = (decoder_buffer_data.ByteSize() >> 8) & 0xff; |
| + (*buffer)[pos++] = decoder_buffer_data.ByteSize() & 0xff; |
| + // Protobuf-encoded DecoderBuffer. |
| + DCHECK(decoder_buffer_data.SerializeToArray((*buffer).data() + pos, |
|
miu
2016/09/08 01:07:34
FYI--DCHECKs() do not evaluate in release builds.
erickung1
2016/09/13 03:52:52
Done.
|
| + decoder_buffer_data.ByteSize())); |
| + pos += decoder_buffer_data.ByteSize(); |
| + // Length of data segment. |
| + (*buffer)[pos++] = (decoder_buffer_size >> 24) & 0xff; |
| + (*buffer)[pos++] = (decoder_buffer_size >> 16) & 0xff; |
| + (*buffer)[pos++] = (decoder_buffer_size >> 8) & 0xff; |
| + (*buffer)[pos++] = decoder_buffer_size & 0xff; |
| + // DecoderBuffer frame data. |
| + if (decoder_buffer_size) { |
| + std::copy(decoder_buffer_->data(), |
| + decoder_buffer_->data() + decoder_buffer_->data_size(), |
| + (*buffer).data() + pos); |
| + } |
| + return size; |
| +} |
| + |
| +} // namespace remoting |
| +} // namespace media |