blob: e5d245a2d84519310a20362d6003acba5fa639cc [file] [log] [blame]
// Copyright 2014 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 "chromecast/media/cma/ipc_streamer/decoder_buffer_base_marshaller.h"
#include "base/logging.h"
#include "chromecast/media/cma/base/decoder_buffer_base.h"
#include "chromecast/media/cma/ipc/media_message.h"
#include "chromecast/media/cma/ipc/media_message_type.h"
#include "chromecast/media/cma/ipc_streamer/decrypt_config_marshaller.h"
#include "media/base/decrypt_config.h"
namespace chromecast {
namespace media {
namespace {
const size_t kMaxFrameSize = 4 * 1024 * 1024;
class DecoderBufferFromMsg : public DecoderBufferBase {
public:
explicit DecoderBufferFromMsg(scoped_ptr<MediaMessage> msg);
void Initialize();
// DecoderBufferBase implementation.
base::TimeDelta timestamp() const override;
const uint8* data() const override;
uint8* writable_data() const override;
int data_size() const override;
const ::media::DecryptConfig* decrypt_config() const override;
bool end_of_stream() const override;
private:
~DecoderBufferFromMsg() override;
// Indicates whether this is an end of stream frame.
bool is_eos_;
// Frame timestamp.
base::TimeDelta pts_;
// CENC parameters.
scoped_ptr< ::media::DecryptConfig> decrypt_config_;
// Size of the frame.
int data_size_;
// Keeps the message since frame data is not copied.
scoped_ptr<MediaMessage> msg_;
uint8* data_;
DISALLOW_COPY_AND_ASSIGN(DecoderBufferFromMsg);
};
DecoderBufferFromMsg::DecoderBufferFromMsg(
scoped_ptr<MediaMessage> msg)
: msg_(msg.Pass()),
is_eos_(true),
data_(NULL) {
CHECK(msg_);
}
DecoderBufferFromMsg::~DecoderBufferFromMsg() {
}
void DecoderBufferFromMsg::Initialize() {
CHECK_EQ(msg_->type(), FrameMediaMsg);
CHECK(msg_->ReadPod(&is_eos_));
if (is_eos_)
return;
int64 pts_internal = 0;
CHECK(msg_->ReadPod(&pts_internal));
pts_ = base::TimeDelta::FromInternalValue(pts_internal);
bool has_decrypt_config = false;
CHECK(msg_->ReadPod(&has_decrypt_config));
if (has_decrypt_config)
decrypt_config_.reset(DecryptConfigMarshaller::Read(msg_.get()).release());
CHECK(msg_->ReadPod(&data_size_));
CHECK_GT(data_size_, 0);
CHECK_LT(data_size_, kMaxFrameSize);
// Get a pointer to the frame data inside the message.
// Avoid copying the frame data here.
data_ = static_cast<uint8*>(msg_->GetWritableBuffer(data_size_));
CHECK(data_);
if (decrypt_config_) {
uint32 subsample_total_size = 0;
for (size_t k = 0; k < decrypt_config_->subsamples().size(); k++) {
subsample_total_size += decrypt_config_->subsamples()[k].clear_bytes;
subsample_total_size += decrypt_config_->subsamples()[k].cypher_bytes;
}
CHECK_EQ(subsample_total_size, data_size_);
}
}
base::TimeDelta DecoderBufferFromMsg::timestamp() const {
return pts_;
}
const uint8* DecoderBufferFromMsg::data() const {
CHECK(msg_->IsSerializedMsgAvailable());
return data_;
}
uint8* DecoderBufferFromMsg::writable_data() const {
CHECK(msg_->IsSerializedMsgAvailable());
return data_;
}
int DecoderBufferFromMsg::data_size() const {
return data_size_;
}
const ::media::DecryptConfig* DecoderBufferFromMsg::decrypt_config() const {
return decrypt_config_.get();
}
bool DecoderBufferFromMsg::end_of_stream() const {
return is_eos_;
}
} // namespace
// static
void DecoderBufferBaseMarshaller::Write(
const scoped_refptr<DecoderBufferBase>& buffer,
MediaMessage* msg) {
CHECK(msg->WritePod(buffer->end_of_stream()));
if (buffer->end_of_stream())
return;
CHECK(msg->WritePod(buffer->timestamp().ToInternalValue()));
bool has_decrypt_config =
(buffer->decrypt_config() != NULL &&
buffer->decrypt_config()->iv().size() > 0);
CHECK(msg->WritePod(has_decrypt_config));
if (has_decrypt_config) {
// DecryptConfig may contain 0 subsamples if all content is encrypted.
// Map this case to a single fully-encrypted "subsample" for more consistent
// backend handling.
if (buffer->decrypt_config()->subsamples().empty()) {
std::vector< ::media::SubsampleEntry> encrypted_subsample_list(1);
encrypted_subsample_list[0].clear_bytes = 0;
encrypted_subsample_list[0].cypher_bytes = buffer->data_size();
::media::DecryptConfig full_sample_config(
buffer->decrypt_config()->key_id(),
buffer->decrypt_config()->iv(),
encrypted_subsample_list);
DecryptConfigMarshaller::Write(full_sample_config, msg);
} else {
DecryptConfigMarshaller::Write(*buffer->decrypt_config(), msg);
}
}
CHECK(msg->WritePod(buffer->data_size()));
CHECK(msg->WriteBuffer(buffer->data(), buffer->data_size()));
}
// static
scoped_refptr<DecoderBufferBase> DecoderBufferBaseMarshaller::Read(
scoped_ptr<MediaMessage> msg) {
scoped_refptr<DecoderBufferFromMsg> buffer(
new DecoderBufferFromMsg(msg.Pass()));
buffer->Initialize();
return buffer;
}
} // namespace media
} // namespace chromecast