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

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 unittest on win_chromium_x64_rel_ng Created 5 years, 9 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
« no previous file with comments | « ppapi/proxy/video_encoder_resource.h ('k') | ppapi/proxy/video_encoder_resource_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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,
254 base::checked_cast<uint32_t>(profiles.size()),
255 base::checked_cast<uint32_t>(sizeof(PP_VideoProfileDescription)));
256
257 if (!ptr) {
258 RunCallback(&get_supported_profiles_callback_, PP_ERROR_FAILED);
259 return;
260 }
261
262 if (profiles.size() > 0)
263 memcpy(ptr, &profiles[0],
264 profiles.size() * sizeof(PP_VideoProfileDescription));
265 RunCallback(&get_supported_profiles_callback_, PP_OK);
266 }
267
268 void VideoEncoderResource::OnPluginMsgInitializeReply(
269 const ResourceMessageReplyParams& params,
270 uint32_t input_frame_count,
271 const PP_Size& input_coded_size) {
272 DCHECK(!initialized_);
273
274 encoder_last_error_ = params.result();
275 if (!encoder_last_error_)
276 initialized_ = true;
277
278 input_frame_count_ = input_frame_count;
279 input_coded_size_ = input_coded_size;
280
281 RunCallback(&initialize_callback_, encoder_last_error_);
282 }
283
284 void VideoEncoderResource::OnPluginMsgGetVideoFramesReply(
285 const ResourceMessageReplyParams& params,
286 uint32_t frame_count,
287 uint32_t frame_length,
288 const PP_Size& frame_size) {
289 int32_t error = params.result();
290 if (error) {
291 NotifyError(error);
292 return;
293 }
294
295 base::SharedMemoryHandle buffer_handle;
296 params.TakeSharedMemoryHandleAtIndex(0, &buffer_handle);
297
298 if (!buffer_manager_.SetBuffers(
299 frame_count, frame_length,
300 make_scoped_ptr(new base::SharedMemory(buffer_handle, false)),
301 true)) {
302 NotifyError(PP_ERROR_FAILED);
303 return;
304 }
305
306 if (TrackedCallback::IsPending(get_video_frame_callback_))
307 TryWriteVideoFrame();
308 }
309
310 void VideoEncoderResource::OnPluginMsgEncodeReply(
311 PP_Resource video_frame,
312 const ResourceMessageReplyParams& params,
313 uint32_t frame_id) {
314 DCHECK_NE(encode_callbacks_.size(), 0U);
315 encoder_last_error_ = params.result();
316
317 EncodeMap::iterator it = encode_callbacks_.find(video_frame);
318 DCHECK(encode_callbacks_.end() != it);
319
320 scoped_refptr<TrackedCallback> callback = it->second;
321 encode_callbacks_.erase(it);
322 RunCallback(&callback, encoder_last_error_);
323
324 buffer_manager_.EnqueueBuffer(frame_id);
325 // If the plugin is waiting for a video frame, we can give the one
326 // that just became available again.
327 if (TrackedCallback::IsPending(get_video_frame_callback_))
328 TryWriteVideoFrame();
329 }
330
331 void VideoEncoderResource::OnPluginMsgBitstreamBuffers(
332 const ResourceMessageReplyParams& params,
333 uint32_t buffer_length) {
334 std::vector<base::SharedMemoryHandle> shm_handles;
335 params.TakeAllSharedMemoryHandles(&shm_handles);
336 if (shm_handles.size() == 0) {
337 NotifyError(PP_ERROR_FAILED);
338 return;
339 }
340
341 for (uint32_t i = 0; i < shm_handles.size(); ++i) {
342 scoped_ptr<base::SharedMemory> shm(
343 new base::SharedMemory(shm_handles[i], true));
344 CHECK(shm->Map(buffer_length));
345
346 ShmBuffer* buffer = new ShmBuffer(i, shm.Pass());
347 shm_buffers_.push_back(buffer);
348 bitstream_buffer_map_.insert(
349 std::make_pair(buffer->shm->memory(), buffer->id));
350 }
351 }
352
353 void VideoEncoderResource::OnPluginMsgBitstreamBufferReady(
354 const ResourceMessageReplyParams& params,
355 uint32_t buffer_id,
356 uint32_t buffer_size,
357 bool key_frame) {
358 available_bitstream_buffers_.push_back(
359 BitstreamBuffer(buffer_id, buffer_size, key_frame));
360
361 if (TrackedCallback::IsPending(get_bitstream_buffer_callback_)) {
362 BitstreamBuffer buffer(available_bitstream_buffers_.front());
363 available_bitstream_buffers_.pop_front();
364 WriteBitstreamBuffer(buffer);
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 get_video_frame_data_ = nullptr;
380 RunCallback(&get_bitstream_buffer_callback_, error);
381 get_bitstream_buffer_data_ = nullptr;
382 for (EncodeMap::iterator it = encode_callbacks_.begin();
383 it != encode_callbacks_.end(); ++it) {
384 scoped_refptr<TrackedCallback> callback = it->second;
385 RunCallback(&callback, error);
386 }
387 encode_callbacks_.clear();
388 }
389
390 void VideoEncoderResource::TryWriteVideoFrame() {
391 DCHECK(TrackedCallback::IsPending(get_video_frame_callback_));
392
393 int32_t frame_id = buffer_manager_.DequeueBuffer();
394 if (frame_id < 0)
395 return;
396
397 scoped_refptr<VideoFrameResource> resource = new VideoFrameResource(
398 pp_instance(), frame_id, buffer_manager_.GetBufferPointer(frame_id));
399 video_frames_.insert(
400 VideoFrameMap::value_type(resource->pp_resource(), resource));
401
402 *get_video_frame_data_ = resource->GetReference();
403 get_video_frame_data_ = nullptr;
404 RunCallback(&get_video_frame_callback_, PP_OK);
405 }
406
407 void VideoEncoderResource::WriteBitstreamBuffer(const BitstreamBuffer& buffer) {
408 DCHECK_LT(buffer.id, shm_buffers_.size());
409
410 get_bitstream_buffer_data_->size = buffer.size;
411 get_bitstream_buffer_data_->buffer = shm_buffers_[buffer.id]->shm->memory();
412 get_bitstream_buffer_data_->key_frame = PP_FromBool(buffer.key_frame);
413 get_bitstream_buffer_data_ = nullptr;
414 RunCallback(&get_bitstream_buffer_callback_, PP_OK);
415 }
416
417 void VideoEncoderResource::ReleaseFrames() {
418 for (VideoFrameMap::iterator it = video_frames_.begin();
419 it != video_frames_.end(); ++it) {
420 it->second->Invalidate();
421 it->second = nullptr;
422 }
423 video_frames_.clear();
76 } 424 }
77 425
78 } // namespace proxy 426 } // namespace proxy
79 } // namespace ppapi 427 } // namespace ppapi
OLDNEW
« no previous file with comments | « ppapi/proxy/video_encoder_resource.h ('k') | ppapi/proxy/video_encoder_resource_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698