Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2014 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 <GLES2/gl2.h> | |
| 6 #include <GLES2/gl2ext.h> | |
| 7 #include <GLES2/gl2extchromium.h> | |
| 8 | |
| 5 #include "content/renderer/pepper/pepper_video_decoder_host.h" | 9 #include "content/renderer/pepper/pepper_video_decoder_host.h" |
| 6 | 10 |
| 7 #include "base/bind.h" | 11 #include "base/bind.h" |
| 8 #include "base/memory/shared_memory.h" | 12 #include "base/memory/shared_memory.h" |
| 9 #include "content/common/gpu/client/gpu_channel_host.h" | 13 #include "content/common/gpu/client/gpu_channel_host.h" |
| 10 #include "content/public/renderer/render_thread.h" | 14 #include "content/public/renderer/render_thread.h" |
| 11 #include "content/public/renderer/renderer_ppapi_host.h" | 15 #include "content/public/renderer/renderer_ppapi_host.h" |
| 12 #include "content/renderer/pepper/ppb_graphics_3d_impl.h" | 16 #include "content/renderer/pepper/ppb_graphics_3d_impl.h" |
| 13 #include "content/renderer/render_thread_impl.h" | 17 #include "content/renderer/render_thread_impl.h" |
| 14 #include "content/renderer/render_view_impl.h" | 18 #include "content/renderer/render_view_impl.h" |
| 19 #include "gpu/command_buffer/client/gles2_implementation.h" | |
| 20 #include "media/base/decoder_buffer.h" | |
| 21 #include "media/filters/ffmpeg_video_decoder.h" | |
| 15 #include "media/video/picture.h" | 22 #include "media/video/picture.h" |
| 16 #include "media/video/video_decode_accelerator.h" | 23 #include "media/video/video_decode_accelerator.h" |
| 17 #include "ppapi/c/pp_completion_callback.h" | 24 #include "ppapi/c/pp_completion_callback.h" |
| 18 #include "ppapi/c/pp_errors.h" | 25 #include "ppapi/c/pp_errors.h" |
| 19 #include "ppapi/host/dispatch_host_message.h" | 26 #include "ppapi/host/dispatch_host_message.h" |
| 20 #include "ppapi/host/ppapi_host.h" | 27 #include "ppapi/host/ppapi_host.h" |
| 21 #include "ppapi/proxy/ppapi_messages.h" | 28 #include "ppapi/proxy/ppapi_messages.h" |
| 22 #include "ppapi/proxy/video_decoder_constants.h" | 29 #include "ppapi/proxy/video_decoder_constants.h" |
| 23 #include "ppapi/thunk/enter.h" | 30 #include "ppapi/thunk/enter.h" |
| 24 #include "ppapi/thunk/ppb_graphics_3d_api.h" | 31 #include "ppapi/thunk/ppb_graphics_3d_api.h" |
| 32 #include "third_party/libyuv/include/libyuv.h" | |
| 33 #include "webkit/common/gpu/context_provider_web_context.h" | |
| 25 | 34 |
| 26 using ppapi::proxy::SerializedHandle; | 35 using ppapi::proxy::SerializedHandle; |
| 27 using ppapi::thunk::EnterResourceNoLock; | 36 using ppapi::thunk::EnterResourceNoLock; |
| 28 using ppapi::thunk::PPB_Graphics3D_API; | 37 using ppapi::thunk::PPB_Graphics3D_API; |
| 29 | 38 |
| 30 namespace content { | 39 namespace content { |
| 31 | 40 |
| 32 namespace { | 41 namespace { |
| 33 | 42 |
| 34 media::VideoCodecProfile PepperToMediaVideoProfile(PP_VideoProfile profile) { | 43 media::VideoCodecProfile PepperToMediaVideoProfile(PP_VideoProfile profile) { |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 58 case PP_VIDEOPROFILE_VP8MAIN: | 67 case PP_VIDEOPROFILE_VP8MAIN: |
| 59 return media::VP8PROFILE_MAIN; | 68 return media::VP8PROFILE_MAIN; |
| 60 // No default case, to catch unhandled PP_VideoProfile values. | 69 // No default case, to catch unhandled PP_VideoProfile values. |
| 61 } | 70 } |
| 62 | 71 |
| 63 return media::VIDEO_CODEC_PROFILE_UNKNOWN; | 72 return media::VIDEO_CODEC_PROFILE_UNKNOWN; |
| 64 } | 73 } |
| 65 | 74 |
| 66 } // namespace | 75 } // namespace |
| 67 | 76 |
| 77 // This wrapper class calls methods on a media::VideoDecoder on the media thread | |
| 78 // and relays results back to the host on the main thread. It should be created, | |
| 79 // used, and destroyed on the main (render) thread. | |
| 80 class SoftwareDecoder { | |
| 81 public: | |
| 82 explicit SoftwareDecoder(PepperVideoDecoderHost* host); | |
| 83 | |
| 84 void Initialize(media::VideoCodecProfile profile); | |
| 85 void Decode(uint32_t decode_id, | |
| 86 const scoped_refptr<media::DecoderBuffer>& buffer); | |
| 87 void AssignTextures(const std::vector<uint32_t>& texture_ids); | |
| 88 void RecycleTexture(uint32_t texture_id); | |
| 89 void Flush(); | |
| 90 void Reset(); | |
| 91 void Destroy(); | |
| 92 | |
| 93 protected: | |
| 94 // Do not delete directly; use Destroy() or own it with a scoped_ptr, which | |
| 95 // will Destroy() it properly by default. | |
| 96 ~SoftwareDecoder(); | |
| 97 | |
| 98 private: | |
| 99 struct PendingDecode { | |
| 100 PendingDecode(uint32_t decode_id, | |
| 101 const scoped_refptr<media::DecoderBuffer>& buffer); | |
| 102 ~PendingDecode(); | |
| 103 | |
| 104 uint32_t decode_id; | |
| 105 scoped_refptr<media::DecoderBuffer> buffer; | |
| 106 }; | |
| 107 | |
| 108 struct PendingFrame { | |
| 109 PendingFrame(uint32_t decode_id, const gfx::Size& size); | |
| 110 ~PendingFrame(); | |
| 111 | |
| 112 uint32_t decode_id; | |
| 113 gfx::Size size; | |
| 114 std::vector<uint8_t> pixels; | |
| 115 }; | |
| 116 | |
| 117 void InitializeOnMediaThread(media::VideoDecoderConfig config); | |
| 118 void PipelineStatusOnMediaThread(media::PipelineStatus status); | |
| 119 void PipelineStatusOnMainThread(media::PipelineStatus status); | |
| 120 | |
| 121 void ReceiveBufferOnMediaThread(uint32_t decode_id, | |
| 122 scoped_refptr<media::DecoderBuffer> buffer); | |
| 123 void DecodeOnMediaThread(); | |
| 124 void ConvertFrameOnMediaThread(uint32_t decode_id, | |
| 125 media::VideoDecoder::Status status, | |
| 126 const scoped_refptr<media::VideoFrame>& frame); | |
| 127 void ReceiveFrameOnMainThread(media::VideoDecoder::Status status, | |
| 128 scoped_ptr<PendingFrame> frame); | |
| 129 void SendPicturesOnMainThread(); | |
| 130 | |
| 131 void DoResetOnMediaThread(); | |
| 132 void ResetCompleteOnMediaThread(); | |
| 133 void ResetCompleteOnMainThread(); | |
| 134 | |
| 135 void DestroyOnMediaThread(); | |
| 136 void DestroyOnMainThread(); | |
| 137 | |
| 138 void DismissTexture(uint32_t texture_id); | |
| 139 void DeleteTexture(uint32_t texture_id); | |
| 140 void FlushCommandBuffer(); | |
| 141 | |
| 142 // These members are accessed only on the main thread. | |
| 143 | |
| 144 PepperVideoDecoderHost* host_; | |
| 145 scoped_refptr<base::MessageLoopProxy> media_message_loop_; | |
| 146 scoped_refptr<webkit::gpu::ContextProviderWebContext> context_provider_; | |
| 147 // The current decoded frame size. | |
| 148 gfx::Size texture_size_; | |
| 149 // Map that takes the plugin's GL texture id to the renderer's GL texture id. | |
| 150 typedef base::hash_map<uint32_t, uint32_t> TextureIdMap; | |
| 151 TextureIdMap texture_id_map_; | |
| 152 // Available textures (these are plugin ids.) | |
| 153 std::vector<uint32_t> available_textures_; | |
| 154 // Track textures that are no longer needed (these are plugin ids.) | |
| 155 typedef base::hash_set<uint32_t> TextureIdSet; | |
| 156 TextureIdSet textures_to_dismiss_; | |
| 157 // Mailboxes for pending texture requests, to write to plugin's textures. | |
| 158 std::vector<gpu::Mailbox> pending_texture_mailboxes_; | |
| 159 // Queue of pending decoded frames. These have been converted to RGB, and | |
| 160 // await upload to a GL texture. | |
| 161 typedef std::queue<PendingFrame*> PendingFrameQueue; | |
| 162 PendingFrameQueue pending_frames_; | |
| 163 uint32_t num_pending_decodes_; | |
| 164 bool flushing_; | |
| 165 bool resetting_; | |
|
dmichael (off chromium)
2014/06/03 22:27:47
suggestion: Might be clearer to use a 3-state enum
bbudge
2014/06/04 14:10:12
UNITIALIZED, DECODING, FLUSHING, RESETTING.
Done.
| |
| 166 | |
| 167 // These members are accessed only on the media thread. | |
| 168 | |
| 169 scoped_ptr<media::VideoDecoder> decoder_; | |
| 170 scoped_refptr<base::MessageLoopProxy> main_message_loop_; | |
| 171 // Queue of decodes waiting for the decoder. | |
| 172 typedef std::queue<PendingDecode> PendingDecodeQueue; | |
| 173 PendingDecodeQueue pending_decodes_; | |
|
dmichael (off chromium)
2014/06/03 22:27:47
This is a bit hard to follow with the mix of opera
bbudge
2014/06/04 14:10:12
I moved SoftwareDecoder to its own files (video_de
dmichael (off chromium)
2014/06/04 15:47:29
Do you mean you don't want to inherit SupportsWeak
bbudge
2014/06/04 20:52:46
Delegate now references VideoDecoderProxy (formerl
dmichael (off chromium)
2014/06/04 21:03:07
FYI, base::Callbacks have no restriction on the nu
| |
| 174 | |
| 175 DISALLOW_COPY_AND_ASSIGN(SoftwareDecoder); | |
| 176 }; | |
| 177 | |
| 178 SoftwareDecoder::PendingDecode::PendingDecode( | |
| 179 uint32_t decode_id, | |
| 180 const scoped_refptr<media::DecoderBuffer>& buffer) | |
| 181 : decode_id(decode_id), buffer(buffer) { | |
| 182 } | |
| 183 | |
| 184 SoftwareDecoder::PendingDecode::~PendingDecode() { | |
| 185 } | |
| 186 | |
| 187 SoftwareDecoder::PendingFrame::PendingFrame(uint32_t decode_id, | |
| 188 const gfx::Size& size) | |
| 189 : decode_id(decode_id), | |
| 190 size(size), | |
| 191 pixels(size.width() * size.height() * 4) { | |
| 192 } | |
| 193 | |
| 194 SoftwareDecoder::PendingFrame::~PendingFrame() { | |
| 195 } | |
| 196 | |
| 197 SoftwareDecoder::SoftwareDecoder(PepperVideoDecoderHost* host) | |
| 198 : host_(host), | |
| 199 media_message_loop_( | |
| 200 RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy()), | |
| 201 context_provider_( | |
| 202 RenderThreadImpl::current()->SharedMainThreadContextProvider()), | |
| 203 num_pending_decodes_(0), | |
| 204 flushing_(false), | |
| 205 resetting_(false), | |
| 206 main_message_loop_(base::MessageLoopProxy::current()) { | |
| 207 DCHECK(host_); | |
| 208 DCHECK(main_message_loop_); | |
| 209 DCHECK(media_message_loop_); | |
| 210 DCHECK(context_provider_); | |
| 211 } | |
| 212 | |
| 213 SoftwareDecoder::~SoftwareDecoder() { | |
| 214 DCHECK(RenderThreadImpl::current()); | |
| 215 DCHECK(!host_); | |
| 216 // Delete any remaining video frames. | |
| 217 while (!pending_frames_.empty()) { | |
| 218 delete pending_frames_.front(); | |
| 219 pending_frames_.pop(); | |
| 220 } | |
| 221 // Delete any remaining textures. | |
| 222 TextureIdMap::iterator it = texture_id_map_.begin(); | |
| 223 for (; it != texture_id_map_.end(); ++it) | |
| 224 DeleteTexture(it->second); | |
| 225 | |
| 226 FlushCommandBuffer(); | |
| 227 } | |
| 228 | |
| 229 void SoftwareDecoder::Initialize(media::VideoCodecProfile profile) { | |
| 230 DCHECK(RenderThreadImpl::current()); | |
| 231 DCHECK(!decoder_); | |
| 232 media::VideoCodec codec = media::kUnknownVideoCodec; | |
| 233 if (profile <= media::H264PROFILE_MAX) | |
| 234 codec = media::kCodecH264; | |
| 235 else if (profile <= media::VP8PROFILE_MAX) | |
| 236 codec = media::kCodecVP8; | |
| 237 DCHECK_NE(codec, media::kUnknownVideoCodec); | |
| 238 | |
| 239 media::VideoDecoderConfig config( | |
| 240 codec, | |
| 241 profile, | |
| 242 media::VideoFrame::YV12, | |
| 243 gfx::Size(32, 24), // Small sizes that won't fail. | |
| 244 gfx::Rect(32, 24), | |
| 245 gfx::Size(32, 24), | |
| 246 NULL /* extra_data */, | |
| 247 0 /* extra_data_size */, | |
| 248 false /* decryption */); | |
| 249 | |
| 250 decoder_.reset(new media::FFmpegVideoDecoder(media_message_loop_)); | |
| 251 | |
| 252 media_message_loop_->PostTask( | |
| 253 FROM_HERE, | |
| 254 base::Bind(&SoftwareDecoder::InitializeOnMediaThread, | |
| 255 base::Unretained(this), | |
| 256 config)); | |
| 257 } | |
| 258 | |
| 259 void SoftwareDecoder::Decode( | |
| 260 uint32_t decode_id, | |
| 261 const scoped_refptr<media::DecoderBuffer>& buffer) { | |
| 262 DCHECK(RenderThreadImpl::current()); | |
| 263 DCHECK(decoder_); | |
| 264 DCHECK(!resetting_ && !flushing_); | |
| 265 | |
| 266 num_pending_decodes_++; | |
| 267 | |
| 268 media_message_loop_->PostTask( | |
| 269 FROM_HERE, | |
| 270 base::Bind(&SoftwareDecoder::ReceiveBufferOnMediaThread, | |
| 271 base::Unretained(this), | |
| 272 decode_id, | |
| 273 buffer)); | |
| 274 } | |
| 275 | |
| 276 void SoftwareDecoder::AssignTextures(const std::vector<uint32_t>& texture_ids) { | |
| 277 DCHECK(RenderThreadImpl::current()); | |
| 278 DCHECK(decoder_); | |
| 279 DCHECK(texture_ids.size()); | |
| 280 DCHECK_EQ(texture_ids.size(), pending_texture_mailboxes_.size()); | |
| 281 uint32_t num_textures = static_cast<GLuint>(texture_ids.size()); | |
| 282 std::vector<uint32_t> local_texture_ids(num_textures); | |
| 283 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL(); | |
| 284 gles2->GenTextures(num_textures, &local_texture_ids.front()); | |
| 285 for (uint32_t i = 0; i < num_textures; i++) { | |
| 286 gles2->ActiveTexture(GL_TEXTURE0); | |
| 287 gles2->BindTexture(GL_TEXTURE_2D, local_texture_ids[i]); | |
| 288 gles2->ConsumeTextureCHROMIUM(GL_TEXTURE_2D, | |
| 289 pending_texture_mailboxes_[i].name); | |
| 290 // Map the plugin texture id to the local texture id. | |
| 291 texture_id_map_.insert( | |
| 292 std::make_pair(texture_ids[i], local_texture_ids[i])); | |
| 293 } | |
| 294 pending_texture_mailboxes_.clear(); | |
| 295 available_textures_.insert( | |
| 296 available_textures_.end(), texture_ids.begin(), texture_ids.end()); | |
| 297 SendPicturesOnMainThread(); | |
| 298 } | |
| 299 | |
| 300 void SoftwareDecoder::RecycleTexture(uint32_t texture_id) { | |
| 301 DCHECK(RenderThreadImpl::current()); | |
| 302 DCHECK(decoder_); | |
| 303 if (textures_to_dismiss_.find(texture_id) != textures_to_dismiss_.end()) { | |
| 304 DismissTexture(texture_id); | |
| 305 } else if (texture_id_map_.find(texture_id) != texture_id_map_.end()) { | |
| 306 available_textures_.push_back(texture_id); | |
| 307 SendPicturesOnMainThread(); | |
| 308 } else { | |
| 309 NOTREACHED(); | |
| 310 } | |
| 311 } | |
| 312 | |
| 313 void SoftwareDecoder::Flush() { | |
| 314 DCHECK(RenderThreadImpl::current()); | |
| 315 DCHECK(decoder_); | |
| 316 DCHECK(!resetting_ && !flushing_); | |
| 317 flushing_ = true; | |
| 318 } | |
| 319 | |
| 320 void SoftwareDecoder::Reset() { | |
| 321 DCHECK(RenderThreadImpl::current()); | |
| 322 DCHECK(decoder_); | |
| 323 DCHECK(!resetting_ && !flushing_); | |
| 324 resetting_ = true; | |
| 325 media_message_loop_->PostTask( | |
| 326 FROM_HERE, | |
| 327 base::Bind(&SoftwareDecoder::DoResetOnMediaThread, | |
| 328 base::Unretained(this))); | |
| 329 } | |
| 330 | |
| 331 void SoftwareDecoder::Destroy() { | |
| 332 DCHECK(RenderThreadImpl::current()); | |
| 333 DCHECK(decoder_); | |
| 334 DCHECK(host_); | |
| 335 host_ = NULL; | |
| 336 media_message_loop_->PostTask( | |
| 337 FROM_HERE, | |
| 338 base::Bind(&SoftwareDecoder::DestroyOnMediaThread, | |
| 339 base::Unretained(this))); | |
| 340 } | |
| 341 | |
| 342 void SoftwareDecoder::InitializeOnMediaThread( | |
| 343 media::VideoDecoderConfig config) { | |
| 344 DCHECK(decoder_); | |
| 345 decoder_->Initialize(config, | |
| 346 true /* low_delay */, | |
| 347 base::Bind(&SoftwareDecoder::PipelineStatusOnMediaThread, | |
| 348 base::Unretained(this))); | |
| 349 } | |
| 350 | |
| 351 void SoftwareDecoder::PipelineStatusOnMediaThread( | |
| 352 media::PipelineStatus status) { | |
| 353 if (!host_) | |
| 354 return; | |
| 355 main_message_loop_->PostTask( | |
| 356 FROM_HERE, | |
| 357 base::Bind(&SoftwareDecoder::PipelineStatusOnMainThread, | |
| 358 base::Unretained(this), | |
| 359 status)); | |
| 360 } | |
| 361 | |
| 362 void SoftwareDecoder::PipelineStatusOnMainThread(media::PipelineStatus status) { | |
| 363 if (!host_) | |
| 364 return; | |
| 365 int32_t result; | |
| 366 switch (status) { | |
| 367 case media::PIPELINE_OK: | |
| 368 result = PP_OK; | |
| 369 break; | |
| 370 case media::DECODER_ERROR_NOT_SUPPORTED: | |
| 371 result = PP_ERROR_NOTSUPPORTED; | |
| 372 break; | |
| 373 default: | |
| 374 result = PP_ERROR_FAILED; | |
| 375 break; | |
| 376 } | |
| 377 host_->OnInitializeComplete(result); | |
| 378 } | |
| 379 | |
| 380 void SoftwareDecoder::ReceiveBufferOnMediaThread( | |
| 381 uint32_t decode_id, | |
| 382 scoped_refptr<media::DecoderBuffer> buffer) { | |
| 383 bool decoder_busy = !pending_decodes_.empty(); | |
| 384 pending_decodes_.push(PendingDecode(decode_id, buffer)); | |
| 385 if (!decoder_busy) | |
| 386 DecodeOnMediaThread(); | |
| 387 } | |
| 388 | |
| 389 void SoftwareDecoder::DecodeOnMediaThread() { | |
| 390 DCHECK(!pending_decodes_.empty()); | |
| 391 PendingDecode& next_decode = pending_decodes_.front(); | |
| 392 decoder_->Decode(next_decode.buffer, | |
| 393 base::Bind(&SoftwareDecoder::ConvertFrameOnMediaThread, | |
| 394 base::Unretained(this), | |
| 395 next_decode.decode_id)); | |
| 396 pending_decodes_.pop(); | |
| 397 } | |
| 398 | |
| 399 void SoftwareDecoder::ConvertFrameOnMediaThread( | |
| 400 uint32_t decode_id, | |
| 401 media::VideoDecoder::Status status, | |
| 402 const scoped_refptr<media::VideoFrame>& frame) { | |
| 403 if (!host_) | |
| 404 return; | |
| 405 scoped_ptr<PendingFrame> pending_frame( | |
| 406 new PendingFrame(decode_id, gfx::Size())); | |
| 407 if (frame) { | |
| 408 pending_frame->size = frame->coded_size(); | |
| 409 pending_frame->pixels.resize(frame->coded_size().width() * | |
| 410 frame->coded_size().height() * 4); | |
| 411 // Convert the decoded frame to ARGB pixels. | |
| 412 libyuv::I420ToARGB(frame->data(media::VideoFrame::kYPlane), | |
| 413 frame->stride(media::VideoFrame::kYPlane), | |
| 414 frame->data(media::VideoFrame::kUPlane), | |
| 415 frame->stride(media::VideoFrame::kUPlane), | |
| 416 frame->data(media::VideoFrame::kVPlane), | |
| 417 frame->stride(media::VideoFrame::kVPlane), | |
| 418 &pending_frame->pixels.front(), | |
| 419 frame->coded_size().width() * 4, | |
| 420 frame->coded_size().width(), | |
| 421 frame->coded_size().height()); | |
| 422 } | |
| 423 | |
| 424 main_message_loop_->PostTask( | |
| 425 FROM_HERE, | |
| 426 base::Bind(&SoftwareDecoder::ReceiveFrameOnMainThread, | |
| 427 base::Unretained(this), | |
| 428 status, | |
| 429 base::Passed(&pending_frame))); | |
| 430 | |
| 431 if (!pending_decodes_.empty()) | |
| 432 DecodeOnMediaThread(); | |
| 433 } | |
| 434 | |
| 435 void SoftwareDecoder::ReceiveFrameOnMainThread( | |
| 436 media::VideoDecoder::Status status, | |
| 437 scoped_ptr<PendingFrame> frame) { | |
| 438 DCHECK(RenderThreadImpl::current()); | |
| 439 if (!host_) | |
| 440 return; | |
| 441 | |
| 442 num_pending_decodes_--; | |
| 443 | |
| 444 if (frame->pixels.size()) { | |
| 445 if (texture_size_ != frame->size) { | |
| 446 // If the size has changed, all current textures must be dismissed. Add | |
| 447 // all textures to |textures_to_dismiss_| and dismiss any that aren't in | |
| 448 // use by the plugin. We dismiss the rest as they are recycled. | |
| 449 for (TextureIdMap::const_iterator it = texture_id_map_.begin(); | |
| 450 it != texture_id_map_.end(); | |
| 451 ++it) { | |
| 452 textures_to_dismiss_.insert(it->second); | |
| 453 } | |
| 454 for (std::vector<uint32_t>::const_iterator it = | |
| 455 available_textures_.begin(); | |
| 456 it != available_textures_.end(); | |
| 457 ++it) { | |
| 458 DismissTexture(*it); | |
| 459 } | |
| 460 available_textures_.clear(); | |
| 461 FlushCommandBuffer(); | |
| 462 | |
| 463 DCHECK(pending_texture_mailboxes_.empty()); | |
| 464 const uint32_t num_textures = 8; | |
| 465 for (uint32_t i = 0; i < num_textures; i++) | |
| 466 pending_texture_mailboxes_.push_back(gpu::Mailbox::Generate()); | |
| 467 | |
| 468 host_->RequestTextures( | |
| 469 num_textures, frame->size, GL_TEXTURE_2D, pending_texture_mailboxes_); | |
| 470 texture_size_ = frame->size; | |
| 471 } | |
| 472 | |
| 473 pending_frames_.push(frame.release()); | |
| 474 SendPicturesOnMainThread(); | |
| 475 } else { | |
| 476 host_->NotifyEndOfBitstreamBuffer(frame->decode_id); | |
| 477 } | |
| 478 | |
| 479 switch (status) { | |
| 480 case media::VideoDecoder::kOk: | |
| 481 case media::VideoDecoder::kAborted: | |
| 482 break; | |
| 483 case media::VideoDecoder::kNotEnoughData: | |
|
igorc
2014/06/03 20:26:32
This is not an error in H264 case when we feed ind
bbudge
2014/06/03 20:59:20
Do you mean that we should silently ignore this er
bbudge
2014/06/04 14:10:12
Changed to not call NotifyError on kNotEnoughData.
| |
| 484 host_->NotifyError(PP_ERROR_MALFORMED_INPUT); | |
| 485 break; | |
| 486 case media::VideoDecoder::kDecodeError: | |
| 487 case media::VideoDecoder::kDecryptError: | |
| 488 host_->NotifyError(PP_ERROR_RESOURCE_FAILED); | |
| 489 break; | |
| 490 // No default case, to catch unhandled status values. | |
| 491 } | |
| 492 } | |
| 493 | |
| 494 void SoftwareDecoder::SendPicturesOnMainThread() { | |
| 495 DCHECK(RenderThreadImpl::current()); | |
| 496 if (!host_) | |
| 497 return; | |
| 498 while (!pending_frames_.empty() && !available_textures_.empty()) { | |
| 499 scoped_ptr<PendingFrame> frame(pending_frames_.front()); | |
| 500 pending_frames_.pop(); | |
| 501 | |
| 502 uint32_t texture_id = available_textures_.back(); | |
| 503 available_textures_.pop_back(); | |
| 504 | |
| 505 uint32_t local_texture_id = texture_id_map_[texture_id]; | |
| 506 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL(); | |
| 507 gles2->ActiveTexture(GL_TEXTURE0); | |
| 508 gles2->BindTexture(GL_TEXTURE_2D, local_texture_id); | |
| 509 gles2->TexImage2D(GL_TEXTURE_2D, | |
| 510 0, | |
| 511 GL_RGBA, | |
| 512 texture_size_.width(), | |
| 513 texture_size_.height(), | |
| 514 0, | |
| 515 GL_RGBA, | |
| 516 GL_UNSIGNED_BYTE, | |
| 517 &frame->pixels.front()); | |
| 518 | |
| 519 host_->NotifyEndOfBitstreamBuffer(frame->decode_id); | |
| 520 host_->PictureReady(media::Picture(texture_id, frame->decode_id)); | |
| 521 } | |
| 522 | |
| 523 FlushCommandBuffer(); | |
| 524 | |
| 525 if (flushing_ && !num_pending_decodes_ && pending_frames_.empty()) { | |
| 526 flushing_ = false; | |
| 527 host_->NotifyFlushDone(); | |
| 528 } | |
| 529 } | |
| 530 | |
| 531 void SoftwareDecoder::DoResetOnMediaThread() { | |
| 532 decoder_->Reset(base::Bind(&SoftwareDecoder::ResetCompleteOnMediaThread, | |
| 533 base::Unretained(this))); | |
| 534 } | |
| 535 | |
| 536 void SoftwareDecoder::ResetCompleteOnMediaThread() { | |
| 537 // Cancel all remaining decodes, and notify the host so it can free the shm | |
| 538 // buffers. We'll clear pending frames on the main thread. | |
| 539 while (!pending_decodes_.empty()) { | |
| 540 PendingDecode& next_decode = pending_decodes_.front(); | |
| 541 scoped_ptr<PendingFrame> pending_frame( | |
| 542 new PendingFrame(next_decode.decode_id, gfx::Size())); | |
| 543 main_message_loop_->PostTask( | |
| 544 FROM_HERE, | |
| 545 base::Bind(&SoftwareDecoder::ReceiveFrameOnMainThread, | |
| 546 base::Unretained(this), | |
| 547 media::VideoDecoder::kAborted, | |
| 548 base::Passed(&pending_frame))); | |
| 549 pending_decodes_.pop(); | |
| 550 } | |
| 551 main_message_loop_->PostTask( | |
| 552 FROM_HERE, | |
| 553 base::Bind(&SoftwareDecoder::ResetCompleteOnMainThread, | |
| 554 base::Unretained(this))); | |
| 555 } | |
| 556 | |
| 557 void SoftwareDecoder::ResetCompleteOnMainThread() { | |
| 558 if (!host_) | |
| 559 return; | |
| 560 while (!pending_frames_.empty()) { | |
| 561 scoped_ptr<PendingFrame> frame(pending_frames_.front()); | |
| 562 host_->NotifyEndOfBitstreamBuffer(frame->decode_id); | |
| 563 pending_frames_.pop(); | |
| 564 } | |
| 565 | |
| 566 resetting_ = false; | |
| 567 host_->NotifyResetDone(); | |
| 568 } | |
| 569 | |
| 570 void SoftwareDecoder::DestroyOnMediaThread() { | |
| 571 DCHECK(decoder_); | |
| 572 decoder_->Stop(); | |
| 573 // All callbacks have been called on the media thread, and thus all tasks | |
| 574 // posted for the main thread. This is our last task for the main thread. | |
| 575 main_message_loop_->PostTask(FROM_HERE, | |
| 576 base::Bind(&SoftwareDecoder::DestroyOnMainThread, | |
| 577 base::Unretained(this))); | |
| 578 } | |
| 579 | |
| 580 void SoftwareDecoder::DestroyOnMainThread() { | |
| 581 DCHECK(RenderThreadImpl::current()); | |
| 582 DCHECK(!host_); | |
| 583 delete this; | |
| 584 } | |
| 585 | |
| 586 void SoftwareDecoder::DismissTexture(uint32_t texture_id) { | |
| 587 DCHECK(host_); | |
| 588 textures_to_dismiss_.erase(texture_id); | |
| 589 DCHECK(texture_id_map_.find(texture_id) != texture_id_map_.end()); | |
| 590 DeleteTexture(texture_id_map_[texture_id]); | |
| 591 texture_id_map_.erase(texture_id); | |
| 592 host_->DismissPictureBuffer(texture_id); | |
| 593 } | |
| 594 | |
| 595 void SoftwareDecoder::DeleteTexture(uint32_t texture_id) { | |
| 596 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL(); | |
| 597 gles2->DeleteTextures(1, &texture_id); | |
| 598 } | |
| 599 | |
| 600 void SoftwareDecoder::FlushCommandBuffer() { | |
| 601 DCHECK(RenderThreadImpl::current()); | |
| 602 context_provider_->ContextGL()->Flush(); | |
| 603 } | |
| 604 | |
|
dmichael (off chromium)
2014/06/03 22:27:46
I think this class should be in its own file.
bbudge
2014/06/04 14:10:12
Done.
| |
| 68 PepperVideoDecoderHost::PendingDecode::PendingDecode( | 605 PepperVideoDecoderHost::PendingDecode::PendingDecode( |
| 69 uint32_t shm_id, | 606 uint32_t shm_id, |
| 70 const ppapi::host::ReplyMessageContext& reply_context) | 607 const ppapi::host::ReplyMessageContext& reply_context) |
| 71 : shm_id(shm_id), reply_context(reply_context) { | 608 : shm_id(shm_id), reply_context(reply_context) { |
| 72 } | 609 } |
| 73 | 610 |
| 74 PepperVideoDecoderHost::PendingDecode::~PendingDecode() { | 611 PepperVideoDecoderHost::PendingDecode::~PendingDecode() { |
| 75 } | 612 } |
| 76 | 613 |
| 77 PepperVideoDecoderHost::PepperVideoDecoderHost(RendererPpapiHost* host, | 614 PepperVideoDecoderHost::PepperVideoDecoderHost(RendererPpapiHost* host, |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 112 const ppapi::HostResource& graphics_context, | 649 const ppapi::HostResource& graphics_context, |
| 113 PP_VideoProfile profile, | 650 PP_VideoProfile profile, |
| 114 bool allow_software_fallback) { | 651 bool allow_software_fallback) { |
| 115 if (initialized_) | 652 if (initialized_) |
| 116 return PP_ERROR_FAILED; | 653 return PP_ERROR_FAILED; |
| 117 | 654 |
| 118 EnterResourceNoLock<PPB_Graphics3D_API> enter_graphics( | 655 EnterResourceNoLock<PPB_Graphics3D_API> enter_graphics( |
| 119 graphics_context.host_resource(), true); | 656 graphics_context.host_resource(), true); |
| 120 if (enter_graphics.failed()) | 657 if (enter_graphics.failed()) |
| 121 return PP_ERROR_FAILED; | 658 return PP_ERROR_FAILED; |
| 122 graphics3d_ = static_cast<PPB_Graphics3D_Impl*>(enter_graphics.object()); | 659 PPB_Graphics3D_Impl* graphics3d = |
| 660 static_cast<PPB_Graphics3D_Impl*>(enter_graphics.object()); | |
| 123 | 661 |
| 124 int command_buffer_route_id = graphics3d_->GetCommandBufferRouteId(); | 662 int command_buffer_route_id = graphics3d->GetCommandBufferRouteId(); |
| 125 if (!command_buffer_route_id) | 663 if (!command_buffer_route_id) |
| 126 return PP_ERROR_FAILED; | 664 return PP_ERROR_FAILED; |
| 127 | 665 |
| 128 media::VideoCodecProfile media_profile = PepperToMediaVideoProfile(profile); | 666 media::VideoCodecProfile media_profile = PepperToMediaVideoProfile(profile); |
| 129 | 667 |
| 130 // This is not synchronous, but subsequent IPC messages will be buffered, so | 668 // This is not synchronous, but subsequent IPC messages will be buffered, so |
| 131 // it is okay to immediately send IPC messages through the returned channel. | 669 // it is okay to immediately send IPC messages through the returned channel. |
| 132 GpuChannelHost* channel = graphics3d_->channel(); | 670 GpuChannelHost* channel = graphics3d->channel(); |
| 133 DCHECK(channel); | 671 DCHECK(channel); |
| 134 decoder_ = channel->CreateVideoDecoder(command_buffer_route_id); | 672 decoder_ = channel->CreateVideoDecoder(command_buffer_route_id); |
| 135 if (decoder_ && decoder_->Initialize(media_profile, this)) { | 673 if (decoder_ && decoder_->Initialize(media_profile, this)) { |
| 136 initialized_ = true; | 674 initialized_ = true; |
| 137 return PP_OK; | 675 return PP_OK; |
| 138 } | 676 } |
| 139 decoder_.reset(); | 677 decoder_.reset(); |
| 140 | 678 |
| 141 // TODO(bbudge) Implement software fallback. | 679 if (!allow_software_fallback) |
| 142 return PP_ERROR_NOTSUPPORTED; | 680 return PP_ERROR_NOTSUPPORTED; |
| 681 | |
| 682 software_decoder_.reset(new SoftwareDecoder(this)); | |
| 683 initialize_reply_context_ = context->MakeReplyMessageContext(); | |
| 684 software_decoder_->Initialize(media_profile); | |
| 685 | |
| 686 return PP_OK_COMPLETIONPENDING; | |
| 143 } | 687 } |
| 144 | 688 |
| 145 int32_t PepperVideoDecoderHost::OnHostMsgGetShm( | 689 int32_t PepperVideoDecoderHost::OnHostMsgGetShm( |
| 146 ppapi::host::HostMessageContext* context, | 690 ppapi::host::HostMessageContext* context, |
| 147 uint32_t shm_id, | 691 uint32_t shm_id, |
| 148 uint32_t shm_size) { | 692 uint32_t shm_size) { |
| 149 if (!initialized_) | 693 if (!initialized_) |
| 150 return PP_ERROR_FAILED; | 694 return PP_ERROR_FAILED; |
| 151 | 695 |
| 152 // Make the buffers larger since we hope to reuse them. | 696 // Make the buffers larger since we hope to reuse them. |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 201 return PP_OK_COMPLETIONPENDING; | 745 return PP_OK_COMPLETIONPENDING; |
| 202 } | 746 } |
| 203 | 747 |
| 204 int32_t PepperVideoDecoderHost::OnHostMsgDecode( | 748 int32_t PepperVideoDecoderHost::OnHostMsgDecode( |
| 205 ppapi::host::HostMessageContext* context, | 749 ppapi::host::HostMessageContext* context, |
| 206 uint32_t shm_id, | 750 uint32_t shm_id, |
| 207 uint32_t size, | 751 uint32_t size, |
| 208 int32_t decode_id) { | 752 int32_t decode_id) { |
| 209 if (!initialized_) | 753 if (!initialized_) |
| 210 return PP_ERROR_FAILED; | 754 return PP_ERROR_FAILED; |
| 211 DCHECK(decoder_); | 755 DCHECK(decoder_ || software_decoder_); |
| 212 // |shm_id| is just an index into shm_buffers_. Make sure it's in range. | 756 // |shm_id| is just an index into shm_buffers_. Make sure it's in range. |
| 213 if (static_cast<size_t>(shm_id) >= shm_buffers_.size()) | 757 if (static_cast<size_t>(shm_id) >= shm_buffers_.size()) |
| 214 return PP_ERROR_FAILED; | 758 return PP_ERROR_FAILED; |
| 215 // Reject an attempt to pass a busy buffer to the decoder again. | 759 // Reject an attempt to pass a busy buffer to the decoder again. |
| 216 if (shm_buffer_busy_[shm_id]) | 760 if (shm_buffer_busy_[shm_id]) |
| 217 return PP_ERROR_FAILED; | 761 return PP_ERROR_FAILED; |
| 218 // Reject non-unique decode_id values. | 762 // Reject non-unique decode_id values. |
| 219 if (pending_decodes_.find(decode_id) != pending_decodes_.end()) | 763 if (pending_decodes_.find(decode_id) != pending_decodes_.end()) |
| 220 return PP_ERROR_FAILED; | 764 return PP_ERROR_FAILED; |
| 221 | 765 |
| 222 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid()) | 766 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid()) |
| 223 return PP_ERROR_FAILED; | 767 return PP_ERROR_FAILED; |
| 224 | 768 |
| 225 pending_decodes_.insert(std::make_pair( | 769 pending_decodes_.insert(std::make_pair( |
| 226 decode_id, PendingDecode(shm_id, context->MakeReplyMessageContext()))); | 770 decode_id, PendingDecode(shm_id, context->MakeReplyMessageContext()))); |
| 227 | 771 |
| 228 shm_buffer_busy_[shm_id] = true; | 772 shm_buffer_busy_[shm_id] = true; |
| 229 decoder_->Decode( | 773 base::SharedMemory* shm = shm_buffers_[shm_id]; |
| 230 media::BitstreamBuffer(decode_id, shm_buffers_[shm_id]->handle(), size)); | 774 if (decoder_) { |
| 775 decoder_->Decode(media::BitstreamBuffer(decode_id, shm->handle(), size)); | |
| 776 } else { | |
| 777 software_decoder_->Decode(decode_id, | |
| 778 media::DecoderBuffer::CopyFrom( | |
| 779 static_cast<uint8_t*>(shm->memory()), size)); | |
| 780 } | |
| 231 | 781 |
| 232 return PP_OK_COMPLETIONPENDING; | 782 return PP_OK_COMPLETIONPENDING; |
| 233 } | 783 } |
| 234 | 784 |
| 235 int32_t PepperVideoDecoderHost::OnHostMsgAssignTextures( | 785 int32_t PepperVideoDecoderHost::OnHostMsgAssignTextures( |
| 236 ppapi::host::HostMessageContext* context, | 786 ppapi::host::HostMessageContext* context, |
| 237 const PP_Size& size, | 787 const PP_Size& size, |
| 238 const std::vector<uint32_t>& texture_ids) { | 788 const std::vector<uint32_t>& texture_ids) { |
| 239 if (!initialized_) | 789 if (!initialized_) |
| 240 return PP_ERROR_FAILED; | 790 return PP_ERROR_FAILED; |
| 241 DCHECK(decoder_); | 791 DCHECK(decoder_ || software_decoder_); |
| 242 | 792 |
| 243 std::vector<media::PictureBuffer> picture_buffers; | 793 if (decoder_) { |
| 244 for (uint32 i = 0; i < texture_ids.size(); i++) { | 794 std::vector<media::PictureBuffer> picture_buffers; |
| 245 media::PictureBuffer buffer( | 795 for (uint32 i = 0; i < texture_ids.size(); i++) { |
| 246 texture_ids[i], // Use the texture_id to identify the buffer. | 796 media::PictureBuffer buffer( |
| 247 gfx::Size(size.width, size.height), | 797 texture_ids[i], // Use the texture_id to identify the buffer. |
| 248 texture_ids[i]); | 798 gfx::Size(size.width, size.height), |
| 249 picture_buffers.push_back(buffer); | 799 texture_ids[i]); |
| 800 picture_buffers.push_back(buffer); | |
| 801 } | |
| 802 decoder_->AssignPictureBuffers(picture_buffers); | |
| 803 } else { | |
| 804 software_decoder_->AssignTextures(texture_ids); | |
| 250 } | 805 } |
| 251 decoder_->AssignPictureBuffers(picture_buffers); | |
| 252 return PP_OK; | 806 return PP_OK; |
| 253 } | 807 } |
| 254 | 808 |
| 255 int32_t PepperVideoDecoderHost::OnHostMsgRecyclePicture( | 809 int32_t PepperVideoDecoderHost::OnHostMsgRecyclePicture( |
| 256 ppapi::host::HostMessageContext* context, | 810 ppapi::host::HostMessageContext* context, |
| 257 uint32_t texture_id) { | 811 uint32_t texture_id) { |
| 258 if (!initialized_) | 812 if (!initialized_) |
| 259 return PP_ERROR_FAILED; | 813 return PP_ERROR_FAILED; |
| 260 DCHECK(decoder_); | 814 DCHECK(decoder_ || software_decoder_); |
| 261 if (reset_reply_context_.is_valid()) | 815 if (reset_reply_context_.is_valid()) |
| 262 return PP_ERROR_FAILED; | 816 return PP_ERROR_FAILED; |
| 263 | 817 if (decoder_) { |
| 264 decoder_->ReusePictureBuffer(texture_id); | 818 decoder_->ReusePictureBuffer(texture_id); |
| 819 } else { | |
| 820 software_decoder_->RecycleTexture(texture_id); | |
| 821 } | |
| 265 | 822 |
| 266 return PP_OK; | 823 return PP_OK; |
| 267 } | 824 } |
| 268 | 825 |
| 269 int32_t PepperVideoDecoderHost::OnHostMsgFlush( | 826 int32_t PepperVideoDecoderHost::OnHostMsgFlush( |
| 270 ppapi::host::HostMessageContext* context) { | 827 ppapi::host::HostMessageContext* context) { |
| 271 if (!initialized_) | 828 if (!initialized_) |
| 272 return PP_ERROR_FAILED; | 829 return PP_ERROR_FAILED; |
| 273 DCHECK(decoder_); | 830 DCHECK(decoder_ || software_decoder_); |
| 274 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid()) | 831 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid()) |
| 275 return PP_ERROR_FAILED; | 832 return PP_ERROR_FAILED; |
| 276 | 833 |
| 277 flush_reply_context_ = context->MakeReplyMessageContext(); | 834 flush_reply_context_ = context->MakeReplyMessageContext(); |
| 278 decoder_->Flush(); | 835 if (decoder_) |
| 836 decoder_->Flush(); | |
| 837 else | |
| 838 software_decoder_->Flush(); | |
| 279 | 839 |
| 280 return PP_OK_COMPLETIONPENDING; | 840 return PP_OK_COMPLETIONPENDING; |
| 281 } | 841 } |
| 282 | 842 |
| 283 int32_t PepperVideoDecoderHost::OnHostMsgReset( | 843 int32_t PepperVideoDecoderHost::OnHostMsgReset( |
| 284 ppapi::host::HostMessageContext* context) { | 844 ppapi::host::HostMessageContext* context) { |
| 285 if (!initialized_) | 845 if (!initialized_) |
| 286 return PP_ERROR_FAILED; | 846 return PP_ERROR_FAILED; |
| 287 DCHECK(decoder_); | 847 DCHECK(decoder_ || software_decoder_); |
| 288 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid()) | 848 if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid()) |
| 289 return PP_ERROR_FAILED; | 849 return PP_ERROR_FAILED; |
| 290 | 850 |
| 291 reset_reply_context_ = context->MakeReplyMessageContext(); | 851 reset_reply_context_ = context->MakeReplyMessageContext(); |
| 292 decoder_->Reset(); | 852 if (decoder_) |
| 853 decoder_->Reset(); | |
| 854 else | |
| 855 software_decoder_->Reset(); | |
| 293 | 856 |
| 294 return PP_OK_COMPLETIONPENDING; | 857 return PP_OK_COMPLETIONPENDING; |
| 295 } | 858 } |
| 296 | 859 |
| 297 void PepperVideoDecoderHost::ProvidePictureBuffers( | 860 void PepperVideoDecoderHost::ProvidePictureBuffers( |
| 298 uint32 requested_num_of_buffers, | 861 uint32 requested_num_of_buffers, |
| 299 const gfx::Size& dimensions, | 862 const gfx::Size& dimensions, |
| 300 uint32 texture_target) { | 863 uint32 texture_target) { |
| 301 DCHECK(RenderThreadImpl::current()); | 864 RequestTextures(requested_num_of_buffers, |
| 302 host()->SendUnsolicitedReply( | 865 dimensions, |
| 303 pp_resource(), | 866 texture_target, |
| 304 PpapiPluginMsg_VideoDecoder_RequestTextures( | 867 std::vector<gpu::Mailbox>()); |
| 305 requested_num_of_buffers, | |
| 306 PP_MakeSize(dimensions.width(), dimensions.height()), | |
| 307 texture_target)); | |
| 308 } | 868 } |
| 309 | 869 |
| 310 void PepperVideoDecoderHost::PictureReady(const media::Picture& picture) { | 870 void PepperVideoDecoderHost::PictureReady(const media::Picture& picture) { |
| 311 DCHECK(RenderThreadImpl::current()); | |
| 312 host()->SendUnsolicitedReply( | 871 host()->SendUnsolicitedReply( |
| 313 pp_resource(), | 872 pp_resource(), |
| 314 PpapiPluginMsg_VideoDecoder_PictureReady(picture.bitstream_buffer_id(), | 873 PpapiPluginMsg_VideoDecoder_PictureReady(picture.bitstream_buffer_id(), |
| 315 picture.picture_buffer_id())); | 874 picture.picture_buffer_id())); |
| 316 } | 875 } |
| 317 | 876 |
| 318 void PepperVideoDecoderHost::DismissPictureBuffer(int32 picture_buffer_id) { | 877 void PepperVideoDecoderHost::DismissPictureBuffer(int32 picture_buffer_id) { |
| 319 DCHECK(RenderThreadImpl::current()); | |
| 320 host()->SendUnsolicitedReply( | 878 host()->SendUnsolicitedReply( |
| 321 pp_resource(), | 879 pp_resource(), |
| 322 PpapiPluginMsg_VideoDecoder_DismissPicture(picture_buffer_id)); | 880 PpapiPluginMsg_VideoDecoder_DismissPicture(picture_buffer_id)); |
| 323 } | 881 } |
| 324 | 882 |
| 883 void PepperVideoDecoderHost::NotifyEndOfBitstreamBuffer( | |
| 884 int32 bitstream_buffer_id) { | |
| 885 PendingDecodeMap::iterator it = pending_decodes_.find(bitstream_buffer_id); | |
| 886 if (it == pending_decodes_.end()) { | |
| 887 NOTREACHED(); | |
| 888 return; | |
| 889 } | |
| 890 const PendingDecode& pending_decode = it->second; | |
| 891 host()->SendReply( | |
| 892 pending_decode.reply_context, | |
| 893 PpapiPluginMsg_VideoDecoder_DecodeReply(pending_decode.shm_id)); | |
| 894 shm_buffer_busy_[pending_decode.shm_id] = false; | |
| 895 pending_decodes_.erase(it); | |
| 896 } | |
| 897 | |
| 898 void PepperVideoDecoderHost::NotifyFlushDone() { | |
| 899 host()->SendReply(flush_reply_context_, | |
| 900 PpapiPluginMsg_VideoDecoder_FlushReply()); | |
| 901 flush_reply_context_ = ppapi::host::ReplyMessageContext(); | |
| 902 } | |
| 903 | |
| 904 void PepperVideoDecoderHost::NotifyResetDone() { | |
| 905 host()->SendReply(reset_reply_context_, | |
| 906 PpapiPluginMsg_VideoDecoder_ResetReply()); | |
| 907 reset_reply_context_ = ppapi::host::ReplyMessageContext(); | |
| 908 } | |
| 909 | |
| 325 void PepperVideoDecoderHost::NotifyError( | 910 void PepperVideoDecoderHost::NotifyError( |
| 326 media::VideoDecodeAccelerator::Error error) { | 911 media::VideoDecodeAccelerator::Error error) { |
| 327 DCHECK(RenderThreadImpl::current()); | |
| 328 int32_t pp_error = PP_ERROR_FAILED; | 912 int32_t pp_error = PP_ERROR_FAILED; |
| 329 switch (error) { | 913 switch (error) { |
| 330 case media::VideoDecodeAccelerator::UNREADABLE_INPUT: | 914 case media::VideoDecodeAccelerator::UNREADABLE_INPUT: |
| 331 pp_error = PP_ERROR_MALFORMED_INPUT; | 915 pp_error = PP_ERROR_MALFORMED_INPUT; |
| 332 break; | 916 break; |
| 333 case media::VideoDecodeAccelerator::ILLEGAL_STATE: | 917 case media::VideoDecodeAccelerator::ILLEGAL_STATE: |
| 334 case media::VideoDecodeAccelerator::INVALID_ARGUMENT: | 918 case media::VideoDecodeAccelerator::INVALID_ARGUMENT: |
| 335 case media::VideoDecodeAccelerator::PLATFORM_FAILURE: | 919 case media::VideoDecodeAccelerator::PLATFORM_FAILURE: |
| 336 case media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM: | 920 case media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM: |
| 337 pp_error = PP_ERROR_RESOURCE_FAILED; | 921 pp_error = PP_ERROR_RESOURCE_FAILED; |
| 338 break; | 922 break; |
| 339 // No default case, to catch unhandled enum values. | 923 // No default case, to catch unhandled enum values. |
| 340 } | 924 } |
| 925 NotifyError(pp_error); | |
| 926 } | |
| 927 | |
| 928 void PepperVideoDecoderHost::OnInitializeComplete(int32_t result) { | |
| 929 if (!initialized_) { | |
| 930 initialized_ = true; | |
| 931 initialize_reply_context_.params.set_result(result); | |
| 932 host()->SendReply(initialize_reply_context_, | |
| 933 PpapiPluginMsg_VideoDecoder_InitializeReply()); | |
| 934 } | |
| 935 } | |
| 936 | |
| 937 void PepperVideoDecoderHost::RequestTextures( | |
| 938 uint32 requested_num_of_buffers, | |
| 939 const gfx::Size& dimensions, | |
| 940 uint32 texture_target, | |
| 941 const std::vector<gpu::Mailbox>& mailboxes) { | |
| 942 DCHECK(RenderThreadImpl::current()); | |
| 943 host()->SendUnsolicitedReply( | |
| 944 pp_resource(), | |
| 945 PpapiPluginMsg_VideoDecoder_RequestTextures( | |
| 946 requested_num_of_buffers, | |
| 947 PP_MakeSize(dimensions.width(), dimensions.height()), | |
| 948 texture_target, | |
| 949 mailboxes)); | |
| 950 } | |
| 951 | |
| 952 void PepperVideoDecoderHost::NotifyError(int32_t pp_error) { | |
| 341 host()->SendUnsolicitedReply( | 953 host()->SendUnsolicitedReply( |
| 342 pp_resource(), PpapiPluginMsg_VideoDecoder_NotifyError(pp_error)); | 954 pp_resource(), PpapiPluginMsg_VideoDecoder_NotifyError(pp_error)); |
| 343 } | 955 } |
| 344 | 956 |
| 345 void PepperVideoDecoderHost::NotifyResetDone() { | 957 } // namespace content |
| 346 DCHECK(RenderThreadImpl::current()); | 958 |
| 347 host()->SendReply(reset_reply_context_, | 959 namespace base { |
| 348 PpapiPluginMsg_VideoDecoder_ResetReply()); | 960 |
| 349 reset_reply_context_ = ppapi::host::ReplyMessageContext(); | 961 void DefaultDeleter<content::SoftwareDecoder>::operator()( |
| 962 void* software_decoder) const { | |
| 963 static_cast<content::SoftwareDecoder*>(software_decoder)->Destroy(); | |
| 350 } | 964 } |
| 351 | 965 |
| 352 void PepperVideoDecoderHost::NotifyEndOfBitstreamBuffer( | 966 } // namespace base |
| 353 int32 bitstream_buffer_id) { | |
| 354 DCHECK(RenderThreadImpl::current()); | |
| 355 PendingDecodeMap::iterator it = pending_decodes_.find(bitstream_buffer_id); | |
| 356 if (it == pending_decodes_.end()) { | |
| 357 NOTREACHED(); | |
| 358 return; | |
| 359 } | |
| 360 const PendingDecode& pending_decode = it->second; | |
| 361 host()->SendReply( | |
| 362 pending_decode.reply_context, | |
| 363 PpapiPluginMsg_VideoDecoder_DecodeReply(pending_decode.shm_id)); | |
| 364 shm_buffer_busy_[pending_decode.shm_id] = false; | |
| 365 pending_decodes_.erase(it); | |
| 366 } | |
| 367 | |
| 368 void PepperVideoDecoderHost::NotifyFlushDone() { | |
| 369 DCHECK(RenderThreadImpl::current()); | |
| 370 host()->SendReply(flush_reply_context_, | |
| 371 PpapiPluginMsg_VideoDecoder_FlushReply()); | |
| 372 flush_reply_context_ = ppapi::host::ReplyMessageContext(); | |
| 373 } | |
| 374 | |
| 375 } // namespace content | |
| OLD | NEW |