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