Commit 65496f51 authored by Dan Sanders's avatar Dan Sanders Committed by Commit Bot

[media] Reland: Add interface for VDAs to Decode() media::DecoderBuffers.

Using DecoderBuffer removes the need to provided SharedMemoryHandles in
cases that SharedMemory is not already allocated (in particular, when
VDAs are used through MojoVideoDecoder+VdaVideoDecoder). Since
base::SharedMemory is not an interface, a new type is required, and
DecoderBuffer already implements a suitable interface for this use case.

This CL adds:
  - A VideoDecodeAccelerator::Decode() overload for decoding
    DecoderBuffers, which VDAs may optionally implement.
    Note that VdaVideoDecoder will require this, and therefore all VDAs
    will be updated to support DecoderBuffers over time.
  - Support for SHM in DecoderBuffer. This eases the transition by
    allowing BitstreamBuffers to be easily converted to equivalent
    DecoderBuffers.
  - An implementation of the new VideoDecodeAccelerator::Decode()
    overload in VTVideoDecodeAccelerator.
  - Calling the new overload from VdaVideoDecoder.

Originally landed as 4596c802. This
reland removes a DCHECK() in unaligned_shared_memory_unittest.cc so that
SHM is still allocated when DCHECKs are disabled.

Bug: 522298
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: Id5d6bb103070dfcb23e3db82c68d2ead23b9e3b5
Reviewed-on: https://chromium-review.googlesource.com/1028834
Commit-Queue: Dan Sanders <sandersd@chromium.org>
Reviewed-by: default avatarDale Curtis <dalecurtis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#553875}
parent 13590982
...@@ -246,6 +246,8 @@ source_set("base") { ...@@ -246,6 +246,8 @@ source_set("base") {
"time_delta_interpolator.h", "time_delta_interpolator.h",
"time_source.h", "time_source.h",
"timestamp_constants.h", "timestamp_constants.h",
"unaligned_shared_memory.cc",
"unaligned_shared_memory.h",
"user_input_monitor.cc", "user_input_monitor.cc",
"user_input_monitor.h", "user_input_monitor.h",
"video_codecs.cc", "video_codecs.cc",
...@@ -488,6 +490,7 @@ source_set("unit_tests") { ...@@ -488,6 +490,7 @@ source_set("unit_tests") {
"text_ranges_unittest.cc", "text_ranges_unittest.cc",
"text_renderer_unittest.cc", "text_renderer_unittest.cc",
"time_delta_interpolator_unittest.cc", "time_delta_interpolator_unittest.cc",
"unaligned_shared_memory_unittest.cc",
"user_input_monitor_unittest.cc", "user_input_monitor_unittest.cc",
"vector_math_unittest.cc", "vector_math_unittest.cc",
"video_codecs_unittest.cc", "video_codecs_unittest.cc",
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "media/base/bitstream_buffer.h" #include "media/base/bitstream_buffer.h"
#include "media/base/decrypt_config.h"
namespace media { namespace media {
BitstreamBuffer::BitstreamBuffer() BitstreamBuffer::BitstreamBuffer()
...@@ -24,6 +26,19 @@ BitstreamBuffer::BitstreamBuffer(const BitstreamBuffer& other) = default; ...@@ -24,6 +26,19 @@ BitstreamBuffer::BitstreamBuffer(const BitstreamBuffer& other) = default;
BitstreamBuffer::~BitstreamBuffer() = default; BitstreamBuffer::~BitstreamBuffer() = default;
scoped_refptr<DecoderBuffer> BitstreamBuffer::ToDecoderBuffer() const {
scoped_refptr<DecoderBuffer> buffer =
DecoderBuffer::FromSharedMemoryHandle(handle_, offset_, size_);
if (!buffer)
return nullptr;
buffer->set_timestamp(presentation_timestamp_);
if (!key_id_.empty()) {
buffer->set_decrypt_config(
DecryptConfig::CreateCencConfig(key_id_, iv_, subsamples_));
}
return buffer;
}
void BitstreamBuffer::SetDecryptionSettings( void BitstreamBuffer::SetDecryptionSettings(
const std::string& key_id, const std::string& key_id,
const std::string& iv, const std::string& iv,
......
...@@ -9,8 +9,10 @@ ...@@ -9,8 +9,10 @@
#include <stdint.h> #include <stdint.h>
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/shared_memory.h" #include "base/memory/shared_memory.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "media/base/decoder_buffer.h"
#include "media/base/decrypt_config.h" #include "media/base/decrypt_config.h"
#include "media/base/media_export.h" #include "media/base/media_export.h"
#include "media/base/timestamp_constants.h" #include "media/base/timestamp_constants.h"
...@@ -44,6 +46,15 @@ class MEDIA_EXPORT BitstreamBuffer { ...@@ -44,6 +46,15 @@ class MEDIA_EXPORT BitstreamBuffer {
~BitstreamBuffer(); ~BitstreamBuffer();
// Produce an equivalent DecoderBuffer. This consumes handle(), even if
// nullptr is returned.
//
// This method is only intended to be used by VDAs that are being converted to
// use DecoderBuffer.
//
// TODO(sandersd): Remove once all VDAs are converted.
scoped_refptr<DecoderBuffer> ToDecoderBuffer() const;
// TODO(crbug.com/813845): As this is only used by Android, include // TODO(crbug.com/813845): As this is only used by Android, include
// EncryptionMode and optional EncryptionPattern when updating for Android. // EncryptionMode and optional EncryptionPattern when updating for Android.
void SetDecryptionSettings(const std::string& key_id, void SetDecryptionSettings(const std::string& key_id,
......
...@@ -44,6 +44,13 @@ DecoderBuffer::DecoderBuffer(const uint8_t* data, ...@@ -44,6 +44,13 @@ DecoderBuffer::DecoderBuffer(const uint8_t* data,
memcpy(side_data_.get(), side_data, side_data_size_); memcpy(side_data_.get(), side_data, side_data_size_);
} }
DecoderBuffer::DecoderBuffer(std::unique_ptr<UnalignedSharedMemory> shm,
size_t size)
: size_(size),
side_data_size_(0),
shm_(std::move(shm)),
is_key_frame_(false) {}
DecoderBuffer::~DecoderBuffer() = default; DecoderBuffer::~DecoderBuffer() = default;
void DecoderBuffer::Initialize() { void DecoderBuffer::Initialize() {
...@@ -72,6 +79,17 @@ scoped_refptr<DecoderBuffer> DecoderBuffer::CopyFrom(const uint8_t* data, ...@@ -72,6 +79,17 @@ scoped_refptr<DecoderBuffer> DecoderBuffer::CopyFrom(const uint8_t* data,
new DecoderBuffer(data, data_size, side_data, side_data_size)); new DecoderBuffer(data, data_size, side_data, side_data_size));
} }
// static
scoped_refptr<DecoderBuffer> DecoderBuffer::FromSharedMemoryHandle(
const base::SharedMemoryHandle& handle,
off_t offset,
size_t size) {
auto shm = std::make_unique<UnalignedSharedMemory>(handle, true);
if (size == 0 || !shm->MapAt(offset, size))
return nullptr;
return base::WrapRefCounted(new DecoderBuffer(std::move(shm), size));
}
// static // static
scoped_refptr<DecoderBuffer> DecoderBuffer::CreateEOSBuffer() { scoped_refptr<DecoderBuffer> DecoderBuffer::CreateEOSBuffer() {
return base::WrapRefCounted(new DecoderBuffer(NULL, 0, NULL, 0)); return base::WrapRefCounted(new DecoderBuffer(NULL, 0, NULL, 0));
......
...@@ -16,11 +16,13 @@ ...@@ -16,11 +16,13 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/aligned_memory.h" #include "base/memory/aligned_memory.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/shared_memory_handle.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "media/base/decrypt_config.h" #include "media/base/decrypt_config.h"
#include "media/base/media_export.h" #include "media/base/media_export.h"
#include "media/base/timestamp_constants.h" #include "media/base/timestamp_constants.h"
#include "media/base/unaligned_shared_memory.h"
namespace media { namespace media {
...@@ -64,6 +66,19 @@ class MEDIA_EXPORT DecoderBuffer ...@@ -64,6 +66,19 @@ class MEDIA_EXPORT DecoderBuffer
const uint8_t* side_data, const uint8_t* side_data,
size_t side_data_size); size_t side_data_size);
// Create a DecoderBuffer where data() of |size| bytes resides within the
// memory referred to by |handle| at non-negative offset |offset|. The
// buffer's |is_key_frame_| will default to false.
//
// The shared memory will be mapped read-only.
//
// If mapping fails, nullptr will be returned. In all cases |handle| is
// consumed.
static scoped_refptr<DecoderBuffer> FromSharedMemoryHandle(
const base::SharedMemoryHandle& handle,
off_t offset,
size_t size);
// Create a DecoderBuffer indicating we've reached end of stream. // Create a DecoderBuffer indicating we've reached end of stream.
// //
// Calling any method other than end_of_stream() on the resulting buffer // Calling any method other than end_of_stream() on the resulting buffer
...@@ -94,11 +109,15 @@ class MEDIA_EXPORT DecoderBuffer ...@@ -94,11 +109,15 @@ class MEDIA_EXPORT DecoderBuffer
const uint8_t* data() const { const uint8_t* data() const {
DCHECK(!end_of_stream()); DCHECK(!end_of_stream());
if (shm_)
return static_cast<uint8_t*>(shm_->memory());
return data_.get(); return data_.get();
} }
// TODO(sandersd): Remove writable_data(). https://crbug.com/834088
uint8_t* writable_data() const { uint8_t* writable_data() const {
DCHECK(!end_of_stream()); DCHECK(!end_of_stream());
DCHECK(!shm_);
return data_.get(); return data_.get();
} }
...@@ -144,9 +163,7 @@ class MEDIA_EXPORT DecoderBuffer ...@@ -144,9 +163,7 @@ class MEDIA_EXPORT DecoderBuffer
} }
// If there's no data in this buffer, it represents end of stream. // If there's no data in this buffer, it represents end of stream.
bool end_of_stream() const { bool end_of_stream() const { return !shm_ && !data_; }
return data_ == NULL;
}
bool is_key_frame() const { bool is_key_frame() const {
DCHECK(!end_of_stream()); DCHECK(!end_of_stream());
...@@ -179,6 +196,9 @@ class MEDIA_EXPORT DecoderBuffer ...@@ -179,6 +196,9 @@ class MEDIA_EXPORT DecoderBuffer
size_t size, size_t size,
const uint8_t* side_data, const uint8_t* side_data,
size_t side_data_size); size_t side_data_size);
DecoderBuffer(std::unique_ptr<UnalignedSharedMemory> shm, size_t size);
virtual ~DecoderBuffer(); virtual ~DecoderBuffer();
private: private:
...@@ -189,6 +209,7 @@ class MEDIA_EXPORT DecoderBuffer ...@@ -189,6 +209,7 @@ class MEDIA_EXPORT DecoderBuffer
std::unique_ptr<uint8_t, base::AlignedFreeDeleter> data_; std::unique_ptr<uint8_t, base::AlignedFreeDeleter> data_;
size_t side_data_size_; size_t side_data_size_;
std::unique_ptr<uint8_t, base::AlignedFreeDeleter> side_data_; std::unique_ptr<uint8_t, base::AlignedFreeDeleter> side_data_;
std::unique_ptr<UnalignedSharedMemory> shm_;
std::unique_ptr<DecryptConfig> decrypt_config_; std::unique_ptr<DecryptConfig> decrypt_config_;
DiscardPadding discard_padding_; DiscardPadding discard_padding_;
bool is_key_frame_; bool is_key_frame_;
......
...@@ -5,9 +5,12 @@ ...@@ -5,9 +5,12 @@
#include "media/base/decoder_buffer.h" #include "media/base/decoder_buffer.h"
#include <stdint.h> #include <stdint.h>
#include <string.h>
#include <memory> #include <memory>
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/shared_memory.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -59,6 +62,55 @@ TEST(DecoderBufferTest, CopyFrom) { ...@@ -59,6 +62,55 @@ TEST(DecoderBufferTest, CopyFrom) {
EXPECT_FALSE(buffer3->is_key_frame()); EXPECT_FALSE(buffer3->is_key_frame());
} }
TEST(DecoderBufferTest, FromSharedMemoryHandle) {
const uint8_t kData[] = "hello";
const size_t kDataSize = arraysize(kData);
base::SharedMemory mem;
ASSERT_TRUE(mem.CreateAndMapAnonymous(kDataSize));
memcpy(mem.memory(), kData, kDataSize);
scoped_refptr<DecoderBuffer> buffer(
DecoderBuffer::FromSharedMemoryHandle(mem.TakeHandle(), 0, kDataSize));
ASSERT_TRUE(buffer.get());
EXPECT_EQ(buffer->data_size(), kDataSize);
EXPECT_EQ(0, memcmp(buffer->data(), kData, kDataSize));
EXPECT_FALSE(buffer->end_of_stream());
EXPECT_FALSE(buffer->is_key_frame());
}
TEST(DecoderBufferTest, FromSharedMemoryHandle_Unaligned) {
const uint8_t kData[] = "XXXhello";
const size_t kDataSize = arraysize(kData);
const off_t kDataOffset = 3;
base::SharedMemory mem;
ASSERT_TRUE(mem.CreateAndMapAnonymous(kDataSize));
memcpy(mem.memory(), kData, kDataSize);
scoped_refptr<DecoderBuffer> buffer(DecoderBuffer::FromSharedMemoryHandle(
mem.TakeHandle(), kDataOffset, kDataSize - kDataOffset));
ASSERT_TRUE(buffer.get());
EXPECT_EQ(buffer->data_size(), kDataSize - kDataOffset);
EXPECT_EQ(
0, memcmp(buffer->data(), kData + kDataOffset, kDataSize - kDataOffset));
EXPECT_FALSE(buffer->end_of_stream());
EXPECT_FALSE(buffer->is_key_frame());
}
TEST(DecoderBufferTest, FromSharedMemoryHandle_ZeroSize) {
const uint8_t kData[] = "hello";
const size_t kDataSize = arraysize(kData);
base::SharedMemory mem;
ASSERT_TRUE(mem.CreateAndMapAnonymous(kDataSize));
memcpy(mem.memory(), kData, kDataSize);
scoped_refptr<DecoderBuffer> buffer(
DecoderBuffer::FromSharedMemoryHandle(mem.TakeHandle(), 0, 0));
ASSERT_FALSE(buffer.get());
}
#if !defined(OS_ANDROID) #if !defined(OS_ANDROID)
TEST(DecoderBufferTest, PaddingAlignment) { TEST(DecoderBufferTest, PaddingAlignment) {
const uint8_t kData[] = "hello"; const uint8_t kData[] = "hello";
......
// Copyright 2018 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/base/unaligned_shared_memory.h"
#include <limits>
#include "base/logging.h"
#include "base/sys_info.h"
namespace media {
UnalignedSharedMemory::UnalignedSharedMemory(
const base::SharedMemoryHandle& handle,
bool read_only)
: shm_(handle, read_only), misalignment_(0) {}
UnalignedSharedMemory::~UnalignedSharedMemory() = default;
bool UnalignedSharedMemory::MapAt(off_t offset, size_t size) {
if (offset < 0) {
DLOG(ERROR) << "Invalid offset";
return false;
}
/* | | | | | | shm pages
* | offset (may exceed max size_t)
* |-----------| size
* |-| misalignment
* | adjusted offset
* |-------------| requested mapping
*/
// Note: result of % computation may be off_t or size_t, depending on the
// relative ranks of those types. In any case we assume that
// VMAllocationGranularity() fits in both types, so the final result does too.
size_t misalignment = offset % base::SysInfo::VMAllocationGranularity();
// Above this |size|, |size| + |misalignment| overflows.
size_t max_size = std::numeric_limits<size_t>::max() - misalignment;
if (size > max_size) {
DLOG(ERROR) << "Invalid size";
return false;
}
off_t adjusted_offset = offset - static_cast<off_t>(misalignment);
if (!shm_.MapAt(adjusted_offset, size + misalignment)) {
DLOG(ERROR) << "Failed to map shared memory";
return false;
}
misalignment_ = misalignment;
return true;
}
void* UnalignedSharedMemory::memory() const {
return static_cast<uint8_t*>(shm_.memory()) + misalignment_;
}
} // namespace media
// Copyright 2018 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.
#ifndef MEDIA_BASE_UNALIGNED_SHARED_MEMORY_H_
#define MEDIA_BASE_UNALIGNED_SHARED_MEMORY_H_
#include <stdint.h>
#include "base/macros.h"
#include "base/memory/shared_memory.h"
#include "media/base/media_export.h"
namespace media {
// Wrapper over base::SharedMemory that can be mapped at unaligned offsets.
class MEDIA_EXPORT UnalignedSharedMemory {
public:
UnalignedSharedMemory(const base::SharedMemoryHandle& handle, bool read_only);
~UnalignedSharedMemory();
bool MapAt(off_t offset, size_t size);
void* memory() const;
private:
base::SharedMemory shm_;
// Offset withing |shm_| memory that data has been mapped; strictly less than
// base::SysInfo::VMAllocationGranularity().
size_t misalignment_;
DISALLOW_COPY_AND_ASSIGN(UnalignedSharedMemory);
};
} // namespace media
#endif // MEDIA_BASE_UNALIGNED_SHARED_MEMORY_H_
// Copyright 2018 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/base/unaligned_shared_memory.h"
#include <stdint.h>
#include <string.h>
#include <limits>
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/shared_memory.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
namespace {
const uint8_t kUnalignedData[] = "XXXhello";
const size_t kUnalignedDataSize = arraysize(kUnalignedData);
const off_t kUnalignedOffset = 3;
const uint8_t kData[] = "hello";
const size_t kDataSize = arraysize(kData);
base::SharedMemoryHandle CreateHandle(const uint8_t* data, size_t size) {
base::SharedMemory shm;
EXPECT_TRUE(shm.CreateAndMapAnonymous(size));
memcpy(shm.memory(), data, size);
return shm.TakeHandle();
}
} // namespace
TEST(UnalignedSharedMemoryTest, CreateAndDestroy) {
auto handle = CreateHandle(kData, kDataSize);
UnalignedSharedMemory shm(handle, true);
}
TEST(UnalignedSharedMemoryTest, CreateAndDestroy_InvalidHandle) {
base::SharedMemoryHandle handle;
UnalignedSharedMemory shm(handle, true);
}
TEST(UnalignedSharedMemoryTest, Map) {
auto handle = CreateHandle(kData, kDataSize);
UnalignedSharedMemory shm(handle, true);
ASSERT_TRUE(shm.MapAt(0, kDataSize));
EXPECT_EQ(0, memcmp(shm.memory(), kData, kDataSize));
}
TEST(UnalignedSharedMemoryTest, Map_Unaligned) {
auto handle = CreateHandle(kUnalignedData, kUnalignedDataSize);
UnalignedSharedMemory shm(handle, true);
ASSERT_TRUE(shm.MapAt(kUnalignedOffset, kDataSize));
EXPECT_EQ(0, memcmp(shm.memory(), kData, kDataSize));
}
TEST(UnalignedSharedMemoryTest, Map_InvalidHandle) {
base::SharedMemoryHandle handle;
UnalignedSharedMemory shm(handle, true);
ASSERT_FALSE(shm.MapAt(1, kDataSize));
EXPECT_EQ(shm.memory(), nullptr);
}
TEST(UnalignedSharedMemoryTest, Map_NegativeOffset) {
auto handle = CreateHandle(kData, kDataSize);
UnalignedSharedMemory shm(handle, true);
ASSERT_FALSE(shm.MapAt(-1, kDataSize));
}
TEST(UnalignedSharedMemoryTest, Map_SizeOverflow) {
auto handle = CreateHandle(kData, kDataSize);
UnalignedSharedMemory shm(handle, true);
ASSERT_FALSE(shm.MapAt(1, std::numeric_limits<size_t>::max()));
}
TEST(UnalignedSharedMemoryTest, UnmappedIsNullptr) {
auto handle = CreateHandle(kData, kDataSize);
UnalignedSharedMemory shm(handle, true);
ASSERT_EQ(shm.memory(), nullptr);
}
} // namespace media
...@@ -362,41 +362,21 @@ void VdaVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer, ...@@ -362,41 +362,21 @@ void VdaVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
timestamps_.Put(bitstream_buffer_id, buffer->timestamp()); timestamps_.Put(bitstream_buffer_id, buffer->timestamp());
decode_cbs_[bitstream_buffer_id] = decode_cb; decode_cbs_[bitstream_buffer_id] = decode_cb;
// Copy data into shared memory. gpu_task_runner_->PostTask(
// FROM_HERE,
// TODO(sandersd): Change VDA interface to use BitstreamBuffer, which will base::BindOnce(&VdaVideoDecoder::DecodeOnGpuThread, gpu_weak_this_,
// eliminate this work. If necessary, BitstreamBuffer can take responsibility std::move(buffer), bitstream_buffer_id));
// for mapping and unmapping SHM. The old interface may need to exist as long
// as GpuVideoDecoder does, since it uses BitstreamBuffer for IPC.
size_t size = buffer->data_size();
base::SharedMemory mem;
if (!mem.CreateAndMapAnonymous(size)) {
DLOG(ERROR) << "Failed to map SHM with size " << size;
EnterErrorState();
return;
}
memcpy(mem.memory(), buffer->data(), size);
// Note: Once we take the handle, we must close it ourselves. Since Destroy()
// has not already been called, we can be sure that |gpu_weak_this_| will be
// valid.
BitstreamBuffer bitstream_buffer(bitstream_buffer_id, mem.TakeHandle(), size,
0, buffer->timestamp());
gpu_task_runner_->PostTask(FROM_HERE,
base::BindOnce(&VdaVideoDecoder::DecodeOnGpuThread,
gpu_weak_this_, bitstream_buffer));
} }
void VdaVideoDecoder::DecodeOnGpuThread(BitstreamBuffer bitstream_buffer) { void VdaVideoDecoder::DecodeOnGpuThread(scoped_refptr<DecoderBuffer> buffer,
int32_t bitstream_id) {
DVLOG(3) << __func__; DVLOG(3) << __func__;
DCHECK(gpu_task_runner_->BelongsToCurrentThread()); DCHECK(gpu_task_runner_->BelongsToCurrentThread());
if (!gpu_weak_vda_) { if (!gpu_weak_vda_)
base::SharedMemory::CloseHandle(bitstream_buffer.handle());
return; return;
}
vda_->Decode(bitstream_buffer); vda_->Decode(std::move(buffer), bitstream_id);
} }
void VdaVideoDecoder::Reset(const base::RepeatingClosure& reset_cb) { void VdaVideoDecoder::Reset(const base::RepeatingClosure& reset_cb) {
......
...@@ -131,7 +131,8 @@ class VdaVideoDecoder : public VideoDecoder, ...@@ -131,7 +131,8 @@ class VdaVideoDecoder : public VideoDecoder,
void DestroyOnGpuThread(); void DestroyOnGpuThread();
void InitializeOnGpuThread(); void InitializeOnGpuThread();
void InitializeDone(bool status); void InitializeDone(bool status);
void DecodeOnGpuThread(BitstreamBuffer bitstream_buffer); void DecodeOnGpuThread(scoped_refptr<DecoderBuffer> buffer,
int32_t bitstream_id);
void PictureReadyOnParentThread(Picture picture); void PictureReadyOnParentThread(Picture picture);
void NotifyEndOfBitstreamBufferOnParentThread(int32_t bitstream_buffer_id); void NotifyEndOfBitstreamBufferOnParentThread(int32_t bitstream_buffer_id);
void NotifyFlushDoneOnParentThread(); void NotifyFlushDoneOnParentThread();
......
...@@ -87,11 +87,6 @@ VideoDecodeAccelerator::Capabilities GetCapabilities() { ...@@ -87,11 +87,6 @@ VideoDecodeAccelerator::Capabilities GetCapabilities() {
return capabilities; return capabilities;
} }
void CloseShm(const BitstreamBuffer& bitstream) {
DCHECK(base::SharedMemory::IsHandleValid(bitstream.handle()));
base::SharedMemory::CloseHandle(bitstream.handle());
}
} // namespace } // namespace
class VdaVideoDecoderTest : public testing::Test { class VdaVideoDecoderTest : public testing::Test {
...@@ -111,9 +106,6 @@ class VdaVideoDecoderTest : public testing::Test { ...@@ -111,9 +106,6 @@ class VdaVideoDecoderTest : public testing::Test {
// In either case, vda_->Destroy() should be called once. // In either case, vda_->Destroy() should be called once.
EXPECT_CALL(*vda_, Destroy()); EXPECT_CALL(*vda_, Destroy());
// vda_->Decode() must close the shared memory handle.
ON_CALL(*vda_, Decode(_)).WillByDefault(Invoke(&CloseShm));
vdavd_.reset(new VdaVideoDecoder( vdavd_.reset(new VdaVideoDecoder(
task_runner, task_runner, task_runner, task_runner,
base::BindOnce(&VdaVideoDecoderTest::CreatePictureBufferManager, base::BindOnce(&VdaVideoDecoderTest::CreatePictureBufferManager,
...@@ -168,12 +160,11 @@ class VdaVideoDecoderTest : public testing::Test { ...@@ -168,12 +160,11 @@ class VdaVideoDecoderTest : public testing::Test {
} }
int32_t Decode(base::TimeDelta timestamp) { int32_t Decode(base::TimeDelta timestamp) {
BitstreamBuffer bitstream; int32_t bitstream_id = 0;
vdavd_->Decode(CreateDecoderBuffer(timestamp), decode_cb_.Get()); vdavd_->Decode(CreateDecoderBuffer(timestamp), decode_cb_.Get());
EXPECT_CALL(*vda_, Decode(_)).WillOnce(SaveArg<0>(&bitstream)); EXPECT_CALL(*vda_, Decode(_, _)).WillOnce(SaveArg<1>(&bitstream_id));
environment_.RunUntilIdle(); environment_.RunUntilIdle();
CloseShm(bitstream); return bitstream_id;
return bitstream.id();
} }
void NotifyEndOfBitstreamBuffer(int32_t bitstream_id) { void NotifyEndOfBitstreamBuffer(int32_t bitstream_id) {
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "base/sys_info.h"
#include "media/gpu/shared_memory_region.h" #include "media/gpu/shared_memory_region.h"
namespace media { namespace media {
...@@ -11,12 +10,7 @@ SharedMemoryRegion::SharedMemoryRegion(const base::SharedMemoryHandle& handle, ...@@ -11,12 +10,7 @@ SharedMemoryRegion::SharedMemoryRegion(const base::SharedMemoryHandle& handle,
off_t offset, off_t offset,
size_t size, size_t size,
bool read_only) bool read_only)
: shm_(handle, read_only), : shm_(handle, read_only), offset_(offset), size_(size) {}
offset_(offset),
size_(size),
alignment_size_(offset % base::SysInfo::VMAllocationGranularity()) {
DCHECK_GE(offset_, 0) << "Invalid offset: " << offset_;
}
SharedMemoryRegion::SharedMemoryRegion(const BitstreamBuffer& bitstream_buffer, SharedMemoryRegion::SharedMemoryRegion(const BitstreamBuffer& bitstream_buffer,
bool read_only) bool read_only)
...@@ -26,16 +20,11 @@ SharedMemoryRegion::SharedMemoryRegion(const BitstreamBuffer& bitstream_buffer, ...@@ -26,16 +20,11 @@ SharedMemoryRegion::SharedMemoryRegion(const BitstreamBuffer& bitstream_buffer,
read_only) {} read_only) {}
bool SharedMemoryRegion::Map() { bool SharedMemoryRegion::Map() {
if (offset_ < 0) { return shm_.MapAt(offset_, size_);
DVLOG(1) << "Invalid offset: " << offset_;
return false;
}
return shm_.MapAt(offset_ - alignment_size_, size_ + alignment_size_);
} }
void* SharedMemoryRegion::memory() { void* SharedMemoryRegion::memory() {
int8_t* addr = reinterpret_cast<int8_t*>(shm_.memory()); return shm_.memory();
return addr ? addr + alignment_size_ : nullptr;
} }
} // namespace media } // namespace media
...@@ -5,8 +5,9 @@ ...@@ -5,8 +5,9 @@
#ifndef MEDIA_GPU_SHARED_MEMORY_REGION_H_ #ifndef MEDIA_GPU_SHARED_MEMORY_REGION_H_
#define MEDIA_GPU_SHARED_MEMORY_REGION_H_ #define MEDIA_GPU_SHARED_MEMORY_REGION_H_
#include "base/memory/shared_memory.h" #include "base/memory/shared_memory_handle.h"
#include "media/base/bitstream_buffer.h" #include "media/base/bitstream_buffer.h"
#include "media/base/unaligned_shared_memory.h"
namespace media { namespace media {
...@@ -15,6 +16,10 @@ namespace media { ...@@ -15,6 +16,10 @@ namespace media {
// the value of |SysInfo::VMAllocationGranularity()|, the |offset| of a // the value of |SysInfo::VMAllocationGranularity()|, the |offset| of a
// SharedMemoryRegion needs not to be aligned, this class hides the details // SharedMemoryRegion needs not to be aligned, this class hides the details
// and returns the mapped address of the given offset. // and returns the mapped address of the given offset.
//
// TODO(sandersd): This is now a trivial wrapper around
// media::UnalignedSharedMemory. Switch all users over and delete
// SharedMemoryRegion.
class SharedMemoryRegion { class SharedMemoryRegion {
public: public:
// Creates a SharedMemoryRegion. // Creates a SharedMemoryRegion.
...@@ -43,10 +48,9 @@ class SharedMemoryRegion { ...@@ -43,10 +48,9 @@ class SharedMemoryRegion {
size_t size() const { return size_; } size_t size() const { return size_; }
private: private:
base::SharedMemory shm_; UnalignedSharedMemory shm_;
off_t offset_; off_t offset_;
size_t size_; size_t size_;
size_t alignment_size_;
DISALLOW_COPY_AND_ASSIGN(SharedMemoryRegion); DISALLOW_COPY_AND_ASSIGN(SharedMemoryRegion);
}; };
......
...@@ -623,20 +623,11 @@ bool VTVideoDecodeAccelerator::ConfigureDecoder() { ...@@ -623,20 +623,11 @@ bool VTVideoDecodeAccelerator::ConfigureDecoder() {
return true; return true;
} }
void VTVideoDecodeAccelerator::DecodeTask(const BitstreamBuffer& bitstream, void VTVideoDecodeAccelerator::DecodeTask(scoped_refptr<DecoderBuffer> buffer,
Frame* frame) { Frame* frame) {
DVLOG(2) << __func__ << "(" << frame->bitstream_id << ")"; DVLOG(2) << __func__ << "(" << frame->bitstream_id << ")";
DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
// Map the bitstream buffer.
SharedMemoryRegion memory(bitstream, true);
if (!memory.Map()) {
DLOG(ERROR) << "Failed to map bitstream buffer";
NotifyError(PLATFORM_FAILURE, SFT_PLATFORM_ERROR);
return;
}
const uint8_t* buf = static_cast<uint8_t*>(memory.memory());
// NALUs are stored with Annex B format in the bitstream buffer (start codes), // NALUs are stored with Annex B format in the bitstream buffer (start codes),
// but VideoToolbox expects AVC format (length headers), so we must rewrite // but VideoToolbox expects AVC format (length headers), so we must rewrite
// the data. // the data.
...@@ -645,7 +636,7 @@ void VTVideoDecodeAccelerator::DecodeTask(const BitstreamBuffer& bitstream, ...@@ -645,7 +636,7 @@ void VTVideoDecodeAccelerator::DecodeTask(const BitstreamBuffer& bitstream,
// record parameter sets for VideoToolbox initialization. // record parameter sets for VideoToolbox initialization.
size_t data_size = 0; size_t data_size = 0;
std::vector<H264NALU> nalus; std::vector<H264NALU> nalus;
parser_.SetStream(buf, memory.size()); parser_.SetStream(buffer->data(), buffer->data_size());
H264NALU nalu; H264NALU nalu;
while (true) { while (true) {
H264Parser::Result result = parser_.AdvanceToNextNALU(&nalu); H264Parser::Result result = parser_.AdvanceToNextNALU(&nalu);
...@@ -998,25 +989,28 @@ void VTVideoDecodeAccelerator::FlushDone(TaskType type) { ...@@ -998,25 +989,28 @@ void VTVideoDecodeAccelerator::FlushDone(TaskType type) {
} }
void VTVideoDecodeAccelerator::Decode(const BitstreamBuffer& bitstream) { void VTVideoDecodeAccelerator::Decode(const BitstreamBuffer& bitstream) {
DVLOG(2) << __func__ << "(" << bitstream.id() << ")"; Decode(bitstream.ToDecoderBuffer(), bitstream.id());
}
void VTVideoDecodeAccelerator::Decode(scoped_refptr<DecoderBuffer> buffer,
int32_t bitstream_id) {
DVLOG(2) << __func__ << "(" << bitstream_id << ")";
DCHECK(gpu_task_runner_->BelongsToCurrentThread()); DCHECK(gpu_task_runner_->BelongsToCurrentThread());
if (bitstream.id() < 0) { if (!buffer || bitstream_id < 0) {
DLOG(ERROR) << "Invalid bitstream, id: " << bitstream.id(); DLOG(ERROR) << "Invalid bitstream, id: " << bitstream_id;
if (base::SharedMemory::IsHandleValid(bitstream.handle()))
base::SharedMemory::CloseHandle(bitstream.handle());
NotifyError(INVALID_ARGUMENT, SFT_INVALID_STREAM); NotifyError(INVALID_ARGUMENT, SFT_INVALID_STREAM);
return; return;
} }
DCHECK_EQ(0u, assigned_bitstream_ids_.count(bitstream.id())); DCHECK_EQ(0u, assigned_bitstream_ids_.count(bitstream_id));
assigned_bitstream_ids_.insert(bitstream.id()); assigned_bitstream_ids_.insert(bitstream_id);
Frame* frame = new Frame(bitstream.id()); Frame* frame = new Frame(bitstream_id);
pending_frames_[frame->bitstream_id] = make_linked_ptr(frame); pending_frames_[bitstream_id] = make_linked_ptr(frame);
decoder_thread_.task_runner()->PostTask( decoder_thread_.task_runner()->PostTask(
FROM_HERE, base::Bind(&VTVideoDecodeAccelerator::DecodeTask, FROM_HERE, base::Bind(&VTVideoDecodeAccelerator::DecodeTask,
base::Unretained(this), bitstream, frame)); base::Unretained(this), std::move(buffer), frame));
} }
void VTVideoDecodeAccelerator::AssignPictureBuffers( void VTVideoDecodeAccelerator::AssignPictureBuffers(
......
...@@ -46,6 +46,8 @@ class VTVideoDecodeAccelerator : public VideoDecodeAccelerator, ...@@ -46,6 +46,8 @@ class VTVideoDecodeAccelerator : public VideoDecodeAccelerator,
// VideoDecodeAccelerator implementation. // VideoDecodeAccelerator implementation.
bool Initialize(const Config& config, Client* client) override; bool Initialize(const Config& config, Client* client) override;
void Decode(const BitstreamBuffer& bitstream) override; void Decode(const BitstreamBuffer& bitstream) override;
void Decode(scoped_refptr<DecoderBuffer> buffer,
int32_t bitstream_id) override;
void AssignPictureBuffers( void AssignPictureBuffers(
const std::vector<PictureBuffer>& pictures) override; const std::vector<PictureBuffer>& pictures) override;
void ReusePictureBuffer(int32_t picture_id) override; void ReusePictureBuffer(int32_t picture_id) override;
...@@ -163,7 +165,7 @@ class VTVideoDecodeAccelerator : public VideoDecodeAccelerator, ...@@ -163,7 +165,7 @@ class VTVideoDecodeAccelerator : public VideoDecodeAccelerator,
bool FinishDelayedFrames(); bool FinishDelayedFrames();
// |frame| is owned by |pending_frames_|. // |frame| is owned by |pending_frames_|.
void DecodeTask(const BitstreamBuffer&, Frame* frame); void DecodeTask(scoped_refptr<DecoderBuffer> buffer, Frame* frame);
void DecodeDone(Frame* frame); void DecodeDone(Frame* frame);
// //
......
...@@ -28,6 +28,8 @@ class MockVideoDecodeAccelerator : public VideoDecodeAccelerator { ...@@ -28,6 +28,8 @@ class MockVideoDecodeAccelerator : public VideoDecodeAccelerator {
MOCK_METHOD2(Initialize, bool(const Config& config, Client* client)); MOCK_METHOD2(Initialize, bool(const Config& config, Client* client));
MOCK_METHOD1(Decode, void(const BitstreamBuffer& bitstream_buffer)); MOCK_METHOD1(Decode, void(const BitstreamBuffer& bitstream_buffer));
MOCK_METHOD2(Decode,
void(scoped_refptr<DecoderBuffer> buffer, int32_t bitstream_id));
MOCK_METHOD1(AssignPictureBuffers, MOCK_METHOD1(AssignPictureBuffers,
void(const std::vector<PictureBuffer>& buffers)); void(const std::vector<PictureBuffer>& buffers));
MOCK_METHOD1(ReusePictureBuffer, void(int32_t picture_buffer_id)); MOCK_METHOD1(ReusePictureBuffer, void(int32_t picture_buffer_id));
......
...@@ -31,6 +31,11 @@ void VideoDecodeAccelerator::Client::NotifyInitializationComplete( ...@@ -31,6 +31,11 @@ void VideoDecodeAccelerator::Client::NotifyInitializationComplete(
VideoDecodeAccelerator::~VideoDecodeAccelerator() = default; VideoDecodeAccelerator::~VideoDecodeAccelerator() = default;
void VideoDecodeAccelerator::Decode(scoped_refptr<DecoderBuffer> buffer,
int32_t bitstream_id) {
NOTREACHED() << "By default DecoderBuffer is not supported.";
}
bool VideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread( bool VideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread(
const base::WeakPtr<Client>& decode_client, const base::WeakPtr<Client>& decode_client,
const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) { const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) {
......
...@@ -10,12 +10,13 @@ ...@@ -10,12 +10,13 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include "base/memory/ref_counted.h" #include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/unguessable_token.h" #include "base/unguessable_token.h"
#include "media/base/bitstream_buffer.h" #include "media/base/bitstream_buffer.h"
#include "media/base/cdm_context.h" #include "media/base/cdm_context.h"
#include "media/base/decoder_buffer.h"
#include "media/base/encryption_scheme.h" #include "media/base/encryption_scheme.h"
#include "media/base/overlay_info.h" #include "media/base/overlay_info.h"
#include "media/base/surface_manager.h" #include "media/base/surface_manager.h"
...@@ -267,6 +268,16 @@ class MEDIA_EXPORT VideoDecodeAccelerator { ...@@ -267,6 +268,16 @@ class MEDIA_EXPORT VideoDecodeAccelerator {
// |bitstream_buffer| is the input bitstream that is sent for decoding. // |bitstream_buffer| is the input bitstream that is sent for decoding.
virtual void Decode(const BitstreamBuffer& bitstream_buffer) = 0; virtual void Decode(const BitstreamBuffer& bitstream_buffer) = 0;
// Decodes given decoder buffer that contains at most one frame. Once
// decoder is done with processing |buffer| it will call
// NotifyEndOfBitstreamBuffer() with the bitstream id.
// Parameters:
// |buffer| is the input buffer that is sent for decoding.
// |bitstream_id| identifies the buffer for PictureReady() and
// NotifyEndOfBitstreamBuffer()
virtual void Decode(scoped_refptr<DecoderBuffer> buffer,
int32_t bitstream_id);
// Assigns a set of texture-backed picture buffers to the video decoder. // Assigns a set of texture-backed picture buffers to the video decoder.
// //
// Ownership of each picture buffer remains with the client, but the client // Ownership of each picture buffer remains with the client, but the client
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment