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

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(uint32_t id,
35 scoped_ptr<base::SharedMemory> shm)
36 : id(id), shm(shm.Pass()) {
37 }
38
39 VideoEncoderResource::ShmBuffer::~ShmBuffer() {
40 }
41
42 VideoEncoderResource::BitstreamBuffer::BitstreamBuffer(uint32_t id,
43 uint32_t size,
44 bool key_frame)
45 : id(id), size(size), key_frame(key_frame) {
46 }
47
48 VideoEncoderResource::BitstreamBuffer::~BitstreamBuffer() {
49 }
50
12 VideoEncoderResource::VideoEncoderResource(Connection connection, 51 VideoEncoderResource::VideoEncoderResource(Connection connection,
13 PP_Instance instance) 52 PP_Instance instance)
14 : PluginResource(connection, instance) { 53 : PluginResource(connection, instance),
54 initialized_(false),
55 closed_(false),
56 // Set |encoder_last_error_| to PP_OK after successful initialization.
57 // This makes error checking a little more concise, since we can check
58 // that the encoder has been initialized and hasn't returned an error by
59 // just testing |encoder_last_error_|.
60 encoder_last_error_(PP_ERROR_FAILED),
61 input_frame_count_(0),
62 input_coded_size_(PP_MakeSize(0, 0)),
63 buffer_manager_(this),
64 get_video_frame_data_(nullptr),
65 get_bitstream_buffer_data_(nullptr) {
66 SendCreate(RENDERER, PpapiHostMsg_VideoEncoder_Create());
15 } 67 }
16 68
17 VideoEncoderResource::~VideoEncoderResource() { 69 VideoEncoderResource::~VideoEncoderResource() {
70 Close();
18 } 71 }
19 72
20 PPB_VideoEncoder_API* VideoEncoderResource::AsPPB_VideoEncoder_API() { 73 PPB_VideoEncoder_API* VideoEncoderResource::AsPPB_VideoEncoder_API() {
21 return this; 74 return this;
22 } 75 }
23 76
24 int32_t VideoEncoderResource::GetSupportedProfiles( 77 int32_t VideoEncoderResource::GetSupportedProfiles(
25 const PP_ArrayOutput& output, 78 const PP_ArrayOutput& output,
26 const scoped_refptr<TrackedCallback>& callback) { 79 const scoped_refptr<TrackedCallback>& callback) {
27 return PP_ERROR_FAILED; 80 if (TrackedCallback::IsPending(get_supported_profiles_callback_))
81 return PP_ERROR_INPROGRESS;
82
83 get_supported_profiles_callback_ = callback;
84 Call<PpapiPluginMsg_VideoEncoder_GetSupportedProfilesReply>(
85 RENDERER, PpapiHostMsg_VideoEncoder_GetSupportedProfiles(),
86 base::Bind(&VideoEncoderResource::OnPluginMsgGetSupportedProfilesReply,
87 this, output));
88 return PP_OK_COMPLETIONPENDING;
89 }
90
91 int32_t VideoEncoderResource::GetFramesRequired() {
92 if (encoder_last_error_)
93 return encoder_last_error_;
94 return input_frame_count_;
95 }
96
97 int32_t VideoEncoderResource::GetFrameCodedSize(PP_Size* size) {
98 if (encoder_last_error_)
99 return encoder_last_error_;
100 *size = input_coded_size_;
101 return PP_OK;
28 } 102 }
29 103
30 int32_t VideoEncoderResource::Initialize( 104 int32_t VideoEncoderResource::Initialize(
31 PP_VideoFrame_Format input_format, 105 PP_VideoFrame_Format input_format,
32 const PP_Size* input_visible_size, 106 const PP_Size* input_visible_size,
33 PP_VideoProfile output_profile, 107 PP_VideoProfile output_profile,
34 uint32_t initial_bitrate, 108 uint32_t initial_bitrate,
35 PP_HardwareAcceleration acceleration, 109 PP_HardwareAcceleration acceleration,
36 const scoped_refptr<TrackedCallback>& callback) { 110 const scoped_refptr<TrackedCallback>& callback) {
37 return PP_ERROR_FAILED; 111 if (initialized_)
38 } 112 return PP_ERROR_FAILED;
39 113 if (TrackedCallback::IsPending(initialize_callback_))
40 int32_t VideoEncoderResource::GetFramesRequired() { 114 return PP_ERROR_INPROGRESS;
41 return PP_ERROR_FAILED; 115
42 } 116 initialize_callback_ = callback;
43 117 Call<PpapiPluginMsg_VideoEncoder_InitializeReply>(
44 int32_t VideoEncoderResource::GetFrameCodedSize(PP_Size* size) { 118 RENDERER, PpapiHostMsg_VideoEncoder_Initialize(
45 return PP_ERROR_FAILED; 119 input_format, *input_visible_size, output_profile,
120 initial_bitrate, acceleration),
121 base::Bind(&VideoEncoderResource::OnPluginMsgInitializeReply, this));
122 return PP_OK_COMPLETIONPENDING;
46 } 123 }
47 124
48 int32_t VideoEncoderResource::GetVideoFrame( 125 int32_t VideoEncoderResource::GetVideoFrame(
49 PP_Resource* video_frame, 126 PP_Resource* video_frame,
50 const scoped_refptr<TrackedCallback>& callback) { 127 const scoped_refptr<TrackedCallback>& callback) {
51 return PP_ERROR_FAILED; 128 if (encoder_last_error_)
129 return encoder_last_error_;
130
131 if (TrackedCallback::IsPending(get_video_frame_callback_))
132 return PP_ERROR_INPROGRESS;
133
134 get_video_frame_data_ = video_frame;
135 get_video_frame_callback_ = callback;
136
137 // Lazily ask for a shared memory buffer in which video frames are allocated.
138 if (buffer_manager_.number_of_buffers() == 0) {
139 Call<PpapiPluginMsg_VideoEncoder_GetVideoFramesReply>(
140 RENDERER, PpapiHostMsg_VideoEncoder_GetVideoFrames(),
141 base::Bind(&VideoEncoderResource::OnPluginMsgGetVideoFramesReply,
142 this));
143 } else {
144 TryWriteVideoFrame();
145 }
146
147 return PP_OK_COMPLETIONPENDING;
52 } 148 }
53 149
54 int32_t VideoEncoderResource::Encode( 150 int32_t VideoEncoderResource::Encode(
55 PP_Resource video_frame, 151 PP_Resource video_frame,
56 PP_Bool force_keyframe, 152 PP_Bool force_keyframe,
57 const scoped_refptr<TrackedCallback>& callback) { 153 const scoped_refptr<TrackedCallback>& callback) {
58 return PP_ERROR_FAILED; 154 if (encoder_last_error_)
155 return encoder_last_error_;
156
157 VideoFrameMap::iterator it = video_frames_.find(video_frame);
158 if (it == video_frames_.end())
159 // TODO(llandwerlin): accept MediaStreamVideoTrack's video frames.
160 return PP_ERROR_BADRESOURCE;
161
162 scoped_refptr<VideoFrameResource> frame_resource = it->second;
163
164 encode_callbacks_.insert(std::make_pair(video_frame, callback));
165
166 Call<PpapiPluginMsg_VideoEncoder_EncodeReply>(
167 RENDERER,
168 PpapiHostMsg_VideoEncoder_Encode(frame_resource->GetBufferIndex(),
169 PP_ToBool(force_keyframe)),
170 base::Bind(&VideoEncoderResource::OnPluginMsgEncodeReply, this,
171 video_frame));
172
173 // Invalidate the frame to prevent the plugin from modifying it.
174 it->second->Invalidate();
175 video_frames_.erase(it);
176
177 return PP_OK_COMPLETIONPENDING;
59 } 178 }
60 179
61 int32_t VideoEncoderResource::GetBitstreamBuffer( 180 int32_t VideoEncoderResource::GetBitstreamBuffer(
62 PP_BitstreamBuffer* picture, 181 PP_BitstreamBuffer* bitstream_buffer,
63 const scoped_refptr<TrackedCallback>& callback) { 182 const scoped_refptr<TrackedCallback>& callback) {
64 return PP_ERROR_FAILED; 183 if (encoder_last_error_)
184 return encoder_last_error_;
185 if (TrackedCallback::IsPending(get_bitstream_buffer_callback_))
186 return PP_ERROR_INPROGRESS;
187
188 get_bitstream_buffer_callback_ = callback;
189 get_bitstream_buffer_data_ = bitstream_buffer;
190
191 if (!available_bitstream_buffers_.empty()) {
192 BitstreamBuffer buffer(available_bitstream_buffers_.front());
193 available_bitstream_buffers_.pop_front();
194 WriteBitstreamBuffer(buffer);
195 }
196
197 return PP_OK_COMPLETIONPENDING;
65 } 198 }
66 199
67 void VideoEncoderResource::RecycleBitstreamBuffer( 200 void VideoEncoderResource::RecycleBitstreamBuffer(
68 const PP_BitstreamBuffer* picture) { 201 const PP_BitstreamBuffer* bitstream_buffer) {
202 if (encoder_last_error_)
203 return;
204 BitstreamBufferMap::const_iterator iter =
205 bitstream_buffer_map_.find(bitstream_buffer->buffer);
206 if (iter != bitstream_buffer_map_.end()) {
207 Post(RENDERER,
208 PpapiHostMsg_VideoEncoder_RecycleBitstreamBuffer(iter->second));
209 }
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));
73 } 218 }
74 219
75 void VideoEncoderResource::Close() { 220 void VideoEncoderResource::Close() {
221 if (closed_)
222 return;
223 Post(RENDERER, PpapiHostMsg_VideoEncoder_Close());
224 closed_ = true;
225 if (!encoder_last_error_ || !initialized_)
226 NotifyError(PP_ERROR_ABORTED);
227 ReleaseFrames();
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_BitstreamBuffers,
236 OnPluginMsgBitstreamBuffers)
237 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
238 PpapiPluginMsg_VideoEncoder_BitstreamBufferReady,
239 OnPluginMsgBitstreamBufferReady)
240 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(PpapiPluginMsg_VideoEncoder_NotifyError,
241 OnPluginMsgNotifyError)
242 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(
243 PluginResource::OnReplyReceived(params, msg))
244 PPAPI_END_MESSAGE_MAP()
245 }
246
247 void VideoEncoderResource::OnPluginMsgGetSupportedProfilesReply(
248 const PP_ArrayOutput& output,
249 const ResourceMessageReplyParams& params,
250 const std::vector<PP_VideoProfileDescription>& profiles) {
251 void* ptr = output.GetDataBuffer(output.user_data, profiles.size(),
252 sizeof(PP_VideoProfileDescription));
253
254 if (!ptr) {
255 RunCallback(&get_supported_profiles_callback_, PP_ERROR_FAILED);
256 return;
257 }
258
259 if (profiles.size() > 0)
260 memcpy(ptr, &profiles[0],
261 profiles.size() * sizeof(PP_VideoProfileDescription));
262 RunCallback(&get_supported_profiles_callback_, PP_OK);
263 }
264
265 void VideoEncoderResource::OnPluginMsgInitializeReply(
266 const ResourceMessageReplyParams& params,
267 uint32_t input_frame_count,
268 const PP_Size& input_coded_size) {
269 DCHECK(!initialized_);
270
271 encoder_last_error_ = params.result();
272 if (!encoder_last_error_)
273 initialized_ = true;
274
275 input_frame_count_ = input_frame_count;
276 input_coded_size_ = input_coded_size;
277
278 RunCallback(&initialize_callback_, encoder_last_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 DCHECK(TrackedCallback::IsPending(get_video_frame_callback_));
bbudge 2015/02/19 20:30:55 I think this needs to be 'if' DCHECK in TryWriteVi
llandwerlin-old 2015/02/20 12:19:17 Done.
304 TryWriteVideoFrame();
305 }
306
307 void VideoEncoderResource::OnPluginMsgEncodeReply(
308 PP_Resource video_frame,
309 const ResourceMessageReplyParams& params,
310 uint32_t frame_id) {
311 DCHECK_NE(encode_callbacks_.size(), 0U);
312 encoder_last_error_ = params.result();
313
314 EncodeMap::iterator it = encode_callbacks_.find(video_frame);
315 DCHECK(encode_callbacks_.end() != it);
316
317 scoped_refptr<TrackedCallback> callback = it->second;
318 encode_callbacks_.erase(it);
319 RunCallback(&callback, encoder_last_error_);
320
321 buffer_manager_.EnqueueBuffer(frame_id);
322 // If the plugin is waiting for a video frame, we can give the one
323 // that just became available again.
324 if (TrackedCallback::IsPending(get_video_frame_callback_))
325 TryWriteVideoFrame();
326 }
327
328 void VideoEncoderResource::OnPluginMsgBitstreamBuffers(
329 const ResourceMessageReplyParams& params,
330 uint32_t buffer_length) {
331 std::vector<base::SharedMemoryHandle> shm_handles;
332 params.TakeAllSharedMemoryHandles(&shm_handles);
bbudge 2015/02/19 20:30:55 You might consider testing for 0 and considering t
llandwerlin-old 2015/02/20 12:19:17 Done.
333
334 for (uint32_t i = 0; i < shm_handles.size(); ++i) {
335 scoped_ptr<base::SharedMemory> shm(
336 new base::SharedMemory(shm_handles[i], true));
337 CHECK(shm->Map(buffer_length));
338
339 ShmBuffer* buffer = new ShmBuffer(i, shm.Pass());
340 shm_buffers_.push_back(buffer);
341 bitstream_buffer_map_.insert(
342 std::make_pair(buffer->shm->memory(), buffer->id));
343 }
344 }
345
346 void VideoEncoderResource::OnPluginMsgBitstreamBufferReady(
347 const ResourceMessageReplyParams& params,
348 uint32_t buffer_id,
349 uint32_t buffer_size,
350 bool key_frame) {
351 available_bitstream_buffers_.push_back(
352 BitstreamBuffer(buffer_id, buffer_size, PP_FromBool(key_frame)));
353
354 if (TrackedCallback::IsPending(get_bitstream_buffer_callback_)) {
355 BitstreamBuffer buffer(available_bitstream_buffers_.front());
356 available_bitstream_buffers_.pop_front();
357 WriteBitstreamBuffer(buffer);
358 }
359 }
360
361 void VideoEncoderResource::OnPluginMsgNotifyError(
362 const ResourceMessageReplyParams& params,
363 int32_t error) {
364 NotifyError(error);
365 }
366
367 void VideoEncoderResource::NotifyError(int32_t error) {
368 encoder_last_error_ = error;
369 RunCallback(&get_supported_profiles_callback_, error);
370 RunCallback(&initialize_callback_, error);
371 RunCallback(&get_video_frame_callback_, error);
372 RunCallback(&get_bitstream_buffer_callback_, error);
373 get_bitstream_buffer_data_ = nullptr;
bbudge 2015/02/19 20:30:55 get_video_frame_data_ = nullptr;
llandwerlin-old 2015/02/20 12:19:17 Thanks, done.
374 for (EncodeMap::iterator it = encode_callbacks_.begin();
375 it != encode_callbacks_.end(); ++it) {
376 scoped_refptr<TrackedCallback> callback = it->second;
377 RunCallback(&callback, error);
378 }
379 encode_callbacks_.clear();
380 }
381
382 void VideoEncoderResource::TryWriteVideoFrame() {
383 int32_t frame_id = buffer_manager_.DequeueBuffer();
384 if (frame_id < 0)
385 return;
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 *get_video_frame_data_ = resource->GetReference();
393 get_video_frame_data_ = nullptr;
394 RunCallback(&get_video_frame_callback_, PP_OK);
395 }
396
397 void VideoEncoderResource::WriteBitstreamBuffer(const BitstreamBuffer& buffer) {
398 DCHECK_LT(buffer.id, shm_buffers_.size());
399
400 get_bitstream_buffer_data_->size = buffer.size;
401 get_bitstream_buffer_data_->buffer = shm_buffers_[buffer.id]->shm->memory();
402 get_bitstream_buffer_data_->key_frame = PP_FromBool(buffer.key_frame);
403 get_bitstream_buffer_data_ = nullptr;
404 RunCallback(&get_bitstream_buffer_callback_, PP_OK);
405 }
406
407 void VideoEncoderResource::ReleaseFrames() {
408 for (VideoFrameMap::iterator it = video_frames_.begin();
409 it != video_frames_.end(); ++it) {
410 it->second->Invalidate();
411 it->second = nullptr;
412 }
413 video_frames_.clear();
76 } 414 }
77 415
78 } // namespace proxy 416 } // namespace proxy
79 } // namespace ppapi 417 } // namespace ppapi
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698