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") {
"time_delta_interpolator.h",
"time_source.h",
"timestamp_constants.h",
"unaligned_shared_memory.cc",
"unaligned_shared_memory.h",
"user_input_monitor.cc",
"user_input_monitor.h",
"video_codecs.cc",
......@@ -488,6 +490,7 @@ source_set("unit_tests") {
"text_ranges_unittest.cc",
"text_renderer_unittest.cc",
"time_delta_interpolator_unittest.cc",
"unaligned_shared_memory_unittest.cc",
"user_input_monitor_unittest.cc",
"vector_math_unittest.cc",
"video_codecs_unittest.cc",
......
......@@ -4,6 +4,8 @@
#include "media/base/bitstream_buffer.h"
#include "media/base/decrypt_config.h"
namespace media {
BitstreamBuffer::BitstreamBuffer()
......@@ -24,6 +26,19 @@ BitstreamBuffer::BitstreamBuffer(const BitstreamBuffer& other) = 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(
const std::string& key_id,
const std::string& iv,
......
......@@ -9,8 +9,10 @@
#include <stdint.h>
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/shared_memory.h"
#include "base/time/time.h"
#include "media/base/decoder_buffer.h"
#include "media/base/decrypt_config.h"
#include "media/base/media_export.h"
#include "media/base/timestamp_constants.h"
......@@ -44,6 +46,15 @@ class MEDIA_EXPORT 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
// EncryptionMode and optional EncryptionPattern when updating for Android.
void SetDecryptionSettings(const std::string& key_id,
......
......@@ -44,6 +44,13 @@ DecoderBuffer::DecoderBuffer(const uint8_t* data,
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;
void DecoderBuffer::Initialize() {
......@@ -72,6 +79,17 @@ scoped_refptr<DecoderBuffer> DecoderBuffer::CopyFrom(const uint8_t* data,
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
scoped_refptr<DecoderBuffer> DecoderBuffer::CreateEOSBuffer() {
return base::WrapRefCounted(new DecoderBuffer(NULL, 0, NULL, 0));
......
......@@ -16,11 +16,13 @@
#include "base/macros.h"
#include "base/memory/aligned_memory.h"
#include "base/memory/ref_counted.h"
#include "base/memory/shared_memory_handle.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "media/base/decrypt_config.h"
#include "media/base/media_export.h"
#include "media/base/timestamp_constants.h"
#include "media/base/unaligned_shared_memory.h"
namespace media {
......@@ -64,6 +66,19 @@ class MEDIA_EXPORT DecoderBuffer
const uint8_t* side_data,
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.
//
// Calling any method other than end_of_stream() on the resulting buffer
......@@ -94,11 +109,15 @@ class MEDIA_EXPORT DecoderBuffer
const uint8_t* data() const {
DCHECK(!end_of_stream());
if (shm_)
return static_cast<uint8_t*>(shm_->memory());
return data_.get();
}
// TODO(sandersd): Remove writable_data(). https://crbug.com/834088
uint8_t* writable_data() const {
DCHECK(!end_of_stream());
DCHECK(!shm_);
return data_.get();
}
......@@ -144,9 +163,7 @@ class MEDIA_EXPORT DecoderBuffer
}
// If there's no data in this buffer, it represents end of stream.
bool end_of_stream() const {
return data_ == NULL;
}
bool end_of_stream() const { return !shm_ && !data_; }
bool is_key_frame() const {
DCHECK(!end_of_stream());
......@@ -179,6 +196,9 @@ class MEDIA_EXPORT DecoderBuffer
size_t size,
const uint8_t* side_data,
size_t side_data_size);
DecoderBuffer(std::unique_ptr<UnalignedSharedMemory> shm, size_t size);
virtual ~DecoderBuffer();
private:
......@@ -189,6 +209,7 @@ class MEDIA_EXPORT DecoderBuffer
std::unique_ptr<uint8_t, base::AlignedFreeDeleter> data_;
size_t side_data_size_;
std::unique_ptr<uint8_t, base::AlignedFreeDeleter> side_data_;
std::unique_ptr<UnalignedSharedMemory> shm_;
std::unique_ptr<DecryptConfig> decrypt_config_;
DiscardPadding discard_padding_;
bool is_key_frame_;
......
......@@ -5,9 +5,12 @@
#include "media/base/decoder_buffer.h"
#include <stdint.h>
#include <string.h>
#include <memory>
#include "base/macros.h"
#include "base/memory/shared_memory.h"
#include "base/strings/string_util.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
......@@ -59,6 +62,55 @@ TEST(DecoderBufferTest, CopyFrom) {
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)
TEST(DecoderBufferTest, PaddingAlignment) {
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,
timestamps_.Put(bitstream_buffer_id, buffer->timestamp());
decode_cbs_[bitstream_buffer_id] = decode_cb;
// Copy data into shared memory.
//
// TODO(sandersd): Change VDA interface to use BitstreamBuffer, which will
// eliminate this work. If necessary, BitstreamBuffer can take responsibility
// 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));
gpu_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&VdaVideoDecoder::DecodeOnGpuThread, gpu_weak_this_,
std::move(buffer), bitstream_buffer_id));
}
void VdaVideoDecoder::DecodeOnGpuThread(BitstreamBuffer bitstream_buffer) {
void VdaVideoDecoder::DecodeOnGpuThread(scoped_refptr<DecoderBuffer> buffer,
int32_t bitstream_id) {
DVLOG(3) << __func__;
DCHECK(gpu_task_runner_->BelongsToCurrentThread());
if (!gpu_weak_vda_) {
base::SharedMemory::CloseHandle(bitstream_buffer.handle());
if (!gpu_weak_vda_)
return;
}
vda_->Decode(bitstream_buffer);
vda_->Decode(std::move(buffer), bitstream_id);
}
void VdaVideoDecoder::Reset(const base::RepeatingClosure& reset_cb) {
......
......@@ -131,7 +131,8 @@ class VdaVideoDecoder : public VideoDecoder,
void DestroyOnGpuThread();
void InitializeOnGpuThread();
void InitializeDone(bool status);
void DecodeOnGpuThread(BitstreamBuffer bitstream_buffer);
void DecodeOnGpuThread(scoped_refptr<DecoderBuffer> buffer,
int32_t bitstream_id);
void PictureReadyOnParentThread(Picture picture);
void NotifyEndOfBitstreamBufferOnParentThread(int32_t bitstream_buffer_id);
void NotifyFlushDoneOnParentThread();
......
......@@ -87,11 +87,6 @@ VideoDecodeAccelerator::Capabilities GetCapabilities() {
return capabilities;
}
void CloseShm(const BitstreamBuffer& bitstream) {
DCHECK(base::SharedMemory::IsHandleValid(bitstream.handle()));
base::SharedMemory::CloseHandle(bitstream.handle());
}
} // namespace
class VdaVideoDecoderTest : public testing::Test {
......@@ -111,9 +106,6 @@ class VdaVideoDecoderTest : public testing::Test {
// In either case, vda_->Destroy() should be called once.
EXPECT_CALL(*vda_, Destroy());
// vda_->Decode() must close the shared memory handle.
ON_CALL(*vda_, Decode(_)).WillByDefault(Invoke(&CloseShm));
vdavd_.reset(new VdaVideoDecoder(
task_runner, task_runner,
base::BindOnce(&VdaVideoDecoderTest::CreatePictureBufferManager,
......@@ -168,12 +160,11 @@ class VdaVideoDecoderTest : public testing::Test {
}
int32_t Decode(base::TimeDelta timestamp) {
BitstreamBuffer bitstream;
int32_t bitstream_id = 0;
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();
CloseShm(bitstream);
return bitstream.id();
return bitstream_id;
}
void NotifyEndOfBitstreamBuffer(int32_t bitstream_id) {
......
......@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/sys_info.h"
#include "media/gpu/shared_memory_region.h"
namespace media {
......@@ -11,12 +10,7 @@ SharedMemoryRegion::SharedMemoryRegion(const base::SharedMemoryHandle& handle,
off_t offset,
size_t size,
bool read_only)
: shm_(handle, read_only),
offset_(offset),
size_(size),
alignment_size_(offset % base::SysInfo::VMAllocationGranularity()) {
DCHECK_GE(offset_, 0) << "Invalid offset: " << offset_;
}
: shm_(handle, read_only), offset_(offset), size_(size) {}
SharedMemoryRegion::SharedMemoryRegion(const BitstreamBuffer& bitstream_buffer,
bool read_only)
......@@ -26,16 +20,11 @@ SharedMemoryRegion::SharedMemoryRegion(const BitstreamBuffer& bitstream_buffer,
read_only) {}
bool SharedMemoryRegion::Map() {
if (offset_ < 0) {
DVLOG(1) << "Invalid offset: " << offset_;
return false;
}
return shm_.MapAt(offset_ - alignment_size_, size_ + alignment_size_);
return shm_.MapAt(offset_, size_);
}
void* SharedMemoryRegion::memory() {
int8_t* addr = reinterpret_cast<int8_t*>(shm_.memory());
return addr ? addr + alignment_size_ : nullptr;
return shm_.memory();
}
} // namespace media
......@@ -5,8 +5,9 @@
#ifndef 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/unaligned_shared_memory.h"
namespace media {
......@@ -15,6 +16,10 @@ namespace media {
// the value of |SysInfo::VMAllocationGranularity()|, the |offset| of a
// SharedMemoryRegion needs not to be aligned, this class hides the details
// 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 {
public:
// Creates a SharedMemoryRegion.
......@@ -43,10 +48,9 @@ class SharedMemoryRegion {
size_t size() const { return size_; }
private:
base::SharedMemory shm_;
UnalignedSharedMemory shm_;
off_t offset_;
size_t size_;
size_t alignment_size_;
DISALLOW_COPY_AND_ASSIGN(SharedMemoryRegion);
};
......
......@@ -623,20 +623,11 @@ bool VTVideoDecodeAccelerator::ConfigureDecoder() {
return true;
}
void VTVideoDecodeAccelerator::DecodeTask(const BitstreamBuffer& bitstream,
void VTVideoDecodeAccelerator::DecodeTask(scoped_refptr<DecoderBuffer> buffer,
Frame* frame) {
DVLOG(2) << __func__ << "(" << frame->bitstream_id << ")";
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),
// but VideoToolbox expects AVC format (length headers), so we must rewrite
// the data.
......@@ -645,7 +636,7 @@ void VTVideoDecodeAccelerator::DecodeTask(const BitstreamBuffer& bitstream,
// record parameter sets for VideoToolbox initialization.
size_t data_size = 0;
std::vector<H264NALU> nalus;
parser_.SetStream(buf, memory.size());
parser_.SetStream(buffer->data(), buffer->data_size());
H264NALU nalu;
while (true) {
H264Parser::Result result = parser_.AdvanceToNextNALU(&nalu);
......@@ -998,25 +989,28 @@ void VTVideoDecodeAccelerator::FlushDone(TaskType type) {
}
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());
if (bitstream.id() < 0) {
DLOG(ERROR) << "Invalid bitstream, id: " << bitstream.id();
if (base::SharedMemory::IsHandleValid(bitstream.handle()))
base::SharedMemory::CloseHandle(bitstream.handle());
if (!buffer || bitstream_id < 0) {
DLOG(ERROR) << "Invalid bitstream, id: " << bitstream_id;
NotifyError(INVALID_ARGUMENT, SFT_INVALID_STREAM);
return;
}
DCHECK_EQ(0u, assigned_bitstream_ids_.count(bitstream.id()));
assigned_bitstream_ids_.insert(bitstream.id());
DCHECK_EQ(0u, assigned_bitstream_ids_.count(bitstream_id));
assigned_bitstream_ids_.insert(bitstream_id);
Frame* frame = new Frame(bitstream.id());
pending_frames_[frame->bitstream_id] = make_linked_ptr(frame);
Frame* frame = new Frame(bitstream_id);
pending_frames_[bitstream_id] = make_linked_ptr(frame);
decoder_thread_.task_runner()->PostTask(
FROM_HERE, base::Bind(&VTVideoDecodeAccelerator::DecodeTask,
base::Unretained(this), bitstream, frame));
base::Unretained(this), std::move(buffer), frame));
}
void VTVideoDecodeAccelerator::AssignPictureBuffers(
......
......@@ -46,6 +46,8 @@ class VTVideoDecodeAccelerator : public VideoDecodeAccelerator,
// VideoDecodeAccelerator implementation.
bool Initialize(const Config& config, Client* client) override;
void Decode(const BitstreamBuffer& bitstream) override;
void Decode(scoped_refptr<DecoderBuffer> buffer,
int32_t bitstream_id) override;
void AssignPictureBuffers(
const std::vector<PictureBuffer>& pictures) override;
void ReusePictureBuffer(int32_t picture_id) override;
......@@ -163,7 +165,7 @@ class VTVideoDecodeAccelerator : public VideoDecodeAccelerator,
bool FinishDelayedFrames();
// |frame| is owned by |pending_frames_|.
void DecodeTask(const BitstreamBuffer&, Frame* frame);
void DecodeTask(scoped_refptr<DecoderBuffer> buffer, Frame* frame);
void DecodeDone(Frame* frame);
//
......
......@@ -28,6 +28,8 @@ class MockVideoDecodeAccelerator : public VideoDecodeAccelerator {
MOCK_METHOD2(Initialize, bool(const Config& config, Client* client));
MOCK_METHOD1(Decode, void(const BitstreamBuffer& bitstream_buffer));
MOCK_METHOD2(Decode,
void(scoped_refptr<DecoderBuffer> buffer, int32_t bitstream_id));
MOCK_METHOD1(AssignPictureBuffers,
void(const std::vector<PictureBuffer>& buffers));
MOCK_METHOD1(ReusePictureBuffer, void(int32_t picture_buffer_id));
......
......@@ -31,6 +31,11 @@ void VideoDecodeAccelerator::Client::NotifyInitializationComplete(
VideoDecodeAccelerator::~VideoDecodeAccelerator() = default;
void VideoDecodeAccelerator::Decode(scoped_refptr<DecoderBuffer> buffer,
int32_t bitstream_id) {
NOTREACHED() << "By default DecoderBuffer is not supported.";
}
bool VideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread(
const base::WeakPtr<Client>& decode_client,
const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) {
......
......@@ -10,12 +10,13 @@
#include <memory>
#include <vector>
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/unguessable_token.h"
#include "media/base/bitstream_buffer.h"
#include "media/base/cdm_context.h"
#include "media/base/decoder_buffer.h"
#include "media/base/encryption_scheme.h"
#include "media/base/overlay_info.h"
#include "media/base/surface_manager.h"
......@@ -267,6 +268,16 @@ class MEDIA_EXPORT VideoDecodeAccelerator {
// |bitstream_buffer| is the input bitstream that is sent for decoding.
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.
//
// 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