summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/gpu_messages_internal.h20
-rw-r--r--chrome/common/gpu_video_common.cc28
-rw-r--r--chrome/common/gpu_video_common.h25
-rw-r--r--chrome/gpu/gpu_channel.cc20
-rw-r--r--chrome/gpu/gpu_channel.h3
-rw-r--r--chrome/gpu/gpu_video_decoder.cc23
-rw-r--r--chrome/gpu/gpu_video_decoder.h7
-rw-r--r--chrome/gpu/gpu_video_decoder_unittest.cc8
-rw-r--r--chrome/gpu/gpu_video_service.cc31
-rw-r--r--chrome/gpu/gpu_video_service.h12
-rw-r--r--chrome/renderer/gpu_video_decoder_host.cc298
-rw-r--r--chrome/renderer/gpu_video_decoder_host.h77
-rw-r--r--chrome/renderer/gpu_video_decoder_host_unittest.cc259
-rw-r--r--chrome/renderer/gpu_video_service_host.cc18
-rw-r--r--chrome/renderer/gpu_video_service_host.h10
-rw-r--r--media/base/video_frame.h2
-rw-r--r--media/video/mock_objects.h20
18 files changed, 631 insertions, 231 deletions
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 80653b1..1af8b15 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1555,6 +1555,7 @@
'renderer/extensions/extension_api_json_validity_unittest.cc',
'renderer/extensions/extension_renderer_info_unittest.cc',
'renderer/extensions/json_schema_unittest.cc',
+ 'renderer/gpu_video_decoder_host_unittest.cc',
'renderer/media/audio_renderer_impl_unittest.cc',
'renderer/net/predictor_queue_unittest.cc',
'renderer/net/renderer_predictor_unittest.cc',
diff --git a/chrome/common/gpu_messages_internal.h b/chrome/common/gpu_messages_internal.h
index 9a6896b..daaaa24 100644
--- a/chrome/common/gpu_messages_internal.h
+++ b/chrome/common/gpu_messages_internal.h
@@ -188,11 +188,13 @@ IPC_BEGIN_MESSAGES(GpuChannel)
// Create hardware video decoder && associate it with the output |decoder_id|;
// We need this to be control message because we had to map the GpuChannel and
// |decoder_id|.
- IPC_SYNC_MESSAGE_CONTROL0_1(GpuChannelMsg_CreateVideoDecoder,
- GpuVideoDecoderInfoParam)
+ IPC_MESSAGE_CONTROL2(GpuChannelMsg_CreateVideoDecoder,
+ int32, /* context_route_id */
+ int32) /* decoder_id */
// Release all resource of the hardware video decoder which was assocaited
// with the input |decoder_id|.
+ // TODO(hclam): This message needs to be asynchronous.
IPC_SYNC_MESSAGE_CONTROL1_0(GpuChannelMsg_DestroyVideoDecoder,
int32 /* decoder_id */)
@@ -284,8 +286,8 @@ IPC_BEGIN_MESSAGES(GpuCommandBuffer)
IPC_END_MESSAGES(GpuCommandBuffer)
//------------------------------------------------------------------------------
-
-// GpuVideoDecoderMsgs : send from renderer process to gpu process.
+// GPU Video Decoder Messages
+// These messages are sent from Renderer process to GPU process.
IPC_BEGIN_MESSAGES(GpuVideoDecoder)
// Initialize and configure GpuVideoDecoder asynchronously.
IPC_MESSAGE_ROUTED1(GpuVideoDecoderMsg_Initialize,
@@ -314,9 +316,13 @@ IPC_BEGIN_MESSAGES(GpuVideoDecoder)
IPC_END_MESSAGES(GpuVideoDecoder)
//------------------------------------------------------------------------------
-
-// GpuVideoDecoderMsgs : send from gpu process to renderer process.
+// GPU Video Decoder Host Messages
+// These messages are sent from GPU process to Renderer process.
IPC_BEGIN_MESSAGES(GpuVideoDecoderHost)
+ // Inform GpuVideoDecoderHost that a GpuVideoDecoder is created.
+ IPC_MESSAGE_ROUTED1(GpuVideoDecoderHostMsg_CreateVideoDecoderDone,
+ int32) /* decoder_id */
+
// Confirm GpuVideoDecoder had been initialized or failed to initialize.
IPC_MESSAGE_ROUTED1(GpuVideoDecoderHostMsg_InitializeACK,
GpuVideoDecoderInitDoneParam)
@@ -342,7 +348,7 @@ IPC_BEGIN_MESSAGES(GpuVideoDecoderHost)
// Allocate video frames for output of the hardware video decoder.
IPC_MESSAGE_ROUTED4(GpuVideoDecoderHostMsg_AllocateVideoFrames,
- int32, /* Numer of video frames to generate */
+ int32, /* Number of video frames to generate */
uint32, /* Width of the video frame */
uint32, /* Height of the video frame */
int32 /* Format of the video frame */)
diff --git a/chrome/common/gpu_video_common.cc b/chrome/common/gpu_video_common.cc
index 556e385..f6339e3 100644
--- a/chrome/common/gpu_video_common.cc
+++ b/chrome/common/gpu_video_common.cc
@@ -32,34 +32,6 @@ void ParamTraits<GpuVideoServiceInfoParam>::Log(
///////////////////////////////////////////////////////////////////////////////
-void ParamTraits<GpuVideoDecoderInfoParam>::Write(
- Message* m, const GpuVideoDecoderInfoParam& p) {
- WriteParam(m, p.context_id);
- WriteParam(m, p.decoder_id);
- WriteParam(m, p.decoder_route_id);
- WriteParam(m, p.decoder_host_route_id);
-}
-
-bool ParamTraits<GpuVideoDecoderInfoParam>::Read(
- const Message* m, void** iter, GpuVideoDecoderInfoParam* r) {
- if (!ReadParam(m, iter, &r->context_id) ||
- !ReadParam(m, iter, &r->decoder_id) ||
- !ReadParam(m, iter, &r->decoder_route_id) ||
- !ReadParam(m, iter, &r->decoder_host_route_id))
- return false;
- return true;
-}
-
-void ParamTraits<GpuVideoDecoderInfoParam>::Log(
- const GpuVideoDecoderInfoParam& p, std::string* l) {
- l->append(StringPrintf("(%d, %d, %d)",
- p.decoder_id,
- p.decoder_route_id,
- p.decoder_host_route_id));
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
void ParamTraits<GpuVideoDecoderInitParam>::Write(
Message* m, const GpuVideoDecoderInitParam& p) {
WriteParam(m, p.codec_id);
diff --git a/chrome/common/gpu_video_common.h b/chrome/common/gpu_video_common.h
index 30a94be..55a44bc 100644
--- a/chrome/common/gpu_video_common.h
+++ b/chrome/common/gpu_video_common.h
@@ -19,27 +19,14 @@ enum GpuVideoBufferFlag {
struct GpuVideoServiceInfoParam {
// route id for GpuVideoService on GPU process side for this channel.
int32 video_service_route_id;
+
// route id for GpuVideoServiceHost on Render process side for this channel.
int32 video_service_host_route_id;
+
// TODO(jiesun): define capabilities of video service.
int32 service_available;
};
-struct GpuVideoDecoderInfoParam {
- // Context ID of the GLES2 context what this decoder should assicate with.
- int context_id;
-
- // Global decoder id.
- int32 decoder_id;
-
- // Route id for GpuVideoDecoder on GPU process side for this channel.
- int32 decoder_route_id;
-
- // TODO(hclam): Merge this ID with |decoder_route_id_|.
- // Route id for GpuVideoServiceHost on Render process side for this channel.
- int32 decoder_host_route_id;
-};
-
struct GpuVideoDecoderInitParam {
int32 codec_id;
int32 width;
@@ -86,14 +73,6 @@ struct ParamTraits<GpuVideoServiceInfoParam> {
};
template <>
-struct ParamTraits<GpuVideoDecoderInfoParam> {
- typedef GpuVideoDecoderInfoParam param_type;
- static void Write(Message* m, const param_type& p);
- static bool Read(const Message* m, void** iter, param_type* r);
- static void Log(const param_type& p, std::string* l);
-};
-
-template <>
struct ParamTraits<GpuVideoDecoderInitParam> {
typedef GpuVideoDecoderInitParam param_type;
static void Write(Message* m, const param_type& p);
diff --git a/chrome/gpu/gpu_channel.cc b/chrome/gpu/gpu_channel.cc
index c5c5025..9b8095f 100644
--- a/chrome/gpu/gpu_channel.cc
+++ b/chrome/gpu/gpu_channel.cc
@@ -206,24 +206,26 @@ void GpuChannel::OnGetVideoService(GpuVideoServiceInfoParam* info) {
#endif
}
-void GpuChannel::OnCreateVideoDecoder(GpuVideoDecoderInfoParam* info) {
+void GpuChannel::OnCreateVideoDecoder(int32 context_route_id,
+ int32 decoder_host_id) {
#if defined(ENABLE_GPU)
LOG(INFO) << "GpuChannel::OnCreateVideoDecoder";
- info->decoder_id = -1;
GpuVideoService* service = GpuVideoService::get();
- if (service == NULL)
+ if (service == NULL) {
+ // TODO(hclam): Need to send a failure message.
return;
+ }
// The context ID corresponds to the command buffer used.
- GpuCommandBufferStub* stub = stubs_.Lookup(info->context_id);
-
- info->decoder_host_route_id = GenerateRouteID();
- info->decoder_route_id = GenerateRouteID();
+ GpuCommandBufferStub* stub = stubs_.Lookup(context_route_id);
+ int32 decoder_id = GenerateRouteID();
// TODO(hclam): Need to be careful about the lifetime of the command buffer
// decoder.
- service->CreateVideoDecoder(this, &router_, info,
- stub->processor()->decoder());
+ bool ret = service->CreateVideoDecoder(
+ this, &router_, decoder_host_id, decoder_id,
+ stub->processor()->decoder());
+ DCHECK(ret) << "Failed to create a GpuVideoDecoder";
#endif
}
diff --git a/chrome/gpu/gpu_channel.h b/chrome/gpu/gpu_channel.h
index 13994c3..73fce43 100644
--- a/chrome/gpu/gpu_channel.h
+++ b/chrome/gpu/gpu_channel.h
@@ -76,7 +76,8 @@ class GpuChannel : public IPC::Channel::Listener,
void OnDestroyCommandBuffer(int32 route_id);
void OnGetVideoService(GpuVideoServiceInfoParam* info);
- void OnCreateVideoDecoder(GpuVideoDecoderInfoParam* info);
+ void OnCreateVideoDecoder(int32 context_route_id,
+ int32 decoder_host_id);
void OnDestroyVideoDecoder(int32 decoder_id);
scoped_ptr<IPC::SyncChannel> channel_;
diff --git a/chrome/gpu/gpu_video_decoder.cc b/chrome/gpu/gpu_video_decoder.cc
index a7877a0..b316253 100644
--- a/chrome/gpu/gpu_video_decoder.cc
+++ b/chrome/gpu/gpu_video_decoder.cc
@@ -209,12 +209,12 @@ void GpuVideoDecoder::SetGpuVideoDevice(GpuVideoDevice* device) {
GpuVideoDecoder::GpuVideoDecoder(
MessageLoop* message_loop,
- const GpuVideoDecoderInfoParam* param,
+ int32 decoder_host_id,
IPC::Message::Sender* sender,
base::ProcessHandle handle,
gpu::gles2::GLES2Decoder* decoder)
: message_loop_(message_loop),
- decoder_host_route_id_(param->decoder_host_route_id),
+ decoder_host_id_(decoder_host_id),
sender_(sender),
renderer_handle_(handle),
gles2_decoder_(decoder) {
@@ -310,33 +310,34 @@ void GpuVideoDecoder::OnVideoFrameAllocated(int32 frame_id,
void GpuVideoDecoder::SendInitializeDone(
const GpuVideoDecoderInitDoneParam& param) {
if (!sender_->Send(
- new GpuVideoDecoderHostMsg_InitializeACK(route_id(), param))) {
+ new GpuVideoDecoderHostMsg_InitializeACK(decoder_host_id(), param))) {
LOG(ERROR) << "GpuVideoDecoderMsg_InitializeACK failed";
}
}
void GpuVideoDecoder::SendUninitializeDone() {
- if (!sender_->Send(new GpuVideoDecoderHostMsg_DestroyACK(route_id()))) {
+ if (!sender_->Send(
+ new GpuVideoDecoderHostMsg_DestroyACK(decoder_host_id()))) {
LOG(ERROR) << "GpuVideoDecoderMsg_DestroyACK failed";
}
}
void GpuVideoDecoder::SendFlushDone() {
- if (!sender_->Send(new GpuVideoDecoderHostMsg_FlushACK(route_id()))) {
+ if (!sender_->Send(new GpuVideoDecoderHostMsg_FlushACK(decoder_host_id()))) {
LOG(ERROR) << "GpuVideoDecoderMsg_FlushACK failed";
}
}
void GpuVideoDecoder::SendEmptyBufferDone() {
if (!sender_->Send(
- new GpuVideoDecoderHostMsg_EmptyThisBufferDone(route_id()))) {
+ new GpuVideoDecoderHostMsg_EmptyThisBufferDone(decoder_host_id()))) {
LOG(ERROR) << "GpuVideoDecoderMsg_EmptyThisBufferDone failed";
}
}
void GpuVideoDecoder::SendEmptyBufferACK() {
if (!sender_->Send(
- new GpuVideoDecoderHostMsg_EmptyThisBufferACK(route_id()))) {
+ new GpuVideoDecoderHostMsg_EmptyThisBufferACK(decoder_host_id()))) {
LOG(ERROR) << "GpuVideoDecoderMsg_EmptyThisBufferACK failed";
}
}
@@ -345,7 +346,7 @@ void GpuVideoDecoder::SendConsumeVideoFrame(
int32 frame_id, int64 timestamp, int64 duration, int32 flags) {
if (!sender_->Send(
new GpuVideoDecoderHostMsg_ConsumeVideoFrame(
- route_id(), frame_id, timestamp, duration, flags))) {
+ decoder_host_id(), frame_id, timestamp, duration, flags))) {
LOG(ERROR) << "GpuVideoDecodeHostMsg_ConsumeVideoFrame failed.";
}
}
@@ -354,14 +355,16 @@ void GpuVideoDecoder::SendAllocateVideoFrames(
int n, size_t width, size_t height, media::VideoFrame::Format format) {
if (!sender_->Send(
new GpuVideoDecoderHostMsg_AllocateVideoFrames(
- route_id(), n, width, height, static_cast<int32>(format)))) {
+ decoder_host_id(), n, width, height,
+ static_cast<int32>(format)))) {
LOG(ERROR) << "GpuVideoDecoderMsg_AllocateVideoFrames failed";
}
}
void GpuVideoDecoder::SendReleaseAllVideoFrames() {
if (!sender_->Send(
- new GpuVideoDecoderHostMsg_ReleaseAllVideoFrames(route_id()))) {
+ new GpuVideoDecoderHostMsg_ReleaseAllVideoFrames(
+ decoder_host_id()))) {
LOG(ERROR) << "GpuVideoDecoderMsg_ReleaseAllVideoFrames failed";
}
}
diff --git a/chrome/gpu/gpu_video_decoder.h b/chrome/gpu/gpu_video_decoder.h
index f975eb8..786e0de 100644
--- a/chrome/gpu/gpu_video_decoder.h
+++ b/chrome/gpu/gpu_video_decoder.h
@@ -93,7 +93,7 @@ class GpuVideoDecoder
public:
// Constructor and destructor.
GpuVideoDecoder(MessageLoop* message_loop,
- const GpuVideoDecoderInfoParam* param,
+ int32 decoder_host_id,
IPC::Message::Sender* sender,
base::ProcessHandle handle,
gpu::gles2::GLES2Decoder* decoder);
@@ -139,7 +139,7 @@ class GpuVideoDecoder
Task* task;
};
- int32 route_id() { return decoder_host_route_id_; }
+ int32 decoder_host_id() { return decoder_host_id_; }
bool CreateInputTransferBuffer(uint32 size,
base::SharedMemoryHandle* handle);
@@ -168,7 +168,8 @@ class GpuVideoDecoder
// The message loop that this object should run on.
MessageLoop* message_loop_;
- int32 decoder_host_route_id_;
+ // ID of GpuVideoDecoderHost in the Renderer Process.
+ int32 decoder_host_id_;
// Used only in system memory path. i.e. Remove this later.
scoped_refptr<VideoFrame> frame_;
diff --git a/chrome/gpu/gpu_video_decoder_unittest.cc b/chrome/gpu/gpu_video_decoder_unittest.cc
index 4548807..948e30b 100644
--- a/chrome/gpu/gpu_video_decoder_unittest.cc
+++ b/chrome/gpu/gpu_video_decoder_unittest.cc
@@ -18,6 +18,7 @@ using testing::Return;
using testing::SetArgumentPointee;
static const int32 kFrameId = 10;
+static const int32 kDecoderHostId = 50;
static const media::VideoFrame::GlTexture kClientTexture = 101;
static const media::VideoFrame::GlTexture kServiceTexture = 102;
static const size_t kWidth = 320;
@@ -71,11 +72,8 @@ class GpuVideoDecoderTest : public testing::Test,
// Create the mock objects.
gles2_decoder_.reset(new gpu::gles2::MockGLES2Decoder(&group_));
- // Initialize GpuVideoDecoder with the default params.
- GpuVideoDecoderInfoParam param;
- memset(&param, 0, sizeof(param));
gpu_video_decoder_ = new GpuVideoDecoder(
- &message_loop_, &param, this, base::kNullProcessHandle,
+ &message_loop_, kDecoderHostId, this, base::kNullProcessHandle,
gles2_decoder_.get());
// Create the mock objects.
@@ -95,7 +93,7 @@ class GpuVideoDecoderTest : public testing::Test,
&device_frame_);
}
- ~GpuVideoDecoderTest() {
+ virtual ~GpuVideoDecoderTest() {
gpu_video_decoder_->SetVideoDecodeEngine(NULL);
gpu_video_decoder_->SetGpuVideoDevice(NULL);
}
diff --git a/chrome/gpu/gpu_video_service.cc b/chrome/gpu/gpu_video_service.cc
index 6ff2e81..2ef32e8 100644
--- a/chrome/gpu/gpu_video_service.cc
+++ b/chrome/gpu/gpu_video_service.cc
@@ -7,7 +7,7 @@
#include "chrome/gpu/gpu_video_decoder.h"
#include "chrome/gpu/gpu_video_service.h"
-GpuVideoService::GpuVideoService() : next_available_decoder_id_(0) {
+GpuVideoService::GpuVideoService() {
// TODO(jiesun): move this time consuming stuff out of here.
IntializeGpuVideoService();
}
@@ -43,30 +43,27 @@ bool GpuVideoService::UnintializeGpuVideoService() {
bool GpuVideoService::CreateVideoDecoder(
GpuChannel* channel,
MessageRouter* router,
- GpuVideoDecoderInfoParam* param,
+ int32 decoder_host_id,
+ int32 decoder_id,
gpu::gles2::GLES2Decoder* gles2_decoder) {
GpuVideoDecoderInfo decoder_info;
- int32 decoder_id = GetNextAvailableDecoderID();
- param->decoder_id = decoder_id;
- base::ProcessHandle handle = channel->renderer_handle();
- decoder_info.decoder_ = new GpuVideoDecoder(MessageLoop::current(),
- param, channel, handle,
- gles2_decoder);
- decoder_info.channel_ = channel;
- decoder_info.param = *param;
+ decoder_info.decoder = new GpuVideoDecoder(MessageLoop::current(),
+ decoder_host_id,
+ channel,
+ channel->renderer_handle(),
+ gles2_decoder);
+ decoder_info.channel = channel;
decoder_map_[decoder_id] = decoder_info;
- router->AddRoute(param->decoder_route_id, decoder_info.decoder_);
+ router->AddRoute(decoder_id, decoder_info.decoder);
+
+ channel->Send(new GpuVideoDecoderHostMsg_CreateVideoDecoderDone(
+ decoder_host_id, decoder_id));
return true;
}
void GpuVideoService::DestroyVideoDecoder(
MessageRouter* router,
int32 decoder_id) {
- int32 route_id = decoder_map_[decoder_id].param.decoder_route_id;
- router->RemoveRoute(route_id);
+ router->RemoveRoute(decoder_id);
decoder_map_.erase(decoder_id);
}
-
-int32 GpuVideoService::GetNextAvailableDecoderID() {
- return ++next_available_decoder_id_;
-}
diff --git a/chrome/gpu/gpu_video_service.h b/chrome/gpu/gpu_video_service.h
index 0b446bb..a2c090e 100644
--- a/chrome/gpu/gpu_video_service.h
+++ b/chrome/gpu/gpu_video_service.h
@@ -22,32 +22,30 @@ class GpuVideoService : public IPC::Channel::Listener,
virtual void OnChannelError();
virtual void OnMessageReceived(const IPC::Message& message);
+ // TODO(hclam): Remove return value.
bool CreateVideoDecoder(GpuChannel* channel,
MessageRouter* router,
- GpuVideoDecoderInfoParam* param,
+ int32 decoder_host_id,
+ int32 decoder_id,
gpu::gles2::GLES2Decoder* gles2_decoder);
void DestroyVideoDecoder(MessageRouter* router,
int32 decoder_id);
private:
struct GpuVideoDecoderInfo {
- scoped_refptr<GpuVideoDecoder> decoder_;
- GpuChannel* channel_;
- GpuVideoDecoderInfoParam param;
+ scoped_refptr<GpuVideoDecoder> decoder;
+ GpuChannel* channel;
};
GpuVideoService();
virtual ~GpuVideoService();
std::map<int32, GpuVideoDecoderInfo> decoder_map_;
- int32 next_available_decoder_id_;
// Specialize video service on different platform will override.
virtual bool IntializeGpuVideoService();
virtual bool UnintializeGpuVideoService();
- int32 GetNextAvailableDecoderID();
-
friend struct DefaultSingletonTraits<GpuVideoService>;
DISALLOW_COPY_AND_ASSIGN(GpuVideoService);
};
diff --git a/chrome/renderer/gpu_video_decoder_host.cc b/chrome/renderer/gpu_video_decoder_host.cc
index 08e7d5d..4a97702 100644
--- a/chrome/renderer/gpu_video_decoder_host.cc
+++ b/chrome/renderer/gpu_video_decoder_host.cc
@@ -5,22 +5,25 @@
#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"
+#include "chrome/common/message_router.h"
+#include "media/video/video_decode_context.h"
-GpuVideoDecoderHost::GpuVideoDecoderHost(GpuVideoServiceHost* service_host,
+GpuVideoDecoderHost::GpuVideoDecoderHost(MessageRouter* router,
IPC::Message::Sender* ipc_sender,
- int context_route_id)
- : gpu_video_service_host_(service_host),
+ int context_route_id,
+ int32 decoder_host_id)
+ : router_(router),
ipc_sender_(ipc_sender),
context_route_id_(context_route_id),
+ message_loop_(NULL),
event_handler_(NULL),
- buffer_id_serial_(0),
+ context_(NULL),
state_(kStateUninitialized),
- input_buffer_busy_(false) {
+ decoder_host_id_(decoder_host_id),
+ decoder_id_(0),
+ input_buffer_busy_(false),
+ current_frame_id_(0) {
memset(&config_, 0, sizeof(config_));
- memset(&done_param_, 0, sizeof(done_param_));
- memset(&decoder_info_, 0, sizeof(decoder_info_));
}
void GpuVideoDecoderHost::OnChannelError() {
@@ -29,6 +32,8 @@ void GpuVideoDecoderHost::OnChannelError() {
void GpuVideoDecoderHost::OnMessageReceived(const IPC::Message& msg) {
IPC_BEGIN_MESSAGE_MAP(GpuVideoDecoderHost, msg)
+ IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_CreateVideoDecoderDone,
+ OnCreateVideoDecoderDone)
IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_InitializeACK,
OnInitializeDone)
IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_DestroyACK,
@@ -38,7 +43,13 @@ void GpuVideoDecoderHost::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_EmptyThisBufferACK,
OnEmptyThisBufferACK)
IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_EmptyThisBufferDone,
- OnEmptyThisBufferDone)
+ OnProduceVideoSample)
+ IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_ConsumeVideoFrame,
+ OnConsumeVideoFrame)
+ IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_AllocateVideoFrames,
+ OnAllocateVideoFrames)
+ IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_ReleaseAllVideoFrames,
+ OnReleaseAllVideoFrames)
IPC_MESSAGE_UNHANDLED_ERROR()
IPC_END_MESSAGE_MAP()
}
@@ -46,41 +57,44 @@ void GpuVideoDecoderHost::OnMessageReceived(const IPC::Message& msg) {
void GpuVideoDecoderHost::Initialize(
MessageLoop* message_loop, VideoDecodeEngine::EventHandler* event_handler,
media::VideoDecodeContext* context, const media::VideoCodecConfig& config) {
- // TODO(hclam): Call |event_handler| here.
- DCHECK_EQ(state_, kStateUninitialized);
-
- // Save the event handler before we perform initialization operations so
- // that we can report initialization events.
- event_handler_ = event_handler;
-
- // TODO(hclam): This create video decoder operation is synchronous, need to
- // make it asynchronous.
- decoder_info_.context_id = context_route_id_;
- if (!ipc_sender_->Send(
- new GpuChannelMsg_CreateVideoDecoder(&decoder_info_))) {
- LOG(ERROR) << "GpuChannelMsg_CreateVideoDecoder failed";
+ if (MessageLoop::current() != message_loop) {
+ message_loop->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &GpuVideoDecoderHost::Initialize, message_loop,
+ event_handler, context, config));
return;
}
- // Add the route so we'll receive messages.
- gpu_video_service_host_->AddRoute(my_route_id(), this);
-
- // Save the configuration parameters.
+ // Initialization operations should be performed on the message loop assigned.
+ // Save the parameters and post a task to complete initialization.
+ DCHECK_EQ(kStateUninitialized, state_);
+ DCHECK(!message_loop_);
+ message_loop_ = message_loop;
+ event_handler_ = event_handler;
+ context_ = context;
config_ = config;
- // TODO(hclam): Initialize |param| with the right values.
- GpuVideoDecoderInitParam param;
- param.width = config.width;
- param.height = config.height;
+ // Add the route so we'll receive messages.
+ router_->AddRoute(decoder_host_id_, this);
- if (!ipc_sender_ || !ipc_sender_->Send(
- new GpuVideoDecoderMsg_Initialize(route_id(), param))) {
- LOG(ERROR) << "GpuVideoDecoderMsg_Initialize failed";
+ if (!ipc_sender_->Send(
+ new GpuChannelMsg_CreateVideoDecoder(context_route_id_,
+ decoder_host_id_))) {
+ LOG(ERROR) << "GpuChannelMsg_CreateVideoDecoder failed";
+ event_handler_->OnError();
return;
}
}
void GpuVideoDecoderHost::ConsumeVideoSample(scoped_refptr<Buffer> buffer) {
+ if (MessageLoop::current() != message_loop_) {
+ message_loop_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(
+ this, &GpuVideoDecoderHost::ConsumeVideoSample, buffer));
+ return;
+ }
+
DCHECK_NE(state_, kStateUninitialized);
DCHECK_NE(state_, kStateFlushing);
@@ -90,124 +104,226 @@ void GpuVideoDecoderHost::ConsumeVideoSample(scoped_refptr<Buffer> buffer) {
return;
input_buffer_queue_.push_back(buffer);
- SendInputBufferToGpu();
+ SendConsumeVideoSample();
}
void GpuVideoDecoderHost::ProduceVideoFrame(scoped_refptr<VideoFrame> frame) {
+ if (MessageLoop::current() != message_loop_) {
+ message_loop_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(
+ this, &GpuVideoDecoderHost::ProduceVideoFrame, frame));
+ return;
+ }
+
DCHECK_NE(state_, kStateUninitialized);
- // Depends on who provides buffer. client could return buffer to
- // us while flushing.
+ // During flush client of this object will call this method to return all
+ // video frames. We should only ignore such method calls if we are in error
+ // state.
if (state_ == kStateError)
return;
- // TODO(hclam): We should keep an IDMap to convert between a frame a buffer
- // ID so that we can signal GpuVideoDecoder in GPU process to use the buffer.
- // This eliminates one conversion step.
+ // Check that video frame is valid.
+ if (!frame || frame->format() == media::VideoFrame::EMPTY ||
+ frame->IsEndOfStream()) {
+ return;
+ }
+
+ SendProduceVideoFrame(frame);
}
void GpuVideoDecoderHost::Uninitialize() {
- if (!ipc_sender_ || !ipc_sender_->Send(
- new GpuVideoDecoderMsg_Destroy(route_id()))) {
- LOG(ERROR) << "GpuVideoDecoderMsg_Destroy failed";
+ if (MessageLoop::current() != message_loop_) {
+ message_loop_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &GpuVideoDecoderHost::Uninitialize));
return;
}
- gpu_video_service_host_->RemoveRoute(my_route_id());
- return;
+ if (!ipc_sender_->Send(new GpuVideoDecoderMsg_Destroy(decoder_id_))) {
+ LOG(ERROR) << "GpuVideoDecoderMsg_Destroy failed";
+ event_handler_->OnError();
+ }
}
void GpuVideoDecoderHost::Flush() {
+ if (MessageLoop::current() != message_loop_) {
+ message_loop_->PostTask(
+ FROM_HERE, NewRunnableMethod(this, &GpuVideoDecoderHost::Flush));
+ return;
+ }
+
state_ = kStateFlushing;
- if (!ipc_sender_ || !ipc_sender_->Send(
- new GpuVideoDecoderMsg_Flush(route_id()))) {
+ if (!ipc_sender_->Send(new GpuVideoDecoderMsg_Flush(decoder_id_))) {
LOG(ERROR) << "GpuVideoDecoderMsg_Flush failed";
+ event_handler_->OnError();
return;
}
+
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;
}
void GpuVideoDecoderHost::Seek() {
// TODO(hclam): Implement.
}
+void GpuVideoDecoderHost::OnCreateVideoDecoderDone(int32 decoder_id) {
+ DCHECK_EQ(message_loop_, MessageLoop::current());
+ decoder_id_ = decoder_id;
+
+ // TODO(hclam): Initialize |param| with the right values.
+ GpuVideoDecoderInitParam param;
+ param.width = config_.width;
+ param.height = config_.height;
+
+ if (!ipc_sender_->Send(
+ new GpuVideoDecoderMsg_Initialize(decoder_id, param))) {
+ LOG(ERROR) << "GpuVideoDecoderMsg_Initialize failed";
+ event_handler_->OnError();
+ }
+}
+
void GpuVideoDecoderHost::OnInitializeDone(
const GpuVideoDecoderInitDoneParam& param) {
- done_param_ = param;
- bool success = false;
+ DCHECK_EQ(message_loop_, MessageLoop::current());
- do {
- if (!param.success)
- break;
+ bool success = param.success &&
+ base::SharedMemory::IsHandleValid(param.input_buffer_handle);
- if (!base::SharedMemory::IsHandleValid(param.input_buffer_handle))
- break;
+ if (success) {
input_transfer_buffer_.reset(
new base::SharedMemory(param.input_buffer_handle, false));
- if (!input_transfer_buffer_->Map(param.input_buffer_size))
- break;
-
- success = true;
- } while (0);
-
+ success = input_transfer_buffer_->Map(param.input_buffer_size);
+ }
state_ = success ? kStateNormal : kStateError;
- media::VideoCodecInfo info;
- info.success = success;
// TODO(hclam): There's too many unnecessary copies for width and height!
// Need to clean it up.
// TODO(hclam): Need to fill in more information.
+ media::VideoCodecInfo info;
+ info.success = success;
info.stream_info.surface_width = config_.width;
info.stream_info.surface_height = config_.height;
event_handler_->OnInitializeComplete(info);
}
void GpuVideoDecoderHost::OnUninitializeDone() {
+ DCHECK_EQ(message_loop_, MessageLoop::current());
+
input_transfer_buffer_.reset();
+ router_->RemoveRoute(decoder_host_id_);
+ context_->ReleaseAllVideoFrames();
event_handler_->OnUninitializeComplete();
}
void GpuVideoDecoderHost::OnFlushDone() {
+ DCHECK_EQ(message_loop_, MessageLoop::current());
+
state_ = kStateNormal;
event_handler_->OnFlushComplete();
}
-void GpuVideoDecoderHost::OnEmptyThisBufferDone() {
+void GpuVideoDecoderHost::OnEmptyThisBufferACK() {
+ DCHECK_EQ(message_loop_, MessageLoop::current());
+
+ input_buffer_busy_ = false;
+ SendConsumeVideoSample();
+}
+
+void GpuVideoDecoderHost::OnProduceVideoSample() {
+ DCHECK_EQ(message_loop_, MessageLoop::current());
+ DCHECK_EQ(kStateNormal, state_);
+
event_handler_->ProduceVideoSample(NULL);
}
void GpuVideoDecoderHost::OnConsumeVideoFrame(int32 frame_id, int64 timestamp,
int64 duration, int32 flags) {
- scoped_refptr<VideoFrame> frame;
+ DCHECK_EQ(message_loop_, MessageLoop::current());
+ scoped_refptr<VideoFrame> frame;
if (flags & kGpuVideoEndOfStream) {
VideoFrame::CreateEmptyFrame(&frame);
} else {
- // TODO(hclam): Use |frame_id| to find the VideoFrame.
+ frame = video_frame_map_[frame_id];
+ DCHECK(frame) << "Invalid frame ID received";
+
+ frame->SetDuration(base::TimeDelta::FromMilliseconds(duration));
+ frame->SetTimestamp(base::TimeDelta::FromMilliseconds(timestamp));
}
- // TODO(hclam): Call the event handler.
event_handler_->ConsumeVideoFrame(frame);
}
-void GpuVideoDecoderHost::OnEmptyThisBufferACK() {
- input_buffer_busy_ = false;
- SendInputBufferToGpu();
+void GpuVideoDecoderHost::OnAllocateVideoFrames(
+ int32 n, uint32 width, uint32 height, int32 format) {
+ DCHECK_EQ(message_loop_, MessageLoop::current());
+ DCHECK_EQ(0u, video_frames_.size());
+
+ context_->AllocateVideoFrames(
+ n, width, height, static_cast<media::VideoFrame::Format>(format),
+ &video_frames_,
+ NewRunnableMethod(this,
+ &GpuVideoDecoderHost::OnAllocateVideoFramesDone));
+}
+
+void GpuVideoDecoderHost::OnReleaseAllVideoFrames() {
+ DCHECK_EQ(message_loop_, MessageLoop::current());
+
+ context_->ReleaseAllVideoFrames();
+ video_frame_map_.clear();
+ video_frames_.clear();
+}
+
+void GpuVideoDecoderHost::OnAllocateVideoFramesDone() {
+ if (MessageLoop::current() != message_loop_) {
+ message_loop_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(
+ this, &GpuVideoDecoderHost::OnAllocateVideoFramesDone));
+ return;
+ }
+
+ // After video frame allocation is done we add these frames to a map and
+ // send them to the GPU process.
+ DCHECK(video_frames_.size()) << "No video frames allocated";
+ for (size_t i = 0; i < video_frames_.size(); ++i) {
+ DCHECK(video_frames_[i]);
+ video_frame_map_.insert(
+ std::make_pair(current_frame_id_, video_frames_[i]));
+ SendVideoFrameAllocated(current_frame_id_, video_frames_[i]);
+ ++current_frame_id_;
+ }
+}
+
+void GpuVideoDecoderHost::SendVideoFrameAllocated(
+ int32 frame_id, scoped_refptr<media::VideoFrame> frame) {
+ DCHECK_EQ(message_loop_, MessageLoop::current());
+
+ std::vector<uint32> textures;
+ for (size_t i = 0; i < frame->planes(); ++i) {
+ textures.push_back(frame->gl_texture(i));
+ }
+
+ if (!ipc_sender_->Send(new GpuVideoDecoderMsg_VideoFrameAllocated(
+ decoder_id_, frame_id, textures))) {
+ LOG(ERROR) << "GpuVideoDecoderMsg_EmptyThisBuffer failed";
+ }
}
-void GpuVideoDecoderHost::SendInputBufferToGpu() {
- if (input_buffer_busy_) return;
- if (input_buffer_queue_.empty()) return;
+void GpuVideoDecoderHost::SendConsumeVideoSample() {
+ DCHECK_EQ(message_loop_, MessageLoop::current());
+ if (input_buffer_busy_ || input_buffer_queue_.empty())
+ return;
input_buffer_busy_ = true;
- scoped_refptr<Buffer> buffer;
- buffer = input_buffer_queue_.front();
+ scoped_refptr<Buffer> buffer = input_buffer_queue_.front();
input_buffer_queue_.pop_front();
// Send input data to GPU process.
@@ -216,8 +332,36 @@ void GpuVideoDecoderHost::SendInputBufferToGpu() {
param.size = buffer->GetDataSize();
param.timestamp = buffer->GetTimestamp().InMicroseconds();
memcpy(input_transfer_buffer_->memory(), buffer->GetData(), param.size);
- if (!ipc_sender_ || !ipc_sender_->Send(
- new GpuVideoDecoderMsg_EmptyThisBuffer(route_id(), param))) {
+
+ if (!ipc_sender_->Send(
+ new GpuVideoDecoderMsg_EmptyThisBuffer(decoder_id_, param))) {
LOG(ERROR) << "GpuVideoDecoderMsg_EmptyThisBuffer failed";
}
}
+
+void GpuVideoDecoderHost::SendProduceVideoFrame(
+ scoped_refptr<media::VideoFrame> frame) {
+ DCHECK_EQ(message_loop_, MessageLoop::current());
+
+ // TODO(hclam): I should mark a frame being used to DCHECK and make sure
+ // user doesn't use it the second time.
+ // TODO(hclam): Derive a faster way to lookup the frame ID.
+ bool found = false;
+ int32 frame_id = 0;
+ for (VideoFrameMap::iterator i = video_frame_map_.begin();
+ i != video_frame_map_.end(); ++i) {
+ if (frame == i->second) {
+ frame_id = i->first;
+ found = true;
+ break;
+ }
+ }
+
+ DCHECK(found) << "Invalid video frame received";
+ if (found && !ipc_sender_->Send(
+ new GpuVideoDecoderMsg_ProduceVideoFrame(decoder_id_, frame_id))) {
+ LOG(ERROR) << "GpuVideoDecoderMsg_ProduceVideoFrame failed";
+ }
+}
+
+DISABLE_RUNNABLE_METHOD_REFCOUNT(GpuVideoDecoderHost);
diff --git a/chrome/renderer/gpu_video_decoder_host.h b/chrome/renderer/gpu_video_decoder_host.h
index 68953f6..e5a26fd 100644
--- a/chrome/renderer/gpu_video_decoder_host.h
+++ b/chrome/renderer/gpu_video_decoder_host.h
@@ -6,6 +6,7 @@
#define CHROME_RENDERER_GPU_VIDEO_DECODER_HOST_H_
#include <deque>
+#include <map>
#include "base/singleton.h"
#include "chrome/common/gpu_video_common.h"
@@ -18,7 +19,7 @@
using media::VideoFrame;
using media::Buffer;
-class GpuVideoServiceHost;
+class MessageRouter;
// This class is used to talk to GpuVideoDecoder in the GPU process through
// IPC messages. It implements the interface of VideoDecodeEngine so users
@@ -36,6 +37,10 @@ class GpuVideoServiceHost;
class GpuVideoDecoderHost : public media::VideoDecodeEngine,
public IPC::Channel::Listener {
public:
+ GpuVideoDecoderHost(MessageRouter* router,
+ IPC::Message::Sender* ipc_sender,
+ int context_route_id,
+ int32 decoder_host_id);
virtual ~GpuVideoDecoderHost() {}
// IPC::Channel::Listener.
@@ -55,7 +60,7 @@ class GpuVideoDecoderHost : public media::VideoDecodeEngine,
virtual void Seek();
private:
- friend class GpuVideoServiceHost;
+ typedef std::map<int32, scoped_refptr<media::VideoFrame> > VideoFrameMap;
// Internal states.
enum GpuVideoDecoderHostState {
@@ -65,30 +70,38 @@ class GpuVideoDecoderHost : public media::VideoDecodeEngine,
kStateFlushing,
};
- // Private constructor.
- GpuVideoDecoderHost(GpuVideoServiceHost* service_host,
- IPC::Message::Sender* ipc_sender,
- int context_route_id);
-
- // Input message handler.
+ // Handlers for messages received from the GPU process.
+ void OnCreateVideoDecoderDone(int32 decoder_id);
void OnInitializeDone(const GpuVideoDecoderInitDoneParam& param);
void OnUninitializeDone();
void OnFlushDone();
- void OnEmptyThisBufferDone();
+ void OnEmptyThisBufferACK();
+ void OnProduceVideoSample();
void OnConsumeVideoFrame(int32 frame_id, int64 timestamp,
int64 duration, int32 flags);
- void OnEmptyThisBufferACK();
+ void OnAllocateVideoFrames(int32 n, uint32 width,
+ uint32 height, int32 format);
+ void OnReleaseAllVideoFrames();
+
+ // Handler for VideoDecodeContext. This method is called when video frames
+ // allocation is done.
+ void OnAllocateVideoFramesDone();
- // Helper function.
- void SendInputBufferToGpu();
+ // Send a message to the GPU process to inform that a video frame is
+ // allocated.
+ void SendVideoFrameAllocated(int32 frame_id,
+ scoped_refptr<media::VideoFrame> frame);
- // Getter methods for IDs.
- int32 decoder_id() { return decoder_info_.decoder_id; }
- int32 route_id() { return decoder_info_.decoder_route_id; }
- int32 my_route_id() { return decoder_info_.decoder_host_route_id; }
+ // Send a video sample to the GPU process and tell it to use the buffer for
+ // video decoding.
+ void SendConsumeVideoSample();
- // We expect that GpuVideoServiceHost's always available during our life span.
- GpuVideoServiceHost* gpu_video_service_host_;
+ // Look up the frame_id for |frame| and send a message to the GPU process
+ // to use that video frame to produce an output.
+ void SendProduceVideoFrame(scoped_refptr<media::VideoFrame> frame);
+
+ // A router used to send us IPC messages.
+ MessageRouter* router_;
// Sends IPC messages to the GPU process.
IPC::Message::Sender* ipc_sender_;
@@ -96,24 +109,27 @@ class GpuVideoDecoderHost : public media::VideoDecodeEngine,
// Route ID of the GLES2 context in the GPU process.
int context_route_id_;
+ // Message loop that this object runs on.
+ MessageLoop* message_loop_;
+
// We expect that the client of us will always available during our life span.
EventHandler* event_handler_;
- // Globally identify this decoder in the GPU process.
- GpuVideoDecoderInfoParam decoder_info_;
-
- // Input buffer id serial number generator.
- int32 buffer_id_serial_;
+ // A Context for allocating video frame textures.
+ media::VideoDecodeContext* context_;
// Hold information about GpuVideoDecoder configuration.
media::VideoCodecConfig config_;
- // Hold information about output surface format, etc.
- GpuVideoDecoderInitDoneParam done_param_;
-
// Current state of video decoder.
GpuVideoDecoderHostState state_;
+ // ID of this GpuVideoDecoderHost.
+ int32 decoder_host_id_;
+
+ // ID of GpuVideoDecoder in the GPU process.
+ int32 decoder_id_;
+
// We are not able to push all received buffer to gpu process at once.
std::deque<scoped_refptr<Buffer> > input_buffer_queue_;
@@ -125,6 +141,15 @@ class GpuVideoDecoderHost : public media::VideoDecodeEngine,
// TODO(jiesun): remove output buffer when hardware composition is ready.
scoped_ptr<base::SharedMemory> input_transfer_buffer_;
+ // Frame ID for the newly generated video frame.
+ int32 current_frame_id_;
+
+ // The list of video frames allocated by VideoDecodeContext.
+ std::vector<scoped_refptr<media::VideoFrame> > video_frames_;
+
+ // The mapping between video frame ID and a video frame.
+ VideoFrameMap video_frame_map_;
+
DISALLOW_COPY_AND_ASSIGN(GpuVideoDecoderHost);
};
diff --git a/chrome/renderer/gpu_video_decoder_host_unittest.cc b/chrome/renderer/gpu_video_decoder_host_unittest.cc
new file mode 100644
index 0000000..c0a10be
--- /dev/null
+++ b/chrome/renderer/gpu_video_decoder_host_unittest.cc
@@ -0,0 +1,259 @@
+// 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 "base/message_loop.h"
+#include "chrome/common/gpu_messages.h"
+#include "chrome/common/message_router.h"
+#include "chrome/renderer/gpu_video_decoder_host.h"
+#include "media/video/mock_objects.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::DoAll;
+using testing::NotNull;
+using testing::Return;
+using testing::SetArgumentPointee;
+
+static const int kContextRouteId = 50;
+static const int kDecoderHostId = 51;
+static const int kDecoderId = 51;
+static const int kVideoFrames = 3;
+static const int kWidth = 320;
+static const int kHeight = 240;
+static const int kTransportBufferSize = 1024;
+
+ACTION_P(SimulateAllocateVideoFrames, frames) {
+ // Fake some texture IDs here.
+ media::VideoFrame::GlTexture textures[] = {4, 5, 6};
+ for (int i = 0; i < kVideoFrames; ++i) {
+ scoped_refptr<media::VideoFrame> frame;
+ media::VideoFrame::CreateFrameGlTexture(media::VideoFrame::YV12,
+ kWidth, kHeight, textures,
+ base::TimeDelta(),
+ base::TimeDelta(),
+ &frame);
+ frames->push_back(frame);
+ arg4->push_back(frame);
+ }
+
+ // Execute the callback to complete the task.
+ arg5->Run();
+ delete arg5;
+}
+
+ACTION_P2(SendMessage, handler, msg) {
+ handler->OnMessageReceived(msg);
+}
+
+class GpuVideoDecoderHostTest : public testing::Test,
+ public IPC::Message::Sender,
+ public media::VideoDecodeEngine::EventHandler {
+ public:
+ // This method is used to dispatch IPC messages to mock methods.
+ virtual bool Send(IPC::Message* msg) {
+ EXPECT_TRUE(msg);
+ if (!msg)
+ return false;
+
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(GpuVideoDecoderHostTest, *msg)
+ IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateVideoDecoder,
+ OnCreateVideoDecoder)
+ IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_Initialize,
+ OnInitialize)
+ IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_Destroy,
+ OnDestroy)
+ IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_Flush,
+ OnFlush)
+ IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_EmptyThisBuffer,
+ OnEmptyThisBuffer)
+ IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_VideoFrameAllocated,
+ OnVideoFrameAllocated)
+ IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_ProduceVideoFrame,
+ OnProduceVideoFrame)
+ IPC_MESSAGE_UNHANDLED_ERROR()
+ IPC_END_MESSAGE_MAP()
+ EXPECT_TRUE(handled);
+ delete msg;
+ return true;
+ }
+
+ // Mock methods for outgoing messages.
+ MOCK_METHOD1(OnInitialize, void(GpuVideoDecoderInitParam param));
+ MOCK_METHOD0(OnDestroy, void());
+ MOCK_METHOD0(OnFlush, void());
+ MOCK_METHOD1(OnEmptyThisBuffer,
+ void(GpuVideoDecoderInputBufferParam param));
+ MOCK_METHOD1(OnProduceVideoFrame, void(int32 frame_id));
+ MOCK_METHOD2(OnVideoFrameAllocated,
+ void(int32 frame_id, std::vector<uint32> textures));
+ MOCK_METHOD2(OnCreateVideoDecoder,
+ void(int32 context_route_id, int32 decoder_host_id));
+
+ // Mock methods for VideoDecodeEngine::EventHandler.
+ MOCK_METHOD1(ProduceVideoSample,
+ void(scoped_refptr<media::Buffer> buffer));
+ MOCK_METHOD1(ConsumeVideoFrame,
+ void(scoped_refptr<media::VideoFrame> frame));
+ MOCK_METHOD1(OnInitializeComplete,
+ void(const media::VideoCodecInfo& info));
+ MOCK_METHOD0(OnUninitializeComplete, void());
+ MOCK_METHOD0(OnFlushComplete, void());
+ MOCK_METHOD0(OnSeekComplete, void());
+ MOCK_METHOD0(OnError, void());
+ MOCK_METHOD1(OnFormatChange,
+ void(media::VideoStreamInfo stream_info));
+
+ void Initialize() {
+ decoder_host_.reset(
+ new GpuVideoDecoderHost(&router_, this, kContextRouteId,
+ kDecoderHostId));
+ shared_memory_.reset(new base::SharedMemory());
+ shared_memory_->Create("", false, false, kTransportBufferSize);
+
+ GpuVideoDecoderHostMsg_CreateVideoDecoderDone msg1(kDecoderHostId,
+ kDecoderId);
+ EXPECT_CALL(*this, OnCreateVideoDecoder(kContextRouteId, kDecoderHostId))
+ .WillOnce(SendMessage(decoder_host_.get(), msg1));
+
+ GpuVideoDecoderInitDoneParam param;
+ param.success = true;
+ param.input_buffer_size = kTransportBufferSize;
+ param.input_buffer_handle = shared_memory_->handle();
+
+ GpuVideoDecoderHostMsg_InitializeACK msg2(kDecoderHostId, param);
+ EXPECT_CALL(*this, OnInitialize(_))
+ .WillOnce(SendMessage(decoder_host_.get(), msg2));
+ EXPECT_CALL(*this, OnInitializeComplete(_));
+
+ media::VideoCodecConfig config;
+ config.codec = media::kCodecH264;
+ config.width = kWidth;
+ config.height = kHeight;
+ decoder_host_->Initialize(&message_loop_, this, &context_, config);
+ message_loop_.RunAllPending();
+ }
+
+ void Uninitialize() {
+ // A message is sent to GPU process to destroy the decoder.
+ GpuVideoDecoderHostMsg_DestroyACK msg(kDecoderHostId);
+ EXPECT_CALL(*this, OnDestroy())
+ .WillOnce(SendMessage(decoder_host_.get(), msg));
+ EXPECT_CALL(context_, ReleaseAllVideoFrames());
+ EXPECT_CALL(*this, OnUninitializeComplete());
+ decoder_host_->Uninitialize();
+ }
+
+ void AllocateVideoFrames() {
+ // Expect context is called to allocate video frames.
+ EXPECT_CALL(context_,
+ AllocateVideoFrames(kVideoFrames, kWidth, kHeight,
+ media::VideoFrame::YV12,
+ NotNull(), NotNull()))
+ .WillOnce(SimulateAllocateVideoFrames(&frames_))
+ .RetiresOnSaturation();
+
+ // Expect that we send the video frames to the GPU process.
+ EXPECT_CALL(*this, OnVideoFrameAllocated(_, _))
+ .Times(kVideoFrames)
+ .RetiresOnSaturation();
+
+ // Pretend that a message is sent to GpuVideoDecoderHost to allocate
+ // video frames.
+ GpuVideoDecoderHostMsg_AllocateVideoFrames msg(
+ kDecoderHostId, kVideoFrames, kWidth, kHeight,
+ static_cast<int32>(media::VideoFrame::YV12));
+ decoder_host_->OnMessageReceived(msg);
+ }
+
+ void ReleaseVideoFrames() {
+ // Expect that context is called to release all video frames.
+ EXPECT_CALL(context_, ReleaseAllVideoFrames())
+ .RetiresOnSaturation();
+
+ // Pretend a message is sent to release all video frames.
+ GpuVideoDecoderHostMsg_ReleaseAllVideoFrames msg(kDecoderHostId);
+ decoder_host_->OnMessageReceived(msg);
+
+ // Clear the list of video frames allocated.
+ frames_.clear();
+ }
+
+ void ProduceVideoFrame(int first_frame_id) {
+ for (int i = 0; i < kVideoFrames; ++i) {
+ // Expect that a request is received to produce a video frame.
+ GpuVideoDecoderHostMsg_ConsumeVideoFrame msg(
+ kDecoderHostId, first_frame_id + i, 0, 0, 0);
+ EXPECT_CALL(*this, OnProduceVideoFrame(first_frame_id + i))
+ .WillOnce(SendMessage(decoder_host_.get(), msg))
+ .RetiresOnSaturation();
+
+ // Expect that a reply is made when a video frame is ready.
+ EXPECT_CALL(*this, ConsumeVideoFrame(frames_[i]))
+ .RetiresOnSaturation();
+
+ // Use the allocated video frames to make a request.
+ decoder_host_->ProduceVideoFrame(frames_[i]);
+ }
+ }
+
+ private:
+ MessageLoop message_loop_;
+ MessageRouter router_;
+ media::MockVideoDecodeContext context_;
+
+ scoped_ptr<GpuVideoDecoderHost> decoder_host_;
+ scoped_ptr<base::SharedMemory> shared_memory_;
+
+ // Keeps the video frames allocated.
+ std::vector<scoped_refptr<media::VideoFrame> > frames_;
+};
+
+// Test that when we initialize GpuVideoDecoderHost the corresponding
+// IPC messages are sent and at the end OnInitializeComplete() is
+// called with the right parameters.
+TEST_F(GpuVideoDecoderHostTest, Initialize) {
+ Initialize();
+}
+
+// Test that the sequence of method calls and IPC messages is correct.
+// And at the end OnUninitializeComplete() is called.
+TEST_F(GpuVideoDecoderHostTest, Uninitialize) {
+ Initialize();
+ Uninitialize();
+}
+
+// Test that IPC messages are sent to GpuVideoDecoderHost and it
+// calls VideoDecodeContext to allocate textures and send these
+// textures back to the GPU process by IPC messages.
+TEST_F(GpuVideoDecoderHostTest, AllocateVideoFrames) {
+ Initialize();
+ AllocateVideoFrames();
+ Uninitialize();
+}
+
+// Test that IPC messages are sent to GpuVideoDecoderHost to
+// release textures and VideoDecodeContext is called correctly.
+TEST_F(GpuVideoDecoderHostTest, ReleaseVideoFrames) {
+ Initialize();
+ AllocateVideoFrames();
+ ReleaseVideoFrames();
+ AllocateVideoFrames();
+ ReleaseVideoFrames();
+ Uninitialize();
+}
+
+// Test the sequence of IPC messages and methods calls for a decode
+// routine. This tests the output port only.
+TEST_F(GpuVideoDecoderHostTest, ProduceVideoFrame) {
+ Initialize();
+ AllocateVideoFrames();
+ ProduceVideoFrame(0);
+ ReleaseVideoFrames();
+ AllocateVideoFrames();
+ ProduceVideoFrame(kVideoFrames);
+ ReleaseVideoFrames();
+ Uninitialize();
+}
diff --git a/chrome/renderer/gpu_video_service_host.cc b/chrome/renderer/gpu_video_service_host.cc
index 94803a4..d47e309 100644
--- a/chrome/renderer/gpu_video_service_host.cc
+++ b/chrome/renderer/gpu_video_service_host.cc
@@ -11,7 +11,8 @@
GpuVideoServiceHost::GpuVideoServiceHost()
: channel_host_(NULL),
router_(NULL),
- message_loop_(NULL) {
+ message_loop_(NULL),
+ next_decoder_host_id_(0) {
memset(&service_info_, 0, sizeof(service_info_));
}
@@ -55,14 +56,9 @@ GpuVideoDecoderHost* GpuVideoServiceHost::CreateVideoDecoder(
int context_route_id) {
DCHECK(RenderThread::current());
- return new GpuVideoDecoderHost(this, channel_host_, context_route_id);
-}
-
-void GpuVideoServiceHost::AddRoute(int route_id,
- GpuVideoDecoderHost* decoder_host) {
- router_->AddRoute(route_id, decoder_host);
-}
-
-void GpuVideoServiceHost::RemoveRoute(int route_id) {
- router_->RemoveRoute(route_id);
+ GpuVideoDecoderHost* host = new GpuVideoDecoderHost(router_, channel_host_,
+ context_route_id,
+ next_decoder_host_id_);
+ ++next_decoder_host_id_;
+ return host;
}
diff --git a/chrome/renderer/gpu_video_service_host.h b/chrome/renderer/gpu_video_service_host.h
index e5417a4..ff54cd2 100644
--- a/chrome/renderer/gpu_video_service_host.h
+++ b/chrome/renderer/gpu_video_service_host.h
@@ -45,13 +45,6 @@ class GpuVideoServiceHost : public IPC::Channel::Listener,
// Returns a GpuVideoDecoderHost as a handle to control the video decoder.
GpuVideoDecoderHost* CreateVideoDecoder(int context_route_id);
- // TODO(hclam): Provide a method to destroy the decoder. We also need to
- // listen to context lost event.
-
- // Methods called by GpuVideoDecoderHost.
- void AddRoute(int route_id, GpuVideoDecoderHost* decoder_host);
- void RemoveRoute(int route_id);
-
private:
GpuVideoServiceHost();
@@ -60,6 +53,9 @@ class GpuVideoServiceHost : public IPC::Channel::Listener,
GpuVideoServiceInfoParam service_info_;
MessageLoop* message_loop_; // Message loop of render thread.
+ // ID for the next GpuVideoDecoderHost.
+ int32 next_decoder_host_id_;
+
friend struct DefaultSingletonTraits<GpuVideoServiceHost>;
DISALLOW_COPY_AND_ASSIGN(GpuVideoServiceHost);
};
diff --git a/media/base/video_frame.h b/media/base/video_frame.h
index 88c11dd..33d3779 100644
--- a/media/base/video_frame.h
+++ b/media/base/video_frame.h
@@ -83,6 +83,7 @@ class VideoFrame : public StreamSample {
scoped_refptr<VideoFrame>* frame_out);
// Creates a new frame with GL textures.
+ // TODO(hclam): Remove timestamp and duration.
static void CreateFrameGlTexture(Format format,
size_t width,
size_t height,
@@ -92,6 +93,7 @@ class VideoFrame : public StreamSample {
scoped_refptr<VideoFrame>* frame_out);
// Creates a new frame with D3d textures.
+ // TODO(hclam): Remove timestamp and duration.
static void CreateFrameD3dTexture(Format format,
size_t width,
size_t height,
diff --git a/media/video/mock_objects.h b/media/video/mock_objects.h
index a975ea8..24cd4d3 100644
--- a/media/video/mock_objects.h
+++ b/media/video/mock_objects.h
@@ -5,6 +5,7 @@
#ifndef MEDIA_VIDEO_MOCK_OBJECTS_H_
#define MEDIA_VIDEO_MOCK_OBJECTS_H_
+#include "media/video/video_decode_context.h"
#include "media/video/video_decode_engine.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -29,6 +30,25 @@ class MockVideoDecodeEngine : public VideoDecodeEngine {
DISALLOW_COPY_AND_ASSIGN(MockVideoDecodeEngine);
};
+class MockVideoDecodeContext : public VideoDecodeContext {
+ public:
+ MockVideoDecodeContext() {}
+ virtual ~MockVideoDecodeContext() {}
+
+ MOCK_METHOD0(GetDevice, void*());
+ MOCK_METHOD6(AllocateVideoFrames, void(
+ int n, size_t width, size_t height, VideoFrame::Format format,
+ std::vector<scoped_refptr<VideoFrame> >* frames,
+ Task* task));
+ MOCK_METHOD0(ReleaseAllVideoFrames, void());
+ MOCK_METHOD3(UploadToVideoFrame, void(
+ void* buffer, scoped_refptr<VideoFrame> frame, Task* task));
+ MOCK_METHOD1(Destroy, void(Task* task));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockVideoDecodeContext);
+};
+
} // namespace media
#endif // MEDIA_VIDEO_MOCK_OBJECTS_H_