blob: 34bb46074c4415953161a2c0efa506de0f1fac6b [file] [log] [blame]
// Copyright (c) 2012 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 "cobalt/media/base/decoder_buffer.h"
#include <vector>
#include "starboard/media.h"
#include "starboard/memory.h"
namespace cobalt {
namespace media {
namespace {
SbMediaType DemuxerStreamTypeToSbMediaType(DemuxerStream::Type type) {
switch (type) {
case DemuxerStream::AUDIO:
return kSbMediaTypeAudio;
case DemuxerStream::VIDEO:
return kSbMediaTypeVideo;
case DemuxerStream::UNKNOWN:
case DemuxerStream::TEXT:
case DemuxerStream::NUM_TYPES:
break;
}
NOTREACHED();
return kSbMediaTypeAudio;
}
} // namespace
DecoderBuffer::ScopedAllocatorPtr::ScopedAllocatorPtr(Allocator* allocator,
Type type, size_t size)
: allocator_(allocator), type_(type) {
if (size > 0) {
DCHECK(allocator_);
int padding = SbMediaGetBufferPadding(DemuxerStreamTypeToSbMediaType(type));
int alignment =
SbMediaGetBufferAlignment(DemuxerStreamTypeToSbMediaType(type));
allocations_ = allocator_->Allocate(size + padding, alignment,
static_cast<intptr_t>(type));
static bool logged_warning = false;
if (padding > 0) {
if (allocations_.number_of_buffers() > 0) {
const int kMaxPadding = 1024;
if (padding > kMaxPadding) {
if (!logged_warning) {
LOG(WARNING) << "Media buffer padding is larger than "
<< kMaxPadding
<< ", this will cause extra allocations.";
logged_warning = true;
}
std::vector<char> zeros(padding + 1, 0);
allocations_.Write(size, zeros.data(), padding);
} else {
char zeros[kMaxPadding + 1] = {0};
allocations_.Write(size, zeros, padding);
}
allocations_.ShrinkTo(size);
}
}
}
}
DecoderBuffer::ScopedAllocatorPtr::~ScopedAllocatorPtr() {
// |allocator_| can be NULL for EOS buffer.
if (allocator_) {
allocator_->Free(allocations_);
}
}
DecoderBuffer::DecoderBuffer() : data_(NULL, DemuxerStream::UNKNOWN, 0) {}
DecoderBuffer::DecoderBuffer(Allocator* allocator, Type type, size_t size)
: data_(allocator, type, size) {}
DecoderBuffer::DecoderBuffer(Allocator* allocator, Type type,
const uint8_t* data, size_t size,
const uint8_t* side_data, size_t side_data_size)
: data_(allocator, type, size), side_data_size_(side_data_size) {
if (!data) {
CHECK_EQ(size, 0u);
return;
}
if (allocations().number_of_buffers()) {
allocations().Write(0, data, size);
}
if (side_data_size_ > 0) {
DCHECK(side_data);
side_data_.reset(new uint8_t[side_data_size_]);
SbMemoryCopy(side_data_.get(), side_data, side_data_size_);
}
}
DecoderBuffer::DecoderBuffer(Allocator* allocator, Type type,
Allocator::Allocations allocations,
const uint8_t* side_data, size_t side_data_size)
: data_(allocator, type, allocations.size()),
side_data_size_(side_data_size) {
int offset = 0;
for (int i = 0; i < allocations.number_of_buffers(); ++i) {
this->allocations().Write(offset, allocations.buffers()[i],
allocations.buffer_sizes()[i]);
offset += allocations.buffer_sizes()[i];
}
if (side_data_size_ > 0) {
side_data_.reset(new uint8_t[side_data_size_]);
SbMemoryCopy(side_data_.get(), side_data, side_data_size_);
}
}
DecoderBuffer::~DecoderBuffer() {}
// static
scoped_refptr<DecoderBuffer> DecoderBuffer::Create(Allocator* allocator,
Type type, size_t size) {
DCHECK_GT(size, 0);
scoped_refptr<DecoderBuffer> decoder_buffer =
new DecoderBuffer(allocator, type, size);
if (decoder_buffer->has_data()) {
return decoder_buffer;
}
return NULL;
}
// static
scoped_refptr<DecoderBuffer> DecoderBuffer::CopyFrom(Allocator* allocator,
Type type,
const uint8_t* data,
size_t data_size) {
// If you hit this CHECK you likely have a bug in a demuxer. Go fix it.
CHECK(data);
scoped_refptr<DecoderBuffer> decoder_buffer =
new DecoderBuffer(allocator, type, data, data_size, NULL, 0);
if (decoder_buffer->has_data()) {
return decoder_buffer;
}
return NULL;
}
// static
scoped_refptr<DecoderBuffer> DecoderBuffer::CopyFrom(
Allocator* allocator, Type type, const uint8_t* data, size_t data_size,
const uint8_t* side_data, size_t side_data_size) {
// If you hit this CHECK you likely have a bug in a demuxer. Go fix it.
CHECK(data);
CHECK(side_data);
scoped_refptr<DecoderBuffer> decoder_buffer = new DecoderBuffer(
allocator, type, data, data_size, side_data, side_data_size);
if (decoder_buffer->has_data() && decoder_buffer->has_side_data()) {
return decoder_buffer;
}
return NULL;
}
// static
scoped_refptr<DecoderBuffer> DecoderBuffer::CreateEOSBuffer() {
return base::WrapRefCounted(new DecoderBuffer);
}
const char* DecoderBuffer::GetTypeName() const {
switch (type()) {
case DemuxerStream::AUDIO:
return "audio";
case DemuxerStream::VIDEO:
return "video";
case DemuxerStream::TEXT:
return "text";
case DemuxerStream::UNKNOWN:
return "unknown";
case DemuxerStream::NUM_TYPES:
// Fall-through to NOTREACHED().
break;
}
NOTREACHED();
return "";
}
std::string DecoderBuffer::AsHumanReadableString() {
if (end_of_stream()) {
return "end of stream";
}
std::ostringstream s;
s << "type: " << GetTypeName()
<< " timestamp: " << timestamp_.InMicroseconds()
<< " duration: " << duration_.InMicroseconds() << " size: " << data_size()
<< " side_data_size: " << side_data_size_
<< " is_key_frame: " << is_key_frame_
<< " encrypted: " << (decrypt_config_ != NULL) << " discard_padding (ms): ("
<< discard_padding_.first.InMilliseconds() << ", "
<< discard_padding_.second.InMilliseconds() << ")";
if (decrypt_config_) s << " decrypt:" << (*decrypt_config_);
return s.str();
}
void DecoderBuffer::set_timestamp(base::TimeDelta timestamp) {
DCHECK(!end_of_stream());
timestamp_ = timestamp;
}
} // namespace media
} // namespace cobalt