| Index: chrome/renderer/gpu_video_decoder_host.cc
|
| diff --git a/chrome/renderer/gpu_video_decoder_host.cc b/chrome/renderer/gpu_video_decoder_host.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..5e0f727695bc8ce7220de87fba88c9d8b5ac590e
|
| --- /dev/null
|
| +++ b/chrome/renderer/gpu_video_decoder_host.cc
|
| @@ -0,0 +1,199 @@
|
| +// Copyright (c) 2010 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 "chrome/renderer/gpu_video_decoder_host.h"
|
| +
|
| +#include "chrome/common/gpu_messages.h"
|
| +#include "chrome/renderer/gpu_video_service_host.h"
|
| +#include "chrome/renderer/render_thread.h"
|
| +
|
| +void GpuVideoDecoderHost::OnChannelError() {
|
| + channel_host_.release();
|
| +}
|
| +
|
| +void GpuVideoDecoderHost::OnMessageReceived(const IPC::Message& msg) {
|
| + IPC_BEGIN_MESSAGE_MAP(GpuVideoDecoderHost, msg)
|
| + IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_InitializeACK,
|
| + OnInitializeDone)
|
| + IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_DestroyACK,
|
| + OnUninitializeDone)
|
| + IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_FlushACK,
|
| + OnFlushDone)
|
| + IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_EmptyThisBufferACK,
|
| + OnEmptyThisBufferACK)
|
| + IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_EmptyThisBufferDone,
|
| + OnEmptyThisBufferDone)
|
| + IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_FillThisBufferDone,
|
| + OnFillThisBufferDone)
|
| + IPC_MESSAGE_UNHANDLED_ERROR()
|
| + IPC_END_MESSAGE_MAP()
|
| +}
|
| +
|
| +bool GpuVideoDecoderHost::Initialize(const GpuVideoDecoderInitParam& param) {
|
| + DCHECK_EQ(state_, kStateUninitialized);
|
| +
|
| + init_param_ = param;
|
| + if (!channel_host_->Send(
|
| + new GpuVideoDecoderMsg_Initialize(route_id(), param))) {
|
| + LOG(ERROR) << "GpuVideoDecoderMsg_Initialize failed";
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool GpuVideoDecoderHost::Uninitialize() {
|
| + if (!channel_host_->Send(new GpuVideoDecoderMsg_Destroy(route_id()))) {
|
| + LOG(ERROR) << "GpuVideoDecoderMsg_Destroy failed";
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +void GpuVideoDecoderHost::EmptyThisBuffer(scoped_refptr<Buffer> buffer) {
|
| + DCHECK_NE(state_, kStateUninitialized);
|
| + DCHECK_NE(state_, kStateFlushing);
|
| +
|
| + // We never own input buffers, therefore when client in flush state, it
|
| + // never call us with EmptyThisBuffer.
|
| + if (state_ != kStateNormal)
|
| + return;
|
| +
|
| + input_buffer_queue_.push_back(buffer);
|
| + SendInputBufferToGpu();
|
| +}
|
| +
|
| +void GpuVideoDecoderHost::FillThisBuffer(scoped_refptr<VideoFrame> frame) {
|
| + DCHECK_NE(state_, kStateUninitialized);
|
| +
|
| + // Depends on who provides buffer. client could return buffer to
|
| + // us while flushing.
|
| + if (state_ == kStateError)
|
| + return;
|
| +
|
| + GpuVideoDecoderOutputBufferParam param;
|
| + if (!channel_host_->Send(
|
| + new GpuVideoDecoderMsg_FillThisBuffer(route_id(), param))) {
|
| + LOG(ERROR) << "GpuVideoDecoderMsg_FillThisBuffer failed";
|
| + }
|
| +}
|
| +
|
| +bool GpuVideoDecoderHost::Flush() {
|
| + state_ = kStateFlushing;
|
| + if (!channel_host_->Send(new GpuVideoDecoderMsg_Flush(route_id()))) {
|
| + LOG(ERROR) << "GpuVideoDecoderMsg_Flush failed";
|
| + return false;
|
| + }
|
| + input_buffer_queue_.clear();
|
| + // TODO(jiesun): because GpuVideoDeocder/GpuVideoDecoder are asynchronously.
|
| + // We need a way to make flush logic more clear. but I think ring buffer
|
| + // should make the busy flag obsolete, therefore I will leave it for now.
|
| + input_buffer_busy_ = false;
|
| + return true;
|
| +}
|
| +
|
| +void GpuVideoDecoderHost::OnInitializeDone(
|
| + const GpuVideoDecoderInitDoneParam& param) {
|
| + done_param_ = param;
|
| + bool success = false;
|
| +
|
| + do {
|
| + if (!param.success_)
|
| + break;
|
| +
|
| + if (!base::SharedMemory::IsHandleValid(param.input_buffer_handle_))
|
| + break;
|
| + input_transfer_buffer_.reset(
|
| + new base::SharedMemory(param.input_buffer_handle_, false));
|
| + if (!input_transfer_buffer_->Map(param.input_buffer_size_))
|
| + break;
|
| +
|
| + if (!base::SharedMemory::IsHandleValid(param.output_buffer_handle_))
|
| + break;
|
| + output_transfer_buffer_.reset(
|
| + new base::SharedMemory(param.output_buffer_handle_, false));
|
| + if (!output_transfer_buffer_->Map(param.output_buffer_size_))
|
| + break;
|
| +
|
| + success = true;
|
| + } while (0);
|
| +
|
| + state_ = success ? kStateNormal : kStateError;
|
| + event_handler_->OnInitializeDone(success, param);
|
| +}
|
| +
|
| +void GpuVideoDecoderHost::OnUninitializeDone() {
|
| + input_transfer_buffer_.reset();
|
| + output_transfer_buffer_.reset();
|
| +
|
| + event_handler_->OnUninitializeDone();
|
| +}
|
| +
|
| +void GpuVideoDecoderHost::OnFlushDone() {
|
| + state_ = kStateNormal;
|
| + event_handler_->OnFlushDone();
|
| +}
|
| +
|
| +void GpuVideoDecoderHost::OnEmptyThisBufferDone() {
|
| + scoped_refptr<Buffer> buffer;
|
| + event_handler_->OnEmptyBufferDone(buffer);
|
| +}
|
| +
|
| +void GpuVideoDecoderHost::OnFillThisBufferDone(
|
| + const GpuVideoDecoderOutputBufferParam& param) {
|
| + scoped_refptr<VideoFrame> frame;
|
| +
|
| + if (param.flags_ & GpuVideoDecoderOutputBufferParam::kFlagsEndOfStream) {
|
| + VideoFrame::CreateEmptyFrame(&frame);
|
| + } else {
|
| + VideoFrame::CreateFrame(VideoFrame::YV12,
|
| + init_param_.width_,
|
| + init_param_.height_,
|
| + base::TimeDelta::FromMicroseconds(param.timestamp_),
|
| + base::TimeDelta::FromMicroseconds(param.duration_),
|
| + &frame);
|
| +
|
| + uint8* src = static_cast<uint8*>(output_transfer_buffer_->memory());
|
| + uint8* data0 = frame->data(0);
|
| + uint8* data1 = frame->data(1);
|
| + uint8* data2 = frame->data(2);
|
| + int32 size = init_param_.width_ * init_param_.height_;
|
| + memcpy(data0, src, size);
|
| + memcpy(data1, src + size, size / 4);
|
| + memcpy(data2, src + size + size / 4, size / 4);
|
| + }
|
| +
|
| + event_handler_->OnFillBufferDone(frame);
|
| + if (!channel_host_->Send(
|
| + new GpuVideoDecoderMsg_FillThisBufferDoneACK(route_id()))) {
|
| + LOG(ERROR) << "GpuVideoDecoderMsg_FillThisBufferDoneACK failed";
|
| + }
|
| +}
|
| +
|
| +void GpuVideoDecoderHost::OnEmptyThisBufferACK() {
|
| + input_buffer_busy_ = false;
|
| + SendInputBufferToGpu();
|
| +}
|
| +
|
| +void GpuVideoDecoderHost::SendInputBufferToGpu() {
|
| + if (input_buffer_busy_) return;
|
| + if (input_buffer_queue_.empty()) return;
|
| +
|
| + input_buffer_busy_ = true;
|
| +
|
| + scoped_refptr<Buffer> buffer;
|
| + buffer = input_buffer_queue_.front();
|
| + input_buffer_queue_.pop_front();
|
| +
|
| + // Send input data to GPU process.
|
| + GpuVideoDecoderInputBufferParam param;
|
| + param.offset_ = 0;
|
| + param.size_ = buffer->GetDataSize();
|
| + param.timestamp_ = buffer->GetTimestamp().InMicroseconds();
|
| + memcpy(input_transfer_buffer_->memory(), buffer->GetData(), param.size_);
|
| + if (!channel_host_->Send(
|
| + new GpuVideoDecoderMsg_EmptyThisBuffer(route_id(), param))) {
|
| + LOG(ERROR) << "GpuVideoDecoderMsg_EmptyThisBuffer failed";
|
| + }
|
| +}
|
| +
|
|
|