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, &params, &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(&params);
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, &params, &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(&params, &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(&params, &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(&params, &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(&params, &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(&params));
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(&params2, &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(&params, &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