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

Side by Side Diff: ppapi/proxy/video_encoder_resource.cc

Issue 859313002: Pepper: Define PPB_VideoEncoder API + Implementation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 11 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/shared_impl/media_stream_buffer_manager.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/memory/shared_memory.h"
6 #include "ppapi/c/pp_array_output.h"
7 #include "ppapi/proxy/ppapi_messages.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"
13
14 using ppapi::proxy::SerializedHandle;
15 using ppapi::thunk::EnterResourceNoLock;
16 using ppapi::thunk::PPB_VideoEncoder_API;
17
18 namespace ppapi {
19 namespace proxy {
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 };
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)
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
68 VideoEncoderResource::VideoEncoderResource(Connection connection,
69 PP_Instance 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),
78 waiting_for_video_frames_(false),
79 buffer_manager_delegate_(new BufferManagerDelegate()),
80 media_stream_buffer_manager_(
81 new MediaStreamBufferManager(buffer_manager_delegate_.get())) {
82 SendCreate(RENDERER, PpapiHostMsg_VideoEncoder_Create());
83 }
84
85 VideoEncoderResource::~VideoEncoderResource() {
86 encoder_last_error_ = PP_ERROR_ABORTED;
87 RunCallback(&initialize_callback_, encoder_last_error_);
88 RunCallback(&get_bitstreamer_buffer_callback_, encoder_last_error_);
89 NotifyGetVideoFrameCallbacksError(encoder_last_error_);
90
91 for (VideoFrameMap::iterator it = video_frames_.begin();
92 it != video_frames_.end(); ++it) {
93 it->second->Invalidate();
94 it->second = nullptr;
95 }
96 }
97
98 PPB_VideoEncoder_API* VideoEncoderResource::AsPPB_VideoEncoder_API() {
99 return this;
100 }
101
102 int32_t VideoEncoderResource::GetSupportedProfiles(
103 const PP_ArrayOutput& output,
104 const scoped_refptr<TrackedCallback>& callback) {
105 // TODO(llandwerlin): should we prevent concurrent calls?
106 Call<PpapiPluginMsg_VideoEncoder_GetSupportedProfilesReply>(
107 RENDERER, PpapiHostMsg_VideoEncoder_GetSupportedProfiles(),
108 base::Bind(&VideoEncoderResource::OnPluginMsgGetSupportedProfilesReply,
109 this, output, callback));
110 return PP_OK_COMPLETIONPENDING;
111 }
112
113 int32_t VideoEncoderResource::GetFramesRequired() {
114 if (encoder_last_error_)
115 return encoder_last_error_;
116 return encoder_frame_count_;
117 }
118
119 int32_t VideoEncoderResource::GetFrameCodedSize(PP_Size* size) {
120 if (encoder_last_error_)
121 return encoder_last_error_;
122 *size = encoder_coded_size_;
123 return PP_OK;
124 }
125
126 int32_t VideoEncoderResource::Initialize(
127 PP_VideoFrame_Format input_format,
128 const PP_Size* input_visible_size,
129 PP_VideoProfile output_profile,
130 uint32_t initial_bitrate,
131 PP_HardwareAcceleration acceleration,
132 const scoped_refptr<TrackedCallback>& callback) {
133 if (initialized_)
134 return PP_ERROR_FAILED;
135 if (TrackedCallback::IsPending(initialize_callback_))
136 return PP_ERROR_INPROGRESS;
137
138 initialize_callback_ = callback;
139 Call<PpapiPluginMsg_VideoEncoder_InitializeReply>(
140 RENDERER, PpapiHostMsg_VideoEncoder_Initialize(
141 input_format, *input_visible_size, output_profile,
142 initial_bitrate, acceleration),
143 base::Bind(&VideoEncoderResource::OnPluginMsgInitializeReply, this));
144 return PP_OK_COMPLETIONPENDING;
145 }
146
147 int32_t VideoEncoderResource::GetVideoFrame(
148 PP_Resource* video_frame,
149 const scoped_refptr<TrackedCallback>& callback) {
150 if (encoder_last_error_)
151 return encoder_last_error_;
152
153 get_video_frame_cbs_.push_back(std::make_pair(video_frame, callback));
154
155 // Lazily ask for video frames buffers.
156 if (media_stream_buffer_manager_->number_of_buffers() < 1) {
157 // Check that we haven't ask for the buffers already.
158 if (!waiting_for_video_frames_) {
159 waiting_for_video_frames_ = true;
160 Call<PpapiPluginMsg_VideoEncoder_GetVideoFramesReply>(
161 RENDERER, PpapiHostMsg_VideoEncoder_GetVideoFrames(),
162 base::Bind(&VideoEncoderResource::OnPluginMsgGetVideoFramesReply,
163 this));
164 }
165 return PP_OK_COMPLETIONPENDING;
166 }
167
168 NotifyGetVideoFrameCallbacks();
169
170 return PP_OK_COMPLETIONPENDING;
171 }
172
173 int32_t VideoEncoderResource::Encode(
174 PP_Resource video_frame,
175 PP_Bool force_keyframe,
176 const scoped_refptr<TrackedCallback>& callback) {
177 if (encoder_last_error_)
178 return encoder_last_error_;
179
180 EnterResourceNoLock<thunk::PPB_VideoFrame_API> enter(video_frame, true);
181 if (enter.failed())
182 return PP_ERROR_BADRESOURCE;
183
184 thunk::PPB_VideoFrame_API* ppb_video_frame = enter.object();
185
186 if (media_stream_buffer_manager_->ContainsBuffer(
187 ppb_video_frame->GetBuffer())) {
188 int32_t frame_id = ppb_video_frame->GetBufferIndex();
189 Call<PpapiPluginMsg_VideoEncoder_EncodeReply>(
190 RENDERER, PpapiHostMsg_VideoEncoder_Encode(frame_id, force_keyframe),
191 base::Bind(&VideoEncoderResource::OnPluginMsgEncodeReply, this,
192 callback));
193 } else {
194 // TODO(llandwerlin): deal MediaStreamVideoTrack's video frames.
195 return PP_ERROR_BADARGUMENT;
196 }
197
198 return PP_OK_COMPLETIONPENDING;
199 }
200
201 int32_t VideoEncoderResource::GetBitstreamBuffer(
202 PP_BitstreamBuffer* bitstream_buffer,
203 const scoped_refptr<TrackedCallback>& callback) {
204 if (TrackedCallback::IsPending(get_bitstreamer_buffer_callback_))
205 return PP_ERROR_INPROGRESS;
206
207 if (available_bitstream_buffers_.empty()) {
208 get_bitstreamer_buffer_callback_ = callback;
209 get_bitstreamer_buffer_data_ = bitstream_buffer;
210 return PP_OK_COMPLETIONPENDING;
211 }
212
213 BitstreamBuffer buffer(available_bitstream_buffers_.front());
214
215 available_bitstream_buffers_.pop_front();
216 WriteBitstreamerBuffer(bitstream_buffer, buffer);
217
218 return PP_OK;
219 }
220
221 void VideoEncoderResource::RecycleBitstreamBuffer(
222 const PP_BitstreamBuffer* bitstream_buffer) {
223 BitstreamBufferMap::const_iterator iter =
224 bitstream_buffers_map_.find(bitstream_buffer->buffer);
225 if (iter != bitstream_buffers_map_.end())
226 Post(RENDERER,
227 PpapiHostMsg_VideoEncoder_RecycleBitstreamBuffer(iter->second));
228 }
229
230 void VideoEncoderResource::RequestEncodingParametersChange(uint32_t bitrate,
231 uint32_t framerate) {
232 Post(RENDERER, PpapiHostMsg_VideoEncoder_RequestEncodingParametersChange(
233 bitrate, framerate));
234 }
235
236 void VideoEncoderResource::OnReplyReceived(
237 const ResourceMessageReplyParams& params,
238 const IPC::Message& msg) {
239 PPAPI_BEGIN_MESSAGE_MAP(VideoEncoderResource, msg)
240 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
241 PpapiPluginMsg_VideoEncoder_BitstreamBufferReady,
242 OnPluginMsgBitstreamBufferReady)
243 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(PpapiPluginMsg_VideoDecoder_NotifyError,
244 OnPluginMsgNotifyError)
245 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(
246 PluginResource::OnReplyReceived(params, msg))
247 PPAPI_END_MESSAGE_MAP()
248 }
249
250 void VideoEncoderResource::OnPluginMsgGetSupportedProfilesReply(
251 const PP_ArrayOutput& output,
252 const scoped_refptr<TrackedCallback>& callback,
253 const ResourceMessageReplyParams& params,
254 const std::vector<PP_SupportedVideoProfile>& profiles) {
255 void* ptr = output.GetDataBuffer(output.user_data, profiles.size(),
256 sizeof(PP_SupportedVideoProfile));
257
258 if (!ptr) {
259 callback->Run(PP_ERROR_BADARGUMENT);
260 return;
261 }
262
263 memcpy(ptr, &profiles[0], profiles.size() * sizeof(PP_SupportedVideoProfile));
264 callback->Run(PP_OK);
265 }
266
267 void VideoEncoderResource::OnPluginMsgInitializeReply(
268 const ResourceMessageReplyParams& params,
269 uint32_t buffer_count,
270 uint32_t buffer_length,
271 uint32_t input_frame_count,
272 const PP_Size& input_coded_size) {
273 encoder_last_error_ = params.result();
274 if (encoder_last_error_) {
275 RunCallback(&initialize_callback_, encoder_last_error_);
276 return;
277 }
278
279 std::vector<base::SharedMemoryHandle> buffer_handles;
280 params.TakeAllSharedMemoryHandles(&buffer_handles);
281
282 CHECK(buffer_handles.size() >= buffer_count);
283
284 bitstream_buffers_.clear();
285 bitstream_buffers_map_.clear();
286 for (uint32_t i = 0; i < buffer_count; ++i) {
287 ShmBuffer* buffer = new ShmBuffer(buffer_handles[i], i, buffer_length);
288 bitstream_buffers_.push_back(buffer);
289 bitstream_buffers_map_.insert(
290 std::make_pair(buffer->shm->memory(), buffer->id));
291 }
292
293 encoder_frame_count_ = input_frame_count;
294 encoder_coded_size_ = input_coded_size;
295 initialized_ = true;
296 RunCallback(&initialize_callback_, encoder_last_error_);
297 }
298
299 void VideoEncoderResource::OnPluginMsgGetVideoFramesReply(
300 const ResourceMessageReplyParams& params,
301 uint32_t frame_count,
302 uint32_t frame_length,
303 const PP_Size& frame_size) {
304 encoder_last_error_ = params.result();
305 if (encoder_last_error_) {
306 OnPluginMsgNotifyError(params, encoder_last_error_);
307 return;
308 }
309
310 std::vector<base::SharedMemoryHandle> buffer_handles;
311 params.TakeAllSharedMemoryHandles(&buffer_handles);
312 CHECK(buffer_handles.size() == 1);
313
314 if (!media_stream_buffer_manager_->SetBuffers(
315 frame_count, frame_length,
316 make_scoped_ptr(new base::SharedMemory(buffer_handles[0], false)),
317 true)) {
318 OnPluginMsgNotifyError(params, PP_ERROR_FAILED);
319 return;
320 }
321
322 for (uint32_t frame_id = 0; frame_id < frame_count; frame_id++) {
323 video_frames_[frame_id] = make_scoped_refptr(new VideoFrameResource(
324 pp_instance(), frame_id,
325 media_stream_buffer_manager_->GetBufferPointer(frame_id)));
326 }
327 waiting_for_video_frames_ = false;
328
329 NotifyGetVideoFrameCallbacks();
330 }
331
332 void VideoEncoderResource::OnPluginMsgEncodeReply(
333 const scoped_refptr<TrackedCallback>& callback,
334 const ResourceMessageReplyParams& params,
335 uint32_t frame_id) {
336 callback->Run(encoder_last_error_);
337 media_stream_buffer_manager_->EnqueueBuffer(frame_id);
338 NotifyGetVideoFrameCallbacks();
339 }
340
341 void VideoEncoderResource::OnPluginMsgBitstreamBufferReady(
342 const ResourceMessageReplyParams& params,
343 uint32_t buffer_id,
344 uint32_t buffer_size,
345 bool key_frame) {
346 available_bitstream_buffers_.push_back(
347 BitstreamBuffer(buffer_id, buffer_size, key_frame));
348
349 if (TrackedCallback::IsPending(get_bitstreamer_buffer_callback_)) {
350 BitstreamBuffer buffer(available_bitstream_buffers_.front());
351 available_bitstream_buffers_.pop_front();
352 WriteBitstreamerBuffer(get_bitstreamer_buffer_data_, buffer);
353 get_bitstreamer_buffer_data_ = nullptr;
354
355 scoped_refptr<TrackedCallback> callback;
356 get_bitstreamer_buffer_callback_.swap(callback);
357 callback->Run(PP_OK);
358 }
359 }
360
361 void VideoEncoderResource::OnPluginMsgNotifyError(
362 const ResourceMessageReplyParams& params,
363 int32_t error) {
364 encoder_last_error_ = error;
365 RunCallback(&initialize_callback_, error);
366 RunCallback(&get_bitstreamer_buffer_callback_, error);
367 NotifyGetVideoFrameCallbacksError(error);
368 }
369
370 void VideoEncoderResource::NotifyGetVideoFrameCallbacks() {
371 while (!get_video_frame_cbs_.empty() &&
372 media_stream_buffer_manager_->BuffersAvailable() > 0) {
373 std::pair<PP_Resource*, scoped_refptr<TrackedCallback>> cb =
374 get_video_frame_cbs_.front();
375 get_video_frame_cbs_.pop_front();
376
377 int32_t frame_id = media_stream_buffer_manager_->DequeueBuffer();
378 *cb.first = video_frames_[frame_id]->GetReference();
379 cb.second->Run(PP_OK);
380 }
381 }
382
383 void VideoEncoderResource::NotifyGetVideoFrameCallbacksError(int32_t error) {
384 while (!get_video_frame_cbs_.empty()) {
385 std::pair<PP_Resource*, scoped_refptr<TrackedCallback>> cb =
386 get_video_frame_cbs_.front();
387 get_video_frame_cbs_.pop_front();
388 cb.second->Run(error);
389 }
390 }
391
392 void VideoEncoderResource::WriteBitstreamerBuffer(
393 PP_BitstreamBuffer* bitstream_buffer,
394 const BitstreamBuffer& buffer) {
395 bitstream_buffer->size = buffer.size;
396 bitstream_buffer->buffer = bitstream_buffers_[buffer.id]->shm->memory();
397 bitstream_buffer->key_frame = PP_FromBool(buffer.key_frame);
398 }
399
400 } // namespace proxy
401 } // namespace ppapi
OLDNEW
« no previous file with comments | « ppapi/proxy/video_encoder_resource.h ('k') | ppapi/shared_impl/media_stream_buffer_manager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698