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

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: 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 class BufferManagerDelegate : public MediaStreamBufferManager::Delegate {
24 public:
25 BufferManagerDelegate() {}
26 ~BufferManagerDelegate() override {}
27
28 private:
29 DISALLOW_COPY_AND_ASSIGN(BufferManagerDelegate);
30 };
bbudge 2015/02/10 01:31:08 Same comment as on PepperVideoEncoderHost.
llandwerlin-old 2015/02/10 14:28:13 Done.
31
32 void RunCallback(scoped_refptr<TrackedCallback>* callback, int32_t error) {
33 if (!TrackedCallback::IsPending(*callback))
34 return;
35
36 scoped_refptr<TrackedCallback> temp;
37 callback->swap(temp);
38 temp->Run(error);
39 }
40
41 } // namespace
42
43 VideoEncoderResource::ShmBuffer::ShmBuffer(base::SharedMemoryHandle handle,
44 uint32_t id,
45 uint32_t size)
46 : shm(new base::SharedMemory(handle, true)), id(id), size(size) {
47 if (shm)
bbudge 2015/02/10 01:31:08 You can assume shm is non-null here.
llandwerlin-old 2015/02/10 14:28:13 Done.
48 shm->Map(size);
49 }
50
51 VideoEncoderResource::ShmBuffer::~ShmBuffer() {
52 }
53
54 VideoEncoderResource::BitstreamBuffer::BitstreamBuffer(uint32_t id,
55 uint32_t size,
56 bool key_frame)
57 : id(id), size(size), key_frame(key_frame) {
58 }
59
60 VideoEncoderResource::BitstreamBuffer::BitstreamBuffer(
61 const BitstreamBuffer& other)
62 : id(other.id), size(other.size), key_frame(other.key_frame) {
63 }
64
65 VideoEncoderResource::BitstreamBuffer::~BitstreamBuffer() {
66 }
67
12 VideoEncoderResource::VideoEncoderResource(Connection connection, 68 VideoEncoderResource::VideoEncoderResource(Connection connection,
13 PP_Instance instance) 69 PP_Instance instance)
14 : PluginResource(connection, instance) { 70 : PluginResource(connection, instance),
71 initialized_(false),
72 // Set |encoder_last_error_| to PP_OK after successful initialization.
73 // This makes error checking a little more concise, since we can check
74 // that the encoder has been initialized and hasn't returned an error by
75 // just testing |encoder_last_error_|.
76 encoder_last_error_(PP_ERROR_FAILED),
77 encoder_frame_count_(0),
bbudge 2015/02/10 01:31:08 initialize encoder_coded_size_.
llandwerlin-old 2015/02/10 14:28:13 Done.
78 waiting_for_video_frames_(false),
79 buffer_manager_delegate_(new BufferManagerDelegate()),
80 buffer_manager_(
81 new MediaStreamBufferManager(buffer_manager_delegate_.get())) {
82 SendCreate(RENDERER, PpapiHostMsg_VideoEncoder_Create());
15 } 83 }
16 84
17 VideoEncoderResource::~VideoEncoderResource() { 85 VideoEncoderResource::~VideoEncoderResource() {
86 encoder_last_error_ = PP_ERROR_ABORTED;
bbudge 2015/02/10 01:31:08 I think it's clearer if encoder_last_error_ repres
llandwerlin-old 2015/02/10 14:28:12 Done.
87 RunCallback(&initialize_callback_, encoder_last_error_);
88 RunCallback(&get_bitstreamer_buffer_callback_, encoder_last_error_);
89 NotifyGetVideoFrameCallbacksError(encoder_last_error_);
90 ReleaseFrames();
bbudge 2015/02/10 01:31:07 I think Close() should be called somewhere in here
llandwerlin-old 2015/02/10 14:28:12 Done.
18 } 91 }
19 92
20 PPB_VideoEncoder_API* VideoEncoderResource::AsPPB_VideoEncoder_API() { 93 PPB_VideoEncoder_API* VideoEncoderResource::AsPPB_VideoEncoder_API() {
21 return this; 94 return this;
22 } 95 }
23 96
24 int32_t VideoEncoderResource::GetSupportedProfiles( 97 int32_t VideoEncoderResource::GetSupportedProfiles(
25 const PP_ArrayOutput& output, 98 const PP_ArrayOutput& output,
26 const scoped_refptr<TrackedCallback>& callback) { 99 const scoped_refptr<TrackedCallback>& callback) {
27 return PP_ERROR_FAILED; 100 // TODO(llandwerlin): should we prevent concurrent calls?
bbudge 2015/02/10 01:31:08 The IDL leaves it unspecified but I don't think co
llandwerlin-old 2015/02/10 14:28:13 Acknowledged.
101 Call<PpapiPluginMsg_VideoEncoder_GetSupportedProfilesReply>(
102 RENDERER, PpapiHostMsg_VideoEncoder_GetSupportedProfiles(),
103 base::Bind(&VideoEncoderResource::OnPluginMsgGetSupportedProfilesReply,
104 this, output, callback));
105 return PP_OK_COMPLETIONPENDING;
106 }
107
108 int32_t VideoEncoderResource::GetFramesRequired() {
109 if (encoder_last_error_)
110 return encoder_last_error_;
111 return encoder_frame_count_;
112 }
113
114 int32_t VideoEncoderResource::GetFrameCodedSize(PP_Size* size) {
115 if (encoder_last_error_)
116 return encoder_last_error_;
117 *size = encoder_coded_size_;
118 return PP_OK;
28 } 119 }
29 120
30 int32_t VideoEncoderResource::Initialize( 121 int32_t VideoEncoderResource::Initialize(
31 PP_VideoFrame_Format input_format, 122 PP_VideoFrame_Format input_format,
32 const PP_Size* input_visible_size, 123 const PP_Size* input_visible_size,
33 PP_VideoProfile output_profile, 124 PP_VideoProfile output_profile,
34 uint32_t initial_bitrate, 125 uint32_t initial_bitrate,
35 PP_HardwareAcceleration acceleration, 126 PP_HardwareAcceleration acceleration,
36 const scoped_refptr<TrackedCallback>& callback) { 127 const scoped_refptr<TrackedCallback>& callback) {
37 return PP_ERROR_FAILED; 128 if (initialized_)
38 } 129 return PP_ERROR_FAILED;
39 130 if (TrackedCallback::IsPending(initialize_callback_))
40 int32_t VideoEncoderResource::GetFramesRequired() { 131 return PP_ERROR_INPROGRESS;
41 return PP_ERROR_FAILED; 132
42 } 133 initialize_callback_ = callback;
43 134 Call<PpapiPluginMsg_VideoEncoder_InitializeReply>(
44 int32_t VideoEncoderResource::GetFrameCodedSize(PP_Size* size) { 135 RENDERER, PpapiHostMsg_VideoEncoder_Initialize(
45 return PP_ERROR_FAILED; 136 input_format, *input_visible_size, output_profile,
137 initial_bitrate, acceleration),
138 base::Bind(&VideoEncoderResource::OnPluginMsgInitializeReply, this));
139 return PP_OK_COMPLETIONPENDING;
46 } 140 }
47 141
48 int32_t VideoEncoderResource::GetVideoFrame( 142 int32_t VideoEncoderResource::GetVideoFrame(
49 PP_Resource* video_frame, 143 PP_Resource* video_frame,
50 const scoped_refptr<TrackedCallback>& callback) { 144 const scoped_refptr<TrackedCallback>& callback) {
51 return PP_ERROR_FAILED; 145 if (encoder_last_error_)
146 return encoder_last_error_;
147
148 get_video_frame_cbs_.push_back(std::make_pair(video_frame, callback));
149
150 // Lazily ask for video frames buffers.
bbudge 2015/02/10 01:31:08 The terminology here is a little confusing. You're
llandwerlin-old 2015/02/10 14:28:13 Done.
151 if (buffer_manager_->number_of_buffers() < 1) {
152 // Check that we haven't ask for the buffers already.
153 if (!waiting_for_video_frames_) {
154 waiting_for_video_frames_ = true;
155 Call<PpapiPluginMsg_VideoEncoder_GetVideoFramesReply>(
156 RENDERER, PpapiHostMsg_VideoEncoder_GetVideoFrames(),
157 base::Bind(&VideoEncoderResource::OnPluginMsgGetVideoFramesReply,
158 this));
159 }
160 return PP_OK_COMPLETIONPENDING;
161 }
162
163 NotifyGetVideoFrameCallbacks();
164
165 return PP_OK_COMPLETIONPENDING;
52 } 166 }
53 167
54 int32_t VideoEncoderResource::Encode( 168 int32_t VideoEncoderResource::Encode(
55 PP_Resource video_frame, 169 PP_Resource video_frame,
56 PP_Bool force_keyframe, 170 PP_Bool force_keyframe,
57 const scoped_refptr<TrackedCallback>& callback) { 171 const scoped_refptr<TrackedCallback>& callback) {
58 return PP_ERROR_FAILED; 172 if (encoder_last_error_)
173 return encoder_last_error_;
174
175 VideoFrameMap::iterator it = video_frames_.find(video_frame);
176 if (it == video_frames_.end())
177 // TODO(llandwerlin): deal MediaStreamVideoTrack's video frames.
178 return PP_ERROR_BADRESOURCE;
179
180 scoped_refptr<VideoFrameResource> frame_resource = it->second;
181
182 Call<PpapiPluginMsg_VideoEncoder_EncodeReply>(
183 RENDERER,
184 PpapiHostMsg_VideoEncoder_Encode(frame_resource->GetBufferIndex(),
185 PP_ToBool(force_keyframe)),
186 base::Bind(&VideoEncoderResource::OnPluginMsgEncodeReply, this,
187 callback));
188
189 return PP_OK_COMPLETIONPENDING;
59 } 190 }
60 191
61 int32_t VideoEncoderResource::GetBitstreamBuffer( 192 int32_t VideoEncoderResource::GetBitstreamBuffer(
62 PP_BitstreamBuffer* picture, 193 PP_BitstreamBuffer* bitstream_buffer,
63 const scoped_refptr<TrackedCallback>& callback) { 194 const scoped_refptr<TrackedCallback>& callback) {
64 return PP_ERROR_FAILED; 195 if (encoder_last_error_)
196 return encoder_last_error_;
197 if (TrackedCallback::IsPending(get_bitstreamer_buffer_callback_))
198 return PP_ERROR_INPROGRESS;
199
200 if (available_bitstream_buffers_.empty()) {
201 get_bitstreamer_buffer_callback_ = callback;
202 get_bitstreamer_buffer_data_ = bitstream_buffer;
203 return PP_OK_COMPLETIONPENDING;
204 }
205
206 BitstreamBuffer buffer(available_bitstream_buffers_.front());
207
208 available_bitstream_buffers_.pop_front();
209 WriteBitstreamerBuffer(bitstream_buffer, buffer);
210
211 return PP_OK;
65 } 212 }
66 213
67 void VideoEncoderResource::RecycleBitstreamBuffer( 214 void VideoEncoderResource::RecycleBitstreamBuffer(
68 const PP_BitstreamBuffer* picture) { 215 const PP_BitstreamBuffer* bitstream_buffer) {
216 if (encoder_last_error_)
217 return;
218 BitstreamBufferMap::const_iterator iter =
219 bitstream_buffers_map_.find(bitstream_buffer->buffer);
220 if (iter != bitstream_buffers_map_.end())
221 Post(RENDERER,
222 PpapiHostMsg_VideoEncoder_RecycleBitstreamBuffer(iter->second));
69 } 223 }
70 224
71 void VideoEncoderResource::RequestEncodingParametersChange(uint32_t bitrate, 225 void VideoEncoderResource::RequestEncodingParametersChange(uint32_t bitrate,
72 uint32_t framerate) { 226 uint32_t framerate) {
227 if (encoder_last_error_)
228 return;
229 Post(RENDERER, PpapiHostMsg_VideoEncoder_RequestEncodingParametersChange(
230 bitrate, framerate));
73 } 231 }
74 232
75 void VideoEncoderResource::Close() { 233 void VideoEncoderResource::Close() {
234 if (encoder_last_error_)
235 return;
236 // Synchronously call into the host to make sure all in flight
237 // Encode request are properly cancelled. This will also trigger the
238 // NotifyError callback before SyncCall() returns.
239 SyncCall<PpapiPluginMsg_VideoEncoder_CloseReply>(
240 RENDERER, PpapiHostMsg_VideoEncoder_Close());
241 }
242
243 void VideoEncoderResource::OnReplyReceived(
244 const ResourceMessageReplyParams& params,
245 const IPC::Message& msg) {
246 PPAPI_BEGIN_MESSAGE_MAP(VideoEncoderResource, msg)
247 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
248 PpapiPluginMsg_VideoEncoder_BitstreamBufferReady,
249 OnPluginMsgBitstreamBufferReady)
250 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(PpapiPluginMsg_VideoEncoder_NotifyError,
251 OnPluginMsgNotifyError)
252 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(
253 PluginResource::OnReplyReceived(params, msg))
254 PPAPI_END_MESSAGE_MAP()
255 }
256
257 void VideoEncoderResource::OnPluginMsgGetSupportedProfilesReply(
258 const PP_ArrayOutput& output,
259 const scoped_refptr<TrackedCallback>& callback,
260 const ResourceMessageReplyParams& params,
261 const std::vector<PP_VideoProfileDescription>& profiles) {
262 void* ptr = output.GetDataBuffer(output.user_data, profiles.size(),
263 sizeof(PP_VideoProfileDescription));
264
265 if (!ptr) {
266 callback->Run(PP_ERROR_BADARGUMENT);
bbudge 2015/02/10 01:31:07 The plugin is allowed to return null, so I think P
llandwerlin-old 2015/02/10 14:28:13 Done.
267 return;
268 }
269
270 memcpy(ptr, &profiles[0],
bbudge 2015/02/10 01:31:08 profiles could be empty in theory, in which case &
llandwerlin-old 2015/02/10 14:28:12 Thanks for spotting this. Done.
271 profiles.size() * sizeof(PP_VideoProfileDescription));
272 callback->Run(PP_OK);
273 }
274
275 void VideoEncoderResource::OnPluginMsgInitializeReply(
276 const ResourceMessageReplyParams& params,
277 uint32_t buffer_count,
278 uint32_t buffer_length,
279 uint32_t input_frame_count,
280 const PP_Size& input_coded_size) {
281 encoder_last_error_ = params.result();
282 if (encoder_last_error_) {
283 RunCallback(&initialize_callback_, encoder_last_error_);
284 return;
285 }
286
287 std::vector<base::SharedMemoryHandle> buffer_handles;
bbudge 2015/02/10 01:31:08 shm_handles to match shm_buffers_?
llandwerlin-old 2015/02/10 14:28:12 Done.
288 params.TakeAllSharedMemoryHandles(&buffer_handles);
289
290 CHECK(buffer_handles.size() >= buffer_count);
bbudge 2015/02/10 01:31:08 This implies that buffer_handles is the source of
llandwerlin-old 2015/02/10 14:28:12 Make sense. Done.
291
292 bitstream_buffers_.clear();
293 bitstream_buffers_map_.clear();
bbudge 2015/02/10 01:31:08 I don't see how these two collections could be non
llandwerlin-old 2015/02/10 14:28:13 I was thinking that maybe after the encoder is clo
bbudge 2015/02/10 22:47:36 In Pepper the convention is that calling Close is
294 for (uint32_t i = 0; i < buffer_count; ++i) {
295 ShmBuffer* buffer = new ShmBuffer(buffer_handles[i], i, buffer_length);
296 bitstream_buffers_.push_back(buffer);
297 bitstream_buffers_map_.insert(
298 std::make_pair(buffer->shm->memory(), buffer->id));
299 }
300
301 encoder_frame_count_ = input_frame_count;
302 encoder_coded_size_ = input_coded_size;
bbudge 2015/02/10 01:31:08 Looking at this, I think 'input_frame_count_' and
llandwerlin-old 2015/02/10 14:28:13 Done.
303 initialized_ = true;
304 RunCallback(&initialize_callback_, encoder_last_error_);
305 }
306
307 void VideoEncoderResource::OnPluginMsgGetVideoFramesReply(
308 const ResourceMessageReplyParams& params,
309 uint32_t frame_count,
310 uint32_t frame_length,
311 const PP_Size& frame_size) {
312 int32_t error = params.result();
313 if (error) {
314 NotifyError(error);
315 return;
316 }
317
318 std::vector<base::SharedMemoryHandle> buffer_handles;
319 params.TakeAllSharedMemoryHandles(&buffer_handles);
320 CHECK(buffer_handles.size() == 1);
321
322 if (!buffer_manager_->SetBuffers(
323 frame_count, frame_length,
324 make_scoped_ptr(new base::SharedMemory(buffer_handles[0], false)),
325 true)) {
326 NotifyError(PP_ERROR_FAILED);
327 return;
328 }
329
330 waiting_for_video_frames_ = false;
331
332 NotifyGetVideoFrameCallbacks();
333 }
334
335 void VideoEncoderResource::OnPluginMsgEncodeReply(
336 const scoped_refptr<TrackedCallback>& callback,
337 const ResourceMessageReplyParams& params,
338 uint32_t frame_id) {
339 encoder_last_error_ = params.result();
340 callback->Run(encoder_last_error_);
341 buffer_manager_->EnqueueBuffer(frame_id);
342 NotifyGetVideoFrameCallbacks();
343 }
344
345 void VideoEncoderResource::OnPluginMsgBitstreamBufferReady(
346 const ResourceMessageReplyParams& params,
347 uint32_t buffer_id,
348 uint32_t buffer_size,
349 bool key_frame) {
350 available_bitstream_buffers_.push_back(
351 BitstreamBuffer(buffer_id, buffer_size, PP_FromBool(key_frame)));
352
353 if (TrackedCallback::IsPending(get_bitstreamer_buffer_callback_)) {
354 BitstreamBuffer buffer(available_bitstream_buffers_.front());
355 available_bitstream_buffers_.pop_front();
356 WriteBitstreamerBuffer(get_bitstreamer_buffer_data_, buffer);
357 get_bitstreamer_buffer_data_ = nullptr;
358
359 scoped_refptr<TrackedCallback> callback;
360 get_bitstreamer_buffer_callback_.swap(callback);
361 callback->Run(PP_OK);
362 }
363 }
364
365 void VideoEncoderResource::OnPluginMsgNotifyError(
366 const ResourceMessageReplyParams& params,
367 int32_t error) {
368 NotifyError(error);
369 }
370
371 void VideoEncoderResource::NotifyError(int32_t error) {
372 encoder_last_error_ = error;
373 RunCallback(&initialize_callback_, error);
374 RunCallback(&get_bitstreamer_buffer_callback_, error);
375 NotifyGetVideoFrameCallbacksError(error);
376 }
377
378 void VideoEncoderResource::NotifyGetVideoFrameCallbacks() {
379 int32_t frame_id;
380
381 while (!get_video_frame_cbs_.empty() &&
382 (frame_id = buffer_manager_->DequeueBuffer()) >= 0) {
383 std::pair<PP_Resource*, scoped_refptr<TrackedCallback> > cb =
384 get_video_frame_cbs_.front();
385 get_video_frame_cbs_.pop_front();
386
387 scoped_refptr<VideoFrameResource> resource = new VideoFrameResource(
388 pp_instance(), frame_id, buffer_manager_->GetBufferPointer(frame_id));
389 video_frames_.insert(
390 VideoFrameMap::value_type(resource->pp_resource(), resource));
391
392 *cb.first = resource->GetReference();
393 cb.second->Run(PP_OK);
394 }
395 }
396
397 void VideoEncoderResource::NotifyGetVideoFrameCallbacksError(int32_t error) {
398 while (!get_video_frame_cbs_.empty()) {
399 std::pair<PP_Resource*, scoped_refptr<TrackedCallback> > cb =
400 get_video_frame_cbs_.front();
401 get_video_frame_cbs_.pop_front();
402 cb.second->Run(error);
403 }
404 }
405
406 void VideoEncoderResource::WriteBitstreamerBuffer(
407 PP_BitstreamBuffer* bitstream_buffer,
408 const BitstreamBuffer& buffer) {
409 bitstream_buffer->size = buffer.size;
410 bitstream_buffer->buffer = bitstream_buffers_[buffer.id]->shm->memory();
411 bitstream_buffer->key_frame = PP_FromBool(buffer.key_frame);
412 }
413
414 void VideoEncoderResource::ReleaseFrames() {
415 for (VideoFrameMap::iterator it = video_frames_.begin();
416 it != video_frames_.end(); ++it) {
417 it->second->Invalidate();
418 it->second = nullptr;
419 }
76 } 420 }
77 421
78 } // namespace proxy 422 } // namespace proxy
79 } // namespace ppapi 423 } // namespace ppapi
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698