OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 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 <GLES2/gl2.h> | |
6 | |
7 #include "base/memory/shared_memory.h" | |
8 #include "base/message_loop/message_loop.h" | |
9 #include "ppapi/c/pp_errors.h" | |
10 #include "ppapi/c/ppb_video_decoder.h" | |
11 #include "ppapi/proxy/locking_resource_releaser.h" | |
12 #include "ppapi/proxy/plugin_message_filter.h" | |
13 #include "ppapi/proxy/ppapi_message_utils.h" | |
14 #include "ppapi/proxy/ppapi_messages.h" | |
15 #include "ppapi/proxy/ppapi_proxy_test.h" | |
16 #include "ppapi/proxy/ppb_graphics_3d_proxy.h" | |
17 #include "ppapi/proxy/video_decoder_resource.h" | |
18 #include "ppapi/shared_impl/proxy_lock.h" | |
19 #include "ppapi/thunk/thunk.h" | |
20 | |
21 using ppapi::proxy::ResourceMessageTestSink; | |
22 | |
23 namespace ppapi { | |
24 namespace proxy { | |
25 | |
26 namespace { | |
27 | |
28 const PP_Bool kAllowSoftwareFallback = PP_TRUE; | |
29 const PP_Resource kGraphics3D = 7; | |
30 const size_t kDecodeBufferSize = 16; | |
31 const uint8_t kDecodeBufferElement = 0x55; | |
32 const uint32_t kDecodeId = 5; | |
33 const uint32_t kTextureId1 = 1; | |
34 const uint32_t kTextureId2 = 2; | |
35 const uint32_t kNumRequestedTextures = 2; | |
36 | |
37 class MockCompletionCallback { | |
38 public: | |
39 MockCompletionCallback() : called_(false) {} | |
40 | |
41 bool called() { return called_; } | |
42 int32_t result() { return result_; } | |
43 | |
44 void Reset() { called_ = false; } | |
45 | |
46 static void Callback(void* user_data, int32_t result) { | |
47 MockCompletionCallback* that = | |
48 reinterpret_cast<MockCompletionCallback*>(user_data); | |
49 that->called_ = true; | |
50 that->result_ = result; | |
51 } | |
52 | |
53 private: | |
54 bool called_; | |
55 int32_t result_; | |
56 }; | |
57 | |
58 class VideoDecoderResourceTest : public PluginProxyTest { | |
59 public: | |
60 const PPB_VideoDecoder_0_1* decoder_iface; | |
61 const PPB_Graphics3D_1_0* graphics3d_iface; | |
piman
2014/05/22 20:43:19
nit: order is methods, then fields (fields should
bbudge
2014/05/23 12:24:35
Done.
| |
62 | |
63 VideoDecoderResourceTest() | |
64 : decoder_iface(thunk::GetPPB_VideoDecoder_0_1_Thunk()), | |
65 graphics3d_iface(thunk::GetPPB_Graphics3D_1_0_Thunk()) {} | |
66 | |
67 void SendReply(const ResourceMessageCallParams& params, | |
68 int32_t result, | |
69 const IPC::Message& nested_message) { | |
70 ResourceMessageReplyParams reply_params(params.pp_resource(), | |
71 params.sequence()); | |
72 reply_params.set_result(result); | |
73 PluginMessageFilter::DispatchResourceReplyForTest(reply_params, | |
74 nested_message); | |
75 } | |
76 | |
77 void SendReplyWithHandle(const ResourceMessageCallParams& params, | |
78 int32_t result, | |
79 const IPC::Message& nested_message, | |
80 const SerializedHandle& handle) { | |
81 ResourceMessageReplyParams reply_params(params.pp_resource(), | |
82 params.sequence()); | |
83 reply_params.set_result(result); | |
84 reply_params.AppendHandle(handle); | |
85 PluginMessageFilter::DispatchResourceReplyForTest(reply_params, | |
86 nested_message); | |
87 } | |
88 | |
89 PP_Resource CreateDecoder() { | |
90 PP_Resource result = decoder_iface->Create(pp_instance()); | |
91 if (result) { | |
92 ProxyAutoLock lock; | |
93 ppapi::Resource* resource = | |
94 GetGlobals()->GetResourceTracker()->GetResource(result); | |
95 proxy::VideoDecoderResource* decoder = | |
96 static_cast<proxy::VideoDecoderResource*>(resource); | |
97 decoder->SetForTest(); | |
98 } | |
99 | |
100 return result; | |
101 } | |
102 | |
103 PP_Resource CreateGraphics3d() { | |
104 ProxyAutoLock lock; | |
105 | |
106 HostResource host_resource; | |
107 host_resource.SetHostResource(pp_instance(), kGraphics3D); | |
108 scoped_refptr<ppapi::proxy::Graphics3D> graphics_3d( | |
109 new ppapi::proxy::Graphics3D(host_resource)); | |
110 return graphics_3d->GetReference(); | |
111 } | |
112 | |
113 PP_Resource CreateAndInitializeDecoder() { | |
114 PP_Resource decoder = CreateDecoder(); | |
115 LockingResourceReleaser graphics3d(CreateGraphics3d()); | |
116 MockCompletionCallback cb; | |
117 int32_t result = | |
118 decoder_iface->Initialize(decoder, | |
119 graphics3d.get(), | |
120 PP_VIDEOPROFILE_H264MAIN, | |
121 PP_TRUE /* allow_software_fallback */, | |
122 PP_MakeOptionalCompletionCallback( | |
123 &MockCompletionCallback::Callback, &cb)); | |
124 if (result != PP_OK_COMPLETIONPENDING) | |
125 return 0; | |
126 ResourceMessageCallParams params; | |
127 IPC::Message msg; | |
128 if (!sink().GetFirstResourceCallMatching( | |
129 PpapiHostMsg_VideoDecoder_Initialize::ID, ¶ms, &msg)) | |
130 return 0; | |
131 sink().ClearMessages(); | |
132 SendReply(params, PP_OK, PpapiPluginMsg_VideoDecoder_InitializeReply()); | |
133 return decoder; | |
134 } | |
135 | |
136 SerializedHandle CreateSharedMemory(uint32_t size) { | |
137 base::SharedMemory shm; | |
138 shm.CreateAnonymous(size); | |
139 base::SharedMemoryHandle shm_handle; | |
140 shm.ShareToProcess(base::GetCurrentProcessHandle(), &shm_handle); | |
141 return SerializedHandle(shm_handle, size); | |
142 } | |
143 | |
144 int32_t CallDecode(PP_Resource pp_decoder, MockCompletionCallback* cb) { | |
145 memset(decode_buffer, 0x55, kDecodeBufferSize); | |
146 int32_t result = | |
147 decoder_iface->Decode(pp_decoder, | |
148 kDecodeId, | |
149 kDecodeBufferSize, | |
150 decode_buffer, | |
151 PP_MakeOptionalCompletionCallback( | |
152 &MockCompletionCallback::Callback, cb)); | |
153 return result; | |
154 } | |
155 | |
156 int32_t CallGetPicture(PP_Resource pp_decoder, | |
157 PP_VideoPicture* picture, | |
158 MockCompletionCallback* cb) { | |
159 int32_t result = | |
160 decoder_iface->GetPicture(pp_decoder, | |
161 picture, | |
162 PP_MakeOptionalCompletionCallback( | |
163 &MockCompletionCallback::Callback, cb)); | |
164 return result; | |
165 } | |
166 | |
167 void CallRecyclePicture(PP_Resource pp_decoder, | |
168 const PP_VideoPicture& picture) { | |
169 decoder_iface->RecyclePicture(pp_decoder, &picture); | |
170 } | |
171 | |
172 int32_t CallFlush(PP_Resource pp_decoder, MockCompletionCallback* cb) { | |
173 int32_t result = | |
174 decoder_iface->Flush(pp_decoder, | |
175 PP_MakeOptionalCompletionCallback( | |
176 &MockCompletionCallback::Callback, cb)); | |
177 return result; | |
178 } | |
179 | |
180 int32_t CallReset(PP_Resource pp_decoder, MockCompletionCallback* cb) { | |
181 int32_t result = | |
182 decoder_iface->Reset(pp_decoder, | |
183 PP_MakeOptionalCompletionCallback( | |
184 &MockCompletionCallback::Callback, cb)); | |
185 return result; | |
186 } | |
187 | |
188 void SendCreatedShm(const ResourceMessageCallParams& params, uint32_t size) { | |
189 SendReplyWithHandle(params, | |
190 PP_OK, | |
191 PpapiPluginMsg_VideoDecoder_CreatedShm(size), | |
192 CreateSharedMemory(size)); | |
193 } | |
194 | |
195 void SendDecodeReply(const ResourceMessageCallParams& params, | |
196 uint32_t shm_id) { | |
197 SendReply(params, PP_OK, PpapiPluginMsg_VideoDecoder_DecodeReply(shm_id)); | |
198 } | |
199 | |
200 void SendPictureReady(const ResourceMessageCallParams& params, | |
201 uint32_t decode_count, | |
202 uint32_t texture_id) { | |
203 SendReply(params, | |
204 PP_OK, | |
205 PpapiPluginMsg_VideoDecoder_PictureReady( | |
206 decode_count, texture_id)); | |
207 } | |
208 | |
209 void SendFlushReply(const ResourceMessageCallParams& params) { | |
210 SendReply(params, PP_OK, PpapiPluginMsg_VideoDecoder_FlushReply()); | |
211 } | |
212 | |
213 void SendResetReply(const ResourceMessageCallParams& params) { | |
214 SendReply(params, PP_OK, PpapiPluginMsg_VideoDecoder_ResetReply()); | |
215 } | |
216 | |
217 void SendRequestTextures(const ResourceMessageCallParams& params) { | |
218 SendReply(params, | |
219 PP_OK, | |
220 PpapiPluginMsg_VideoDecoder_RequestTextures( | |
221 kNumRequestedTextures, PP_MakeSize(320, 240), GL_TEXTURE_2D)); | |
222 } | |
223 | |
224 void SendNotifyError(const ResourceMessageCallParams& params, int32_t error) { | |
225 SendReply(params, PP_OK, PpapiPluginMsg_VideoDecoder_NotifyError(error)); | |
226 } | |
227 | |
228 bool CheckDecodeBufferMsg(ResourceMessageCallParams* params, | |
229 std::vector<uint8_t>* buffer, | |
230 uint32_t* pending_shm_id) { | |
231 IPC::Message msg; | |
232 if (!sink().GetFirstResourceCallMatching( | |
233 PpapiHostMsg_VideoDecoder_DecodeBuffer::ID, params, &msg)) | |
234 return false; | |
235 sink().ClearMessages(); | |
236 return UnpackMessage<PpapiHostMsg_VideoDecoder_DecodeBuffer>( | |
237 msg, buffer, pending_shm_id); | |
238 } | |
239 | |
240 bool CheckDecodeMsg(ResourceMessageCallParams* params, | |
241 uint32_t* shm_id, | |
242 uint32_t* size) { | |
243 IPC::Message msg; | |
244 if (!sink().GetFirstResourceCallMatching( | |
245 PpapiHostMsg_VideoDecoder_Decode::ID, params, &msg)) | |
246 return false; | |
247 sink().ClearMessages(); | |
248 return UnpackMessage<PpapiHostMsg_VideoDecoder_Decode>(msg, shm_id, size); | |
249 } | |
250 | |
251 bool CheckRecyclePictureMsg(ResourceMessageCallParams* params, | |
252 uint32_t* texture_id) { | |
253 IPC::Message msg; | |
254 if (!sink().GetFirstResourceCallMatching( | |
255 PpapiHostMsg_VideoDecoder_RecyclePicture::ID, params, &msg)) | |
256 return false; | |
257 sink().ClearMessages(); | |
258 return UnpackMessage<PpapiHostMsg_VideoDecoder_RecyclePicture>(msg, | |
259 texture_id); | |
260 } | |
261 | |
262 bool CheckFlushMsg(ResourceMessageCallParams* params) { | |
263 return CheckMsg(params, PpapiHostMsg_VideoDecoder_Flush::ID); | |
264 } | |
265 | |
266 bool CheckResetMsg(ResourceMessageCallParams* params) { | |
267 return CheckMsg(params, PpapiHostMsg_VideoDecoder_Reset::ID); | |
268 } | |
269 | |
270 void ClearCallbacks(PP_Resource pp_decoder) { | |
271 ResourceMessageCallParams params; | |
272 MockCompletionCallback cb; | |
273 | |
274 // Reset to abort Decode and GetPicture callbacks. | |
275 CallReset(pp_decoder, &cb); | |
276 // Initialize params so we can reply to the Reset. | |
277 CheckResetMsg(¶ms); | |
278 // Run the Reset callback. | |
279 SendResetReply(params); | |
280 } | |
281 | |
282 char decode_buffer[kDecodeBufferSize]; | |
283 | |
284 private: | |
285 bool CheckMsg(ResourceMessageCallParams* params, int id) { | |
286 IPC::Message msg; | |
287 if (!sink().GetFirstResourceCallMatching(id, params, &msg)) | |
288 return false; | |
289 sink().ClearMessages(); | |
290 return true; | |
291 } | |
292 }; | |
293 | |
294 } // namespace | |
295 | |
296 TEST_F(VideoDecoderResourceTest, Initialize) { | |
297 // Initialize with 0 graphics3d_context should fail. | |
298 { | |
299 LockingResourceReleaser decoder(CreateDecoder()); | |
300 MockCompletionCallback cb; | |
301 int32_t result = | |
302 decoder_iface->Initialize(decoder.get(), | |
303 0 /* invalid 3d graphics */, | |
304 PP_VIDEOPROFILE_H264MAIN, | |
305 kAllowSoftwareFallback, | |
306 PP_MakeOptionalCompletionCallback( | |
307 &MockCompletionCallback::Callback, &cb)); | |
308 ASSERT_EQ(PP_ERROR_BADRESOURCE, result); | |
309 } | |
310 // Initialize with bad profile value should fail. | |
311 { | |
312 LockingResourceReleaser decoder(CreateDecoder()); | |
313 MockCompletionCallback cb; | |
314 int32_t result = | |
315 decoder_iface->Initialize(decoder.get(), | |
316 1 /* non-zero resource */, | |
317 static_cast<PP_VideoProfile>(-1), | |
318 kAllowSoftwareFallback, | |
319 PP_MakeOptionalCompletionCallback( | |
320 &MockCompletionCallback::Callback, &cb)); | |
321 ASSERT_EQ(PP_ERROR_BADARGUMENT, result); | |
322 } | |
323 // Initialize with valid graphics3d_context and profile should succeed. | |
324 { | |
325 LockingResourceReleaser decoder(CreateDecoder()); | |
326 LockingResourceReleaser graphics3d(CreateGraphics3d()); | |
327 MockCompletionCallback cb; | |
328 int32_t result = | |
329 decoder_iface->Initialize(decoder.get(), | |
330 graphics3d.get(), | |
331 PP_VIDEOPROFILE_H264MAIN, | |
332 kAllowSoftwareFallback, | |
333 PP_MakeOptionalCompletionCallback( | |
334 &MockCompletionCallback::Callback, &cb)); | |
335 ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); | |
336 ASSERT_TRUE(decoder_iface->IsVideoDecoder(decoder.get())); | |
337 | |
338 // Another attempt while pending should fail. | |
339 result = | |
340 decoder_iface->Initialize(decoder.get(), | |
341 graphics3d.get(), | |
342 PP_VIDEOPROFILE_H264MAIN, | |
343 kAllowSoftwareFallback, | |
344 PP_MakeOptionalCompletionCallback( | |
345 &MockCompletionCallback::Callback, &cb)); | |
346 ASSERT_EQ(PP_ERROR_INPROGRESS, result); | |
347 | |
348 // Check for host message and send a reply to complete initialization. | |
349 ResourceMessageCallParams params; | |
350 IPC::Message msg; | |
351 ASSERT_TRUE(sink().GetFirstResourceCallMatching( | |
352 PpapiHostMsg_VideoDecoder_Initialize::ID, ¶ms, &msg)); | |
353 sink().ClearMessages(); | |
354 SendReply(params, PP_OK, PpapiPluginMsg_VideoDecoder_InitializeReply()); | |
355 ASSERT_TRUE(cb.called()); | |
356 ASSERT_EQ(PP_OK, cb.result()); | |
357 } | |
358 } | |
359 | |
360 TEST_F(VideoDecoderResourceTest, Uninitialized) { | |
361 // Operations on uninitialized decoders should fail. | |
362 LockingResourceReleaser decoder(CreateDecoder()); | |
363 MockCompletionCallback uncalled_cb; | |
364 | |
365 ASSERT_EQ(PP_ERROR_FAILED, CallDecode(decoder.get(), &uncalled_cb)); | |
366 ASSERT_FALSE(uncalled_cb.called()); | |
367 | |
368 ASSERT_EQ(PP_ERROR_FAILED, CallGetPicture(decoder.get(), NULL, &uncalled_cb)); | |
369 ASSERT_FALSE(uncalled_cb.called()); | |
370 | |
371 ASSERT_EQ(PP_ERROR_FAILED, CallFlush(decoder.get(), &uncalled_cb)); | |
372 ASSERT_FALSE(uncalled_cb.called()); | |
373 | |
374 ASSERT_EQ(PP_ERROR_FAILED, CallReset(decoder.get(), &uncalled_cb)); | |
375 ASSERT_FALSE(uncalled_cb.called()); | |
376 } | |
377 | |
378 TEST_F(VideoDecoderResourceTest, DecodeAndGetPicture) { | |
379 LockingResourceReleaser decoder(CreateAndInitializeDecoder()); | |
380 ResourceMessageCallParams params, params2; | |
381 MockCompletionCallback decode_cb, get_picture_cb, uncalled_cb; | |
382 ASSERT_EQ(PP_OK_COMPLETIONPENDING, CallDecode(decoder.get(), &decode_cb)); | |
383 ASSERT_FALSE(decode_cb.called()); | |
384 | |
385 // Calling Decode when another Decode is pending should fail. | |
386 ASSERT_EQ(PP_ERROR_INPROGRESS, CallDecode(decoder.get(), &uncalled_cb)); | |
387 ASSERT_FALSE(uncalled_cb.called()); | |
388 | |
389 // Check for host message DecodeBuffer. | |
390 std::vector<uint8_t> buffer; | |
391 uint32_t shm_id; | |
392 uint32_t decode_size; | |
393 CheckDecodeBufferMsg(¶ms, &buffer, &shm_id); | |
394 ASSERT_EQ(buffer.size(), kDecodeBufferSize); | |
395 ASSERT_EQ(kDecodeBufferElement, buffer[0]); | |
396 ASSERT_EQ(kDecodeBufferElement, buffer[kDecodeBufferSize - 1]); | |
397 ASSERT_EQ(0U, shm_id); | |
398 // Send CreatedShm reply with a handle, and DecodeReply. | |
399 SendCreatedShm(params, 2 * kDecodeBufferSize); | |
400 ASSERT_FALSE(decode_cb.called()); | |
401 SendDecodeReply(params, 0U); | |
402 // The decoder should run the callback. | |
403 ASSERT_TRUE(decode_cb.called()); | |
404 ASSERT_EQ(PP_OK, decode_cb.result()); | |
405 decode_cb.Reset(); | |
406 | |
407 // The decoder has a shm buffer and it is available. The next Decode call | |
408 // should use it and complete synchronously. | |
409 ASSERT_EQ(PP_OK, CallDecode(decoder.get(), &decode_cb)); | |
410 ASSERT_FALSE(decode_cb.called()); | |
411 // Check for host message Decode. | |
412 ASSERT_TRUE(CheckDecodeMsg(¶ms, &shm_id, &decode_size)); | |
413 ASSERT_EQ(0U, shm_id); | |
414 ASSERT_EQ(kDecodeBufferSize, decode_size); | |
415 | |
416 // Now try to get a picture. No picture ready message has been received yet. | |
417 PP_VideoPicture picture; | |
418 ASSERT_EQ(PP_OK_COMPLETIONPENDING, | |
419 CallGetPicture(decoder.get(), &picture, &get_picture_cb)); | |
420 ASSERT_FALSE(get_picture_cb.called()); | |
421 // Calling GetPicture when another GetPicture is pending should fail. | |
422 ASSERT_EQ(PP_ERROR_INPROGRESS, | |
423 CallGetPicture(decoder.get(), &picture, &uncalled_cb)); | |
424 ASSERT_FALSE(uncalled_cb.called()); | |
425 // Send 'request textures' message to initialize textures. | |
426 SendRequestTextures(params); | |
427 // Send a picture ready message for Decode call 0. The GetPicture callback | |
428 // should complete. | |
429 SendPictureReady(params, 0U, kTextureId1); | |
430 ASSERT_TRUE(get_picture_cb.called()); | |
431 ASSERT_EQ(PP_OK, get_picture_cb.result()); | |
432 ASSERT_EQ(kDecodeId, picture.decode_id); | |
433 get_picture_cb.Reset(); | |
434 | |
435 // Send a picture ready message for Decode call 1. Since there is no pending | |
436 // GetPicture call, the picture should be queued. | |
437 SendPictureReady(params, 1U, kTextureId2); | |
438 // The next GetPicture should return synchronously. | |
439 ASSERT_EQ(PP_OK, CallGetPicture(decoder.get(), &picture, &uncalled_cb)); | |
440 ASSERT_FALSE(uncalled_cb.called()); | |
441 ASSERT_EQ(kDecodeId, picture.decode_id); | |
442 } | |
443 | |
444 TEST_F(VideoDecoderResourceTest, RecyclePicture) { | |
445 LockingResourceReleaser decoder(CreateAndInitializeDecoder()); | |
446 ResourceMessageCallParams params; | |
447 MockCompletionCallback decode_cb, get_picture_cb, uncalled_cb; | |
448 | |
449 // Get to a state where we have a picture to recycle. | |
450 ASSERT_EQ(PP_OK_COMPLETIONPENDING, CallDecode(decoder.get(), &decode_cb)); | |
451 ASSERT_FALSE(decode_cb.called()); | |
452 std::vector<uint8_t> buffer; | |
453 uint32_t pending_shm_id; | |
454 CheckDecodeBufferMsg(¶ms, &buffer, &pending_shm_id); | |
455 SendCreatedShm(params, 2 * kDecodeBufferSize); | |
456 SendDecodeReply(params, 0U); | |
457 // Send 'request textures' message to initialize textures. | |
458 SendRequestTextures(params); | |
459 // Call GetPicture and send 'picture ready' message to get a picture to | |
460 // recycle. | |
461 PP_VideoPicture picture; | |
462 ASSERT_EQ(PP_OK_COMPLETIONPENDING, | |
463 CallGetPicture(decoder.get(), &picture, &get_picture_cb)); | |
464 SendPictureReady(params, 0U, kTextureId1); | |
465 ASSERT_EQ(kTextureId1, picture.texture_id); | |
466 | |
467 CallRecyclePicture(decoder.get(), picture); | |
468 uint32_t texture_id; | |
469 ASSERT_TRUE(CheckRecyclePictureMsg(¶ms, &texture_id)); | |
470 ASSERT_EQ(kTextureId1, texture_id); | |
471 | |
472 ClearCallbacks(decoder.get()); | |
473 } | |
474 | |
475 TEST_F(VideoDecoderResourceTest, Flush) { | |
476 LockingResourceReleaser decoder(CreateAndInitializeDecoder()); | |
477 ResourceMessageCallParams params, params2; | |
478 MockCompletionCallback flush_cb, get_picture_cb, uncalled_cb; | |
479 | |
480 ASSERT_EQ(PP_OK_COMPLETIONPENDING, CallFlush(decoder.get(), &flush_cb)); | |
481 ASSERT_FALSE(flush_cb.called()); | |
482 ASSERT_TRUE(CheckFlushMsg(¶ms)); | |
483 | |
484 ASSERT_EQ(PP_ERROR_FAILED, CallDecode(decoder.get(), &uncalled_cb)); | |
485 ASSERT_FALSE(uncalled_cb.called()); | |
486 | |
487 // Plugin can call GetPicture while Flush is pending. | |
488 ASSERT_EQ(PP_OK_COMPLETIONPENDING, | |
489 CallGetPicture(decoder.get(), NULL, &get_picture_cb)); | |
490 ASSERT_FALSE(get_picture_cb.called()); | |
491 | |
492 ASSERT_EQ(PP_ERROR_INPROGRESS, CallFlush(decoder.get(), &uncalled_cb)); | |
493 ASSERT_FALSE(uncalled_cb.called()); | |
494 | |
495 ASSERT_EQ(PP_ERROR_FAILED, CallReset(decoder.get(), &uncalled_cb)); | |
496 ASSERT_FALSE(uncalled_cb.called()); | |
497 | |
498 // Plugin can call RecyclePicture while Flush is pending. | |
499 PP_VideoPicture picture; | |
500 picture.texture_id = kTextureId1; | |
501 CallRecyclePicture(decoder.get(), picture); | |
502 uint32_t texture_id; | |
503 ASSERT_TRUE(CheckRecyclePictureMsg(¶ms2, &texture_id)); | |
504 | |
505 SendFlushReply(params); | |
506 // Any pending GetPicture call is aborted. | |
507 ASSERT_TRUE(get_picture_cb.called()); | |
508 ASSERT_EQ(PP_ERROR_ABORTED, get_picture_cb.result()); | |
509 ASSERT_TRUE(flush_cb.called()); | |
510 ASSERT_EQ(PP_OK, flush_cb.result()); | |
511 } | |
512 | |
513 // TODO(bbudge) Test Reset when we can run the message loop to get aborted | |
514 // callbacks to run. | |
515 | |
516 TEST_F(VideoDecoderResourceTest, NotifyError) { | |
517 LockingResourceReleaser decoder(CreateAndInitializeDecoder()); | |
518 ResourceMessageCallParams params; | |
519 MockCompletionCallback decode_cb, get_picture_cb, uncalled_cb; | |
520 | |
521 // Call Decode and GetPicture to have some pending requests. | |
522 ASSERT_EQ(PP_OK_COMPLETIONPENDING, CallDecode(decoder.get(), &decode_cb)); | |
523 ASSERT_FALSE(decode_cb.called()); | |
524 ASSERT_EQ(PP_OK_COMPLETIONPENDING, | |
525 CallGetPicture(decoder.get(), NULL, &get_picture_cb)); | |
526 ASSERT_FALSE(get_picture_cb.called()); | |
527 | |
528 // Send the decoder resource an unsolicited notify error message. We first | |
529 // need to initialize 'params' so the message is routed to the decoder. | |
530 std::vector<uint8_t> buffer; | |
531 uint32_t pending_shm_id; | |
532 CheckDecodeBufferMsg(¶ms, &buffer, &pending_shm_id); | |
533 SendNotifyError(params, PP_ERROR_RESOURCE_FAILED); | |
534 | |
535 // Both pending messages should be run with the reported error. | |
536 ASSERT_TRUE(decode_cb.called()); | |
537 ASSERT_EQ(PP_ERROR_RESOURCE_FAILED, decode_cb.result()); | |
538 ASSERT_TRUE(get_picture_cb.called()); | |
539 ASSERT_EQ(PP_ERROR_RESOURCE_FAILED, get_picture_cb.result()); | |
540 | |
541 // All further calls return the reported error. | |
542 ASSERT_EQ(PP_ERROR_RESOURCE_FAILED, CallDecode(decoder.get(), &uncalled_cb)); | |
543 ASSERT_FALSE(uncalled_cb.called()); | |
544 ASSERT_EQ(PP_ERROR_RESOURCE_FAILED, | |
545 CallGetPicture(decoder.get(), NULL, &uncalled_cb)); | |
546 ASSERT_FALSE(uncalled_cb.called()); | |
547 ASSERT_EQ(PP_ERROR_RESOURCE_FAILED, CallFlush(decoder.get(), &uncalled_cb)); | |
548 ASSERT_FALSE(uncalled_cb.called()); | |
549 ASSERT_EQ(PP_ERROR_RESOURCE_FAILED, CallReset(decoder.get(), &uncalled_cb)); | |
550 ASSERT_FALSE(uncalled_cb.called()); | |
551 } | |
552 | |
553 } // namespace proxy | |
554 } // namespace ppapi | |
OLD | NEW |