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

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

Powered by Google App Engine
This is Rietveld 408576698