Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include <GLES2/gl2.h> | |
| 6 #include <GLES2/gl2ext.h> | |
| 7 #include <GLES2/gl2extchromium.h> | |
| 8 | |
| 9 #include "content/renderer/pepper/video_decoder_shim.h" | |
| 10 | |
| 11 #include "base/bind.h" | |
| 12 #include "base/numerics/safe_conversions.h" | |
| 13 #include "content/public/renderer/render_thread.h" | |
| 14 #include "content/renderer/pepper/pepper_video_decoder_host.h" | |
| 15 #include "content/renderer/render_thread_impl.h" | |
| 16 #include "gpu/command_buffer/client/gles2_implementation.h" | |
| 17 #include "media/base/decoder_buffer.h" | |
| 18 #include "media/base/limits.h" | |
| 19 #include "media/base/video_decoder.h" | |
| 20 #include "media/filters/ffmpeg_video_decoder.h" | |
| 21 #include "media/video/picture.h" | |
| 22 #include "media/video/video_decode_accelerator.h" | |
| 23 #include "ppapi/c/pp_errors.h" | |
| 24 #include "third_party/libyuv/include/libyuv.h" | |
| 25 #include "webkit/common/gpu/context_provider_web_context.h" | |
| 26 | |
| 27 namespace content { | |
| 28 | |
| 29 struct VideoDecoderShim::PendingDecode { | |
| 30 PendingDecode(uint32_t decode_id, | |
| 31 const scoped_refptr<media::DecoderBuffer>& buffer); | |
| 32 ~PendingDecode(); | |
| 33 | |
| 34 const uint32_t decode_id; | |
| 35 const scoped_refptr<media::DecoderBuffer> buffer; | |
| 36 }; | |
| 37 | |
| 38 VideoDecoderShim::PendingDecode::PendingDecode( | |
| 39 uint32_t decode_id, | |
| 40 const scoped_refptr<media::DecoderBuffer>& buffer) | |
| 41 : decode_id(decode_id), buffer(buffer) { | |
| 42 } | |
| 43 | |
| 44 VideoDecoderShim::PendingDecode::~PendingDecode() { | |
| 45 } | |
| 46 | |
| 47 struct VideoDecoderShim::PendingFrame { | |
| 48 explicit PendingFrame(uint32_t decode_id); | |
| 49 PendingFrame(uint32_t decode_id, const gfx::Size& size); | |
| 50 ~PendingFrame(); | |
| 51 | |
| 52 const uint32_t decode_id; | |
| 53 const gfx::Size size; | |
| 54 std::vector<uint8_t> argb_pixels; | |
| 55 | |
| 56 private: | |
| 57 // This could be expensive to copy, so guard against that. | |
| 58 DISALLOW_COPY_AND_ASSIGN(PendingFrame); | |
| 59 }; | |
| 60 | |
| 61 VideoDecoderShim::PendingFrame::PendingFrame(uint32_t decode_id) | |
| 62 : decode_id(decode_id) { | |
| 63 } | |
| 64 | |
| 65 VideoDecoderShim::PendingFrame::PendingFrame(uint32_t decode_id, | |
| 66 const gfx::Size& size) | |
| 67 : decode_id(decode_id), | |
| 68 size(size), | |
| 69 argb_pixels(size.width() * size.height() * 4) { | |
| 70 } | |
| 71 | |
| 72 VideoDecoderShim::PendingFrame::~PendingFrame() { | |
| 73 } | |
| 74 | |
| 75 // DecoderImpl runs the underlying VideoDecoder on the media thread, receiving | |
| 76 // calls from the VideoDecodeShim on the main thread and sending results back. | |
| 77 // This class is constructed on the main thread, but used and destructed on the | |
| 78 // media thread. | |
| 79 class VideoDecoderShim::DecoderImpl { | |
| 80 public: | |
| 81 explicit DecoderImpl(const base::WeakPtr<VideoDecoderShim>& proxy); | |
| 82 ~DecoderImpl(); | |
| 83 | |
| 84 void Initialize(media::VideoDecoderConfig config); | |
| 85 void Decode(uint32_t decode_id, scoped_refptr<media::DecoderBuffer> buffer); | |
| 86 void Reset(); | |
| 87 void Stop(); | |
| 88 | |
| 89 private: | |
| 90 void OnPipelineStatus(media::PipelineStatus status); | |
| 91 void DoDecode(); | |
| 92 void OnDecodeComplete(uint32_t decode_id, | |
| 93 media::VideoDecoder::Status status, | |
| 94 const scoped_refptr<media::VideoFrame>& frame); | |
| 95 void OnResetComplete(); | |
| 96 | |
| 97 // WeakPtr is bound to main_message_loop_. Use only in shim callbacks. | |
| 98 base::WeakPtr<VideoDecoderShim> shim_; | |
| 99 scoped_ptr<media::VideoDecoder> decoder_; | |
| 100 scoped_refptr<base::MessageLoopProxy> main_message_loop_; | |
| 101 // Queue of decodes waiting for the decoder. | |
| 102 typedef std::queue<PendingDecode> PendingDecodeQueue; | |
| 103 PendingDecodeQueue pending_decodes_; | |
| 104 int max_decodes_at_decoder_; | |
| 105 int num_decodes_at_decoder_; | |
| 106 }; | |
| 107 | |
| 108 VideoDecoderShim::DecoderImpl::DecoderImpl( | |
| 109 const base::WeakPtr<VideoDecoderShim>& proxy) | |
| 110 : shim_(proxy), | |
| 111 main_message_loop_(base::MessageLoopProxy::current()), | |
| 112 max_decodes_at_decoder_(0), | |
| 113 num_decodes_at_decoder_(0) { | |
| 114 } | |
| 115 | |
| 116 VideoDecoderShim::DecoderImpl::~DecoderImpl() { | |
| 117 DCHECK(pending_decodes_.empty()); | |
| 118 } | |
| 119 | |
| 120 void VideoDecoderShim::DecoderImpl::Initialize( | |
| 121 media::VideoDecoderConfig config) { | |
| 122 DCHECK(!decoder_); | |
| 123 decoder_.reset( | |
| 124 new media::FFmpegVideoDecoder(base::MessageLoopProxy::current())); | |
| 125 max_decodes_at_decoder_ = decoder_->GetMaxDecodeRequests(); | |
| 126 // We can use base::Unretained() safely in decoder callbacks because we call | |
| 127 // VideoDecoder::Stop() before deletion. Stop() guarantees there will be no | |
| 128 // outstanding callbacks after it returns. | |
| 129 decoder_->Initialize( | |
| 130 config, | |
| 131 true /* low_delay */, | |
|
Ami GONE FROM CHROMIUM
2014/06/07 18:26:40
Igor: the commentary on your new API is that it di
igorc
2014/06/11 20:13:18
It could be poor commenting and/or incomplete unde
DaleCurtis
2014/06/11 21:08:08
The comment is incorrect / opposite and should pro
igorc
2014/06/11 22:30:08
Just spoke to Dale, and we agreed to delete "Disab
| |
| 132 base::Bind(&VideoDecoderShim::DecoderImpl::OnPipelineStatus, | |
| 133 base::Unretained(this))); | |
| 134 } | |
| 135 | |
| 136 void VideoDecoderShim::DecoderImpl::OnPipelineStatus( | |
| 137 media::PipelineStatus status) { | |
| 138 int32_t result; | |
| 139 switch (status) { | |
| 140 case media::PIPELINE_OK: | |
| 141 result = PP_OK; | |
| 142 break; | |
| 143 case media::DECODER_ERROR_NOT_SUPPORTED: | |
| 144 result = PP_ERROR_NOTSUPPORTED; | |
| 145 break; | |
| 146 default: | |
| 147 result = PP_ERROR_FAILED; | |
| 148 break; | |
| 149 } | |
| 150 | |
| 151 // Calculate how many textures the shim should create. | |
| 152 uint32_t texture_pool_size = | |
| 153 max_decodes_at_decoder_ + media::limits::kMaxVideoFrames; | |
| 154 main_message_loop_->PostTask( | |
| 155 FROM_HERE, | |
| 156 base::Bind(&VideoDecoderShim::OnInitializeComplete, | |
| 157 shim_, | |
| 158 result, | |
| 159 texture_pool_size)); | |
| 160 } | |
| 161 | |
| 162 void VideoDecoderShim::DecoderImpl::Decode( | |
| 163 uint32_t decode_id, | |
| 164 scoped_refptr<media::DecoderBuffer> buffer) { | |
| 165 DCHECK(decoder_); | |
| 166 pending_decodes_.push(PendingDecode(decode_id, buffer)); | |
| 167 DoDecode(); | |
|
Ami GONE FROM CHROMIUM
2014/06/07 18:26:40
lol I start out thinking it was a bug but convince
bbudge
2014/06/07 21:28:33
I am still searching for some way to test this mor
| |
| 168 } | |
| 169 | |
| 170 void VideoDecoderShim::DecoderImpl::Reset() { | |
| 171 DCHECK(decoder_); | |
| 172 // Abort all pending decodes. | |
| 173 while (!pending_decodes_.empty()) { | |
| 174 const PendingDecode& decode = pending_decodes_.front(); | |
| 175 scoped_ptr<PendingFrame> pending_frame(new PendingFrame(decode.decode_id)); | |
| 176 main_message_loop_->PostTask(FROM_HERE, | |
| 177 base::Bind(&VideoDecoderShim::OnDecodeComplete, | |
| 178 shim_, | |
| 179 media::VideoDecoder::kAborted, | |
| 180 base::Passed(&pending_frame))); | |
| 181 pending_decodes_.pop(); | |
| 182 } | |
| 183 decoder_->Reset(base::Bind(&VideoDecoderShim::DecoderImpl::OnResetComplete, | |
| 184 base::Unretained(this))); | |
| 185 } | |
| 186 | |
| 187 void VideoDecoderShim::DecoderImpl::Stop() { | |
| 188 DCHECK(decoder_); | |
| 189 // Clear pending decodes now. We don't want OnDecodeComplete to call Decode | |
| 190 // again. | |
| 191 while (!pending_decodes_.empty()) | |
| 192 pending_decodes_.pop(); | |
| 193 decoder_->Stop(); | |
| 194 // This instance is deleted once we exit this scope. | |
| 195 } | |
| 196 | |
| 197 void VideoDecoderShim::DecoderImpl::DoDecode() { | |
| 198 while (!pending_decodes_.empty() && | |
| 199 num_decodes_at_decoder_ < max_decodes_at_decoder_) { | |
| 200 num_decodes_at_decoder_++; | |
| 201 const PendingDecode& decode = pending_decodes_.front(); | |
| 202 decoder_->Decode( | |
| 203 decode.buffer, | |
| 204 base::Bind(&VideoDecoderShim::DecoderImpl::OnDecodeComplete, | |
| 205 base::Unretained(this), | |
| 206 decode.decode_id)); | |
| 207 pending_decodes_.pop(); | |
| 208 } | |
| 209 } | |
| 210 | |
| 211 void VideoDecoderShim::DecoderImpl::OnDecodeComplete( | |
| 212 uint32_t decode_id, | |
| 213 media::VideoDecoder::Status status, | |
| 214 const scoped_refptr<media::VideoFrame>& frame) { | |
| 215 num_decodes_at_decoder_--; | |
| 216 scoped_ptr<PendingFrame> pending_frame; | |
| 217 if (status == media::VideoDecoder::kOk && !frame->end_of_stream()) { | |
| 218 pending_frame.reset(new PendingFrame(decode_id, frame->coded_size())); | |
| 219 // Convert the VideoFrame pixels to ARGB. | |
| 220 libyuv::I420ToARGB(frame->data(media::VideoFrame::kYPlane), | |
| 221 frame->stride(media::VideoFrame::kYPlane), | |
| 222 frame->data(media::VideoFrame::kUPlane), | |
| 223 frame->stride(media::VideoFrame::kUPlane), | |
| 224 frame->data(media::VideoFrame::kVPlane), | |
| 225 frame->stride(media::VideoFrame::kVPlane), | |
| 226 &pending_frame->argb_pixels.front(), | |
| 227 frame->coded_size().width() * 4, | |
| 228 frame->coded_size().width(), | |
| 229 frame->coded_size().height()); | |
| 230 } else { | |
| 231 pending_frame.reset(new PendingFrame(decode_id)); | |
| 232 } | |
| 233 | |
| 234 int32_t result; | |
| 235 switch (status) { | |
| 236 case media::VideoDecoder::kOk: | |
| 237 // We allow partial frames, so this is OK. | |
| 238 case media::VideoDecoder::kNotEnoughData: | |
| 239 result = PP_OK; | |
| 240 break; | |
| 241 case media::VideoDecoder::kAborted: | |
| 242 result = PP_ERROR_ABORTED; | |
| 243 break; | |
| 244 case media::VideoDecoder::kDecodeError: | |
| 245 result = PP_ERROR_RESOURCE_FAILED; | |
| 246 break; | |
| 247 default: | |
| 248 NOTREACHED(); | |
| 249 result = PP_ERROR_FAILED; | |
| 250 break; | |
| 251 } | |
| 252 | |
| 253 main_message_loop_->PostTask(FROM_HERE, | |
| 254 base::Bind(&VideoDecoderShim::OnDecodeComplete, | |
| 255 shim_, | |
| 256 result, | |
| 257 base::Passed(&pending_frame))); | |
| 258 | |
| 259 DoDecode(); | |
| 260 } | |
| 261 | |
| 262 void VideoDecoderShim::DecoderImpl::OnResetComplete() { | |
| 263 main_message_loop_->PostTask( | |
| 264 FROM_HERE, base::Bind(&VideoDecoderShim::OnResetComplete, shim_)); | |
| 265 } | |
| 266 | |
| 267 VideoDecoderShim::VideoDecoderShim(PepperVideoDecoderHost* host) | |
| 268 : state_(UNINITIALIZED), | |
| 269 host_(host), | |
| 270 media_message_loop_( | |
| 271 RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy()), | |
| 272 context_provider_( | |
| 273 RenderThreadImpl::current()->SharedMainThreadContextProvider()), | |
| 274 num_pending_decodes_(0), | |
| 275 texture_pool_size_(0), | |
| 276 weak_ptr_factory_(this) { | |
| 277 DCHECK(host_); | |
| 278 DCHECK(media_message_loop_); | |
| 279 DCHECK(context_provider_); | |
| 280 decoder_impl_.reset(new DecoderImpl(weak_ptr_factory_.GetWeakPtr())); | |
| 281 } | |
| 282 | |
| 283 VideoDecoderShim::~VideoDecoderShim() { | |
| 284 DCHECK(RenderThreadImpl::current()); | |
| 285 // Delete any remaining textures. | |
| 286 TextureIdMap::iterator it = texture_id_map_.begin(); | |
| 287 for (; it != texture_id_map_.end(); ++it) | |
| 288 DeleteTexture(it->second); | |
| 289 texture_id_map_.clear(); | |
| 290 | |
| 291 FlushCommandBuffer(); | |
| 292 | |
| 293 host_ = NULL; | |
| 294 // No methods can post tasks to the delegate now. | |
| 295 weak_ptr_factory_.InvalidateWeakPtrs(); | |
| 296 // No more callbacks from the delegate will be received now. | |
| 297 | |
| 298 // The callback now holds the only reference to the DecoderImpl, which will be | |
| 299 // deleted when Stop completes. | |
| 300 media_message_loop_->PostTask( | |
| 301 FROM_HERE, | |
| 302 base::Bind(&VideoDecoderShim::DecoderImpl::Stop, | |
| 303 base::Owned(decoder_impl_.release()))); | |
| 304 | |
| 305 } | |
| 306 | |
| 307 bool VideoDecoderShim::Initialize( | |
| 308 media::VideoCodecProfile profile, | |
| 309 media::VideoDecodeAccelerator::Client* client) { | |
| 310 // Ignore the |client| parameter, which is the same as |host_|. | |
|
Ami GONE FROM CHROMIUM
2014/06/07 18:26:39
DCHECK this instead of the comment?
bbudge
2014/06/07 21:28:33
Done.
| |
| 311 DCHECK(RenderThreadImpl::current()); | |
| 312 DCHECK_EQ(state_, UNINITIALIZED); | |
| 313 media::VideoCodec codec = media::kUnknownVideoCodec; | |
| 314 if (profile <= media::H264PROFILE_MAX) | |
| 315 codec = media::kCodecH264; | |
| 316 else if (profile <= media::VP8PROFILE_MAX) | |
| 317 codec = media::kCodecVP8; | |
| 318 DCHECK_NE(codec, media::kUnknownVideoCodec); | |
| 319 | |
| 320 media::VideoDecoderConfig config( | |
| 321 codec, | |
| 322 profile, | |
| 323 media::VideoFrame::YV12, | |
| 324 gfx::Size(32, 24), // Small sizes that won't fail. | |
| 325 gfx::Rect(32, 24), | |
| 326 gfx::Size(32, 24), | |
| 327 NULL /* extra_data */, // TODO(bbudge) Verify this isn't needed. | |
| 328 0 /* extra_data_size */, | |
| 329 false /* decryption */); | |
| 330 | |
| 331 media_message_loop_->PostTask( | |
| 332 FROM_HERE, | |
| 333 base::Bind(&VideoDecoderShim::DecoderImpl::Initialize, | |
| 334 base::Unretained(decoder_impl_.get()), | |
| 335 config)); | |
| 336 // Return success, even though we are asynchronous, to mimic | |
| 337 // media::VideoDecodeAccelerator. | |
| 338 return true; | |
| 339 } | |
| 340 | |
| 341 void VideoDecoderShim::Decode(const media::BitstreamBuffer& bitstream_buffer) { | |
| 342 DCHECK(RenderThreadImpl::current()); | |
| 343 DCHECK_EQ(state_, DECODING); | |
| 344 | |
| 345 num_pending_decodes_++; | |
| 346 | |
| 347 // We need the address of the shared memory, so we can copy into our buffer. | |
| 348 const uint8_t* buffer = host_->ShmHandleToAddress(bitstream_buffer.handle()); | |
| 349 DCHECK(buffer); | |
| 350 | |
| 351 media_message_loop_->PostTask( | |
| 352 FROM_HERE, | |
| 353 base::Bind( | |
| 354 &VideoDecoderShim::DecoderImpl::Decode, | |
| 355 base::Unretained(decoder_impl_.get()), | |
| 356 bitstream_buffer.id(), | |
| 357 media::DecoderBuffer::CopyFrom(buffer, bitstream_buffer.size()))); | |
| 358 } | |
| 359 | |
| 360 void VideoDecoderShim::AssignPictureBuffers( | |
| 361 const std::vector<media::PictureBuffer>& buffers) { | |
| 362 DCHECK(RenderThreadImpl::current()); | |
| 363 DCHECK_EQ(state_, DECODING); | |
| 364 if (buffers.empty()) { | |
| 365 NOTREACHED(); | |
| 366 return; | |
| 367 } | |
| 368 DCHECK_EQ(buffers.size(), pending_texture_mailboxes_.size()); | |
| 369 GLuint num_textures = base::checked_cast<GLuint>(buffers.size()); | |
| 370 std::vector<uint32_t> local_texture_ids(num_textures); | |
| 371 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL(); | |
| 372 gles2->GenTextures(num_textures, &local_texture_ids.front()); | |
| 373 for (uint32_t i = 0; i < num_textures; i++) { | |
| 374 gles2->ActiveTexture(GL_TEXTURE0); | |
| 375 gles2->BindTexture(GL_TEXTURE_2D, local_texture_ids[i]); | |
| 376 gles2->ConsumeTextureCHROMIUM(GL_TEXTURE_2D, | |
| 377 pending_texture_mailboxes_[i].name); | |
| 378 // Map the plugin texture id to the local texture id. | |
| 379 uint32_t plugin_texture_id = buffers[i].texture_id(); | |
| 380 texture_id_map_[plugin_texture_id] = local_texture_ids[i]; | |
| 381 available_textures_.push_back(plugin_texture_id); | |
| 382 } | |
| 383 pending_texture_mailboxes_.clear(); | |
| 384 SendPictures(); | |
| 385 } | |
| 386 | |
| 387 void VideoDecoderShim::ReusePictureBuffer(int32 picture_buffer_id) { | |
| 388 DCHECK(RenderThreadImpl::current()); | |
| 389 uint32_t texture_id = static_cast<uint32_t>(picture_buffer_id); | |
| 390 if (textures_to_dismiss_.find(texture_id) != textures_to_dismiss_.end()) { | |
| 391 DismissTexture(texture_id); | |
| 392 } else if (texture_id_map_.find(texture_id) != texture_id_map_.end()) { | |
| 393 available_textures_.push_back(texture_id); | |
| 394 SendPictures(); | |
| 395 } else { | |
| 396 NOTREACHED(); | |
| 397 } | |
| 398 } | |
| 399 | |
| 400 void VideoDecoderShim::Flush() { | |
| 401 DCHECK(RenderThreadImpl::current()); | |
| 402 DCHECK_EQ(state_, DECODING); | |
| 403 state_ = FLUSHING; | |
| 404 } | |
| 405 | |
| 406 void VideoDecoderShim::Reset() { | |
| 407 DCHECK(RenderThreadImpl::current()); | |
| 408 DCHECK_EQ(state_, DECODING); | |
| 409 state_ = RESETTING; | |
| 410 media_message_loop_->PostTask( | |
| 411 FROM_HERE, | |
| 412 base::Bind(&VideoDecoderShim::DecoderImpl::Reset, | |
| 413 base::Unretained(decoder_impl_.get()))); | |
| 414 } | |
| 415 | |
| 416 void VideoDecoderShim::Destroy() { | |
| 417 // This will be called, but our destructor can do the actual work. | |
| 418 } | |
| 419 | |
| 420 void VideoDecoderShim::OnInitializeComplete(int32_t result, | |
| 421 uint32_t texture_pool_size) { | |
| 422 DCHECK(RenderThreadImpl::current()); | |
| 423 DCHECK(host_); | |
| 424 | |
| 425 if (result == PP_OK) { | |
| 426 state_ = DECODING; | |
| 427 texture_pool_size_ = texture_pool_size; | |
| 428 } | |
| 429 | |
| 430 host_->OnInitializeComplete(result); | |
| 431 } | |
| 432 | |
| 433 void VideoDecoderShim::OnDecodeComplete(int32_t result, | |
| 434 scoped_ptr<PendingFrame> frame) { | |
| 435 DCHECK(RenderThreadImpl::current()); | |
| 436 DCHECK(host_); | |
| 437 | |
| 438 num_pending_decodes_--; | |
| 439 | |
| 440 if (result == PP_OK && !frame->argb_pixels.empty()) { | |
| 441 if (texture_size_ != frame->size) { | |
| 442 // If the size has changed, all current textures must be dismissed. Add | |
| 443 // all textures to |textures_to_dismiss_| and dismiss any that aren't in | |
| 444 // use by the plugin. We dismiss the rest as they are recycled. | |
| 445 for (TextureIdMap::const_iterator it = texture_id_map_.begin(); | |
| 446 it != texture_id_map_.end(); | |
| 447 ++it) { | |
| 448 textures_to_dismiss_.insert(it->second); | |
| 449 } | |
| 450 for (std::vector<uint32_t>::const_iterator it = | |
| 451 available_textures_.begin(); | |
| 452 it != available_textures_.end(); | |
| 453 ++it) { | |
| 454 DismissTexture(*it); | |
| 455 } | |
| 456 available_textures_.clear(); | |
| 457 FlushCommandBuffer(); | |
| 458 | |
| 459 DCHECK(pending_texture_mailboxes_.empty()); | |
| 460 for (uint32_t i = 0; i < texture_pool_size_; i++) | |
| 461 pending_texture_mailboxes_.push_back(gpu::Mailbox::Generate()); | |
| 462 | |
| 463 host_->RequestTextures(texture_pool_size_, | |
| 464 frame->size, | |
| 465 GL_TEXTURE_2D, | |
| 466 pending_texture_mailboxes_); | |
| 467 texture_size_ = frame->size; | |
| 468 } | |
| 469 | |
| 470 pending_frames_.push(linked_ptr<PendingFrame>(frame.release())); | |
| 471 SendPictures(); | |
| 472 } else { | |
| 473 host_->NotifyEndOfBitstreamBuffer(frame->decode_id); | |
| 474 } | |
| 475 | |
| 476 // Report any VDA type errors. | |
| 477 if (result == PP_ERROR_RESOURCE_FAILED) | |
| 478 host_->NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); | |
| 479 } | |
| 480 | |
| 481 void VideoDecoderShim::SendPictures() { | |
| 482 DCHECK(RenderThreadImpl::current()); | |
| 483 DCHECK(host_); | |
| 484 | |
| 485 while (!pending_frames_.empty() && !available_textures_.empty()) { | |
| 486 const linked_ptr<PendingFrame>& frame = pending_frames_.front(); | |
| 487 | |
| 488 uint32_t texture_id = available_textures_.back(); | |
| 489 available_textures_.pop_back(); | |
| 490 | |
| 491 uint32_t local_texture_id = texture_id_map_[texture_id]; | |
| 492 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL(); | |
| 493 gles2->ActiveTexture(GL_TEXTURE0); | |
| 494 gles2->BindTexture(GL_TEXTURE_2D, local_texture_id); | |
| 495 gles2->TexImage2D(GL_TEXTURE_2D, | |
| 496 0, | |
| 497 GL_RGBA, | |
| 498 texture_size_.width(), | |
| 499 texture_size_.height(), | |
| 500 0, | |
| 501 GL_RGBA, | |
| 502 GL_UNSIGNED_BYTE, | |
| 503 &frame->argb_pixels.front()); | |
| 504 | |
| 505 host_->NotifyEndOfBitstreamBuffer(frame->decode_id); | |
| 506 host_->PictureReady(media::Picture(texture_id, frame->decode_id)); | |
| 507 pending_frames_.pop(); | |
| 508 } | |
| 509 | |
| 510 FlushCommandBuffer(); | |
| 511 | |
| 512 if (state_ == FLUSHING && !num_pending_decodes_ && pending_frames_.empty()) { | |
| 513 state_ = DECODING; | |
| 514 host_->NotifyFlushDone(); | |
| 515 } | |
| 516 } | |
| 517 | |
| 518 void VideoDecoderShim::OnResetComplete() { | |
| 519 DCHECK(RenderThreadImpl::current()); | |
| 520 DCHECK(host_); | |
| 521 | |
| 522 while (!pending_frames_.empty()) { | |
| 523 const linked_ptr<PendingFrame>& frame = pending_frames_.front(); | |
| 524 host_->NotifyEndOfBitstreamBuffer(frame->decode_id); | |
| 525 pending_frames_.pop(); | |
| 526 } | |
| 527 | |
| 528 state_ = DECODING; | |
| 529 host_->NotifyResetDone(); | |
| 530 } | |
| 531 | |
| 532 void VideoDecoderShim::DismissTexture(uint32_t texture_id) { | |
| 533 DCHECK(host_); | |
| 534 textures_to_dismiss_.erase(texture_id); | |
| 535 DCHECK(texture_id_map_.find(texture_id) != texture_id_map_.end()); | |
| 536 DeleteTexture(texture_id_map_[texture_id]); | |
| 537 texture_id_map_.erase(texture_id); | |
| 538 host_->DismissPictureBuffer(texture_id); | |
| 539 } | |
| 540 | |
| 541 void VideoDecoderShim::DeleteTexture(uint32_t texture_id) { | |
| 542 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL(); | |
| 543 gles2->DeleteTextures(1, &texture_id); | |
| 544 } | |
| 545 | |
| 546 void VideoDecoderShim::FlushCommandBuffer() { | |
| 547 context_provider_->ContextGL()->Flush(); | |
| 548 } | |
| 549 | |
| 550 } // namespace content | |
| OLD | NEW |