Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(88)

Side by Side Diff: ppapi/proxy/video_encoder_resource.cc

Issue 905023005: Pepper: PPB_VideoEncoder implementation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Deal with Encode() callbacks in the proxy Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/memory/shared_memory.h"
6 #include "ppapi/c/pp_array_output.h"
7 #include "ppapi/proxy/ppapi_messages.h"
5 #include "ppapi/proxy/video_encoder_resource.h" 8 #include "ppapi/proxy/video_encoder_resource.h"
9 #include "ppapi/proxy/video_frame_resource.h"
10 #include "ppapi/shared_impl/media_stream_buffer.h"
11 #include "ppapi/shared_impl/media_stream_buffer_manager.h"
12 #include "ppapi/thunk/enter.h"
6 13
14 using ppapi::proxy::SerializedHandle;
15 using ppapi::thunk::EnterResourceNoLock;
7 using ppapi::thunk::PPB_VideoEncoder_API; 16 using ppapi::thunk::PPB_VideoEncoder_API;
8 17
9 namespace ppapi { 18 namespace ppapi {
10 namespace proxy { 19 namespace proxy {
11 20
21 namespace {
22
23 void RunCallback(scoped_refptr<TrackedCallback>* callback, int32_t error) {
24 if (!TrackedCallback::IsPending(*callback))
25 return;
26
27 scoped_refptr<TrackedCallback> temp;
28 callback->swap(temp);
29 temp->Run(error);
30 }
31
32 } // namespace
33
34 VideoEncoderResource::ShmBuffer::ShmBuffer(base::SharedMemoryHandle handle,
35 uint32_t id,
36 uint32_t size)
37 : shm(new base::SharedMemory(handle, true)), id(id), size(size) {
38 shm->Map(size);
39 }
40
41 VideoEncoderResource::ShmBuffer::~ShmBuffer() {
42 }
43
44 VideoEncoderResource::BitstreamBuffer::BitstreamBuffer(uint32_t id,
45 uint32_t size,
46 bool key_frame)
47 : id(id), size(size), key_frame(key_frame) {
48 }
49
50 VideoEncoderResource::BitstreamBuffer::BitstreamBuffer(
51 const BitstreamBuffer& other)
52 : id(other.id), size(other.size), key_frame(other.key_frame) {
53 }
54
55 VideoEncoderResource::BitstreamBuffer::~BitstreamBuffer() {
56 }
57
12 VideoEncoderResource::VideoEncoderResource(Connection connection, 58 VideoEncoderResource::VideoEncoderResource(Connection connection,
13 PP_Instance instance) 59 PP_Instance instance)
14 : PluginResource(connection, instance) { 60 : PluginResource(connection, instance),
61 initialized_(false),
62 closed_(false),
63 // Set |encoder_last_error_| to PP_OK after successful initialization.
64 // This makes error checking a little more concise, since we can check
65 // that the encoder has been initialized and hasn't returned an error by
66 // just testing |encoder_last_error_|.
67 encoder_last_error_(PP_ERROR_FAILED),
68 input_frame_count_(0),
69 input_coded_size_(PP_MakeSize(0, 0)),
70 buffer_manager_(this),
71 get_video_frame_data_(nullptr),
72 get_bitstream_buffer_data_(nullptr) {
73 SendCreate(RENDERER, PpapiHostMsg_VideoEncoder_Create());
15 } 74 }
16 75
17 VideoEncoderResource::~VideoEncoderResource() { 76 VideoEncoderResource::~VideoEncoderResource() {
77 Close();
18 } 78 }
19 79
20 PPB_VideoEncoder_API* VideoEncoderResource::AsPPB_VideoEncoder_API() { 80 PPB_VideoEncoder_API* VideoEncoderResource::AsPPB_VideoEncoder_API() {
21 return this; 81 return this;
22 } 82 }
23 83
24 int32_t VideoEncoderResource::GetSupportedProfiles( 84 int32_t VideoEncoderResource::GetSupportedProfiles(
25 const PP_ArrayOutput& output, 85 const PP_ArrayOutput& output,
26 const scoped_refptr<TrackedCallback>& callback) { 86 const scoped_refptr<TrackedCallback>& callback) {
27 return PP_ERROR_FAILED; 87 if (TrackedCallback::IsPending(get_supported_profiles_callback_))
88 return PP_ERROR_INPROGRESS;
89
90 get_supported_profiles_callback_ = callback;
91 Call<PpapiPluginMsg_VideoEncoder_GetSupportedProfilesReply>(
92 RENDERER, PpapiHostMsg_VideoEncoder_GetSupportedProfiles(),
93 base::Bind(&VideoEncoderResource::OnPluginMsgGetSupportedProfilesReply,
94 this, output));
95 return PP_OK_COMPLETIONPENDING;
96 }
97
98 int32_t VideoEncoderResource::GetFramesRequired() {
99 if (encoder_last_error_)
100 return encoder_last_error_;
101 return input_frame_count_;
102 }
103
104 int32_t VideoEncoderResource::GetFrameCodedSize(PP_Size* size) {
105 if (encoder_last_error_)
106 return encoder_last_error_;
107 *size = input_coded_size_;
108 return PP_OK;
28 } 109 }
29 110
30 int32_t VideoEncoderResource::Initialize( 111 int32_t VideoEncoderResource::Initialize(
31 PP_VideoFrame_Format input_format, 112 PP_VideoFrame_Format input_format,
32 const PP_Size* input_visible_size, 113 const PP_Size* input_visible_size,
33 PP_VideoProfile output_profile, 114 PP_VideoProfile output_profile,
34 uint32_t initial_bitrate, 115 uint32_t initial_bitrate,
35 PP_HardwareAcceleration acceleration, 116 PP_HardwareAcceleration acceleration,
36 const scoped_refptr<TrackedCallback>& callback) { 117 const scoped_refptr<TrackedCallback>& callback) {
37 return PP_ERROR_FAILED; 118 if (initialized_)
38 } 119 return PP_ERROR_FAILED;
39 120 if (TrackedCallback::IsPending(initialize_callback_))
40 int32_t VideoEncoderResource::GetFramesRequired() { 121 return PP_ERROR_INPROGRESS;
41 return PP_ERROR_FAILED; 122
42 } 123 initialize_callback_ = callback;
43 124 Call<PpapiPluginMsg_VideoEncoder_InitializeReply>(
44 int32_t VideoEncoderResource::GetFrameCodedSize(PP_Size* size) { 125 RENDERER, PpapiHostMsg_VideoEncoder_Initialize(
45 return PP_ERROR_FAILED; 126 input_format, *input_visible_size, output_profile,
127 initial_bitrate, acceleration),
128 base::Bind(&VideoEncoderResource::OnPluginMsgInitializeReply, this));
129 return PP_OK_COMPLETIONPENDING;
46 } 130 }
47 131
48 int32_t VideoEncoderResource::GetVideoFrame( 132 int32_t VideoEncoderResource::GetVideoFrame(
49 PP_Resource* video_frame, 133 PP_Resource* video_frame,
50 const scoped_refptr<TrackedCallback>& callback) { 134 const scoped_refptr<TrackedCallback>& callback) {
51 return PP_ERROR_FAILED; 135 if (encoder_last_error_)
136 return encoder_last_error_;
137
138 if (TrackedCallback::IsPending(get_video_frame_callback_))
139 return PP_ERROR_INPROGRESS;
140
141 // Lazily ask for a shared memory buffer in which video frames are allocated.
142 if (buffer_manager_.number_of_buffers() == 0) {
143 get_video_frame_data_ = video_frame;
144 get_video_frame_callback_ = callback;
145 Call<PpapiPluginMsg_VideoEncoder_GetVideoFramesReply>(
146 RENDERER, PpapiHostMsg_VideoEncoder_GetVideoFrames(),
147 base::Bind(&VideoEncoderResource::OnPluginMsgGetVideoFramesReply,
148 this));
149 return PP_OK_COMPLETIONPENDING;
150 }
151
152 if (!WriteVideoFrame(video_frame)) {
bbudge 2015/02/12 22:22:10 Suggestion: Move the next two statements to above
llandwerlin-old 2015/02/13 20:12:25 Done.
153 get_video_frame_data_ = video_frame;
154 get_video_frame_callback_ = callback;
155 return PP_OK_COMPLETIONPENDING;
156 }
157
158 return PP_OK;
52 } 159 }
53 160
54 int32_t VideoEncoderResource::Encode( 161 int32_t VideoEncoderResource::Encode(
55 PP_Resource video_frame, 162 PP_Resource video_frame,
56 PP_Bool force_keyframe, 163 PP_Bool force_keyframe,
57 const scoped_refptr<TrackedCallback>& callback) { 164 const scoped_refptr<TrackedCallback>& callback) {
58 return PP_ERROR_FAILED; 165 if (encoder_last_error_)
166 return encoder_last_error_;
167
168 VideoFrameMap::iterator it = video_frames_.find(video_frame);
169 if (it == video_frames_.end())
170 // TODO(llandwerlin): accept MediaStreamVideoTrack's video frames.
171 return PP_ERROR_BADRESOURCE;
172
173 scoped_refptr<VideoFrameResource> frame_resource = it->second;
174
175 encode_callbacks_.push_back(callback);
176
177 Call<PpapiPluginMsg_VideoEncoder_EncodeReply>(
178 RENDERER,
179 PpapiHostMsg_VideoEncoder_Encode(frame_resource->GetBufferIndex(),
180 PP_ToBool(force_keyframe)),
181 base::Bind(&VideoEncoderResource::OnPluginMsgEncodeReply, this));
182
183 return PP_OK_COMPLETIONPENDING;
59 } 184 }
60 185
61 int32_t VideoEncoderResource::GetBitstreamBuffer( 186 int32_t VideoEncoderResource::GetBitstreamBuffer(
62 PP_BitstreamBuffer* picture, 187 PP_BitstreamBuffer* bitstream_buffer,
63 const scoped_refptr<TrackedCallback>& callback) { 188 const scoped_refptr<TrackedCallback>& callback) {
64 return PP_ERROR_FAILED; 189 if (encoder_last_error_)
190 return encoder_last_error_;
191 if (TrackedCallback::IsPending(get_bitstream_buffer_callback_))
192 return PP_ERROR_INPROGRESS;
193
194 if (available_bitstream_buffers_.empty()) {
195 get_bitstream_buffer_callback_ = callback;
196 get_bitstream_buffer_data_ = bitstream_buffer;
197 return PP_OK_COMPLETIONPENDING;
198 }
199
200 BitstreamBuffer buffer(available_bitstream_buffers_.front());
bbudge 2015/02/12 22:22:10 Could you make this const BitstreamBuffer& instead
llandwerlin-old 2015/02/13 20:12:25 Can't actually do that, because of reentrancy. We
201 available_bitstream_buffers_.pop_front();
202 WriteBitstreamBuffer(bitstream_buffer, buffer);
203
204 return PP_OK;
65 } 205 }
bbudge 2015/02/12 22:22:10 Suggestion: similarly to GetVideoFrame, you could
llandwerlin-old 2015/02/13 20:12:25 Done. Didn't rename WriteBitstreamBuffer as we're
66 206
67 void VideoEncoderResource::RecycleBitstreamBuffer( 207 void VideoEncoderResource::RecycleBitstreamBuffer(
68 const PP_BitstreamBuffer* picture) { 208 const PP_BitstreamBuffer* bitstream_buffer) {
209 if (encoder_last_error_)
210 return;
211 BitstreamBufferMap::const_iterator iter =
212 bitstream_buffer_map_.find(bitstream_buffer->buffer);
213 if (iter != bitstream_buffer_map_.end()) {
214 Post(RENDERER,
215 PpapiHostMsg_VideoEncoder_RecycleBitstreamBuffer(iter->second));
216 }
69 } 217 }
70 218
71 void VideoEncoderResource::RequestEncodingParametersChange(uint32_t bitrate, 219 void VideoEncoderResource::RequestEncodingParametersChange(uint32_t bitrate,
72 uint32_t framerate) { 220 uint32_t framerate) {
221 if (encoder_last_error_)
222 return;
223 Post(RENDERER, PpapiHostMsg_VideoEncoder_RequestEncodingParametersChange(
224 bitrate, framerate));
73 } 225 }
74 226
75 void VideoEncoderResource::Close() { 227 void VideoEncoderResource::Close() {
228 if (closed_)
229 return;
230 Post(RENDERER, PpapiHostMsg_VideoEncoder_Close());
231 closed_ = true;
232 if (!encoder_last_error_ || !initialized_)
233 NotifyError(PP_ERROR_ABORTED);
234 ReleaseFrames();
235 }
236
237 void VideoEncoderResource::OnReplyReceived(
238 const ResourceMessageReplyParams& params,
239 const IPC::Message& msg) {
240 PPAPI_BEGIN_MESSAGE_MAP(VideoEncoderResource, msg)
241 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
242 PpapiPluginMsg_VideoEncoder_BitstreamBuffers,
243 OnPluginMsgBitstreamBuffers)
244 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
245 PpapiPluginMsg_VideoEncoder_BitstreamBufferReady,
246 OnPluginMsgBitstreamBufferReady)
247 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(PpapiPluginMsg_VideoEncoder_NotifyError,
248 OnPluginMsgNotifyError)
249 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(
250 PluginResource::OnReplyReceived(params, msg))
251 PPAPI_END_MESSAGE_MAP()
252 }
253
254 void VideoEncoderResource::OnPluginMsgGetSupportedProfilesReply(
255 const PP_ArrayOutput& output,
256 const ResourceMessageReplyParams& params,
257 const std::vector<PP_VideoProfileDescription>& profiles) {
258 void* ptr = output.GetDataBuffer(output.user_data, profiles.size(),
259 sizeof(PP_VideoProfileDescription));
260
261 if (!ptr) {
262 RunCallback(&get_supported_profiles_callback_, PP_ERROR_FAILED);
263 return;
264 }
265
266 if (profiles.size() > 0)
267 memcpy(ptr, &profiles[0],
268 profiles.size() * sizeof(PP_VideoProfileDescription));
269 RunCallback(&get_supported_profiles_callback_, PP_OK);
270 }
271
272 void VideoEncoderResource::OnPluginMsgInitializeReply(
273 const ResourceMessageReplyParams& params) {
274 DCHECK(!initialized_);
275
bbudge 2015/02/12 22:22:10 initialized_ = true; Here, not below.
llandwerlin-old 2015/02/13 20:12:25 Done.
276 int32_t error = params.result();
277 if (error)
bbudge 2015/02/12 22:22:10 We should always run the callback here, not below.
llandwerlin-old 2015/02/13 20:12:26 Done.
278 RunCallback(&initialize_callback_, error);
279 }
280
281 void VideoEncoderResource::OnPluginMsgGetVideoFramesReply(
282 const ResourceMessageReplyParams& params,
283 uint32_t frame_count,
284 uint32_t frame_length,
285 const PP_Size& frame_size) {
286 int32_t error = params.result();
287 if (error) {
288 NotifyError(error);
289 return;
290 }
291
292 base::SharedMemoryHandle buffer_handle;
293 params.TakeSharedMemoryHandleAtIndex(0, &buffer_handle);
294
295 if (!buffer_manager_.SetBuffers(
296 frame_count, frame_length,
297 make_scoped_ptr(new base::SharedMemory(buffer_handle, false)),
298 true)) {
299 NotifyError(PP_ERROR_FAILED);
300 return;
301 }
302
303 WriteVideoFrame(get_video_frame_data_);
304 get_video_frame_data_ = nullptr;
305 RunCallback(&get_video_frame_callback_, PP_OK);
306 }
307
308 void VideoEncoderResource::OnPluginMsgEncodeReply(
309 const ResourceMessageReplyParams& params,
310 uint32_t frame_id) {
311 DCHECK_NE(encode_callbacks_.size(), 0U);
312 encoder_last_error_ = params.result();
313
314 scoped_refptr<TrackedCallback> callback = encode_callbacks_.front();
315 encode_callbacks_.pop_front();
316 RunCallback(&callback, encoder_last_error_);
317
318 buffer_manager_.EnqueueBuffer(frame_id);
319 // If the plugin is waiting for a video frame, we can give the one
320 // that just became available again.
321 if (TrackedCallback::IsPending(get_video_frame_callback_)) {
322 WriteVideoFrame(get_video_frame_data_);
323 RunCallback(&get_video_frame_callback_, PP_OK);
324 }
325 }
326
327 void VideoEncoderResource::OnPluginMsgBitstreamBuffers(
328 const ResourceMessageReplyParams& params,
329 uint32_t buffer_length,
330 uint32_t input_frame_count,
331 const PP_Size& input_coded_size) {
332 DCHECK(!initialized_);
333
334 std::vector<base::SharedMemoryHandle> shm_handles;
335 params.TakeAllSharedMemoryHandles(&shm_handles);
336
337 for (uint32_t i = 0; i < shm_handles.size(); ++i) {
338 ShmBuffer* buffer = new ShmBuffer(shm_handles[i], i, buffer_length);
339 shm_buffers_.push_back(buffer);
340 bitstream_buffer_map_.insert(
341 std::make_pair(buffer->shm->memory(), buffer->id));
342 }
343
344 input_frame_count_ = input_frame_count;
345 input_coded_size_ = input_coded_size;
346 initialized_ = true;
347 encoder_last_error_ = params.result();
348 RunCallback(&initialize_callback_, encoder_last_error_);
349 }
350
351 void VideoEncoderResource::OnPluginMsgBitstreamBufferReady(
352 const ResourceMessageReplyParams& params,
353 uint32_t buffer_id,
354 uint32_t buffer_size,
355 bool key_frame) {
356 available_bitstream_buffers_.push_back(
357 BitstreamBuffer(buffer_id, buffer_size, PP_FromBool(key_frame)));
358
359 if (TrackedCallback::IsPending(get_bitstream_buffer_callback_)) {
360 BitstreamBuffer buffer(available_bitstream_buffers_.front());
361 available_bitstream_buffers_.pop_front();
362 WriteBitstreamBuffer(get_bitstream_buffer_data_, buffer);
363 get_bitstream_buffer_data_ = nullptr;
364 RunCallback(&get_bitstream_buffer_callback_, PP_OK);
365 }
366 }
367
368 void VideoEncoderResource::OnPluginMsgNotifyError(
369 const ResourceMessageReplyParams& params,
370 int32_t error) {
371 NotifyError(error);
372 }
373
374 void VideoEncoderResource::NotifyError(int32_t error) {
375 encoder_last_error_ = error;
376 RunCallback(&get_supported_profiles_callback_, error);
377 RunCallback(&initialize_callback_, error);
378 RunCallback(&get_video_frame_callback_, error);
379 RunCallback(&get_bitstream_buffer_callback_, error);
380 while (!encode_callbacks_.empty()) {
381 scoped_refptr<TrackedCallback> callback = encode_callbacks_.front();
382 encode_callbacks_.pop_front();
383 RunCallback(&callback, error);
384 }
385 }
386
387 bool VideoEncoderResource::WriteVideoFrame(PP_Resource* output) {
388 int32_t frame_id = buffer_manager_.DequeueBuffer();
389 if (frame_id < 0)
390 return false;
391
392 scoped_refptr<VideoFrameResource> resource = new VideoFrameResource(
393 pp_instance(), frame_id, buffer_manager_.GetBufferPointer(frame_id));
394 video_frames_.insert(
395 VideoFrameMap::value_type(resource->pp_resource(), resource));
396
397 *output = resource->GetReference();
398
399 return true;
400 }
401
402 void VideoEncoderResource::WriteBitstreamBuffer(
403 PP_BitstreamBuffer* bitstream_buffer,
404 const BitstreamBuffer& buffer) {
405 bitstream_buffer->size = buffer.size;
406 bitstream_buffer->buffer = shm_buffers_[buffer.id]->shm->memory();
407 bitstream_buffer->key_frame = PP_FromBool(buffer.key_frame);
408 }
409
410 void VideoEncoderResource::ReleaseFrames() {
411 for (VideoFrameMap::iterator it = video_frames_.begin();
412 it != video_frames_.end(); ++it) {
413 it->second->Invalidate();
414 it->second = nullptr;
415 }
bbudge 2015/02/12 22:22:10 Maybe clear video_frames_ for hygiene?
llandwerlin-old 2015/02/13 20:12:25 Done.
76 } 416 }
77 417
78 } // namespace proxy 418 } // namespace proxy
79 } // namespace ppapi 419 } // namespace ppapi
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698