[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 1 | // Copyright (c) 2012 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 "ppapi/proxy/video_decoder_resource.h" |
| 6 | |
dcheng | d2b9f61 | 2015-12-18 19:08:51 | [diff] [blame] | 7 | #include <utility> |
| 8 | |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 9 | #include "base/bind.h" |
| 10 | #include "gpu/command_buffer/client/gles2_cmd_helper.h" |
| 11 | #include "gpu/command_buffer/client/gles2_implementation.h" |
[email protected] | 0ff052d | 2014-06-13 15:00:14 | [diff] [blame] | 12 | #include "gpu/command_buffer/common/mailbox.h" |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 13 | #include "ipc/ipc_message.h" |
| 14 | #include "ppapi/c/pp_errors.h" |
| 15 | #include "ppapi/c/ppb_opengles2.h" |
| 16 | #include "ppapi/proxy/plugin_dispatcher.h" |
| 17 | #include "ppapi/proxy/ppapi_messages.h" |
| 18 | #include "ppapi/proxy/ppb_graphics_3d_proxy.h" |
| 19 | #include "ppapi/proxy/serialized_handle.h" |
| 20 | #include "ppapi/proxy/video_decoder_constants.h" |
| 21 | #include "ppapi/shared_impl/ppapi_globals.h" |
| 22 | #include "ppapi/shared_impl/ppb_graphics_3d_shared.h" |
| 23 | #include "ppapi/shared_impl/proxy_lock.h" |
| 24 | #include "ppapi/shared_impl/resource_tracker.h" |
| 25 | #include "ppapi/thunk/enter.h" |
| 26 | |
| 27 | using ppapi::thunk::EnterResourceNoLock; |
| 28 | using ppapi::thunk::PPB_Graphics3D_API; |
| 29 | using ppapi::thunk::PPB_VideoDecoder_API; |
| 30 | |
| 31 | namespace ppapi { |
| 32 | namespace proxy { |
| 33 | |
| 34 | VideoDecoderResource::ShmBuffer::ShmBuffer( |
Matthew Cary | 66e4f70 | 2019-06-05 08:47:52 | [diff] [blame^] | 35 | base::UnsafeSharedMemoryRegion region, |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 36 | uint32_t shm_id) |
Matthew Cary | 66e4f70 | 2019-06-05 08:47:52 | [diff] [blame^] | 37 | : region(std::move(region)), shm_id(shm_id) { |
| 38 | mapping = this->region.Map(); |
| 39 | if (mapping.IsValid()) |
| 40 | addr = mapping.memory(); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 41 | } |
| 42 | |
| 43 | VideoDecoderResource::ShmBuffer::~ShmBuffer() { |
| 44 | } |
| 45 | |
| 46 | VideoDecoderResource::Texture::Texture(uint32_t texture_target, |
| 47 | const PP_Size& size) |
| 48 | : texture_target(texture_target), size(size) { |
| 49 | } |
| 50 | |
| 51 | VideoDecoderResource::Texture::~Texture() { |
| 52 | } |
| 53 | |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 54 | VideoDecoderResource::Picture::Picture(int32_t decode_id, |
| 55 | uint32_t texture_id, |
| 56 | const PP_Rect& visible_rect) |
| 57 | : decode_id(decode_id), texture_id(texture_id), visible_rect(visible_rect) { |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 58 | } |
| 59 | |
| 60 | VideoDecoderResource::Picture::~Picture() { |
| 61 | } |
| 62 | |
| 63 | VideoDecoderResource::VideoDecoderResource(Connection connection, |
| 64 | PP_Instance instance) |
| 65 | : PluginResource(connection, instance), |
| 66 | num_decodes_(0), |
lpique | 9dd55e54 | 2015-08-20 01:06:53 | [diff] [blame] | 67 | min_picture_count_(0), |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 68 | get_picture_(NULL), |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 69 | get_picture_0_1_(NULL), |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 70 | gles2_impl_(NULL), |
| 71 | initialized_(false), |
| 72 | testing_(false), |
| 73 | // Set |decoder_last_error_| to PP_OK after successful initialization. |
| 74 | // This makes error checking a little more concise, since we can check |
| 75 | // that the decoder has been initialized and hasn't returned an error by |
| 76 | // just testing |decoder_last_error_|. |
| 77 | decoder_last_error_(PP_ERROR_FAILED) { |
| 78 | // Clear the decode_ids_ array. |
tsepez | e9faf30 | 2015-03-21 07:48:29 | [diff] [blame] | 79 | memset(decode_ids_, 0, sizeof(decode_ids_)); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 80 | SendCreate(RENDERER, PpapiHostMsg_VideoDecoder_Create()); |
| 81 | } |
| 82 | |
| 83 | VideoDecoderResource::~VideoDecoderResource() { |
| 84 | // Destroy any textures which haven't been dismissed. |
| 85 | TextureMap::iterator it = textures_.begin(); |
| 86 | for (; it != textures_.end(); ++it) |
| 87 | DeleteGLTexture(it->first); |
| 88 | } |
| 89 | |
| 90 | PPB_VideoDecoder_API* VideoDecoderResource::AsPPB_VideoDecoder_API() { |
| 91 | return this; |
| 92 | } |
| 93 | |
bbudge | 4d6acaf | 2014-08-23 22:17:45 | [diff] [blame] | 94 | int32_t VideoDecoderResource::Initialize0_1( |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 95 | PP_Resource graphics_context, |
| 96 | PP_VideoProfile profile, |
| 97 | PP_Bool allow_software_fallback, |
| 98 | scoped_refptr<TrackedCallback> callback) { |
bbudge | 4d6acaf | 2014-08-23 22:17:45 | [diff] [blame] | 99 | return Initialize(graphics_context, |
| 100 | profile, |
| 101 | allow_software_fallback |
| 102 | ? PP_HARDWAREACCELERATION_WITHFALLBACK |
| 103 | : PP_HARDWAREACCELERATION_ONLY, |
lpique | 9dd55e54 | 2015-08-20 01:06:53 | [diff] [blame] | 104 | 0, |
| 105 | callback); |
| 106 | } |
| 107 | |
| 108 | int32_t VideoDecoderResource::Initialize0_2( |
| 109 | PP_Resource graphics_context, |
| 110 | PP_VideoProfile profile, |
| 111 | PP_HardwareAcceleration acceleration, |
| 112 | scoped_refptr<TrackedCallback> callback) { |
| 113 | return Initialize(graphics_context, |
| 114 | profile, |
| 115 | acceleration, |
| 116 | 0, |
bbudge | 4d6acaf | 2014-08-23 22:17:45 | [diff] [blame] | 117 | callback); |
| 118 | } |
| 119 | |
| 120 | int32_t VideoDecoderResource::Initialize( |
| 121 | PP_Resource graphics_context, |
| 122 | PP_VideoProfile profile, |
| 123 | PP_HardwareAcceleration acceleration, |
lpique | 9dd55e54 | 2015-08-20 01:06:53 | [diff] [blame] | 124 | uint32_t min_picture_count, |
bbudge | 4d6acaf | 2014-08-23 22:17:45 | [diff] [blame] | 125 | scoped_refptr<TrackedCallback> callback) { |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 126 | if (initialized_) |
| 127 | return PP_ERROR_FAILED; |
| 128 | if (profile < 0 || profile > PP_VIDEOPROFILE_MAX) |
| 129 | return PP_ERROR_BADARGUMENT; |
lpique | 9dd55e54 | 2015-08-20 01:06:53 | [diff] [blame] | 130 | if (min_picture_count > kMaximumPictureCount) |
| 131 | return PP_ERROR_BADARGUMENT; |
Daniel Cheng | 6d3ae97 | 2014-08-26 00:27:38 | [diff] [blame] | 132 | if (initialize_callback_.get()) |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 133 | return PP_ERROR_INPROGRESS; |
| 134 | if (!graphics_context) |
| 135 | return PP_ERROR_BADRESOURCE; |
| 136 | |
lpique | 9dd55e54 | 2015-08-20 01:06:53 | [diff] [blame] | 137 | min_picture_count_ = min_picture_count; |
| 138 | |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 139 | HostResource host_resource; |
| 140 | if (!testing_) { |
| 141 | // Create a new Graphics3D resource that can create texture resources to |
| 142 | // share with the plugin. We can't use the plugin's Graphics3D, since we |
| 143 | // create textures on a proxy thread, and would interfere with the plugin. |
| 144 | thunk::EnterResourceCreationNoLock enter_create(pp_instance()); |
| 145 | if (enter_create.failed()) |
| 146 | return PP_ERROR_FAILED; |
| 147 | int32_t attrib_list[] = {PP_GRAPHICS3DATTRIB_NONE}; |
| 148 | graphics3d_ = |
| 149 | ScopedPPResource(ScopedPPResource::PassRef(), |
| 150 | enter_create.functions()->CreateGraphics3D( |
| 151 | pp_instance(), graphics_context, attrib_list)); |
| 152 | EnterResourceNoLock<PPB_Graphics3D_API> enter_graphics(graphics3d_.get(), |
[email protected] | 0ff052d | 2014-06-13 15:00:14 | [diff] [blame] | 153 | false); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 154 | if (enter_graphics.failed()) |
| 155 | return PP_ERROR_BADRESOURCE; |
| 156 | |
| 157 | PPB_Graphics3D_Shared* ppb_graphics3d_shared = |
| 158 | static_cast<PPB_Graphics3D_Shared*>(enter_graphics.object()); |
| 159 | gles2_impl_ = ppb_graphics3d_shared->gles2_impl(); |
| 160 | host_resource = ppb_graphics3d_shared->host_resource(); |
| 161 | } |
| 162 | |
| 163 | initialize_callback_ = callback; |
| 164 | |
| 165 | Call<PpapiPluginMsg_VideoDecoder_InitializeReply>( |
| 166 | RENDERER, |
| 167 | PpapiHostMsg_VideoDecoder_Initialize( |
lpique | 9dd55e54 | 2015-08-20 01:06:53 | [diff] [blame] | 168 | host_resource, profile, acceleration, min_picture_count), |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 169 | base::Bind(&VideoDecoderResource::OnPluginMsgInitializeComplete, this)); |
| 170 | |
| 171 | return PP_OK_COMPLETIONPENDING; |
| 172 | } |
| 173 | |
| 174 | int32_t VideoDecoderResource::Decode(uint32_t decode_id, |
| 175 | uint32_t size, |
| 176 | const void* buffer, |
| 177 | scoped_refptr<TrackedCallback> callback) { |
| 178 | if (decoder_last_error_) |
| 179 | return decoder_last_error_; |
Daniel Cheng | 6d3ae97 | 2014-08-26 00:27:38 | [diff] [blame] | 180 | if (flush_callback_.get() || reset_callback_.get()) |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 181 | return PP_ERROR_FAILED; |
Daniel Cheng | 6d3ae97 | 2014-08-26 00:27:38 | [diff] [blame] | 182 | if (decode_callback_.get()) |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 183 | return PP_ERROR_INPROGRESS; |
| 184 | if (size > kMaximumBitstreamBufferSize) |
| 185 | return PP_ERROR_NOMEMORY; |
| 186 | |
| 187 | // If we allow the plugin to call Decode again, we must have somewhere to |
| 188 | // copy their buffer. |
| 189 | DCHECK(!available_shm_buffers_.empty() || |
| 190 | shm_buffers_.size() < kMaximumPendingDecodes); |
| 191 | |
| 192 | // Count up, wrapping back to 0 before overflowing. |
| 193 | int32_t uid = ++num_decodes_; |
| 194 | if (uid == std::numeric_limits<int32_t>::max()) |
| 195 | num_decodes_ = 0; |
| 196 | |
| 197 | // Save decode_id in a ring buffer. The ring buffer is sized to store |
| 198 | // decode_id for the maximum picture delay. |
| 199 | decode_ids_[uid % kMaximumPictureDelay] = decode_id; |
| 200 | |
| 201 | if (available_shm_buffers_.empty() || |
Matthew Cary | 66e4f70 | 2019-06-05 08:47:52 | [diff] [blame^] | 202 | available_shm_buffers_.back()->mapping.size() < size) { |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 203 | uint32_t shm_id; |
| 204 | if (shm_buffers_.size() < kMaximumPendingDecodes) { |
| 205 | // Signal the host to create a new shm buffer by passing an index outside |
| 206 | // the legal range. |
| 207 | shm_id = static_cast<uint32_t>(shm_buffers_.size()); |
| 208 | } else { |
| 209 | // Signal the host to grow a buffer by passing a legal index. Choose the |
| 210 | // last available shm buffer for simplicity. |
| 211 | shm_id = available_shm_buffers_.back()->shm_id; |
| 212 | available_shm_buffers_.pop_back(); |
| 213 | } |
| 214 | |
| 215 | // Synchronously get shared memory. Use GenericSyncCall so we can get the |
| 216 | // reply params, which contain the handle. |
| 217 | uint32_t shm_size = 0; |
| 218 | IPC::Message reply; |
| 219 | ResourceMessageReplyParams reply_params; |
| 220 | int32_t result = |
| 221 | GenericSyncCall(RENDERER, |
| 222 | PpapiHostMsg_VideoDecoder_GetShm(shm_id, size), |
| 223 | &reply, |
| 224 | &reply_params); |
| 225 | if (result != PP_OK) |
| 226 | return PP_ERROR_FAILED; |
| 227 | if (!UnpackMessage<PpapiPluginMsg_VideoDecoder_GetShmReply>(reply, |
| 228 | &shm_size)) |
| 229 | return PP_ERROR_FAILED; |
Matthew Cary | 66e4f70 | 2019-06-05 08:47:52 | [diff] [blame^] | 230 | base::UnsafeSharedMemoryRegion shm_region; |
| 231 | if (!reply_params.TakeUnsafeSharedMemoryRegionAtIndex(0, &shm_region) || |
| 232 | !shm_region.IsValid() || shm_region.GetSize() != shm_size) |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 233 | return PP_ERROR_NOMEMORY; |
dcheng | ced9224 | 2016-04-07 00:00:12 | [diff] [blame] | 234 | std::unique_ptr<ShmBuffer> shm_buffer( |
Matthew Cary | 66e4f70 | 2019-06-05 08:47:52 | [diff] [blame^] | 235 | new ShmBuffer(std::move(shm_region), shm_id)); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 236 | if (!shm_buffer->addr) |
| 237 | return PP_ERROR_NOMEMORY; |
| 238 | |
| 239 | available_shm_buffers_.push_back(shm_buffer.get()); |
avi | 9bf1749 | 2017-07-10 02:19:38 | [diff] [blame] | 240 | if (shm_buffers_.size() < kMaximumPendingDecodes) |
| 241 | shm_buffers_.push_back(std::move(shm_buffer)); |
| 242 | else |
| 243 | shm_buffers_[shm_id] = std::move(shm_buffer); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 244 | } |
| 245 | |
| 246 | // At this point we should have shared memory to hold the plugin's buffer. |
| 247 | DCHECK(!available_shm_buffers_.empty() && |
Matthew Cary | 66e4f70 | 2019-06-05 08:47:52 | [diff] [blame^] | 248 | available_shm_buffers_.back()->mapping.size() >= size); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 249 | |
| 250 | ShmBuffer* shm_buffer = available_shm_buffers_.back(); |
| 251 | available_shm_buffers_.pop_back(); |
| 252 | memcpy(shm_buffer->addr, buffer, size); |
| 253 | |
| 254 | Call<PpapiPluginMsg_VideoDecoder_DecodeReply>( |
| 255 | RENDERER, |
| 256 | PpapiHostMsg_VideoDecoder_Decode(shm_buffer->shm_id, size, uid), |
| 257 | base::Bind(&VideoDecoderResource::OnPluginMsgDecodeComplete, this)); |
| 258 | |
| 259 | // If we have another free buffer, or we can still create new buffers, let |
| 260 | // the plugin call Decode again. |
| 261 | if (!available_shm_buffers_.empty() || |
| 262 | shm_buffers_.size() < kMaximumPendingDecodes) |
| 263 | return PP_OK; |
| 264 | |
| 265 | // All buffers are busy and we can't create more. Delay completion until a |
| 266 | // buffer is available. |
| 267 | decode_callback_ = callback; |
| 268 | return PP_OK_COMPLETIONPENDING; |
| 269 | } |
| 270 | |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 271 | int32_t VideoDecoderResource::GetPicture0_1( |
| 272 | PP_VideoPicture_0_1* picture, |
| 273 | scoped_refptr<TrackedCallback> callback) { |
| 274 | get_picture_0_1_ = picture; |
| 275 | return GetPicture(NULL, callback); |
| 276 | } |
| 277 | |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 278 | int32_t VideoDecoderResource::GetPicture( |
| 279 | PP_VideoPicture* picture, |
| 280 | scoped_refptr<TrackedCallback> callback) { |
| 281 | if (decoder_last_error_) |
| 282 | return decoder_last_error_; |
Daniel Cheng | 6d3ae97 | 2014-08-26 00:27:38 | [diff] [blame] | 283 | if (reset_callback_.get()) |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 284 | return PP_ERROR_FAILED; |
Daniel Cheng | 6d3ae97 | 2014-08-26 00:27:38 | [diff] [blame] | 285 | if (get_picture_callback_.get()) |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 286 | return PP_ERROR_INPROGRESS; |
| 287 | |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 288 | get_picture_ = picture; |
| 289 | |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 290 | // If the next picture is ready, return it synchronously. |
| 291 | if (!received_pictures_.empty()) { |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 292 | WriteNextPicture(); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 293 | return PP_OK; |
| 294 | } |
| 295 | |
| 296 | get_picture_callback_ = callback; |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 297 | |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 298 | return PP_OK_COMPLETIONPENDING; |
| 299 | } |
| 300 | |
| 301 | void VideoDecoderResource::RecyclePicture(const PP_VideoPicture* picture) { |
| 302 | if (decoder_last_error_) |
| 303 | return; |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 304 | |
| 305 | Post(RENDERER, PpapiHostMsg_VideoDecoder_RecyclePicture(picture->texture_id)); |
| 306 | } |
| 307 | |
| 308 | int32_t VideoDecoderResource::Flush(scoped_refptr<TrackedCallback> callback) { |
| 309 | if (decoder_last_error_) |
| 310 | return decoder_last_error_; |
Daniel Cheng | 6d3ae97 | 2014-08-26 00:27:38 | [diff] [blame] | 311 | if (reset_callback_.get()) |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 312 | return PP_ERROR_FAILED; |
Daniel Cheng | 6d3ae97 | 2014-08-26 00:27:38 | [diff] [blame] | 313 | if (flush_callback_.get()) |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 314 | return PP_ERROR_INPROGRESS; |
| 315 | flush_callback_ = callback; |
| 316 | |
| 317 | Call<PpapiPluginMsg_VideoDecoder_FlushReply>( |
| 318 | RENDERER, |
| 319 | PpapiHostMsg_VideoDecoder_Flush(), |
| 320 | base::Bind(&VideoDecoderResource::OnPluginMsgFlushComplete, this)); |
| 321 | |
| 322 | return PP_OK_COMPLETIONPENDING; |
| 323 | } |
| 324 | |
| 325 | int32_t VideoDecoderResource::Reset(scoped_refptr<TrackedCallback> callback) { |
| 326 | if (decoder_last_error_) |
| 327 | return decoder_last_error_; |
Daniel Cheng | 6d3ae97 | 2014-08-26 00:27:38 | [diff] [blame] | 328 | if (flush_callback_.get()) |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 329 | return PP_ERROR_FAILED; |
Daniel Cheng | 6d3ae97 | 2014-08-26 00:27:38 | [diff] [blame] | 330 | if (reset_callback_.get()) |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 331 | return PP_ERROR_INPROGRESS; |
| 332 | reset_callback_ = callback; |
| 333 | |
| 334 | // Cause any pending Decode or GetPicture callbacks to abort after we return, |
| 335 | // to avoid reentering the plugin. |
| 336 | if (TrackedCallback::IsPending(decode_callback_)) |
| 337 | decode_callback_->PostAbort(); |
| 338 | decode_callback_ = NULL; |
| 339 | if (TrackedCallback::IsPending(get_picture_callback_)) |
| 340 | get_picture_callback_->PostAbort(); |
| 341 | get_picture_callback_ = NULL; |
| 342 | Call<PpapiPluginMsg_VideoDecoder_ResetReply>( |
| 343 | RENDERER, |
| 344 | PpapiHostMsg_VideoDecoder_Reset(), |
| 345 | base::Bind(&VideoDecoderResource::OnPluginMsgResetComplete, this)); |
| 346 | |
| 347 | return PP_OK_COMPLETIONPENDING; |
| 348 | } |
| 349 | |
| 350 | void VideoDecoderResource::OnReplyReceived( |
| 351 | const ResourceMessageReplyParams& params, |
| 352 | const IPC::Message& msg) { |
| 353 | PPAPI_BEGIN_MESSAGE_MAP(VideoDecoderResource, msg) |
| 354 | PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( |
| 355 | PpapiPluginMsg_VideoDecoder_RequestTextures, OnPluginMsgRequestTextures) |
| 356 | PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( |
| 357 | PpapiPluginMsg_VideoDecoder_PictureReady, OnPluginMsgPictureReady) |
| 358 | PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( |
| 359 | PpapiPluginMsg_VideoDecoder_DismissPicture, OnPluginMsgDismissPicture) |
| 360 | PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( |
| 361 | PpapiPluginMsg_VideoDecoder_NotifyError, OnPluginMsgNotifyError) |
| 362 | PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED( |
| 363 | PluginResource::OnReplyReceived(params, msg)) |
| 364 | PPAPI_END_MESSAGE_MAP() |
| 365 | } |
| 366 | |
| 367 | void VideoDecoderResource::SetForTest() { |
| 368 | testing_ = true; |
| 369 | } |
| 370 | |
| 371 | void VideoDecoderResource::OnPluginMsgRequestTextures( |
| 372 | const ResourceMessageReplyParams& params, |
| 373 | uint32_t num_textures, |
| 374 | const PP_Size& size, |
Antoine Labour | 04cb3b2 | 2018-06-01 23:25:10 | [diff] [blame] | 375 | uint32_t texture_target) { |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 376 | DCHECK(num_textures); |
lpique | 9dd55e54 | 2015-08-20 01:06:53 | [diff] [blame] | 377 | DCHECK(num_textures >= min_picture_count_); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 378 | std::vector<uint32_t> texture_ids(num_textures); |
Antoine Labour | 04cb3b2 | 2018-06-01 23:25:10 | [diff] [blame] | 379 | std::vector<gpu::Mailbox> mailboxes(num_textures); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 380 | if (gles2_impl_) { |
Antoine Labour | 04cb3b2 | 2018-06-01 23:25:10 | [diff] [blame] | 381 | gles2_impl_->GenTextures(num_textures, texture_ids.data()); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 382 | for (uint32_t i = 0; i < num_textures; ++i) { |
| 383 | gles2_impl_->ActiveTexture(GL_TEXTURE0); |
| 384 | gles2_impl_->BindTexture(texture_target, texture_ids[i]); |
| 385 | gles2_impl_->TexParameteri( |
CodeByThePound | de2d8397 | 2015-04-30 20:41:47 | [diff] [blame] | 386 | texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 387 | gles2_impl_->TexParameteri( |
CodeByThePound | de2d8397 | 2015-04-30 20:41:47 | [diff] [blame] | 388 | texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 389 | gles2_impl_->TexParameterf( |
| 390 | texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| 391 | gles2_impl_->TexParameterf( |
| 392 | texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| 393 | |
| 394 | if (texture_target == GL_TEXTURE_2D) { |
| 395 | gles2_impl_->TexImage2D(texture_target, |
| 396 | 0, |
| 397 | GL_RGBA, |
| 398 | size.width, |
| 399 | size.height, |
| 400 | 0, |
| 401 | GL_RGBA, |
| 402 | GL_UNSIGNED_BYTE, |
| 403 | NULL); |
| 404 | } |
Antoine Labour | 04cb3b2 | 2018-06-01 23:25:10 | [diff] [blame] | 405 | gles2_impl_->ProduceTextureDirectCHROMIUM(texture_ids[i], |
| 406 | mailboxes[i].name); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 407 | |
| 408 | textures_.insert( |
| 409 | std::make_pair(texture_ids[i], Texture(texture_target, size))); |
| 410 | } |
| 411 | gles2_impl_->Flush(); |
| 412 | } else { |
| 413 | DCHECK(testing_); |
| 414 | // Create some fake texture ids so we can test picture handling. |
| 415 | for (uint32_t i = 0; i < num_textures; ++i) { |
| 416 | texture_ids[i] = i + 1; |
| 417 | textures_.insert( |
| 418 | std::make_pair(texture_ids[i], Texture(texture_target, size))); |
| 419 | } |
| 420 | } |
| 421 | |
Antoine Labour | 04cb3b2 | 2018-06-01 23:25:10 | [diff] [blame] | 422 | Post(RENDERER, PpapiHostMsg_VideoDecoder_AssignTextures( |
| 423 | size, std::move(texture_ids), std::move(mailboxes))); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 424 | } |
| 425 | |
| 426 | void VideoDecoderResource::OnPluginMsgPictureReady( |
| 427 | const ResourceMessageReplyParams& params, |
| 428 | int32_t decode_id, |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 429 | uint32_t texture_id, |
| 430 | const PP_Rect& visible_rect) { |
| 431 | received_pictures_.push(Picture(decode_id, texture_id, visible_rect)); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 432 | |
| 433 | if (TrackedCallback::IsPending(get_picture_callback_)) { |
| 434 | // The plugin may call GetPicture in its callback. |
| 435 | scoped_refptr<TrackedCallback> callback; |
| 436 | callback.swap(get_picture_callback_); |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 437 | WriteNextPicture(); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 438 | callback->Run(PP_OK); |
| 439 | } |
| 440 | } |
| 441 | |
| 442 | void VideoDecoderResource::OnPluginMsgDismissPicture( |
| 443 | const ResourceMessageReplyParams& params, |
| 444 | uint32_t texture_id) { |
| 445 | DeleteGLTexture(texture_id); |
| 446 | textures_.erase(texture_id); |
| 447 | } |
| 448 | |
| 449 | void VideoDecoderResource::OnPluginMsgNotifyError( |
| 450 | const ResourceMessageReplyParams& params, |
| 451 | int32_t error) { |
| 452 | decoder_last_error_ = error; |
| 453 | // Cause any pending callbacks to run immediately. Reentrancy isn't a problem, |
| 454 | // since the plugin wasn't calling us. |
| 455 | RunCallbackWithError(&initialize_callback_); |
| 456 | RunCallbackWithError(&decode_callback_); |
| 457 | RunCallbackWithError(&get_picture_callback_); |
| 458 | RunCallbackWithError(&flush_callback_); |
| 459 | RunCallbackWithError(&reset_callback_); |
| 460 | } |
| 461 | |
| 462 | void VideoDecoderResource::OnPluginMsgInitializeComplete( |
| 463 | const ResourceMessageReplyParams& params) { |
| 464 | decoder_last_error_ = params.result(); |
| 465 | if (decoder_last_error_ == PP_OK) |
| 466 | initialized_ = true; |
| 467 | |
| 468 | // Let the plugin call Initialize again from its callback in case of failure. |
| 469 | scoped_refptr<TrackedCallback> callback; |
| 470 | callback.swap(initialize_callback_); |
| 471 | callback->Run(decoder_last_error_); |
| 472 | } |
| 473 | |
| 474 | void VideoDecoderResource::OnPluginMsgDecodeComplete( |
| 475 | const ResourceMessageReplyParams& params, |
| 476 | uint32_t shm_id) { |
| 477 | if (shm_id >= shm_buffers_.size()) { |
| 478 | NOTREACHED(); |
| 479 | return; |
| 480 | } |
| 481 | // Make the shm buffer available. |
avi | 9bf1749 | 2017-07-10 02:19:38 | [diff] [blame] | 482 | available_shm_buffers_.push_back(shm_buffers_[shm_id].get()); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 483 | // If the plugin is waiting, let it call Decode again. |
Daniel Cheng | 6d3ae97 | 2014-08-26 00:27:38 | [diff] [blame] | 484 | if (decode_callback_.get()) { |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 485 | scoped_refptr<TrackedCallback> callback; |
| 486 | callback.swap(decode_callback_); |
| 487 | callback->Run(PP_OK); |
| 488 | } |
| 489 | } |
| 490 | |
| 491 | void VideoDecoderResource::OnPluginMsgFlushComplete( |
| 492 | const ResourceMessageReplyParams& params) { |
| 493 | // All shm buffers should have been made available by now. |
| 494 | DCHECK_EQ(shm_buffers_.size(), available_shm_buffers_.size()); |
| 495 | |
Daniel Cheng | 6d3ae97 | 2014-08-26 00:27:38 | [diff] [blame] | 496 | if (get_picture_callback_.get()) { |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 497 | scoped_refptr<TrackedCallback> callback; |
| 498 | callback.swap(get_picture_callback_); |
| 499 | callback->Abort(); |
| 500 | } |
| 501 | |
| 502 | scoped_refptr<TrackedCallback> callback; |
| 503 | callback.swap(flush_callback_); |
| 504 | callback->Run(params.result()); |
| 505 | } |
| 506 | |
| 507 | void VideoDecoderResource::OnPluginMsgResetComplete( |
| 508 | const ResourceMessageReplyParams& params) { |
| 509 | // All shm buffers should have been made available by now. |
| 510 | DCHECK_EQ(shm_buffers_.size(), available_shm_buffers_.size()); |
[email protected] | 7ee85d6 | 2014-07-16 20:24:01 | [diff] [blame] | 511 | // Recycle any pictures which haven't been passed to the plugin. |
| 512 | while (!received_pictures_.empty()) { |
| 513 | Post(RENDERER, PpapiHostMsg_VideoDecoder_RecyclePicture( |
| 514 | received_pictures_.front().texture_id)); |
[email protected] | e9fc71c1 | 2014-06-16 22:01:20 | [diff] [blame] | 515 | received_pictures_.pop(); |
[email protected] | 7ee85d6 | 2014-07-16 20:24:01 | [diff] [blame] | 516 | } |
[email protected] | e9fc71c1 | 2014-06-16 22:01:20 | [diff] [blame] | 517 | |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 518 | scoped_refptr<TrackedCallback> callback; |
| 519 | callback.swap(reset_callback_); |
| 520 | callback->Run(params.result()); |
| 521 | } |
| 522 | |
| 523 | void VideoDecoderResource::RunCallbackWithError( |
| 524 | scoped_refptr<TrackedCallback>* callback) { |
Daniel Bratell | eb5dcde | 2018-10-25 08:39:50 | [diff] [blame] | 525 | SafeRunCallback(callback, decoder_last_error_); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 526 | } |
| 527 | |
| 528 | void VideoDecoderResource::DeleteGLTexture(uint32_t id) { |
| 529 | if (gles2_impl_) { |
| 530 | gles2_impl_->DeleteTextures(1, &id); |
| 531 | gles2_impl_->Flush(); |
| 532 | } |
| 533 | } |
| 534 | |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 535 | void VideoDecoderResource::WriteNextPicture() { |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 536 | DCHECK(!received_pictures_.empty()); |
| 537 | Picture& picture = received_pictures_.front(); |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 538 | |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 539 | // Internally, we identify decodes by a unique id, which the host returns |
| 540 | // to us in the picture. Use this to get the plugin's decode_id. |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 541 | uint32_t decode_id = decode_ids_[picture.decode_id % kMaximumPictureDelay]; |
| 542 | uint32_t texture_id = picture.texture_id; |
| 543 | uint32_t texture_target = 0; |
| 544 | PP_Size texture_size = PP_MakeSize(0, 0); |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 545 | TextureMap::iterator it = textures_.find(picture.texture_id); |
| 546 | if (it != textures_.end()) { |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 547 | texture_target = it->second.texture_target; |
| 548 | texture_size = it->second.size; |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 549 | } else { |
| 550 | NOTREACHED(); |
| 551 | } |
Bill Budge | 2d4bf3a | 2014-11-06 22:31:21 | [diff] [blame] | 552 | |
| 553 | if (get_picture_) { |
| 554 | DCHECK(!get_picture_0_1_); |
| 555 | get_picture_->decode_id = decode_id; |
| 556 | get_picture_->texture_id = texture_id; |
| 557 | get_picture_->texture_target = texture_target; |
| 558 | get_picture_->texture_size = texture_size; |
| 559 | get_picture_->visible_rect = picture.visible_rect; |
| 560 | get_picture_ = NULL; |
| 561 | } else { |
| 562 | DCHECK(get_picture_0_1_); |
| 563 | get_picture_0_1_->decode_id = decode_id; |
| 564 | get_picture_0_1_->texture_id = texture_id; |
| 565 | get_picture_0_1_->texture_target = texture_target; |
| 566 | get_picture_0_1_->texture_size = texture_size; |
| 567 | get_picture_0_1_ = NULL; |
| 568 | } |
| 569 | |
[email protected] | dfb0d06f3 | 2014-05-30 22:45:56 | [diff] [blame] | 570 | received_pictures_.pop(); |
| 571 | } |
| 572 | |
| 573 | } // namespace proxy |
| 574 | } // namespace ppapi |