| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "base/message_loop.h" | |
| 6 #include "chrome/renderer/gpu_video_decoder_host.h" | |
| 7 #include "content/common/message_router.h" | |
| 8 #include "content/common/gpu_messages.h" | |
| 9 #include "media/base/pipeline.h" | |
| 10 #include "media/video/video_mock_objects.h" | |
| 11 #include "testing/gmock/include/gmock/gmock.h" | |
| 12 #include "testing/gtest/include/gtest/gtest.h" | |
| 13 | |
| 14 using testing::_; | |
| 15 using testing::DoAll; | |
| 16 using testing::NotNull; | |
| 17 using testing::Return; | |
| 18 using testing::SetArgumentPointee; | |
| 19 | |
| 20 static const int kContextRouteId = 50; | |
| 21 static const int kDecoderHostId = 51; | |
| 22 static const int kDecoderId = 51; | |
| 23 static const int kVideoFrames = 3; | |
| 24 static const int kWidth = 320; | |
| 25 static const int kHeight = 240; | |
| 26 static const int kFrameRateNumerator = 25; | |
| 27 static const int kFrameRateDenominator = 1; | |
| 28 static const int kTransportBufferSize = 1024; | |
| 29 | |
| 30 ACTION_P(SimulateAllocateVideoFrames, frames) { | |
| 31 // Fake some texture IDs here. | |
| 32 media::VideoFrame::GlTexture textures[] = {4, 5, 6}; | |
| 33 for (int i = 0; i < kVideoFrames; ++i) { | |
| 34 scoped_refptr<media::VideoFrame> frame; | |
| 35 media::VideoFrame::CreateFrameGlTexture(media::VideoFrame::YV12, | |
| 36 kWidth, kHeight, textures, | |
| 37 &frame); | |
| 38 frames->push_back(frame); | |
| 39 arg4->push_back(frame); | |
| 40 } | |
| 41 | |
| 42 // Execute the callback to complete the task. | |
| 43 arg5->Run(); | |
| 44 delete arg5; | |
| 45 } | |
| 46 | |
| 47 ACTION_P2(SendMessage, handler, msg) { | |
| 48 handler->OnMessageReceived(msg); | |
| 49 } | |
| 50 | |
| 51 class GpuVideoDecoderHostTest : public testing::Test, | |
| 52 public IPC::Message::Sender, | |
| 53 public media::VideoDecodeEngine::EventHandler { | |
| 54 public: | |
| 55 // This method is used to dispatch IPC messages to mock methods. | |
| 56 virtual bool Send(IPC::Message* msg) { | |
| 57 EXPECT_TRUE(msg); | |
| 58 if (!msg) | |
| 59 return false; | |
| 60 | |
| 61 bool handled = true; | |
| 62 IPC_BEGIN_MESSAGE_MAP(GpuVideoDecoderHostTest, *msg) | |
| 63 IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateVideoDecoder, | |
| 64 OnCreateVideoDecoder) | |
| 65 IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_Initialize, | |
| 66 OnInitialize) | |
| 67 IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_Destroy, | |
| 68 OnDestroy) | |
| 69 IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_Flush, | |
| 70 OnFlush) | |
| 71 IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_EmptyThisBuffer, | |
| 72 OnEmptyThisBuffer) | |
| 73 IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_VideoFrameAllocated, | |
| 74 OnVideoFrameAllocated) | |
| 75 IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_ProduceVideoFrame, | |
| 76 OnProduceVideoFrame) | |
| 77 IPC_MESSAGE_UNHANDLED_ERROR() | |
| 78 IPC_END_MESSAGE_MAP() | |
| 79 EXPECT_TRUE(handled); | |
| 80 delete msg; | |
| 81 return true; | |
| 82 } | |
| 83 | |
| 84 // Mock methods for outgoing messages. | |
| 85 MOCK_METHOD1(OnInitialize, void(GpuVideoDecoderInitParam param)); | |
| 86 MOCK_METHOD0(OnDestroy, void()); | |
| 87 MOCK_METHOD0(OnFlush, void()); | |
| 88 MOCK_METHOD1(OnEmptyThisBuffer, | |
| 89 void(GpuVideoDecoderInputBufferParam param)); | |
| 90 MOCK_METHOD1(OnProduceVideoFrame, void(int32 frame_id)); | |
| 91 MOCK_METHOD2(OnVideoFrameAllocated, | |
| 92 void(int32 frame_id, std::vector<uint32> textures)); | |
| 93 MOCK_METHOD2(OnCreateVideoDecoder, | |
| 94 void(int32 context_route_id, int32 decoder_host_id)); | |
| 95 | |
| 96 // Mock methods for VideoDecodeEngine::EventHandler. | |
| 97 MOCK_METHOD1(ProduceVideoSample, | |
| 98 void(scoped_refptr<media::Buffer> buffer)); | |
| 99 MOCK_METHOD2(ConsumeVideoFrame, | |
| 100 void(scoped_refptr<media::VideoFrame> frame, | |
| 101 const media::PipelineStatistics& statistics)); | |
| 102 MOCK_METHOD1(OnInitializeComplete, | |
| 103 void(const media::VideoCodecInfo& info)); | |
| 104 MOCK_METHOD0(OnUninitializeComplete, void()); | |
| 105 MOCK_METHOD0(OnFlushComplete, void()); | |
| 106 MOCK_METHOD0(OnSeekComplete, void()); | |
| 107 MOCK_METHOD0(OnError, void()); | |
| 108 MOCK_METHOD1(OnFormatChange, | |
| 109 void(media::VideoStreamInfo stream_info)); | |
| 110 | |
| 111 void Initialize() { | |
| 112 decoder_host_.reset( | |
| 113 new GpuVideoDecoderHost(&router_, this, kContextRouteId, | |
| 114 kDecoderHostId)); | |
| 115 shared_memory_.reset(new base::SharedMemory()); | |
| 116 shared_memory_->CreateAnonymous(kTransportBufferSize); | |
| 117 | |
| 118 GpuVideoDecoderHostMsg_CreateVideoDecoderDone msg1(kDecoderHostId, | |
| 119 kDecoderId); | |
| 120 EXPECT_CALL(*this, OnCreateVideoDecoder(kContextRouteId, kDecoderHostId)) | |
| 121 .WillOnce(SendMessage(decoder_host_.get(), msg1)); | |
| 122 | |
| 123 GpuVideoDecoderInitDoneParam param; | |
| 124 param.success = true; | |
| 125 param.input_buffer_size = kTransportBufferSize; | |
| 126 param.input_buffer_handle = shared_memory_->handle(); | |
| 127 | |
| 128 GpuVideoDecoderHostMsg_InitializeACK msg2(kDecoderHostId, param); | |
| 129 EXPECT_CALL(*this, OnInitialize(_)) | |
| 130 .WillOnce(SendMessage(decoder_host_.get(), msg2)); | |
| 131 EXPECT_CALL(*this, OnInitializeComplete(_)); | |
| 132 | |
| 133 media::VideoCodecConfig config( | |
| 134 media::kCodecH264, | |
| 135 kWidth, | |
| 136 kHeight, | |
| 137 kFrameRateNumerator, | |
| 138 kFrameRateDenominator, | |
| 139 NULL, | |
| 140 0); | |
| 141 decoder_host_->Initialize(&message_loop_, this, &context_, config); | |
| 142 message_loop_.RunAllPending(); | |
| 143 } | |
| 144 | |
| 145 void Uninitialize() { | |
| 146 // A message is sent to GPU process to destroy the decoder. | |
| 147 GpuVideoDecoderHostMsg_DestroyACK msg(kDecoderHostId); | |
| 148 EXPECT_CALL(*this, OnDestroy()) | |
| 149 .WillOnce(SendMessage(decoder_host_.get(), msg)); | |
| 150 EXPECT_CALL(context_, ReleaseAllVideoFrames()); | |
| 151 EXPECT_CALL(*this, OnUninitializeComplete()); | |
| 152 decoder_host_->Uninitialize(); | |
| 153 } | |
| 154 | |
| 155 void AllocateVideoFrames() { | |
| 156 // Expect context is called to allocate video frames. | |
| 157 EXPECT_CALL(context_, | |
| 158 AllocateVideoFrames(kVideoFrames, kWidth, kHeight, | |
| 159 media::VideoFrame::YV12, | |
| 160 NotNull(), NotNull())) | |
| 161 .WillOnce(SimulateAllocateVideoFrames(&frames_)) | |
| 162 .RetiresOnSaturation(); | |
| 163 | |
| 164 // Expect that we send the video frames to the GPU process. | |
| 165 EXPECT_CALL(*this, OnVideoFrameAllocated(_, _)) | |
| 166 .Times(kVideoFrames) | |
| 167 .RetiresOnSaturation(); | |
| 168 | |
| 169 // Pretend that a message is sent to GpuVideoDecoderHost to allocate | |
| 170 // video frames. | |
| 171 GpuVideoDecoderHostMsg_AllocateVideoFrames msg( | |
| 172 kDecoderHostId, kVideoFrames, kWidth, kHeight, | |
| 173 static_cast<int32>(media::VideoFrame::YV12)); | |
| 174 decoder_host_->OnMessageReceived(msg); | |
| 175 } | |
| 176 | |
| 177 void ReleaseVideoFrames() { | |
| 178 // Expect that context is called to release all video frames. | |
| 179 EXPECT_CALL(context_, ReleaseAllVideoFrames()) | |
| 180 .RetiresOnSaturation(); | |
| 181 | |
| 182 // Pretend a message is sent to release all video frames. | |
| 183 GpuVideoDecoderHostMsg_ReleaseAllVideoFrames msg(kDecoderHostId); | |
| 184 decoder_host_->OnMessageReceived(msg); | |
| 185 | |
| 186 // Clear the list of video frames allocated. | |
| 187 frames_.clear(); | |
| 188 } | |
| 189 | |
| 190 void ProduceVideoFrame(int first_frame_id) { | |
| 191 for (int i = 0; i < kVideoFrames; ++i) { | |
| 192 // Expect that a request is received to produce a video frame. | |
| 193 GpuVideoDecoderHostMsg_ConsumeVideoFrame msg( | |
| 194 kDecoderHostId, first_frame_id + i, 0, 0, 0); | |
| 195 EXPECT_CALL(*this, OnProduceVideoFrame(first_frame_id + i)) | |
| 196 .WillOnce(SendMessage(decoder_host_.get(), msg)) | |
| 197 .RetiresOnSaturation(); | |
| 198 | |
| 199 // Expect that a reply is made when a video frame is ready. | |
| 200 EXPECT_CALL(*this, ConsumeVideoFrame(frames_[i], _)) | |
| 201 .RetiresOnSaturation(); | |
| 202 | |
| 203 // Use the allocated video frames to make a request. | |
| 204 decoder_host_->ProduceVideoFrame(frames_[i]); | |
| 205 } | |
| 206 } | |
| 207 | |
| 208 private: | |
| 209 MessageLoop message_loop_; | |
| 210 MessageRouter router_; | |
| 211 media::MockVideoDecodeContext context_; | |
| 212 | |
| 213 scoped_ptr<GpuVideoDecoderHost> decoder_host_; | |
| 214 scoped_ptr<base::SharedMemory> shared_memory_; | |
| 215 | |
| 216 // Keeps the video frames allocated. | |
| 217 std::vector<scoped_refptr<media::VideoFrame> > frames_; | |
| 218 }; | |
| 219 | |
| 220 // Test that when we initialize GpuVideoDecoderHost the corresponding | |
| 221 // IPC messages are sent and at the end OnInitializeComplete() is | |
| 222 // called with the right parameters. | |
| 223 TEST_F(GpuVideoDecoderHostTest, Initialize) { | |
| 224 Initialize(); | |
| 225 } | |
| 226 | |
| 227 // Test that the sequence of method calls and IPC messages is correct. | |
| 228 // And at the end OnUninitializeComplete() is called. | |
| 229 TEST_F(GpuVideoDecoderHostTest, Uninitialize) { | |
| 230 Initialize(); | |
| 231 Uninitialize(); | |
| 232 } | |
| 233 | |
| 234 // Test that IPC messages are sent to GpuVideoDecoderHost and it | |
| 235 // calls VideoDecodeContext to allocate textures and send these | |
| 236 // textures back to the GPU process by IPC messages. | |
| 237 TEST_F(GpuVideoDecoderHostTest, AllocateVideoFrames) { | |
| 238 Initialize(); | |
| 239 AllocateVideoFrames(); | |
| 240 Uninitialize(); | |
| 241 } | |
| 242 | |
| 243 // Test that IPC messages are sent to GpuVideoDecoderHost to | |
| 244 // release textures and VideoDecodeContext is called correctly. | |
| 245 TEST_F(GpuVideoDecoderHostTest, ReleaseVideoFrames) { | |
| 246 Initialize(); | |
| 247 AllocateVideoFrames(); | |
| 248 ReleaseVideoFrames(); | |
| 249 AllocateVideoFrames(); | |
| 250 ReleaseVideoFrames(); | |
| 251 Uninitialize(); | |
| 252 } | |
| 253 | |
| 254 // Test the sequence of IPC messages and methods calls for a decode | |
| 255 // routine. This tests the output port only. | |
| 256 TEST_F(GpuVideoDecoderHostTest, ProduceVideoFrame) { | |
| 257 Initialize(); | |
| 258 AllocateVideoFrames(); | |
| 259 ProduceVideoFrame(0); | |
| 260 ReleaseVideoFrames(); | |
| 261 AllocateVideoFrames(); | |
| 262 ProduceVideoFrame(kVideoFrames); | |
| 263 ReleaseVideoFrames(); | |
| 264 Uninitialize(); | |
| 265 } | |
| OLD | NEW |