Index: ppapi/proxy/video_encoder_resource_unittest.cc |
diff --git a/ppapi/proxy/video_encoder_resource_unittest.cc b/ppapi/proxy/video_encoder_resource_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d01f352f4d11645dd675193ad1656a6c49a2c6ea |
--- /dev/null |
+++ b/ppapi/proxy/video_encoder_resource_unittest.cc |
@@ -0,0 +1,919 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "base/memory/shared_memory.h" |
+#include "base/process/process.h" |
+#include "base/synchronization/waitable_event.h" |
+#include "ppapi/c/pp_codecs.h" |
+#include "ppapi/c/pp_errors.h" |
+#include "ppapi/c/ppb_video_encoder.h" |
+#include "ppapi/c/ppb_video_frame.h" |
+#include "ppapi/proxy/locking_resource_releaser.h" |
+#include "ppapi/proxy/plugin_message_filter.h" |
+#include "ppapi/proxy/ppapi_message_utils.h" |
+#include "ppapi/proxy/ppapi_messages.h" |
+#include "ppapi/proxy/ppapi_proxy_test.h" |
+#include "ppapi/proxy/video_encoder_resource.h" |
+#include "ppapi/shared_impl/media_stream_buffer.h" |
+#include "ppapi/shared_impl/proxy_lock.h" |
+#include "ppapi/thunk/thunk.h" |
+ |
+using ppapi::proxy::ResourceMessageTestSink; |
+ |
+namespace ppapi { |
+namespace proxy { |
+ |
+namespace { |
+ |
+const uint32_t kShmSize = 256; |
+const size_t kDecodeBufferSize = 16; |
+const uint32_t kDecodeId = 5; |
bbudge
2015/02/13 01:45:54
I don't think you need these definitions.
llandwerlin-old
2015/02/13 20:12:26
Done.
|
+ |
+class MockCompletionCallback { |
+ public: |
+ MockCompletionCallback() : called_(false), call_event_(false, false) {} |
+ |
+ bool called() { return called_; } |
+ int32_t result() { return result_; } |
+ |
+ void WaitUntilCalled() { call_event_.Wait(); } |
+ |
+ void Reset() { |
+ called_ = false; |
+ call_event_.Reset(); |
+ } |
+ |
+ static void Callback(void* user_data, int32_t result) { |
+ MockCompletionCallback* that = |
+ reinterpret_cast<MockCompletionCallback*>(user_data); |
+ that->call_event_.Signal(); |
+ that->called_ = true; |
+ that->result_ = result; |
+ } |
+ |
+ private: |
+ bool called_; |
+ int32_t result_; |
+ base::WaitableEvent call_event_; |
+}; |
+ |
+class VideoEncoderResourceTest : public PluginProxyTest { |
+ public: |
+ VideoEncoderResourceTest() |
+ : encoder_iface_(thunk::GetPPB_VideoEncoder_0_1_Thunk()) {} |
+ |
+ const PPB_VideoEncoder_0_1* encoder_iface() const { return encoder_iface_; } |
+ |
+ const uint32_t kBitstreamBufferSize = 4000; |
+ const uint32_t kBitstreamBufferNb = 5; |
+ const uint32_t kVideoFrameNb = 3; |
bbudge
2015/02/13 01:45:54
It took me a while to get that Nb is 'Count'.
llandwerlin-old
2015/02/13 20:12:26
Done.
|
+ const uint32_t kBitrate = 200000; |
+ |
+ const PP_Size kSize = {640, 480}; |
bbudge
2015/02/13 01:45:54
kFrameSize?
llandwerlin-old
2015/02/13 20:12:26
Done.
|
+ |
+ void SendReply(const ResourceMessageCallParams& params, |
+ int32_t result, |
+ const IPC::Message& nested_message) { |
+ ResourceMessageReplyParams reply_params(params.pp_resource(), |
+ params.sequence()); |
+ reply_params.set_result(result); |
+ PluginMessageFilter::DispatchResourceReplyForTest(reply_params, |
+ nested_message); |
+ } |
+ |
+ void SendReplyWithHandle(const ResourceMessageCallParams& params, |
+ int32_t result, |
+ const IPC::Message& nested_message, |
+ const SerializedHandle& handle) { |
+ ResourceMessageReplyParams reply_params(params.pp_resource(), |
+ params.sequence()); |
+ reply_params.set_result(result); |
+ reply_params.AppendHandle(handle); |
+ PluginMessageFilter::DispatchResourceReplyForTest(reply_params, |
+ nested_message); |
+ } |
+ |
+ void SendReplyWithHandles(const ResourceMessageCallParams& params, |
+ int32_t result, |
+ const IPC::Message& nested_message, |
+ const std::vector<SerializedHandle>& handles) { |
+ ResourceMessageReplyParams reply_params(params.pp_resource(), |
+ params.sequence()); |
+ reply_params.set_result(result); |
+ for (SerializedHandle handle : handles) |
+ reply_params.AppendHandle(handle); |
+ PluginMessageFilter::DispatchResourceReplyForTest(reply_params, |
+ nested_message); |
+ } |
+ |
+ PP_Resource CreateEncoder() { |
+ PP_Resource result = encoder_iface()->Create(pp_instance()); |
+ return result; |
+ } |
+ |
+ void CreateBitstreamSharedMemory(uint32_t buffer_size, uint32_t nb_buffers) { |
+ shared_memory_bitstreams_.clear(); |
+ for (uint32_t i = 0; i < nb_buffers; ++i) { |
+ scoped_ptr<base::SharedMemory> mem(new base::SharedMemory()); |
+ ASSERT_TRUE(mem->CreateAnonymous(buffer_size)); |
+ shared_memory_bitstreams_.push_back(mem.Pass()); |
+ } |
+ } |
+ |
+ void CreateVideoFramesSharedMemory(uint32_t frame_length, |
+ uint32_t frame_count) { |
+ shared_memory_frames_.reset(new base::SharedMemory()); |
+ uint32_t frame_buffer_length = |
+ frame_length + sizeof(ppapi::MediaStreamBuffer::Video) - |
+ sizeof(ppapi::MediaStreamBuffer::Video::data); |
+ ASSERT_TRUE(shared_memory_frames_->CreateAnonymous(frame_buffer_length * |
+ frame_count)); |
+ } |
+ |
+ PP_Resource CreateAndInitializeEncoder() { |
+ PP_Resource encoder = CreateEncoder(); |
+ PP_Size size = kSize; |
+ MockCompletionCallback cb; |
+ int32_t result = encoder_iface()->Initialize( |
+ encoder, PP_VIDEOFRAME_FORMAT_I420, &size, PP_VIDEOPROFILE_H264MAIN, |
+ kBitrate, PP_HARDWAREACCELERATION_WITHFALLBACK, |
+ PP_MakeOptionalCompletionCallback(&MockCompletionCallback::Callback, |
+ &cb)); |
+ if (result != PP_OK_COMPLETIONPENDING) |
+ return 0; |
+ ResourceMessageCallParams params; |
+ IPC::Message msg; |
+ if (!sink().GetFirstResourceCallMatching( |
+ PpapiHostMsg_VideoEncoder_Initialize::ID, ¶ms, &msg)) |
+ return 0; |
+ sink().ClearMessages(); |
+ |
+ CreateBitstreamSharedMemory(kBitstreamBufferSize, kBitstreamBufferNb); |
+ SendInitializeReply(params, kBitstreamBufferSize, kVideoFrameNb, size); |
+ |
+ if (!cb.called() || cb.result() != PP_OK) |
+ return 0; |
+ |
+ return encoder; |
+ } |
+ |
+ int32_t CallGetFramesRequired(PP_Resource pp_encoder) { |
+ return encoder_iface()->GetFramesRequired(pp_encoder); |
+ } |
+ |
+ int32_t CallGetFrameCodedSize(PP_Resource pp_encoder, PP_Size* coded_size) { |
+ return encoder_iface()->GetFrameCodedSize(pp_encoder, coded_size); |
+ } |
+ |
+ int32_t CallGetVideoFrame(PP_Resource pp_encoder, |
+ PP_Resource* video_frame, |
+ MockCompletionCallback* cb) { |
+ return encoder_iface()->GetVideoFrame( |
+ pp_encoder, video_frame, PP_MakeOptionalCompletionCallback( |
+ &MockCompletionCallback::Callback, cb)); |
+ } |
+ |
+ int32_t CallFirstGetVideoFrame(PP_Resource pp_encoder, |
+ PP_Resource* video_frame, |
+ MockCompletionCallback* cb) { |
+ int32_t result = encoder_iface()->GetVideoFrame( |
+ pp_encoder, video_frame, PP_MakeOptionalCompletionCallback( |
+ &MockCompletionCallback::Callback, cb)); |
+ if (result != PP_OK_COMPLETIONPENDING) |
+ return result; |
+ |
+ ResourceMessageCallParams params; |
+ CheckGetVideoFramesMsg(¶ms); |
+ |
+ uint32_t frame_length = kSize.width * kSize.height * 2; |
+ CreateVideoFramesSharedMemory(frame_length, kVideoFrameNb); |
+ SendGetVideoFramesReply(params, kVideoFrameNb, frame_length, kSize); |
+ |
+ return result; |
+ } |
+ |
+ int32_t CallEncode(PP_Resource pp_encoder, |
+ PP_Resource video_frame, |
+ PP_Bool force_keyframe, |
+ MockCompletionCallback* cb) { |
+ return encoder_iface()->Encode(pp_encoder, video_frame, force_keyframe, |
+ PP_MakeOptionalCompletionCallback( |
+ &MockCompletionCallback::Callback, cb)); |
+ } |
+ |
+ int32_t CallCompleteEncode(PP_Resource pp_encoder, |
+ PP_Resource video_frame, |
+ PP_Bool force_keyframe, |
+ MockCompletionCallback* cb) { |
+ int32_t result = |
+ encoder_iface()->Encode(pp_encoder, video_frame, force_keyframe, |
+ PP_MakeOptionalCompletionCallback( |
+ &MockCompletionCallback::Callback, cb)); |
+ if (result != PP_OK_COMPLETIONPENDING) |
+ return result; |
+ |
+ ResourceMessageCallParams params; |
+ uint32_t frame_id; |
+ bool forced_keyframe; |
+ if (!CheckEncodeMsg(¶ms, &frame_id, &forced_keyframe)) |
+ return PP_ERROR_FAILED; |
+ |
+ SendEncodeReply(params, frame_id); |
+ |
+ return result; |
+ } |
+ |
+ int32_t CallGetBitstreamBuffer(PP_Resource pp_encoder, |
+ PP_BitstreamBuffer* bitstream_buffer, |
+ MockCompletionCallback* cb) { |
+ return encoder_iface()->GetBitstreamBuffer( |
+ pp_encoder, bitstream_buffer, |
+ PP_MakeOptionalCompletionCallback(&MockCompletionCallback::Callback, |
+ cb)); |
+ } |
+ |
+ void CallRecycleBitstreamBuffer(PP_Resource pp_encoder, |
+ const PP_BitstreamBuffer& buffer) { |
+ encoder_iface()->RecycleBitstreamBuffer(pp_encoder, &buffer); |
+ } |
+ |
+ void CallRequestEncodingParametersChange(PP_Resource pp_encoder, |
+ uint32_t bitrate, |
+ uint32_t framerate) { |
+ encoder_iface()->RequestEncodingParametersChange(pp_encoder, bitrate, |
+ framerate); |
+ } |
+ |
+ void CallClose(PP_Resource pp_encoder) { |
+ encoder_iface()->Close(pp_encoder); |
+ } |
+ |
+ void SendGetSupportedProfilesReply( |
+ const ResourceMessageCallParams& params, |
+ const std::vector<PP_VideoProfileDescription>& profiles) { |
+ SendReply(params, PP_OK, |
+ PpapiPluginMsg_VideoEncoder_GetSupportedProfilesReply(profiles)); |
+ } |
+ |
+ void SendInitializeReply(const ResourceMessageCallParams& params, |
+ uint32_t buffer_length, |
+ uint32_t input_frame_count, |
+ const PP_Size& coded_size) { |
+ SendReply(params, PP_OK, PpapiPluginMsg_VideoEncoder_InitializeReply()); |
+ std::vector<SerializedHandle> handles; |
+ for (base::SharedMemory* mem : shared_memory_bitstreams_) { |
+ ASSERT_EQ(mem->requested_size(), buffer_length); |
+ base::SharedMemoryHandle handle; |
+ |
+ ASSERT_TRUE( |
+ mem->ShareToProcess(base::Process::Current().Handle(), &handle)); |
+ handles.push_back(SerializedHandle(handle, buffer_length)); |
+ } |
+ SendReplyWithHandles(params, PP_OK, |
+ PpapiPluginMsg_VideoEncoder_BitstreamBuffers( |
+ buffer_length, input_frame_count, coded_size), |
+ handles); |
+ } |
+ |
+ void SendGetVideoFramesReply(const ResourceMessageCallParams& params, |
+ uint32_t frame_count, |
+ uint32_t frame_length, |
+ const PP_Size& size) { |
+ base::SharedMemoryHandle handle; |
+ ASSERT_TRUE(shared_memory_frames_->ShareToProcess( |
+ base::Process::Current().Handle(), &handle)); |
+ SendReplyWithHandle( |
+ params, PP_OK, PpapiPluginMsg_VideoEncoder_GetVideoFramesReply( |
+ frame_count, frame_length, size), |
+ SerializedHandle(handle, shared_memory_frames_->requested_size())); |
+ } |
+ |
+ void SendEncodeReply(const ResourceMessageCallParams& params, |
+ uint32_t frame_id) { |
+ SendReply(params, PP_OK, PpapiPluginMsg_VideoEncoder_EncodeReply(frame_id)); |
+ } |
+ |
+ void SendBitstreamBufferReady(const ResourceMessageCallParams& params, |
+ uint32_t buffer_id, |
+ uint32_t buffer_size, |
+ bool keyframe) { |
+ SendReply(params, PP_OK, |
+ PpapiPluginMsg_VideoEncoder_BitstreamBufferReady( |
+ buffer_id, buffer_size, PP_FromBool(keyframe))); |
+ } |
+ |
+ void SendNotifyError(const ResourceMessageCallParams& params, int32_t error) { |
+ SendReply(params, PP_OK, PpapiPluginMsg_VideoEncoder_NotifyError(error)); |
+ } |
+ |
+ bool CheckGetSupportedProfilesMsg(ResourceMessageCallParams* params) { |
+ IPC::Message msg; |
+ if (!sink().GetFirstResourceCallMatching( |
+ PpapiHostMsg_VideoEncoder_GetSupportedProfiles::ID, params, &msg)) |
+ return false; |
+ return true; |
+ } |
+ |
+ bool CheckInitializeMsg(ResourceMessageCallParams* params, |
+ PP_VideoFrame_Format* input_format, |
+ struct PP_Size* input_visible_size, |
+ PP_VideoProfile* output_profile, |
+ uint32_t* bitrate, |
+ PP_HardwareAcceleration* acceleration) { |
+ IPC::Message msg; |
+ if (!sink().GetFirstResourceCallMatching( |
+ PpapiHostMsg_VideoEncoder_Initialize::ID, params, &msg)) |
+ return false; |
+ sink().ClearMessages(); |
+ return UnpackMessage<PpapiHostMsg_VideoEncoder_Initialize>( |
+ msg, input_format, input_visible_size, output_profile, bitrate, |
+ acceleration); |
+ } |
+ |
+ bool CheckGetVideoFramesMsg(ResourceMessageCallParams* params) { |
+ IPC::Message msg; |
+ if (!sink().GetFirstResourceCallMatching( |
+ PpapiHostMsg_VideoEncoder_GetVideoFrames::ID, params, &msg)) |
+ return false; |
+ sink().ClearMessages(); |
+ return true; |
+ } |
+ |
+ bool CheckEncodeMsg(ResourceMessageCallParams* params, |
+ uint32_t* frame_id, |
+ bool* keyframe) { |
+ IPC::Message msg; |
+ if (!sink().GetFirstResourceCallMatching( |
+ PpapiHostMsg_VideoEncoder_Encode::ID, params, &msg)) |
+ return false; |
+ sink().ClearMessages(); |
+ return UnpackMessage<PpapiHostMsg_VideoEncoder_Encode>(msg, frame_id, |
+ keyframe); |
+ } |
+ |
+ bool CheckRecycleBitstreamBufferMsg(ResourceMessageCallParams* params, |
+ uint32_t* buffer_id) { |
+ IPC::Message msg; |
+ if (!sink().GetFirstResourceCallMatching( |
+ PpapiHostMsg_VideoEncoder_RecycleBitstreamBuffer::ID, params, &msg)) |
+ return false; |
+ sink().ClearMessages(); |
+ return UnpackMessage<PpapiHostMsg_VideoEncoder_RecycleBitstreamBuffer>( |
+ msg, buffer_id); |
+ } |
+ |
+ bool CheckRequestEncodeingParametersChangeMsg( |
bbudge
2015/02/13 01:45:53
s/Encodeing/Encoding
llandwerlin-old
2015/02/13 20:12:26
Done.
|
+ ResourceMessageCallParams* params, |
+ uint32_t* bitrate, |
+ uint32_t* framerate) { |
+ IPC::Message msg; |
+ if (!sink().GetFirstResourceCallMatching( |
+ PpapiHostMsg_VideoEncoder_RequestEncodingParametersChange::ID, |
+ params, &msg)) |
+ return false; |
+ sink().ClearMessages(); |
+ return UnpackMessage< |
+ PpapiHostMsg_VideoEncoder_RequestEncodingParametersChange>(msg, bitrate, |
+ framerate); |
+ } |
+ |
+ bool CheckIsVideoFrame(PP_Resource video_frame) { |
+ return thunk::GetPPB_VideoFrame_0_1_Thunk()->IsVideoFrame(video_frame); |
+ } |
+ |
+ private: |
+ bool CheckMsg(ResourceMessageCallParams* params, int id) { |
bbudge
2015/02/13 01:45:53
Not used
llandwerlin-old
2015/02/13 20:12:26
Done.
|
+ IPC::Message msg; |
+ if (!sink().GetFirstResourceCallMatching(id, params, &msg)) |
+ return false; |
+ sink().ClearMessages(); |
+ return true; |
+ } |
+ |
+ const PPB_VideoEncoder_0_1* encoder_iface_; |
+ |
+ ScopedVector<base::SharedMemory> shared_memory_bitstreams_; |
+ scoped_ptr<base::SharedMemory> shared_memory_frames_; |
+ |
+ char decode_buffer_[kDecodeBufferSize]; |
bbudge
2015/02/13 01:45:54
Not used.
llandwerlin-old
2015/02/13 20:12:26
Done.
|
+}; |
+ |
+void* ForwardUserData(void* user_data, |
+ uint32_t element_count, |
+ uint32_t element_size) { |
+ return user_data; |
+} |
+ |
+} // namespace |
+ |
+TEST_F(VideoEncoderResourceTest, GetSupportedProfiles) { |
+ // Verifies that GetSupportedProfiles calls into the renderer and |
+ // the we get the right results back. |
+ { |
+ LockingResourceReleaser encoder(CreateEncoder()); |
+ std::vector<PP_VideoProfileDescription> profiles; |
bbudge
2015/02/13 01:45:54
This could just be an array, i.e. PP_VideoProfileD
llandwerlin-old
2015/02/13 20:12:26
Done.
|
+ profiles.resize(2); |
+ PP_ArrayOutput output; |
+ output.user_data = &profiles[0]; |
+ output.GetDataBuffer = ForwardUserData; |
+ ResourceMessageCallParams params; |
+ MockCompletionCallback cb; |
+ int32_t result = encoder_iface()->GetSupportedProfiles( |
+ encoder.get(), output, PP_MakeOptionalCompletionCallback( |
+ &MockCompletionCallback::Callback, &cb)); |
+ ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); |
+ ASSERT_TRUE(CheckGetSupportedProfilesMsg(¶ms)); |
+ |
+ std::vector<PP_VideoProfileDescription> profiles_response; |
+ PP_VideoProfileDescription profile; |
+ profile.profile = PP_VIDEOPROFILE_H264MAIN; |
+ profile.max_resolution.width = 1920; |
+ profile.max_resolution.height = 1080; |
+ profile.max_framerate_numerator = 30; |
+ profile.max_framerate_denominator = 1; |
+ profiles_response.push_back(profile); |
+ profile.profile = PP_VIDEOPROFILE_VP8_ANY; |
+ profile.max_resolution.width = 1920; |
+ profile.max_resolution.height = 1080; |
+ profile.max_framerate_numerator = 30; |
+ profile.max_framerate_denominator = 1; |
+ profiles_response.push_back(profile); |
+ |
+ SendGetSupportedProfilesReply(params, profiles_response); |
+ ASSERT_EQ(PP_OK, cb.result()); |
+ |
+ ASSERT_EQ(profiles_response.size(), profiles.size()); |
+ ASSERT_EQ(0, memcmp(&profiles[0], &profiles_response[0], |
+ sizeof(PP_VideoProfileDescription) * 2)); |
+ } |
+} |
+ |
+TEST_F(VideoEncoderResourceTest, InitializeFailure) { |
+ { |
+ // Verify the initialize callback is called in case of failure. |
+ LockingResourceReleaser encoder(CreateEncoder()); |
+ ResourceMessageCallParams params; |
+ PP_Size size = kSize; |
+ MockCompletionCallback cb; |
+ int32_t result = encoder_iface()->Initialize( |
+ encoder.get(), PP_VIDEOFRAME_FORMAT_BGRA, &size, |
+ PP_VIDEOPROFILE_H264MAIN, kBitrate, |
+ PP_HARDWAREACCELERATION_WITHFALLBACK, |
+ PP_MakeOptionalCompletionCallback(&MockCompletionCallback::Callback, |
+ &cb)); |
+ ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); |
+ |
+ PP_VideoFrame_Format input_format; |
+ PP_Size input_visible_size; |
+ PP_VideoProfile output_profile; |
+ uint32_t bitrate; |
+ PP_HardwareAcceleration acceleration; |
+ ASSERT_TRUE(CheckInitializeMsg(¶ms, &input_format, &input_visible_size, |
+ &output_profile, &bitrate, &acceleration)); |
+ ASSERT_EQ(PP_VIDEOFRAME_FORMAT_BGRA, input_format); |
+ ASSERT_EQ(size.width, input_visible_size.width); |
+ ASSERT_EQ(size.height, input_visible_size.height); |
+ ASSERT_EQ(kBitrate, bitrate); |
+ ASSERT_EQ(PP_VIDEOPROFILE_H264MAIN, output_profile); |
+ ASSERT_EQ(PP_HARDWAREACCELERATION_WITHFALLBACK, acceleration); |
+ |
+ SendReply(params, PP_ERROR_NOTSUPPORTED, |
+ PpapiPluginMsg_VideoEncoder_InitializeReply()); |
+ ASSERT_TRUE(cb.called()); |
+ ASSERT_EQ(PP_ERROR_NOTSUPPORTED, cb.result()); |
+ } |
+ { |
+ // Verify the initialize callback is called in case of error |
+ // notification. |
+ LockingResourceReleaser encoder(CreateEncoder()); |
+ ResourceMessageCallParams params; |
+ PP_Size size = kSize; |
+ MockCompletionCallback cb; |
+ int32_t result = encoder_iface()->Initialize( |
+ encoder.get(), PP_VIDEOFRAME_FORMAT_BGRA, &size, |
+ PP_VIDEOPROFILE_H264MAIN, kBitrate, |
+ PP_HARDWAREACCELERATION_WITHFALLBACK, |
+ PP_MakeOptionalCompletionCallback(&MockCompletionCallback::Callback, |
+ &cb)); |
+ ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); |
+ |
+ PP_VideoFrame_Format input_format; |
+ PP_Size input_visible_size; |
+ PP_VideoProfile output_profile; |
+ uint32_t bitrate; |
+ PP_HardwareAcceleration acceleration; |
+ ASSERT_TRUE(CheckInitializeMsg(¶ms, &input_format, &input_visible_size, |
+ &output_profile, &bitrate, &acceleration)); |
+ ASSERT_EQ(PP_VIDEOFRAME_FORMAT_BGRA, input_format); |
+ ASSERT_EQ(kSize.width, input_visible_size.width); |
+ ASSERT_EQ(kSize.height, input_visible_size.height); |
+ ASSERT_EQ(kBitrate, bitrate); |
+ ASSERT_EQ(PP_VIDEOPROFILE_H264MAIN, output_profile); |
+ ASSERT_EQ(PP_HARDWAREACCELERATION_WITHFALLBACK, acceleration); |
+ |
+ ResourceMessageCallParams error_params(encoder.get(), 0); |
+ SendNotifyError(error_params, PP_ERROR_FAILED); |
+ ASSERT_TRUE(cb.called()); |
+ ASSERT_EQ(PP_ERROR_FAILED, cb.result()); |
+ } |
+} |
bbudge
2015/02/13 01:45:54
As discussed, the Initialize callback should alway
llandwerlin-old
2015/02/13 20:12:26
Done.
|
+ |
+TEST_F(VideoEncoderResourceTest, InitializeSuccess) { |
+ { |
+ // Verify the initialize callback is called when initialization is |
+ // successfull. |
+ LockingResourceReleaser encoder(CreateEncoder()); |
+ ResourceMessageCallParams params; |
+ PP_Size size = kSize; |
+ const uint32_t kBitrate = 420000; |
+ MockCompletionCallback cb; |
+ int32_t result = encoder_iface()->Initialize( |
+ encoder.get(), PP_VIDEOFRAME_FORMAT_I420, &size, |
+ PP_VIDEOPROFILE_H264MAIN, kBitrate, |
+ PP_HARDWAREACCELERATION_WITHFALLBACK, |
+ PP_MakeOptionalCompletionCallback(&MockCompletionCallback::Callback, |
+ &cb)); |
+ ASSERT_EQ(PP_OK_COMPLETIONPENDING, result); |
+ |
+ PP_VideoFrame_Format input_format; |
+ PP_Size input_visible_size; |
+ PP_VideoProfile output_profile; |
+ uint32_t bitrate; |
+ PP_HardwareAcceleration acceleration; |
+ ASSERT_TRUE(CheckInitializeMsg(¶ms, &input_format, &input_visible_size, |
+ &output_profile, &bitrate, &acceleration)); |
+ ASSERT_EQ(PP_VIDEOFRAME_FORMAT_I420, input_format); |
+ ASSERT_EQ(kSize.width, input_visible_size.width); |
+ ASSERT_EQ(kSize.height, input_visible_size.height); |
+ ASSERT_EQ(kBitrate, bitrate); |
+ ASSERT_EQ(PP_VIDEOPROFILE_H264MAIN, output_profile); |
+ ASSERT_EQ(PP_HARDWAREACCELERATION_WITHFALLBACK, acceleration); |
+ |
+ CreateBitstreamSharedMemory(kBitstreamBufferSize, kBitstreamBufferNb); |
+ SendInitializeReply(params, kBitstreamBufferSize, kVideoFrameNb, size); |
bbudge
2015/02/13 01:45:54
Again, Initialize completes without getting buffer
llandwerlin-old
2015/02/13 20:12:26
Done.
|
+ |
+ ASSERT_TRUE(cb.called()); |
+ ASSERT_EQ(PP_OK, cb.result()); |
+ |
+ PP_Size coded_size; |
+ CallGetFrameCodedSize(encoder.get(), &coded_size); |
+ ASSERT_EQ(kSize.width, coded_size.width); |
+ ASSERT_EQ(kSize.height, coded_size.height); |
+ ASSERT_EQ(static_cast<int32_t>(kVideoFrameNb), |
+ CallGetFramesRequired(encoder.get())); |
+ } |
+} |
+ |
+TEST_F(VideoEncoderResourceTest, Uninitialized) { |
+ // Operations on uninitialized encoders should fail. |
+ LockingResourceReleaser encoder(CreateEncoder()); |
+ |
+ ASSERT_EQ(PP_ERROR_FAILED, CallGetFramesRequired(encoder.get())); |
+ |
+ PP_Size size; |
+ ASSERT_EQ(PP_ERROR_FAILED, CallGetFrameCodedSize(encoder.get(), &size)); |
+ |
+ MockCompletionCallback uncalled_cb; |
+ PP_Resource video_frame = 0; |
+ ASSERT_EQ(PP_ERROR_FAILED, |
+ CallGetVideoFrame(encoder.get(), &video_frame, &uncalled_cb)); |
+ ASSERT_FALSE(uncalled_cb.called()); |
+ ASSERT_EQ(0, video_frame); |
+ |
+ ASSERT_EQ(PP_ERROR_FAILED, |
+ CallEncode(encoder.get(), video_frame, PP_FALSE, &uncalled_cb)); |
+ ASSERT_FALSE(uncalled_cb.called()); |
+ |
+ PP_BitstreamBuffer bitstream_buffer; |
+ ASSERT_EQ( |
+ PP_ERROR_FAILED, |
+ CallGetBitstreamBuffer(encoder.get(), &bitstream_buffer, &uncalled_cb)); |
+ ASSERT_FALSE(uncalled_cb.called()); |
+ |
+ ResourceMessageCallParams params; |
+ uint32_t buffer_id; |
+ CallRecycleBitstreamBuffer(encoder.get(), bitstream_buffer); |
+ ASSERT_FALSE(CheckRecycleBitstreamBufferMsg(¶ms, &buffer_id)); |
+ |
+ uint32_t bitrate, framerate; |
+ CallRequestEncodingParametersChange(encoder.get(), 0, 0); |
+ ASSERT_FALSE( |
+ CheckRequestEncodeingParametersChangeMsg(¶ms, &bitrate, &framerate)); |
+} |
+ |
+TEST_F(VideoEncoderResourceTest, InitializeAndGetVideoFrame) { |
+ // Verify that we can pull the right number of video frames before |
+ // the proxy makes us wait. |
+ LockingResourceReleaser encoder(CreateAndInitializeEncoder()); |
+ ResourceMessageCallParams params; |
+ PP_Resource video_frames[kVideoFrameNb + 1]; |
+ MockCompletionCallback get_frame_cb; |
+ |
+ ASSERT_EQ(PP_OK_COMPLETIONPENDING, |
+ CallGetVideoFrame(encoder.get(), &video_frames[0], &get_frame_cb)); |
+ ASSERT_FALSE(get_frame_cb.called()); |
+ ASSERT_TRUE(CheckGetVideoFramesMsg(¶ms)); |
+ |
+ uint32_t frame_length = kSize.width * kSize.height * 2; |
+ CreateVideoFramesSharedMemory(frame_length, kVideoFrameNb); |
+ SendGetVideoFramesReply(params, kVideoFrameNb, frame_length, kSize); |
+ |
+ for (uint32_t i = 1; i < kVideoFrameNb; ++i) { |
+ get_frame_cb.Reset(); |
+ ASSERT_EQ(PP_OK, CallGetVideoFrame(encoder.get(), &video_frames[i], |
+ &get_frame_cb)); |
+ ASSERT_FALSE(get_frame_cb.called()); |
+ ASSERT_TRUE(CheckIsVideoFrame(video_frames[i])); |
+ } |
+ |
+ get_frame_cb.Reset(); |
+ ASSERT_EQ(PP_OK_COMPLETIONPENDING, |
+ CallGetVideoFrame(encoder.get(), &video_frames[kVideoFrameNb], |
+ &get_frame_cb)); |
+ ASSERT_FALSE(get_frame_cb.called()); |
+ |
+ MockCompletionCallback get_frame_fail_cb; |
+ ASSERT_EQ(PP_ERROR_INPROGRESS, |
+ CallGetVideoFrame(encoder.get(), &video_frames[kVideoFrameNb], |
+ &get_frame_fail_cb)); |
+ ASSERT_FALSE(get_frame_fail_cb.called()); |
+ |
+ // Unlock the GetVideoFrame callback. |
bbudge
2015/02/13 01:45:53
// Unblock the GetVideoFrame callback by freeing u
llandwerlin-old
2015/02/13 20:12:26
Done.
|
+ MockCompletionCallback encode_cb; |
+ ASSERT_EQ( |
+ PP_OK_COMPLETIONPENDING, |
+ CallCompleteEncode(encoder.get(), video_frames[0], PP_FALSE, &encode_cb)); |
+ ASSERT_TRUE(encode_cb.called()); |
+ ASSERT_EQ(PP_OK, encode_cb.result()); |
+ ASSERT_TRUE(get_frame_cb.called()); |
+ |
+ { |
+ ProxyAutoLock lock; |
+ for (uint32_t i = 0; i < (kVideoFrameNb + 1); ++i) |
+ PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource( |
+ video_frames[i]); |
bbudge
2015/02/13 01:45:54
Could you call encoder.Close() instead?
llandwerlin-old
2015/02/13 20:12:26
Done.
|
+ } |
+} |
+ |
+TEST_F(VideoEncoderResourceTest, Encode) { |
+ // Check Encode() calls into the renderer. |
+ LockingResourceReleaser encoder(CreateAndInitializeEncoder()); |
+ |
+ PP_Resource video_frame; |
+ MockCompletionCallback get_frame_cb; |
+ ; |
bbudge
2015/02/13 01:45:54
empty statement
llandwerlin-old
2015/02/13 20:12:26
Done.
|
+ ASSERT_EQ(PP_OK_COMPLETIONPENDING, |
+ CallFirstGetVideoFrame(encoder.get(), &video_frame, &get_frame_cb)); |
+ ASSERT_TRUE(get_frame_cb.called()); |
+ ASSERT_EQ(PP_OK, get_frame_cb.result()); |
+ |
+ MockCompletionCallback encode_cb; |
+ ASSERT_EQ(PP_OK_COMPLETIONPENDING, |
+ CallEncode(encoder.get(), video_frame, PP_TRUE, &encode_cb)); |
+ ASSERT_FALSE(encode_cb.called()); |
+ |
+ ResourceMessageCallParams params; |
+ uint32_t frame_id; |
+ bool force_frame; |
+ ASSERT_TRUE(CheckEncodeMsg(¶ms, &frame_id, &force_frame)); |
+ |
+ SendEncodeReply(params, frame_id); |
+ |
+ ASSERT_TRUE(encode_cb.called()); |
+ ASSERT_EQ(PP_OK, encode_cb.result()); |
+} |
+ |
+TEST_F(VideoEncoderResourceTest, EncodeAndGetVideoFrame) { |
+ // Check the encoding loop works well. |
+ LockingResourceReleaser encoder(CreateAndInitializeEncoder()); |
+ ResourceMessageCallParams params; |
+ PP_Resource video_frame; |
+ MockCompletionCallback get_frame_cb, encode_cb; |
+ |
+ ASSERT_EQ(PP_OK_COMPLETIONPENDING, |
+ CallFirstGetVideoFrame(encoder.get(), &video_frame, &get_frame_cb)); |
+ ASSERT_TRUE(get_frame_cb.called()); |
+ ASSERT_EQ(PP_OK, get_frame_cb.result()); |
+ |
+ for (uint32_t i = 1; i < 20 * kVideoFrameNb; ++i) { |
+ encode_cb.Reset(); |
+ ASSERT_EQ( |
+ PP_OK_COMPLETIONPENDING, |
+ CallCompleteEncode(encoder.get(), video_frame, PP_FALSE, &encode_cb)); |
+ ASSERT_TRUE(encode_cb.called()); |
+ ASSERT_EQ(PP_OK, encode_cb.result()); |
+ |
+ get_frame_cb.Reset(); |
+ ASSERT_EQ(PP_OK, |
+ CallGetVideoFrame(encoder.get(), &video_frame, &get_frame_cb)); |
+ ASSERT_FALSE(get_frame_cb.called()); |
+ ASSERT_TRUE(CheckIsVideoFrame(video_frame)); |
+ } |
+ |
+ ASSERT_EQ( |
+ PP_OK_COMPLETIONPENDING, |
+ CallCompleteEncode(encoder.get(), video_frame, PP_FALSE, &encode_cb)); |
+ ASSERT_TRUE(encode_cb.called()); |
+ ASSERT_EQ(PP_OK, encode_cb.result()); |
+} |
+ |
+TEST_F(VideoEncoderResourceTest, GetBitstreamBuffer) { |
+ // Verify that the GetBitstreamBuffer callback is fired whenever the |
+ // renderer signals a buffer is available. |
+ LockingResourceReleaser encoder(CreateAndInitializeEncoder()); |
+ |
+ MockCompletionCallback get_bitstream_buffer_cb; |
+ PP_BitstreamBuffer bitstream_buffer; |
+ ASSERT_EQ(PP_OK_COMPLETIONPENDING, |
+ CallGetBitstreamBuffer(encoder.get(), &bitstream_buffer, |
+ &get_bitstream_buffer_cb)); |
+ ASSERT_FALSE(get_bitstream_buffer_cb.called()); |
+ |
bbudge
2015/02/13 01:45:54
Test a second call gets INPROGRESS.
llandwerlin-old
2015/02/13 20:12:26
Done.
|
+ ResourceMessageCallParams buffer_params(encoder.get(), 0); |
+ SendBitstreamBufferReady(buffer_params, 0, 10, true); |
+ |
+ ASSERT_TRUE(get_bitstream_buffer_cb.called()); |
+ ASSERT_EQ(PP_OK, get_bitstream_buffer_cb.result()); |
+ ASSERT_EQ(static_cast<uint32_t>(10), bitstream_buffer.size); |
+ ASSERT_EQ(PP_TRUE, bitstream_buffer.key_frame); |
+} |
+ |
+TEST_F(VideoEncoderResourceTest, RecycleBitstreamBuffer) { |
+ // Verify that we signal the renderer that a bitstream buffer has been |
+ // recycled. |
+ LockingResourceReleaser encoder(CreateAndInitializeEncoder()); |
+ |
+ MockCompletionCallback get_bitstream_buffer_cb; |
+ PP_BitstreamBuffer bitstream_buffer; |
+ ASSERT_EQ(PP_OK_COMPLETIONPENDING, |
+ CallGetBitstreamBuffer(encoder.get(), &bitstream_buffer, |
+ &get_bitstream_buffer_cb)); |
+ ASSERT_FALSE(get_bitstream_buffer_cb.called()); |
+ |
+ ResourceMessageCallParams buffer_params(encoder.get(), 0); |
+ SendBitstreamBufferReady(buffer_params, kBitstreamBufferNb - 1, 10, true); |
+ |
+ ASSERT_TRUE(get_bitstream_buffer_cb.called()); |
+ ASSERT_EQ(PP_OK, get_bitstream_buffer_cb.result()); |
+ |
+ CallRecycleBitstreamBuffer(encoder.get(), bitstream_buffer); |
+ |
+ ResourceMessageCallParams recycle_params; |
+ uint32_t buffer_id; |
+ ASSERT_TRUE(CheckRecycleBitstreamBufferMsg(&recycle_params, &buffer_id)); |
+ ASSERT_EQ(kBitstreamBufferNb - 1, buffer_id); |
+} |
+ |
+TEST_F(VideoEncoderResourceTest, RequestEncodingParametersChange) { |
+ // Check encoding parameter changes are correctly sent to the |
+ // renderer. |
+ LockingResourceReleaser encoder(CreateAndInitializeEncoder()); |
+ |
+ CallRequestEncodingParametersChange(encoder.get(), 1, 2); |
+ ResourceMessageCallParams params; |
+ uint32_t bitrate, framerate; |
+ ASSERT_TRUE( |
+ CheckRequestEncodeingParametersChangeMsg(¶ms, &bitrate, &framerate)); |
+ ASSERT_EQ(static_cast<uint32_t>(1), bitrate); |
+ ASSERT_EQ(static_cast<uint32_t>(2), framerate); |
+} |
+ |
+TEST_F(VideoEncoderResourceTest, NotifyError) { |
+ { |
+ // Check an error from the encoder calls back GetVideoFrame and |
bbudge
2015/02/13 01:45:53
s/calls back/aborts
|
+ // GetBitstreamBuffer callbacks. |
+ LockingResourceReleaser encoder(CreateAndInitializeEncoder()); |
+ |
+ MockCompletionCallback get_frame_cb; |
+ PP_Resource video_frame; |
+ ASSERT_EQ(PP_OK_COMPLETIONPENDING, |
+ CallGetVideoFrame(encoder.get(), &video_frame, &get_frame_cb)); |
+ ASSERT_FALSE(get_frame_cb.called()); |
+ |
+ MockCompletionCallback get_bitstream_buffer_cb; |
+ PP_BitstreamBuffer bitstream_buffer; |
+ ASSERT_EQ(PP_OK_COMPLETIONPENDING, |
+ CallGetBitstreamBuffer(encoder.get(), &bitstream_buffer, |
+ &get_bitstream_buffer_cb)); |
+ |
+ ResourceMessageCallParams error_params(encoder.get(), 0); |
+ SendNotifyError(error_params, PP_ERROR_FAILED); |
+ |
+ ASSERT_TRUE(get_frame_cb.called()); |
+ ASSERT_EQ(PP_ERROR_FAILED, get_frame_cb.result()); |
+ ASSERT_TRUE(get_bitstream_buffer_cb.called()); |
+ ASSERT_EQ(PP_ERROR_FAILED, get_bitstream_buffer_cb.result()); |
+ } |
+ { |
+ // Check an error from the encoder calls back Encode and GetBitstreamBuffer |
bbudge
2015/02/13 01:45:54
s/calls back/aborts
llandwerlin-old
2015/02/13 20:12:26
Done.
|
+ // callbacks. |
+ LockingResourceReleaser encoder(CreateAndInitializeEncoder()); |
+ |
+ MockCompletionCallback get_frame_cb, encode_cb1, encode_cb2; |
+ PP_Resource video_frame1, video_frame2; |
+ ASSERT_EQ( |
+ PP_OK_COMPLETIONPENDING, |
+ CallFirstGetVideoFrame(encoder.get(), &video_frame1, &get_frame_cb)); |
+ ASSERT_TRUE(get_frame_cb.called()); |
+ ASSERT_EQ(PP_OK, get_frame_cb.result()); |
+ |
+ get_frame_cb.Reset(); |
+ ASSERT_EQ(PP_OK, CallFirstGetVideoFrame(encoder.get(), &video_frame2, |
+ &get_frame_cb)); |
+ ASSERT_FALSE(get_frame_cb.called()); |
+ |
+ ASSERT_EQ(PP_OK_COMPLETIONPENDING, |
+ CallEncode(encoder.get(), video_frame1, PP_FALSE, &encode_cb1)); |
+ ASSERT_FALSE(encode_cb1.called()); |
+ ASSERT_EQ(PP_OK_COMPLETIONPENDING, |
+ CallEncode(encoder.get(), video_frame2, PP_FALSE, &encode_cb2)); |
+ ASSERT_FALSE(encode_cb2.called()); |
+ |
+ MockCompletionCallback get_bitstream_buffer_cb; |
+ PP_BitstreamBuffer bitstream_buffer; |
+ ASSERT_EQ(PP_OK_COMPLETIONPENDING, |
+ CallGetBitstreamBuffer(encoder.get(), &bitstream_buffer, |
+ &get_bitstream_buffer_cb)); |
+ |
+ ResourceMessageCallParams error_params(encoder.get(), 0); |
+ SendNotifyError(error_params, PP_ERROR_FAILED); |
+ |
+ ASSERT_TRUE(encode_cb1.called()); |
+ ASSERT_EQ(PP_ERROR_FAILED, encode_cb1.result()); |
+ ASSERT_TRUE(encode_cb2.called()); |
+ ASSERT_EQ(PP_ERROR_FAILED, encode_cb2.result()); |
+ ASSERT_TRUE(get_bitstream_buffer_cb.called()); |
+ ASSERT_EQ(PP_ERROR_FAILED, get_bitstream_buffer_cb.result()); |
+ } |
+} |
+ |
+TEST_F(VideoEncoderResourceTest, Close) { |
+ { |
+ // Check closing the encoder callbacks back GetVideoFrame and |
bbudge
2015/02/13 01:45:54
s/callbacks back/aborts
llandwerlin-old
2015/02/13 20:12:26
Done.
|
+ // GetBitstreamBuffer callbacks. |
+ LockingResourceReleaser encoder(CreateAndInitializeEncoder()); |
+ |
+ MockCompletionCallback get_frame_cb; |
+ PP_Resource video_frame; |
+ ASSERT_EQ(PP_OK_COMPLETIONPENDING, |
+ CallGetVideoFrame(encoder.get(), &video_frame, &get_frame_cb)); |
+ ASSERT_FALSE(get_frame_cb.called()); |
+ |
+ MockCompletionCallback get_bitstream_buffer_cb; |
+ PP_BitstreamBuffer bitstream_buffer; |
+ ASSERT_EQ(PP_OK_COMPLETIONPENDING, |
+ CallGetBitstreamBuffer(encoder.get(), &bitstream_buffer, |
+ &get_bitstream_buffer_cb)); |
+ |
+ CallClose(encoder.get()); |
+ |
+ ASSERT_TRUE(get_frame_cb.called()); |
+ ASSERT_EQ(PP_ERROR_ABORTED, get_frame_cb.result()); |
+ ASSERT_TRUE(get_bitstream_buffer_cb.called()); |
+ ASSERT_EQ(PP_ERROR_ABORTED, get_bitstream_buffer_cb.result()); |
+ } |
+ { |
+ // Check closing the encoder calls back Encode and GetBitstreamBuffer |
bbudge
2015/02/13 01:45:53
s/calls back/aborts
llandwerlin-old
2015/02/13 20:12:26
Done.
|
+ // callbacks. |
+ LockingResourceReleaser encoder(CreateAndInitializeEncoder()); |
+ |
+ MockCompletionCallback get_frame_cb, encode_cb1, encode_cb2; |
+ PP_Resource video_frame1, video_frame2; |
+ ASSERT_EQ( |
+ PP_OK_COMPLETIONPENDING, |
+ CallFirstGetVideoFrame(encoder.get(), &video_frame1, &get_frame_cb)); |
+ ASSERT_TRUE(get_frame_cb.called()); |
+ ASSERT_EQ(PP_OK, get_frame_cb.result()); |
+ |
+ get_frame_cb.Reset(); |
+ ASSERT_EQ(PP_OK, CallFirstGetVideoFrame(encoder.get(), &video_frame2, |
+ &get_frame_cb)); |
+ ASSERT_FALSE(get_frame_cb.called()); |
+ |
+ ASSERT_EQ(PP_OK_COMPLETIONPENDING, |
+ CallEncode(encoder.get(), video_frame1, PP_FALSE, &encode_cb1)); |
+ ASSERT_FALSE(encode_cb1.called()); |
+ ASSERT_EQ(PP_OK_COMPLETIONPENDING, |
+ CallEncode(encoder.get(), video_frame2, PP_FALSE, &encode_cb2)); |
+ ASSERT_FALSE(encode_cb2.called()); |
+ |
+ MockCompletionCallback get_bitstream_buffer_cb; |
+ PP_BitstreamBuffer bitstream_buffer; |
+ ASSERT_EQ(PP_OK_COMPLETIONPENDING, |
+ CallGetBitstreamBuffer(encoder.get(), &bitstream_buffer, |
+ &get_bitstream_buffer_cb)); |
+ |
+ CallClose(encoder.get()); |
+ |
+ ASSERT_TRUE(encode_cb1.called()); |
+ ASSERT_EQ(PP_ERROR_ABORTED, encode_cb1.result()); |
+ ASSERT_TRUE(encode_cb2.called()); |
+ ASSERT_EQ(PP_ERROR_ABORTED, encode_cb2.result()); |
+ ASSERT_TRUE(get_bitstream_buffer_cb.called()); |
+ ASSERT_EQ(PP_ERROR_ABORTED, get_bitstream_buffer_cb.result()); |
+ } |
+} |
+ |
+} // namespace proxy |
+} // namespace ppapi |