Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1248)

Unified Diff: media/gpu/ipc/service/gpu_video_encode_accelerator.cc

Issue 2427053002: Move video encode accelerator IPC messages to GPU IO thread (Closed)
Patch Set: posciak@ comments. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/gpu/ipc/service/gpu_video_encode_accelerator.h ('k') | media/gpu/ipc/service/media_gpu_channel.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/gpu/ipc/service/gpu_video_encode_accelerator.cc
diff --git a/media/gpu/ipc/service/gpu_video_encode_accelerator.cc b/media/gpu/ipc/service/gpu_video_encode_accelerator.cc
index 26d2aaa55d5f2c2dea38d33181dd7e3f5944d6dc..5c61111e24f3b2077597a03a986b58c1b89db948 100644
--- a/media/gpu/ipc/service/gpu_video_encode_accelerator.cc
+++ b/media/gpu/ipc/service/gpu_video_encode_accelerator.cc
@@ -59,6 +59,10 @@ bool MakeDecoderContextCurrent(
return true;
}
+void DropSharedMemory(std::unique_ptr<base::SharedMemory> shm) {
+ // Just let |shm| fall out of scope.
+}
+
#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC)
std::unique_ptr<VideoEncodeAccelerator> CreateV4L2VEA() {
scoped_refptr<V4L2Device> device = V4L2Device::Create();
@@ -99,13 +103,73 @@ std::unique_ptr<VideoEncodeAccelerator> CreateMediaFoundationVEA() {
} // anonymous namespace
+class GpuVideoEncodeAccelerator::MessageFilter : public IPC::MessageFilter {
+ public:
+ MessageFilter(GpuVideoEncodeAccelerator* owner, int32_t host_route_id)
+ : owner_(owner), host_route_id_(host_route_id) {}
+
+ void OnChannelError() override { sender_ = nullptr; }
+
+ void OnChannelClosing() override { sender_ = nullptr; }
+
+ void OnFilterAdded(IPC::Channel* channel) override { sender_ = channel; }
+
+ void OnFilterRemoved() override { owner_->OnFilterRemoved(); }
+
+ bool OnMessageReceived(const IPC::Message& msg) override {
+ if (msg.routing_id() != host_route_id_)
+ return false;
+
+ IPC_BEGIN_MESSAGE_MAP(MessageFilter, msg)
+ IPC_MESSAGE_FORWARD(AcceleratedVideoEncoderMsg_Encode, owner_,
+ GpuVideoEncodeAccelerator::OnEncode)
+ IPC_MESSAGE_FORWARD(AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer,
+ owner_,
+ GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer)
+ IPC_MESSAGE_FORWARD(
+ AcceleratedVideoEncoderMsg_RequestEncodingParametersChange, owner_,
+ GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange)
+ IPC_MESSAGE_UNHANDLED(return false)
+ IPC_END_MESSAGE_MAP()
+ return true;
+ }
+
+ bool SendOnIOThread(IPC::Message* message) {
+ if (!sender_ || message->is_sync()) {
+ DCHECK(!message->is_sync());
+ delete message;
+ return false;
+ }
+ return sender_->Send(message);
+ }
+
+ protected:
+ ~MessageFilter() override {}
+
+ private:
+ GpuVideoEncodeAccelerator* const owner_;
+ const int32_t host_route_id_;
+ // The sender to which this filter was added.
+ IPC::Sender* sender_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(MessageFilter);
+};
+
GpuVideoEncodeAccelerator::GpuVideoEncodeAccelerator(
int32_t host_route_id,
- gpu::GpuCommandBufferStub* stub)
+ gpu::GpuCommandBufferStub* stub,
+ const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
: host_route_id_(host_route_id),
stub_(stub),
input_format_(PIXEL_FORMAT_UNKNOWN),
output_buffer_size_(0),
+ filter_removed_(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED),
+ encoder_worker_thread_("EncoderWorkerThread"),
+ main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ io_task_runner_(io_task_runner),
+ encode_task_runner_(main_task_runner_),
+ weak_this_factory_for_encoder_worker_(this),
weak_this_factory_(this) {
stub_->AddDestructionObserver(this);
make_context_current_ =
@@ -116,13 +180,21 @@ GpuVideoEncodeAccelerator::~GpuVideoEncodeAccelerator() {
// This class can only be self-deleted from OnWillDestroyStub(), which means
// the VEA has already been destroyed in there.
DCHECK(!encoder_);
+ if (encoder_worker_thread_.IsRunning()) {
+ encoder_worker_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&GpuVideoEncodeAccelerator::DestroyOnEncoderWorker,
+ weak_this_factory_for_encoder_worker_.GetWeakPtr()));
+ encoder_worker_thread_.Stop();
+ }
}
bool GpuVideoEncodeAccelerator::Initialize(VideoPixelFormat input_format,
const gfx::Size& input_visible_size,
VideoCodecProfile output_profile,
uint32_t initial_bitrate) {
- DVLOG(1) << __FUNCTION__
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ DVLOG(1) << __func__
<< " input_format=" << VideoPixelFormatToString(input_format)
<< ", input_visible_size=" << input_visible_size.ToString()
<< ", output_profile=" << GetProfileName(output_profile)
@@ -130,14 +202,14 @@ bool GpuVideoEncodeAccelerator::Initialize(VideoPixelFormat input_format,
DCHECK(!encoder_);
if (!stub_->channel()->AddRoute(host_route_id_, stub_->stream_id(), this)) {
- DLOG(ERROR) << __FUNCTION__ << " failed to add route";
+ DLOG(ERROR) << __func__ << " failed to add route";
return false;
}
if (input_visible_size.width() > limits::kMaxDimension ||
input_visible_size.height() > limits::kMaxDimension ||
input_visible_size.GetArea() > limits::kMaxCanvas) {
- DLOG(ERROR) << __FUNCTION__ << "too large input_visible_size "
+ DLOG(ERROR) << __func__ << "too large input_visible_size "
<< input_visible_size.ToString();
return false;
}
@@ -153,11 +225,26 @@ bool GpuVideoEncodeAccelerator::Initialize(VideoPixelFormat input_format,
initial_bitrate, this)) {
input_format_ = input_format;
input_visible_size_ = input_visible_size;
+ // Attempt to set up performing encoding tasks on IO thread, if supported
+ // by the VEA.
+ if (encoder_->TryToSetupEncodeOnSeparateThread(
+ weak_this_factory_.GetWeakPtr(), io_task_runner_)) {
+ filter_ = new MessageFilter(this, host_route_id_);
+ stub_->channel()->AddFilter(filter_.get());
+ encode_task_runner_ = io_task_runner_;
+ }
+
+ if (!encoder_worker_thread_.Start()) {
+ DLOG(ERROR) << "Failed spawning encoder worker thread.";
+ return false;
+ }
+ encoder_worker_task_runner_ = encoder_worker_thread_.task_runner();
+
return true;
}
}
encoder_.reset();
- DLOG(ERROR) << __FUNCTION__ << " VEA initialization failed";
+ DLOG(ERROR) << __func__ << " VEA initialization failed";
return false;
}
@@ -176,12 +263,24 @@ bool GpuVideoEncodeAccelerator::OnMessageReceived(const IPC::Message& message) {
return handled;
}
+bool GpuVideoEncodeAccelerator::Send(IPC::Message* message) {
+ if (filter_ && io_task_runner_->BelongsToCurrentThread()) {
+ return filter_->SendOnIOThread(message);
+ }
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ return stub_->channel()->Send(message);
+}
+
void GpuVideoEncodeAccelerator::RequireBitstreamBuffers(
unsigned int input_count,
const gfx::Size& input_coded_size,
size_t output_buffer_size) {
- Send(new AcceleratedVideoEncoderHostMsg_RequireBitstreamBuffers(
- host_route_id_, input_count, input_coded_size, output_buffer_size));
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ if (!Send(new AcceleratedVideoEncoderHostMsg_RequireBitstreamBuffers(
+ host_route_id_, input_count, input_coded_size, output_buffer_size))) {
+ DLOG(ERROR) << __func__ << " failed.";
+ return;
+ }
input_coded_size_ = input_coded_size;
output_buffer_size_ = output_buffer_size;
}
@@ -191,17 +290,39 @@ void GpuVideoEncodeAccelerator::BitstreamBufferReady(
size_t payload_size,
bool key_frame,
base::TimeDelta timestamp) {
- Send(new AcceleratedVideoEncoderHostMsg_BitstreamBufferReady(
- host_route_id_, bitstream_buffer_id, payload_size, key_frame, timestamp));
+ DCHECK(CheckIfCalledOnCorrectThread());
+ if (!Send(new AcceleratedVideoEncoderHostMsg_BitstreamBufferReady(
+ host_route_id_, bitstream_buffer_id, payload_size, key_frame,
+ timestamp))) {
+ DLOG(ERROR) << __func__ << " failed.";
+ }
}
void GpuVideoEncodeAccelerator::NotifyError(
VideoEncodeAccelerator::Error error) {
- Send(new AcceleratedVideoEncoderHostMsg_NotifyError(host_route_id_, error));
+ if (!Send(new AcceleratedVideoEncoderHostMsg_NotifyError(host_route_id_,
+ error))) {
+ DLOG(ERROR) << __func__ << " failed.";
+ }
}
void GpuVideoEncodeAccelerator::OnWillDestroyStub() {
+ DVLOG(2) << __func__;
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
DCHECK(stub_);
+
+ // The stub is going away, so we have to stop and destroy VEA here before
+ // returning. We cannot destroy the VEA before the IO thread message filter is
+ // removed however, since we cannot service incoming messages with VEA gone.
+ // We cannot simply check for existence of VEA on IO thread though, because
+ // we don't want to synchronize the IO thread with the ChildThread.
+ // So we have to wait for the RemoveFilter callback here instead and remove
+ // the VEA after it arrives and before returning.
+ if (filter_) {
+ stub_->channel()->RemoveFilter(filter_.get());
+ filter_removed_.Wait();
+ }
+
stub_->channel()->RemoveRoute(host_route_id_);
stub_->RemoveDestructionObserver(this);
encoder_.reset();
@@ -252,80 +373,54 @@ GpuVideoEncodeAccelerator::GetVEAFactoryFunctions(
return vea_factory_functions;
}
+void GpuVideoEncodeAccelerator::OnFilterRemoved() {
+ DVLOG(2) << __func__;
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
+
+ // We're destroying; cancel all callbacks.
+ weak_this_factory_.InvalidateWeakPtrs();
+ filter_removed_.Signal();
+}
+
void GpuVideoEncodeAccelerator::OnEncode(
const AcceleratedVideoEncoderMsg_Encode_Params& params) {
- DVLOG(3) << __FUNCTION__ << " frame_id = " << params.frame_id
+ DVLOG(3) << __func__ << " frame_id = " << params.frame_id
<< ", buffer_size=" << params.buffer_size
<< ", force_keyframe=" << params.force_keyframe;
+ DCHECK(CheckIfCalledOnCorrectThread());
DCHECK_EQ(PIXEL_FORMAT_I420, input_format_);
- // Wrap into a SharedMemory in the beginning, so that |params.buffer_handle|
- // is cleaned properly in case of an early return.
- std::unique_ptr<base::SharedMemory> shm(
- new base::SharedMemory(params.buffer_handle, true));
-
if (!encoder_)
return;
if (params.frame_id < 0) {
- DLOG(ERROR) << __FUNCTION__ << " invalid frame_id=" << params.frame_id;
+ DLOG(ERROR) << __func__ << " invalid frame_id=" << params.frame_id;
NotifyError(VideoEncodeAccelerator::kPlatformFailureError);
return;
}
- const uint32_t aligned_offset =
- params.buffer_offset % base::SysInfo::VMAllocationGranularity();
- base::CheckedNumeric<off_t> map_offset = params.buffer_offset;
- map_offset -= aligned_offset;
- base::CheckedNumeric<size_t> map_size = params.buffer_size;
- map_size += aligned_offset;
-
- if (!map_offset.IsValid() || !map_size.IsValid()) {
- DLOG(ERROR) << __FUNCTION__ << " invalid map_offset or map_size";
- NotifyError(VideoEncodeAccelerator::kPlatformFailureError);
- return;
- }
-
- if (!shm->MapAt(map_offset.ValueOrDie(), map_size.ValueOrDie())) {
- DLOG(ERROR) << __FUNCTION__
- << " could not map frame_id=" << params.frame_id;
- NotifyError(VideoEncodeAccelerator::kPlatformFailureError);
- return;
- }
-
- uint8_t* shm_memory =
- reinterpret_cast<uint8_t*>(shm->memory()) + aligned_offset;
- scoped_refptr<VideoFrame> frame = VideoFrame::WrapExternalSharedMemory(
- input_format_, input_coded_size_, gfx::Rect(input_visible_size_),
- input_visible_size_, shm_memory, params.buffer_size, params.buffer_handle,
- params.buffer_offset, params.timestamp);
- if (!frame) {
- DLOG(ERROR) << __FUNCTION__ << " could not create a frame";
- NotifyError(VideoEncodeAccelerator::kPlatformFailureError);
- return;
- }
- frame->AddDestructionObserver(BindToCurrentLoop(base::Bind(
- &GpuVideoEncodeAccelerator::EncodeFrameFinished,
- weak_this_factory_.GetWeakPtr(), params.frame_id, base::Passed(&shm))));
- encoder_->Encode(frame, params.force_keyframe);
+ encoder_worker_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&GpuVideoEncodeAccelerator::CreateEncodeFrameOnEncoderWorker,
+ weak_this_factory_for_encoder_worker_.GetWeakPtr(), params));
}
void GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(
int32_t buffer_id,
base::SharedMemoryHandle buffer_handle,
uint32_t buffer_size) {
- DVLOG(3) << __FUNCTION__ << " buffer_id=" << buffer_id
+ DVLOG(3) << __func__ << " buffer_id=" << buffer_id
<< ", buffer_size=" << buffer_size;
+ DCHECK(CheckIfCalledOnCorrectThread());
if (!encoder_)
return;
if (buffer_id < 0) {
- DLOG(ERROR) << __FUNCTION__ << " invalid buffer_id=" << buffer_id;
+ DLOG(ERROR) << __func__ << " invalid buffer_id=" << buffer_id;
NotifyError(VideoEncodeAccelerator::kPlatformFailureError);
return;
}
if (buffer_size < output_buffer_size_) {
- DLOG(ERROR) << __FUNCTION__
- << " buffer too small for buffer_id=" << buffer_id;
+ DLOG(ERROR) << __func__ << " buffer too small for buffer_id=" << buffer_id;
NotifyError(VideoEncodeAccelerator::kPlatformFailureError);
return;
}
@@ -334,30 +429,115 @@ void GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(
}
void GpuVideoEncodeAccelerator::OnDestroy() {
- DVLOG(2) << __FUNCTION__;
+ DVLOG(2) << __func__;
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
OnWillDestroyStub();
}
void GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange(
uint32_t bitrate,
uint32_t framerate) {
- DVLOG(2) << __FUNCTION__ << " bitrate=" << bitrate
- << ", framerate=" << framerate;
+ DVLOG(2) << __func__ << " bitrate=" << bitrate << ", framerate=" << framerate;
+ DCHECK(CheckIfCalledOnCorrectThread());
if (!encoder_)
return;
encoder_->RequestEncodingParametersChange(bitrate, framerate);
}
-void GpuVideoEncodeAccelerator::EncodeFrameFinished(
+void GpuVideoEncodeAccelerator::CreateEncodeFrameOnEncoderWorker(
+ const AcceleratedVideoEncoderMsg_Encode_Params& params) {
+ DVLOG(3) << __func__;
+ DCHECK(encoder_worker_task_runner_->BelongsToCurrentThread());
+
+ // Wrap into a SharedMemory in the beginning, so that |params.buffer_handle|
+ // is cleaned properly in case of an early return.
+ std::unique_ptr<base::SharedMemory> shm(
+ new base::SharedMemory(params.buffer_handle, true));
+ const uint32_t aligned_offset =
+ params.buffer_offset % base::SysInfo::VMAllocationGranularity();
+ base::CheckedNumeric<off_t> map_offset = params.buffer_offset;
+ map_offset -= aligned_offset;
+ base::CheckedNumeric<size_t> map_size = params.buffer_size;
+ map_size += aligned_offset;
+
+ if (!map_offset.IsValid() || !map_size.IsValid()) {
+ DLOG(ERROR) << __func__ << " invalid map_offset or map_size";
+ encode_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&GpuVideoEncodeAccelerator::NotifyError,
+ weak_this_factory_.GetWeakPtr(),
+ VideoEncodeAccelerator::kPlatformFailureError));
+ return;
+ }
+
+ if (!shm->MapAt(map_offset.ValueOrDie(), map_size.ValueOrDie())) {
+ DLOG(ERROR) << __func__ << " could not map frame_id=" << params.frame_id;
+ encode_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&GpuVideoEncodeAccelerator::NotifyError,
+ weak_this_factory_.GetWeakPtr(),
+ VideoEncodeAccelerator::kPlatformFailureError));
+ return;
+ }
+
+ uint8_t* shm_memory =
+ reinterpret_cast<uint8_t*>(shm->memory()) + aligned_offset;
+ scoped_refptr<VideoFrame> frame = VideoFrame::WrapExternalSharedMemory(
+ input_format_, input_coded_size_, gfx::Rect(input_visible_size_),
+ input_visible_size_, shm_memory, params.buffer_size, params.buffer_handle,
+ params.buffer_offset, params.timestamp);
+ if (!frame) {
+ DLOG(ERROR) << __func__ << " could not create a frame";
+ encode_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&GpuVideoEncodeAccelerator::NotifyError,
+ weak_this_factory_.GetWeakPtr(),
+ VideoEncodeAccelerator::kPlatformFailureError));
+ return;
+ }
+
+ // We wrap |shm| in a callback and add it as a destruction observer, so it
+ // stays alive and mapped until |frame| goes out of scope.
+ frame->AddDestructionObserver(
+ base::Bind(&DropSharedMemory, base::Passed(&shm)));
+ encode_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&GpuVideoEncodeAccelerator::OnEncodeFrameCreated,
+ weak_this_factory_.GetWeakPtr(), params.frame_id,
+ params.force_keyframe, frame));
+}
+
+void GpuVideoEncodeAccelerator::DestroyOnEncoderWorker() {
+ DCHECK(encoder_worker_task_runner_->BelongsToCurrentThread());
+ weak_this_factory_for_encoder_worker_.InvalidateWeakPtrs();
+}
+
+void GpuVideoEncodeAccelerator::OnEncodeFrameCreated(
int32_t frame_id,
- std::unique_ptr<base::SharedMemory> shm) {
- Send(new AcceleratedVideoEncoderHostMsg_NotifyInputDone(host_route_id_,
- frame_id));
- // Just let |shm| fall out of scope.
+ bool force_keyframe,
+ const scoped_refptr<media::VideoFrame>& frame) {
+ DVLOG(3) << __func__;
+ DCHECK(CheckIfCalledOnCorrectThread());
+
+ if (!frame) {
+ DLOG(ERROR) << __func__ << " could not create a frame";
+ NotifyError(VideoEncodeAccelerator::kPlatformFailureError);
+ return;
+ }
+
+ frame->AddDestructionObserver(BindToCurrentLoop(
+ base::Bind(&GpuVideoEncodeAccelerator::EncodeFrameFinished,
+ weak_this_factory_.GetWeakPtr(), frame_id)));
+ encoder_->Encode(frame, force_keyframe);
+}
+
+void GpuVideoEncodeAccelerator::EncodeFrameFinished(int32_t frame_id) {
+ DCHECK(CheckIfCalledOnCorrectThread());
+ if (!Send(new AcceleratedVideoEncoderHostMsg_NotifyInputDone(host_route_id_,
+ frame_id))) {
+ DLOG(ERROR) << __func__ << " failed.";
+ }
}
-void GpuVideoEncodeAccelerator::Send(IPC::Message* message) {
- stub_->channel()->Send(message);
+bool GpuVideoEncodeAccelerator::CheckIfCalledOnCorrectThread() {
+ return (filter_ && io_task_runner_->BelongsToCurrentThread()) ||
+ (!filter_ && main_task_runner_->BelongsToCurrentThread());
}
} // namespace media
« no previous file with comments | « media/gpu/ipc/service/gpu_video_encode_accelerator.h ('k') | media/gpu/ipc/service/media_gpu_channel.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698