summaryrefslogtreecommitdiffstats
path: root/chrome/renderer/gpu_video_decoder_host.cc
diff options
context:
space:
mode:
authorjiesun@google.com <jiesun@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-09 15:59:44 +0000
committerjiesun@google.com <jiesun@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-09 15:59:44 +0000
commitc9f28a7d16b71b17185b456e3b53e4e638d005d0 (patch)
tree5940cfb4244935b01608e286f84a83413e0329a1 /chrome/renderer/gpu_video_decoder_host.cc
parent6b1b2b6bc21270ef1b90a28293a1cb743e933383 (diff)
downloadchromium_src-c9f28a7d16b71b17185b456e3b53e4e638d005d0.zip
chromium_src-c9f28a7d16b71b17185b456e3b53e4e638d005d0.tar.gz
chromium_src-c9f28a7d16b71b17185b456e3b53e4e638d005d0.tar.bz2
Special thanks for in-ming cheng's MFT hardware decodering code.
1. ipc_video_decoder.cc/h is media pipeline filter which use the gpu decoder facilities in video stack. it is only enabled when (a) hardware composition is on (b) hardware decoding command line is on (c) h264 codec is specified. 2. gpu_video_service.cc/h is a singleton in gpu process which provide video services for renderer process, through it we could create decoder. ( in my imagination, in the future, we could create encoder or capturer too) 3. gpu_video_decoder.cc/h. abstract interface for hardware decoder. 4. gpu_video_decoder_mft.cc/h media foundation transform hardware decoder which run on windows 7 only. 5. gpu_video_service_host.cc/h is singleton in renderer process which provide proxy for gpu_video_service. 6. gpu_video_decoder_host.cc/h is proxy for gpu_video_decoder. (1 to 1 map).basically there is one global GpuVideoService in GPU process, one GpuVideoServiceHost in Renderer process. for each renderer process, there are could be multiple renderer view, each could had multiple GpuVideoDecoderHost the connect to GpuVideoDeocder through GPUCHannelHOst/GpuChannel. 7. gpu_video_common.cc/h: IPC message definition and pickle/marshaling support. ISSUES: 1. in media pipeline, we need let decoder to determine if bit stream filter should be used instead of let command line to determine it. 2. stop readback from D3D surface use ANGLE. 3. Flush logic still need fine tuning. 4. CreateThread in GpuVideoDecoder, and post message in message handler, and derived classs handle message loop. ? 5. Error handling. 6. Input ring buffer implementation. Current impl is naive. 7.Add output queue for MFT decoder. 8. Query Capabilities at GetVideoServices()... BUG=None TEST=Windows7 Review URL: http://codereview.chromium.org/2873089 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@55405 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer/gpu_video_decoder_host.cc')
-rw-r--r--chrome/renderer/gpu_video_decoder_host.cc199
1 files changed, 199 insertions, 0 deletions
diff --git a/chrome/renderer/gpu_video_decoder_host.cc b/chrome/renderer/gpu_video_decoder_host.cc
new file mode 100644
index 0000000..5e0f727
--- /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";
+ }
+}
+