Skip to content

Commit

Permalink
[media] Support DecoderBufferAllocator (#4348)
Browse files Browse the repository at this point in the history
This is to avoid OOM on low-end devices. The current design is the same
as Cobalt C25, and will be revisited once Cobalt is rebased to m126+.

b/374822966
  • Loading branch information
borongc authored Nov 8, 2024
1 parent e7cd5a7 commit ae843b4
Show file tree
Hide file tree
Showing 13 changed files with 179 additions and 67 deletions.
44 changes: 44 additions & 0 deletions media/base/decoder_buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,23 @@

namespace media {

#if BUILDFLAG(USE_STARBOARD_MEDIA)
namespace {
DecoderBuffer::Allocator* s_allocator = nullptr;
} // namespace

// static
DecoderBuffer::Allocator* DecoderBuffer::Allocator::GetInstance() {
DCHECK(s_allocator);
return s_allocator;
}

// static
void DecoderBuffer::Allocator::Set(Allocator* allocator) {
s_allocator = allocator;
}
#endif // BUILDFLAG(USE_STARBOARD_MEDIA)

DecoderBuffer::TimeInfo::TimeInfo() = default;
DecoderBuffer::TimeInfo::~TimeInfo() = default;
DecoderBuffer::TimeInfo::TimeInfo(const TimeInfo&) = default;
Expand All @@ -35,7 +52,11 @@ DecoderBuffer::DecoderBuffer(const uint8_t* data,

Initialize();

#if BUILDFLAG(USE_STARBOARD_MEDIA)
memcpy(data_, data, size_);
#else // BUILDFLAG(USE_STARBOARD_MEDIA)
memcpy(data_.get(), data, size_);
#endif // BUILDFLAG(USE_STARBOARD_MEDIA)

if (!side_data) {
CHECK_EQ(side_data_size, 0u);
Expand All @@ -47,7 +68,13 @@ DecoderBuffer::DecoderBuffer(const uint8_t* data,
}

DecoderBuffer::DecoderBuffer(std::unique_ptr<uint8_t[]> data, size_t size)
#if BUILDFLAG(USE_STARBOARD_MEDIA)
: size_(size) {
// TODO(b/378106931): revisit DecoderBufferAllocator once rebase to m126+
}
#else // BUILDFLAG(USE_STARBOARD_MEDIA)
: data_(std::move(data)), size_(size) {}
#endif // BUILDFLAG(USE_STARBOARD_MEDIA)

DecoderBuffer::DecoderBuffer(base::ReadOnlySharedMemoryMapping mapping,
size_t size)
Expand All @@ -62,12 +89,29 @@ DecoderBuffer::DecoderBuffer(std::unique_ptr<ExternalMemory> external_memory)
external_memory_(std::move(external_memory)) {}

DecoderBuffer::~DecoderBuffer() {
#if BUILDFLAG(USE_STARBOARD_MEDIA)
DCHECK(s_allocator);
s_allocator->Free(data_, allocated_size_);
#else // BUILDFLAG(USE_STARBOARD_MEDIA)
data_.reset();
#endif // BUILDFLAG(USE_STARBOARD_MEDIA)
side_data_.reset();
}

void DecoderBuffer::Initialize() {
#if BUILDFLAG(USE_STARBOARD_MEDIA)
DCHECK(s_allocator);
DCHECK(!data_);

int alignment = s_allocator->GetBufferAlignment();
int padding = s_allocator->GetBufferPadding();
allocated_size_ = size_ + padding;
data_ = static_cast<uint8_t*>(s_allocator->Allocate(allocated_size_,
alignment));
memset(data_ + size_, 0, padding);
#else // BUILDFLAG(USE_STARBOARD_MEDIA)
data_.reset(new uint8_t[size_]);
#endif // BUILDFLAG(USE_STARBOARD_MEDIA)
if (side_data_size_ > 0)
side_data_.reset(new uint8_t[side_data_size_]);
}
Expand Down
52 changes: 52 additions & 0 deletions media/base/decoder_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
#include "media/base/media_export.h"
#include "media/base/timestamp_constants.h"

#if BUILDFLAG(USE_STARBOARD_MEDIA)
#include "starboard/media.h"
#endif // BUILDFLAG(USE_STARBOARD_MEDIA)

namespace media {

// A specialized buffer for interfacing with audio / video decoders.
Expand Down Expand Up @@ -73,6 +77,36 @@ class MEDIA_EXPORT DecoderBuffer
DiscardPadding discard_padding;
};

#if BUILDFLAG(USE_STARBOARD_MEDIA)
class Allocator {
public:
static Allocator* GetInstance();

// The function should never return nullptr. It may terminate the app on
// allocation failure.
virtual void* Allocate(size_t size, size_t alignment) = 0;
virtual void Free(void* p, size_t size) = 0;

virtual int GetAudioBufferBudget() const = 0;
virtual int GetBufferAlignment() const = 0;
virtual int GetBufferPadding() const = 0;
virtual base::TimeDelta GetBufferGarbageCollectionDurationThreshold() const = 0;
virtual int GetProgressiveBufferBudget(SbMediaVideoCodec codec,
int resolution_width,
int resolution_height,
int bits_per_pixel) const = 0;
virtual int GetVideoBufferBudget(SbMediaVideoCodec codec,
int resolution_width,
int resolution_height,
int bits_per_pixel) const = 0;

protected:
~Allocator() {}

static void Set(Allocator* allocator);
};
#endif // BUILDFLAG(USE_STARBOARD_MEDIA)

// Allocates buffer with |size| >= 0. |is_key_frame_| will default to false.
explicit DecoderBuffer(size_t size);

Expand Down Expand Up @@ -166,22 +200,30 @@ class MEDIA_EXPORT DecoderBuffer

const uint8_t* data() const {
DCHECK(!end_of_stream());
#if BUILDFLAG(USE_STARBOARD_MEDIA)
return data_;
#else // BUILDFLAG(USE_STARBOARD_MEDIA)
if (read_only_mapping_.IsValid())
return read_only_mapping_.GetMemoryAs<const uint8_t>();
if (writable_mapping_.IsValid())
return writable_mapping_.GetMemoryAs<const uint8_t>();
if (external_memory_)
return external_memory_->span().data();
return data_.get();
#endif // BUILDFLAG(USE_STARBOARD_MEDIA)
}

// TODO(sandersd): Remove writable_data(). https://crbug.com/834088
uint8_t* writable_data() const {
#if BUILDFLAG(USE_STARBOARD_MEDIA)
return data_;
#else // BUILDFLAG(USE_STARBOARD_MEDIA)
DCHECK(!end_of_stream());
DCHECK(!read_only_mapping_.IsValid());
DCHECK(!writable_mapping_.IsValid());
DCHECK(!external_memory_);
return data_.get();
#endif // BUILDFLAG(USE_STARBOARD_MEDIA)
}

size_t data_size() const {
Expand Down Expand Up @@ -222,10 +264,14 @@ class MEDIA_EXPORT DecoderBuffer
}

// If there's no data in this buffer, it represents end of stream.
#if BUILDFLAG(USE_STARBOARD_MEDIA)
bool end_of_stream() const { return !data_; }
#else // BUILDFLAG(USE_STARBOARD_MEDIA)
bool end_of_stream() const {
return !read_only_mapping_.IsValid() && !writable_mapping_.IsValid() &&
!external_memory_ && !data_;
}
#endif // BUILDFLAG(USE_STARBOARD_MEDIA)

bool is_key_frame() const {
DCHECK(!end_of_stream());
Expand Down Expand Up @@ -271,8 +317,14 @@ class MEDIA_EXPORT DecoderBuffer

virtual ~DecoderBuffer();

#if BUILDFLAG(USE_STARBOARD_MEDIA)
// Encoded data, allocated from DecoderBuffer::Allocator.
uint8_t* data_ = nullptr;
size_t allocated_size_ = 0;
#else // BUILDFLAG(USE_STARBOARD_MEDIA)
// Encoded data, if it is stored on the heap.
std::unique_ptr<uint8_t[]> data_;
#endif // BUILDFLAG(USE_STARBOARD_MEDIA)

private:
TimeInfo time_info_;
Expand Down
10 changes: 10 additions & 0 deletions media/base/media_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
#include "ui/gfx/color_space.h"
#include "url/gurl.h"

#if BUILDFLAG(USE_STARBOARD_MEDIA)
#include "media/starboard/decoder_buffer_allocator.h"
#endif // BUILDFLAG(USE_STARBOARD_MEDIA)

namespace media {

class MediaClient;
Expand Down Expand Up @@ -56,6 +60,12 @@ class MEDIA_EXPORT MediaClient {
// Optionally returns audio renderer algorithm parameters.
virtual absl::optional<::media::AudioRendererAlgorithmParameters>
GetAudioRendererAlgorithmParameters(AudioParameters audio_parameters) = 0;

#if BUILDFLAG(USE_STARBOARD_MEDIA)
private:
// TODO(b/326497953): Support Suspend() and Resume().
DecoderBufferAllocator decoder_buffer_allocator_;
#endif // BUILDFLAG(USE_STARBOARD_MEDIA)
};

} // namespace media
Expand Down
6 changes: 6 additions & 0 deletions media/formats/mp4/mp4_stream_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1011,9 +1011,15 @@ ParseResult MP4StreamParser::EnqueueSample(BufferQueueMap* buffers) {
StreamParserBuffer::Type buffer_type = audio ? DemuxerStream::AUDIO :
DemuxerStream::VIDEO;

#if BUILDFLAG(USE_STARBOARD_MEDIA)
scoped_refptr<StreamParserBuffer> stream_buf =
StreamParserBuffer::CopyFrom(&frame_buf[0], frame_buf.size(), is_keyframe,
buffer_type, runs_->track_id());
#else // BUILDFLAG(USE_STARBOARD_MEDIA)
auto stream_buf = StreamParserBuffer::FromExternalMemory(
std::make_unique<ExternalMemoryAdapter>(std::move(frame_buf)),
is_keyframe, buffer_type, runs_->track_id());
#endif // BUILDFLAG(USE_STARBOARD_MEDIA)

if (decrypt_config)
stream_buf->set_decrypt_config(std::move(decrypt_config));
Expand Down
14 changes: 10 additions & 4 deletions media/starboard/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ source_set("starboard") {
# TODO(b/375069564): Revisit CValStats
"COBALT_MEDIA_ENABLE_CVAL=0",

# TODO(b/374822966): Revisit DecoderBuffer budget
"COBALT_MEDIA_ENABLE_DECODE_BUFFER_BUDGET=0",

# TODO(b/375070492): Revisit decode-to-texture
"COBALT_MEDIA_ENABLE_DECODE_TARGET_PROVIDER=0",

Expand Down Expand Up @@ -57,12 +54,18 @@ source_set("starboard") {
]

sources = [
"bidirectional_fit_reuse_allocator.cc",
"bidirectional_fit_reuse_allocator.h",
"decoder_buffer_allocator.cc",
"decoder_buffer_allocator.h",
"decoder_buffer_memory_info.h",
"sbplayer_bridge.cc",
"sbplayer_bridge.h",
"sbplayer_interface.cc",
"sbplayer_interface.h",
"sbplayer_set_bounds_helper.cc",
"sbplayer_set_bounds_helper.h",
"starboard_memory_allocator.h",
"starboard_renderer.cc",
"starboard_renderer.h",
"starboard_utils.cc",
Expand All @@ -82,7 +85,10 @@ source_set("starboard") {

source_set("unit_tests") {
testonly = true
sources = [ "starboard_utils_test.cc" ]
sources = [
"bidirectional_fit_reuse_allocator_test.cc",
"starboard_utils_test.cc",
]
configs += [ "//media:media_config" ]
deps = [
"//base",
Expand Down
17 changes: 10 additions & 7 deletions media/starboard/bidirectional_fit_reuse_allocator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,28 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#include "cobalt/media/bidirectional_fit_reuse_allocator.h"
#include "media/starboard/bidirectional_fit_reuse_allocator.h"

#include <algorithm>

#include "base/check.h"
#include "base/logging.h"
#include "starboard/common/pointer_arithmetic.h"
#include "starboard/types.h"

namespace cobalt {
namespace media {

BidirectionalFitReuseAllocator::BidirectionalFitReuseAllocator(
Allocator* fallback_allocator, std::size_t initial_capacity,
Allocator* fallback_allocator,
std::size_t initial_capacity,
std::size_t small_allocation_threshold,
std::size_t allocation_increment /*= 0*/, std::size_t max_capacity /* =0 */
std::size_t allocation_increment /*= 0*/,
std::size_t max_capacity /* =0 */
)
: ReuseAllocatorBase(fallback_allocator, initial_capacity,
allocation_increment, max_capacity),
: ReuseAllocatorBase(fallback_allocator,
initial_capacity,
allocation_increment,
max_capacity),
small_allocation_threshold_(small_allocation_threshold) {}

starboard::common::ReuseAllocatorBase::FreeBlockSet::iterator
Expand Down Expand Up @@ -64,4 +68,3 @@ BidirectionalFitReuseAllocator::FindFreeBlock(std::size_t size,
}

} // namespace media
} // namespace cobalt
41 changes: 19 additions & 22 deletions media/starboard/bidirectional_fit_reuse_allocator.h
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
/*
* Copyright 2017 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef COBALT_MEDIA_BIDIRECTIONAL_FIT_REUSE_ALLOCATOR_H_
#define COBALT_MEDIA_BIDIRECTIONAL_FIT_REUSE_ALLOCATOR_H_
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef MEDIA_STARBOARD_BIDIRECTIONAL_FIT_REUSE_ALLOCATOR_H_
#define MEDIA_STARBOARD_BIDIRECTIONAL_FIT_REUSE_ALLOCATOR_H_

#include "starboard/common/reuse_allocator_base.h"
#include "starboard/configuration.h"

namespace cobalt {
namespace media {

// This class uses first-fit allocation strategy to allocate memory block whose
Expand All @@ -41,7 +38,8 @@ class BidirectionalFitReuseAllocator
std::size_t allocation_increment = 0,
std::size_t max_capacity = 0);

FreeBlockSet::iterator FindFreeBlock(std::size_t size, std::size_t alignment,
FreeBlockSet::iterator FindFreeBlock(std::size_t size,
std::size_t alignment,
FreeBlockSet::iterator begin,
FreeBlockSet::iterator end,
bool* allocate_from_front) override;
Expand All @@ -51,6 +49,5 @@ class BidirectionalFitReuseAllocator
};

} // namespace media
} // namespace cobalt

#endif // COBALT_MEDIA_BIDIRECTIONAL_FIT_REUSE_ALLOCATOR_H_
#endif // MEDIA_STARBOARD_BIDIRECTIONAL_FIT_REUSE_ALLOCATOR_H_
3 changes: 2 additions & 1 deletion media/starboard/bidirectional_fit_reuse_allocator_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@
* limitations under the License.
*/

#include "cobalt/media/bidirectional_fit_reuse_allocator.h"
#include "media/starboard/bidirectional_fit_reuse_allocator.h"

#include <memory>

#include "starboard/common/fixed_no_free_allocator.h"
#include "starboard/common/pointer_arithmetic.h"
#include "starboard/configuration.h"
#include "starboard/memory.h"
#include "starboard/types.h"
#include "testing/gtest/include/gtest/gtest.h"

Expand Down
Loading

0 comments on commit ae843b4

Please sign in to comment.