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

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

Powered by Google App Engine
This is Rietveld 408576698