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