Make castv2 performance test work.
[chromium-blink-merge.git] / ppapi / proxy / video_encoder_resource.cc
blobd337b7b8ee6ca845aa05b405c1d1ccbd0896410c
1 // Copyright 2015 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.
5 #include "base/memory/shared_memory.h"
6 #include "base/numerics/safe_conversions.h"
7 #include "ppapi/c/pp_array_output.h"
8 #include "ppapi/proxy/ppapi_messages.h"
9 #include "ppapi/proxy/video_encoder_resource.h"
10 #include "ppapi/proxy/video_frame_resource.h"
11 #include "ppapi/shared_impl/array_writer.h"
12 #include "ppapi/shared_impl/media_stream_buffer.h"
13 #include "ppapi/shared_impl/media_stream_buffer_manager.h"
14 #include "ppapi/thunk/enter.h"
16 using ppapi::proxy::SerializedHandle;
17 using ppapi::thunk::EnterResourceNoLock;
18 using ppapi::thunk::PPB_VideoEncoder_API;
20 namespace ppapi {
21 namespace proxy {
23 namespace {
25 void RunCallback(scoped_refptr<TrackedCallback>* callback, int32_t error) {
26 if (!TrackedCallback::IsPending(*callback))
27 return;
29 scoped_refptr<TrackedCallback> temp;
30 callback->swap(temp);
31 temp->Run(error);
34 } // namespace
36 VideoEncoderResource::ShmBuffer::ShmBuffer(uint32_t id,
37 scoped_ptr<base::SharedMemory> shm)
38 : id(id), shm(shm.Pass()) {
41 VideoEncoderResource::ShmBuffer::~ShmBuffer() {
44 VideoEncoderResource::BitstreamBuffer::BitstreamBuffer(uint32_t id,
45 uint32_t size,
46 bool key_frame)
47 : id(id), size(size), key_frame(key_frame) {
50 VideoEncoderResource::BitstreamBuffer::~BitstreamBuffer() {
53 VideoEncoderResource::VideoEncoderResource(Connection connection,
54 PP_Instance instance)
55 : PluginResource(connection, instance),
56 initialized_(false),
57 closed_(false),
58 // Set |encoder_last_error_| to PP_OK after successful initialization.
59 // This makes error checking a little more concise, since we can check
60 // that the encoder has been initialized and hasn't returned an error by
61 // just testing |encoder_last_error_|.
62 encoder_last_error_(PP_ERROR_FAILED),
63 input_frame_count_(0),
64 input_coded_size_(PP_MakeSize(0, 0)),
65 buffer_manager_(this),
66 get_video_frame_data_(nullptr),
67 get_bitstream_buffer_data_(nullptr) {
68 SendCreate(RENDERER, PpapiHostMsg_VideoEncoder_Create());
71 VideoEncoderResource::~VideoEncoderResource() {
72 Close();
75 PPB_VideoEncoder_API* VideoEncoderResource::AsPPB_VideoEncoder_API() {
76 return this;
79 int32_t VideoEncoderResource::GetSupportedProfiles(
80 const PP_ArrayOutput& output,
81 const scoped_refptr<TrackedCallback>& callback) {
82 if (TrackedCallback::IsPending(get_supported_profiles_callback_))
83 return PP_ERROR_INPROGRESS;
85 get_supported_profiles_callback_ = callback;
86 Call<PpapiPluginMsg_VideoEncoder_GetSupportedProfilesReply>(
87 RENDERER, PpapiHostMsg_VideoEncoder_GetSupportedProfiles(),
88 base::Bind(&VideoEncoderResource::OnPluginMsgGetSupportedProfilesReply,
89 this, output));
90 return PP_OK_COMPLETIONPENDING;
93 int32_t VideoEncoderResource::GetFramesRequired() {
94 if (encoder_last_error_)
95 return encoder_last_error_;
96 return input_frame_count_;
99 int32_t VideoEncoderResource::GetFrameCodedSize(PP_Size* size) {
100 if (encoder_last_error_)
101 return encoder_last_error_;
102 *size = input_coded_size_;
103 return PP_OK;
106 int32_t VideoEncoderResource::Initialize(
107 PP_VideoFrame_Format input_format,
108 const PP_Size* input_visible_size,
109 PP_VideoProfile output_profile,
110 uint32_t initial_bitrate,
111 PP_HardwareAcceleration acceleration,
112 const scoped_refptr<TrackedCallback>& callback) {
113 if (initialized_)
114 return PP_ERROR_FAILED;
115 if (TrackedCallback::IsPending(initialize_callback_))
116 return PP_ERROR_INPROGRESS;
118 initialize_callback_ = callback;
119 Call<PpapiPluginMsg_VideoEncoder_InitializeReply>(
120 RENDERER, PpapiHostMsg_VideoEncoder_Initialize(
121 input_format, *input_visible_size, output_profile,
122 initial_bitrate, acceleration),
123 base::Bind(&VideoEncoderResource::OnPluginMsgInitializeReply, this));
124 return PP_OK_COMPLETIONPENDING;
127 int32_t VideoEncoderResource::GetVideoFrame(
128 PP_Resource* video_frame,
129 const scoped_refptr<TrackedCallback>& callback) {
130 if (encoder_last_error_)
131 return encoder_last_error_;
133 if (TrackedCallback::IsPending(get_video_frame_callback_))
134 return PP_ERROR_INPROGRESS;
136 get_video_frame_data_ = video_frame;
137 get_video_frame_callback_ = callback;
139 // Lazily ask for a shared memory buffer in which video frames are allocated.
140 if (buffer_manager_.number_of_buffers() == 0) {
141 Call<PpapiPluginMsg_VideoEncoder_GetVideoFramesReply>(
142 RENDERER, PpapiHostMsg_VideoEncoder_GetVideoFrames(),
143 base::Bind(&VideoEncoderResource::OnPluginMsgGetVideoFramesReply,
144 this));
145 } else {
146 TryWriteVideoFrame();
149 return PP_OK_COMPLETIONPENDING;
152 int32_t VideoEncoderResource::Encode(
153 PP_Resource video_frame,
154 PP_Bool force_keyframe,
155 const scoped_refptr<TrackedCallback>& callback) {
156 if (encoder_last_error_)
157 return encoder_last_error_;
159 VideoFrameMap::iterator it = video_frames_.find(video_frame);
160 if (it == video_frames_.end())
161 // TODO(llandwerlin): accept MediaStreamVideoTrack's video frames.
162 return PP_ERROR_BADRESOURCE;
164 scoped_refptr<VideoFrameResource> frame_resource = it->second;
166 encode_callbacks_.insert(std::make_pair(video_frame, callback));
168 Call<PpapiPluginMsg_VideoEncoder_EncodeReply>(
169 RENDERER,
170 PpapiHostMsg_VideoEncoder_Encode(frame_resource->GetBufferIndex(),
171 PP_ToBool(force_keyframe)),
172 base::Bind(&VideoEncoderResource::OnPluginMsgEncodeReply, this,
173 video_frame));
175 // Invalidate the frame to prevent the plugin from modifying it.
176 it->second->Invalidate();
177 video_frames_.erase(it);
179 return PP_OK_COMPLETIONPENDING;
182 int32_t VideoEncoderResource::GetBitstreamBuffer(
183 PP_BitstreamBuffer* bitstream_buffer,
184 const scoped_refptr<TrackedCallback>& callback) {
185 if (encoder_last_error_)
186 return encoder_last_error_;
187 if (TrackedCallback::IsPending(get_bitstream_buffer_callback_))
188 return PP_ERROR_INPROGRESS;
190 get_bitstream_buffer_callback_ = callback;
191 get_bitstream_buffer_data_ = bitstream_buffer;
193 if (!available_bitstream_buffers_.empty()) {
194 BitstreamBuffer buffer(available_bitstream_buffers_.front());
195 available_bitstream_buffers_.pop_front();
196 WriteBitstreamBuffer(buffer);
199 return PP_OK_COMPLETIONPENDING;
202 void VideoEncoderResource::RecycleBitstreamBuffer(
203 const PP_BitstreamBuffer* bitstream_buffer) {
204 if (encoder_last_error_)
205 return;
206 BitstreamBufferMap::const_iterator iter =
207 bitstream_buffer_map_.find(bitstream_buffer->buffer);
208 if (iter != bitstream_buffer_map_.end()) {
209 Post(RENDERER,
210 PpapiHostMsg_VideoEncoder_RecycleBitstreamBuffer(iter->second));
214 void VideoEncoderResource::RequestEncodingParametersChange(uint32_t bitrate,
215 uint32_t framerate) {
216 if (encoder_last_error_)
217 return;
218 Post(RENDERER, PpapiHostMsg_VideoEncoder_RequestEncodingParametersChange(
219 bitrate, framerate));
222 void VideoEncoderResource::Close() {
223 if (closed_)
224 return;
225 Post(RENDERER, PpapiHostMsg_VideoEncoder_Close());
226 closed_ = true;
227 if (!encoder_last_error_ || !initialized_)
228 NotifyError(PP_ERROR_ABORTED);
229 ReleaseFrames();
232 void VideoEncoderResource::OnReplyReceived(
233 const ResourceMessageReplyParams& params,
234 const IPC::Message& msg) {
235 PPAPI_BEGIN_MESSAGE_MAP(VideoEncoderResource, msg)
236 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
237 PpapiPluginMsg_VideoEncoder_BitstreamBuffers,
238 OnPluginMsgBitstreamBuffers)
239 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
240 PpapiPluginMsg_VideoEncoder_BitstreamBufferReady,
241 OnPluginMsgBitstreamBufferReady)
242 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(PpapiPluginMsg_VideoEncoder_NotifyError,
243 OnPluginMsgNotifyError)
244 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(
245 PluginResource::OnReplyReceived(params, msg))
246 PPAPI_END_MESSAGE_MAP()
249 void VideoEncoderResource::OnPluginMsgGetSupportedProfilesReply(
250 const PP_ArrayOutput& output,
251 const ResourceMessageReplyParams& params,
252 const std::vector<PP_VideoProfileDescription>& profiles) {
253 int32_t error = params.result();
254 if (error) {
255 NotifyError(error);
256 return;
259 ArrayWriter writer(output);
260 if (!writer.is_valid()) {
261 RunCallback(&get_supported_profiles_callback_, PP_ERROR_BADARGUMENT);
262 return;
265 if (!writer.StoreVector(profiles)) {
266 RunCallback(&get_supported_profiles_callback_, PP_ERROR_FAILED);
267 return;
270 RunCallback(&get_supported_profiles_callback_, PP_OK);
273 void VideoEncoderResource::OnPluginMsgInitializeReply(
274 const ResourceMessageReplyParams& params,
275 uint32_t input_frame_count,
276 const PP_Size& input_coded_size) {
277 DCHECK(!initialized_);
279 encoder_last_error_ = params.result();
280 if (!encoder_last_error_)
281 initialized_ = true;
283 input_frame_count_ = input_frame_count;
284 input_coded_size_ = input_coded_size;
286 RunCallback(&initialize_callback_, encoder_last_error_);
289 void VideoEncoderResource::OnPluginMsgGetVideoFramesReply(
290 const ResourceMessageReplyParams& params,
291 uint32_t frame_count,
292 uint32_t frame_length,
293 const PP_Size& frame_size) {
294 int32_t error = params.result();
295 if (error) {
296 NotifyError(error);
297 return;
300 base::SharedMemoryHandle buffer_handle;
301 params.TakeSharedMemoryHandleAtIndex(0, &buffer_handle);
303 if (!buffer_manager_.SetBuffers(
304 frame_count, frame_length,
305 make_scoped_ptr(new base::SharedMemory(buffer_handle, false)),
306 true)) {
307 NotifyError(PP_ERROR_FAILED);
308 return;
311 if (TrackedCallback::IsPending(get_video_frame_callback_))
312 TryWriteVideoFrame();
315 void VideoEncoderResource::OnPluginMsgEncodeReply(
316 PP_Resource video_frame,
317 const ResourceMessageReplyParams& params,
318 uint32_t frame_id) {
319 DCHECK_NE(encode_callbacks_.size(), 0U);
320 encoder_last_error_ = params.result();
322 EncodeMap::iterator it = encode_callbacks_.find(video_frame);
323 DCHECK(encode_callbacks_.end() != it);
325 scoped_refptr<TrackedCallback> callback = it->second;
326 encode_callbacks_.erase(it);
327 RunCallback(&callback, encoder_last_error_);
329 buffer_manager_.EnqueueBuffer(frame_id);
330 // If the plugin is waiting for a video frame, we can give the one
331 // that just became available again.
332 if (TrackedCallback::IsPending(get_video_frame_callback_))
333 TryWriteVideoFrame();
336 void VideoEncoderResource::OnPluginMsgBitstreamBuffers(
337 const ResourceMessageReplyParams& params,
338 uint32_t buffer_length) {
339 std::vector<base::SharedMemoryHandle> shm_handles;
340 params.TakeAllSharedMemoryHandles(&shm_handles);
341 if (shm_handles.size() == 0) {
342 NotifyError(PP_ERROR_FAILED);
343 return;
346 for (uint32_t i = 0; i < shm_handles.size(); ++i) {
347 scoped_ptr<base::SharedMemory> shm(
348 new base::SharedMemory(shm_handles[i], true));
349 CHECK(shm->Map(buffer_length));
351 ShmBuffer* buffer = new ShmBuffer(i, shm.Pass());
352 shm_buffers_.push_back(buffer);
353 bitstream_buffer_map_.insert(
354 std::make_pair(buffer->shm->memory(), buffer->id));
358 void VideoEncoderResource::OnPluginMsgBitstreamBufferReady(
359 const ResourceMessageReplyParams& params,
360 uint32_t buffer_id,
361 uint32_t buffer_size,
362 bool key_frame) {
363 available_bitstream_buffers_.push_back(
364 BitstreamBuffer(buffer_id, buffer_size, key_frame));
366 if (TrackedCallback::IsPending(get_bitstream_buffer_callback_)) {
367 BitstreamBuffer buffer(available_bitstream_buffers_.front());
368 available_bitstream_buffers_.pop_front();
369 WriteBitstreamBuffer(buffer);
373 void VideoEncoderResource::OnPluginMsgNotifyError(
374 const ResourceMessageReplyParams& params,
375 int32_t error) {
376 NotifyError(error);
379 void VideoEncoderResource::NotifyError(int32_t error) {
380 encoder_last_error_ = error;
381 RunCallback(&get_supported_profiles_callback_, error);
382 RunCallback(&initialize_callback_, error);
383 RunCallback(&get_video_frame_callback_, error);
384 get_video_frame_data_ = nullptr;
385 RunCallback(&get_bitstream_buffer_callback_, error);
386 get_bitstream_buffer_data_ = nullptr;
387 for (EncodeMap::iterator it = encode_callbacks_.begin();
388 it != encode_callbacks_.end(); ++it) {
389 scoped_refptr<TrackedCallback> callback = it->second;
390 RunCallback(&callback, error);
392 encode_callbacks_.clear();
395 void VideoEncoderResource::TryWriteVideoFrame() {
396 DCHECK(TrackedCallback::IsPending(get_video_frame_callback_));
398 int32_t frame_id = buffer_manager_.DequeueBuffer();
399 if (frame_id < 0)
400 return;
402 scoped_refptr<VideoFrameResource> resource = new VideoFrameResource(
403 pp_instance(), frame_id, buffer_manager_.GetBufferPointer(frame_id));
404 video_frames_.insert(
405 VideoFrameMap::value_type(resource->pp_resource(), resource));
407 *get_video_frame_data_ = resource->GetReference();
408 get_video_frame_data_ = nullptr;
409 RunCallback(&get_video_frame_callback_, PP_OK);
412 void VideoEncoderResource::WriteBitstreamBuffer(const BitstreamBuffer& buffer) {
413 DCHECK_LT(buffer.id, shm_buffers_.size());
415 get_bitstream_buffer_data_->size = buffer.size;
416 get_bitstream_buffer_data_->buffer = shm_buffers_[buffer.id]->shm->memory();
417 get_bitstream_buffer_data_->key_frame = PP_FromBool(buffer.key_frame);
418 get_bitstream_buffer_data_ = nullptr;
419 RunCallback(&get_bitstream_buffer_callback_, PP_OK);
422 void VideoEncoderResource::ReleaseFrames() {
423 for (VideoFrameMap::iterator it = video_frames_.begin();
424 it != video_frames_.end(); ++it) {
425 it->second->Invalidate();
426 it->second = nullptr;
428 video_frames_.clear();
431 } // namespace proxy
432 } // namespace ppapi