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_adapter.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/filters/ffmpeg_video_decoder.h" | |
| 19 #include "media/video/picture.h" | |
| 20 #include "media/video/video_decode_accelerator.h" | |
| 21 #include "ppapi/c/pp_errors.h" | |
| 22 #include "third_party/libyuv/include/libyuv.h" | |
| 23 #include "webkit/common/gpu/context_provider_web_context.h" | |
| 24 | |
| 25 namespace content { | |
| 26 | |
| 27 struct VideoDecoderAdapter::PendingDecode { | |
| 28 PendingDecode(uint32_t decode_id, | |
| 29 const scoped_refptr<media::DecoderBuffer>& buffer); | |
| 30 ~PendingDecode(); | |
| 31 | |
| 32 const uint32_t decode_id; | |
| 33 const scoped_refptr<media::DecoderBuffer> buffer; | |
| 34 }; | |
| 35 | |
| 36 VideoDecoderAdapter::PendingDecode::PendingDecode( | |
| 37 uint32_t decode_id, | |
| 38 const scoped_refptr<media::DecoderBuffer>& buffer) | |
| 39 : decode_id(decode_id), buffer(buffer) { | |
| 40 } | |
| 41 | |
| 42 VideoDecoderAdapter::PendingDecode::~PendingDecode() { | |
| 43 } | |
| 44 | |
| 45 struct VideoDecoderAdapter::PendingFrame { | |
| 46 explicit PendingFrame(uint32_t decode_id); | |
| 47 PendingFrame(uint32_t decode_id, const gfx::Size& size); | |
| 48 ~PendingFrame(); | |
| 49 | |
| 50 const uint32_t decode_id; | |
| 51 const gfx::Size size; | |
| 52 std::vector<uint8_t> argb_pixels; | |
|
Ami GONE FROM CHROMIUM
2014/06/06 17:14:33
Experimentation is the only authority :(
dmichael (off chromium)
2014/06/06 17:24:00
private:
DISALLOW_COPY_AND_ASSIGN(PendingFrame);
bbudge
2014/06/07 00:31:09
Done.
bbudge
2014/06/07 00:31:09
Looks like ARGB. I guess as long as there are an e
| |
| 53 }; | |
| 54 | |
| 55 VideoDecoderAdapter::PendingFrame::PendingFrame(uint32_t decode_id) | |
| 56 : decode_id(decode_id) { | |
| 57 } | |
| 58 | |
| 59 VideoDecoderAdapter::PendingFrame::PendingFrame(uint32_t decode_id, | |
| 60 const gfx::Size& size) | |
| 61 : decode_id(decode_id), | |
| 62 size(size), | |
| 63 argb_pixels(size.width() * size.height() * 4) { | |
| 64 } | |
| 65 | |
| 66 VideoDecoderAdapter::PendingFrame::~PendingFrame() { | |
| 67 } | |
| 68 | |
| 69 VideoDecoderAdapter::Delegate::Delegate( | |
| 70 const base::WeakPtr<VideoDecoderAdapter>& proxy) | |
| 71 : adapter_(proxy), | |
| 72 main_message_loop_(base::MessageLoopProxy::current()), | |
| 73 max_pending_decodes_(0), | |
| 74 num_pending_decodes_(0) { | |
| 75 } | |
| 76 | |
| 77 VideoDecoderAdapter::Delegate::~Delegate() { | |
| 78 DCHECK(pending_decodes_.empty()); | |
| 79 } | |
| 80 | |
| 81 void VideoDecoderAdapter::Delegate::Initialize( | |
| 82 media::VideoDecoderConfig config) { | |
| 83 DCHECK(!decoder_); | |
| 84 decoder_.reset( | |
| 85 new media::FFmpegVideoDecoder(base::MessageLoopProxy::current())); | |
| 86 max_pending_decodes_ = decoder_->GetMaxDecodeRequests(); | |
| 87 // We can use base::Unretained() safely in decoder callbacks because we call | |
| 88 // VideoDecoder::Stop() before deletion. Stop() guarantees there will be no | |
| 89 // outstanding callbacks after it returns. | |
| 90 decoder_->Initialize( | |
| 91 config, | |
| 92 true /* low_delay */, | |
| 93 base::Bind(&VideoDecoderAdapter::Delegate::OnPipelineStatus, | |
| 94 base::Unretained(this))); | |
| 95 } | |
| 96 | |
| 97 void VideoDecoderAdapter::Delegate::OnPipelineStatus( | |
| 98 media::PipelineStatus status) { | |
| 99 main_message_loop_->PostTask( | |
| 100 FROM_HERE, | |
| 101 base::Bind(&VideoDecoderAdapter::OnPipelineStatus, adapter_, status)); | |
| 102 } | |
| 103 | |
| 104 void VideoDecoderAdapter::Delegate::Decode( | |
| 105 uint32_t decode_id, | |
| 106 scoped_refptr<media::DecoderBuffer> buffer) { | |
| 107 DCHECK(decoder_); | |
| 108 if (num_pending_decodes_ < max_pending_decodes_) { | |
|
Ami GONE FROM CHROMIUM
2014/06/06 17:14:33
num_pending_decodes_ holding a value other than
pe
bbudge
2014/06/07 00:31:09
Done.
| |
| 109 num_pending_decodes_++; | |
| 110 decoder_->Decode( | |
|
Ami GONE FROM CHROMIUM
2014/06/06 17:14:33
DCHECK(pending_decodes_.empty());
bbudge
2014/06/07 00:31:09
It might not be true. I think you identified a rea
| |
| 111 buffer, | |
| 112 base::Bind(&VideoDecoderAdapter::Delegate::OnDecodeComplete, | |
| 113 base::Unretained(this), | |
| 114 decode_id)); | |
| 115 } else { | |
| 116 pending_decodes_.push(PendingDecode(decode_id, buffer)); | |
| 117 } | |
| 118 } | |
| 119 | |
| 120 void VideoDecoderAdapter::Delegate::Reset() { | |
| 121 DCHECK(decoder_); | |
| 122 // Abort all pending decodes. | |
| 123 while (!pending_decodes_.empty()) { | |
| 124 PendingDecode& decode = pending_decodes_.front(); | |
|
dmichael (off chromium)
2014/06/06 17:24:00
nit: const& ?
bbudge
2014/06/07 00:31:09
Done.
| |
| 125 scoped_ptr<PendingFrame> pending_frame(new PendingFrame(decode.decode_id)); | |
| 126 main_message_loop_->PostTask( | |
| 127 FROM_HERE, | |
| 128 base::Bind(&VideoDecoderAdapter::OnDecodeComplete, | |
| 129 adapter_, | |
| 130 media::VideoDecoder::kAborted, | |
| 131 base::Passed(&pending_frame))); | |
| 132 pending_decodes_.pop(); | |
| 133 } | |
| 134 decoder_->Reset(base::Bind(&VideoDecoderAdapter::Delegate::OnResetComplete, | |
| 135 base::Unretained(this))); | |
| 136 } | |
| 137 | |
| 138 void VideoDecoderAdapter::Delegate::Stop() { | |
| 139 DCHECK(decoder_); | |
| 140 // Clear pending decodes now. We don't want OnDecodeComplete to call Decode | |
| 141 // again. | |
| 142 while (!pending_decodes_.empty()) | |
| 143 pending_decodes_.pop(); | |
|
Ami GONE FROM CHROMIUM
2014/06/06 17:14:33
pending_decodes_.clear() instead of the previous t
bbudge
2014/06/07 00:31:09
Can't, it's std::queue.
| |
| 144 decoder_->Stop(); | |
| 145 // This instance is deleted once we exit this scope. | |
| 146 } | |
| 147 | |
| 148 void VideoDecoderAdapter::Delegate::OnDecodeComplete( | |
| 149 uint32_t decode_id, | |
| 150 media::VideoDecoder::Status status, | |
| 151 const scoped_refptr<media::VideoFrame>& frame) { | |
| 152 num_pending_decodes_--; | |
| 153 scoped_ptr<PendingFrame> pending_frame; | |
| 154 if (status == media::VideoDecoder::kOk && frame && !frame->end_of_stream()) { | |
|
Ami GONE FROM CHROMIUM
2014/06/06 17:14:33
&& frame is unnecessary here.
bbudge
2014/06/07 00:31:09
Done.
| |
| 155 pending_frame.reset(new PendingFrame(decode_id, frame->coded_size())); | |
| 156 // Convert the VideoFrame pixels to ARGB. | |
| 157 libyuv::I420ToARGB(frame->data(media::VideoFrame::kYPlane), | |
| 158 frame->stride(media::VideoFrame::kYPlane), | |
| 159 frame->data(media::VideoFrame::kUPlane), | |
| 160 frame->stride(media::VideoFrame::kUPlane), | |
| 161 frame->data(media::VideoFrame::kVPlane), | |
| 162 frame->stride(media::VideoFrame::kVPlane), | |
| 163 &pending_frame->argb_pixels.front(), | |
| 164 frame->coded_size().width() * 4, | |
| 165 frame->coded_size().width(), | |
| 166 frame->coded_size().height()); | |
| 167 } else { | |
| 168 pending_frame.reset(new PendingFrame(decode_id)); | |
| 169 } | |
| 170 | |
| 171 main_message_loop_->PostTask( | |
| 172 FROM_HERE, | |
| 173 base::Bind(&VideoDecoderAdapter::OnDecodeComplete, | |
| 174 adapter_, | |
| 175 status, | |
| 176 base::Passed(&pending_frame))); | |
| 177 | |
| 178 if (!pending_decodes_.empty()) { | |
| 179 const PendingDecode& decode = pending_decodes_.front(); | |
| 180 Decode(decode.decode_id, decode.buffer); | |
| 181 pending_decodes_.pop(); | |
| 182 } | |
| 183 } | |
| 184 | |
| 185 void VideoDecoderAdapter::Delegate::OnResetComplete() { | |
| 186 main_message_loop_->PostTask( | |
| 187 FROM_HERE, base::Bind(&VideoDecoderAdapter::OnResetComplete, adapter_)); | |
| 188 } | |
| 189 | |
| 190 VideoDecoderAdapter::VideoDecoderAdapter(PepperVideoDecoderHost* host) | |
| 191 : state_(UNINITIALIZED), | |
| 192 host_(host), | |
| 193 media_message_loop_( | |
| 194 RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy()), | |
| 195 context_provider_( | |
| 196 RenderThreadImpl::current()->SharedMainThreadContextProvider()), | |
| 197 num_pending_decodes_(0), | |
| 198 weak_ptr_factory_(this) { | |
| 199 DCHECK(host_); | |
| 200 DCHECK(media_message_loop_); | |
| 201 DCHECK(context_provider_); | |
| 202 delegate_.reset(new Delegate(weak_ptr_factory_.GetWeakPtr())); | |
| 203 } | |
| 204 | |
| 205 VideoDecoderAdapter::~VideoDecoderAdapter() { | |
| 206 DCHECK(RenderThreadImpl::current()); | |
| 207 DCHECK(!host_); | |
| 208 // Delete any remaining textures. | |
| 209 TextureIdMap::iterator it = texture_id_map_.begin(); | |
| 210 for (; it != texture_id_map_.end(); ++it) | |
| 211 DeleteTexture(it->second); | |
|
Ami GONE FROM CHROMIUM
2014/06/06 17:14:33
Yeah, I realize; still that's what I'd do.
(SEGV's
bbudge
2014/06/07 00:31:09
Done.
| |
| 212 | |
| 213 FlushCommandBuffer(); | |
| 214 } | |
| 215 | |
| 216 void VideoDecoderAdapter::Initialize(media::VideoCodecProfile profile) { | |
| 217 DCHECK(RenderThreadImpl::current()); | |
| 218 DCHECK_EQ(state_, UNINITIALIZED); | |
| 219 media::VideoCodec codec = media::kUnknownVideoCodec; | |
| 220 if (profile <= media::H264PROFILE_MAX) | |
| 221 codec = media::kCodecH264; | |
| 222 else if (profile <= media::VP8PROFILE_MAX) | |
| 223 codec = media::kCodecVP8; | |
| 224 DCHECK_NE(codec, media::kUnknownVideoCodec); | |
| 225 | |
| 226 media::VideoDecoderConfig config( | |
| 227 codec, | |
| 228 profile, | |
| 229 media::VideoFrame::YV12, | |
| 230 gfx::Size(32, 24), // Small sizes that won't fail. | |
| 231 gfx::Rect(32, 24), | |
| 232 gfx::Size(32, 24), | |
| 233 NULL /* extra_data */, | |
|
Ami GONE FROM CHROMIUM
2014/06/06 17:14:33
Please add a TODO.
bbudge
2014/06/07 00:31:09
Done.
| |
| 234 0 /* extra_data_size */, | |
| 235 false /* decryption */); | |
| 236 | |
| 237 media_message_loop_->PostTask( | |
| 238 FROM_HERE, | |
| 239 base::Bind(&VideoDecoderAdapter::Delegate::Initialize, | |
| 240 base::Unretained(delegate_.get()), | |
| 241 config)); | |
| 242 } | |
| 243 | |
| 244 void VideoDecoderAdapter::Decode(uint32_t decode_id, | |
| 245 const uint8_t* buffer, | |
| 246 uint32_t size) { | |
| 247 DCHECK(RenderThreadImpl::current()); | |
| 248 DCHECK_EQ(state_, DECODING); | |
| 249 | |
| 250 num_pending_decodes_++; | |
| 251 | |
| 252 media_message_loop_->PostTask( | |
| 253 FROM_HERE, | |
| 254 base::Bind(&VideoDecoderAdapter::Delegate::Decode, | |
| 255 base::Unretained(delegate_.get()), | |
| 256 decode_id, | |
| 257 media::DecoderBuffer::CopyFrom(buffer, size))); | |
| 258 } | |
| 259 | |
| 260 void VideoDecoderAdapter::AssignTextures( | |
| 261 const std::vector<uint32_t>& texture_ids) { | |
| 262 DCHECK(RenderThreadImpl::current()); | |
| 263 DCHECK_EQ(state_, DECODING); | |
| 264 DCHECK(texture_ids.size()); | |
|
Ami GONE FROM CHROMIUM
2014/06/06 17:14:33
Wouldn't such a texture be in textures_to_dismiss_
dmichael (off chromium)
2014/06/06 17:24:00
I think you should maybe reformat this to somethin
bbudge
2014/06/07 00:31:09
Done.
bbudge
2014/06/07 00:31:09
It would be in both. textures_to_dismiss_ may cont
| |
| 265 DCHECK_EQ(texture_ids.size(), pending_texture_mailboxes_.size()); | |
| 266 GLuint num_textures = base::checked_cast<GLuint>(texture_ids.size()); | |
| 267 std::vector<uint32_t> local_texture_ids(num_textures); | |
| 268 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL(); | |
| 269 gles2->GenTextures(num_textures, &local_texture_ids.front()); | |
| 270 for (uint32_t i = 0; i < num_textures; i++) { | |
| 271 gles2->ActiveTexture(GL_TEXTURE0); | |
| 272 gles2->BindTexture(GL_TEXTURE_2D, local_texture_ids[i]); | |
| 273 gles2->ConsumeTextureCHROMIUM(GL_TEXTURE_2D, | |
| 274 pending_texture_mailboxes_[i].name); | |
| 275 // Map the plugin texture id to the local texture id. | |
| 276 texture_id_map_[texture_ids[i]] = local_texture_ids[i]; | |
| 277 } | |
| 278 pending_texture_mailboxes_.clear(); | |
| 279 available_textures_.insert( | |
| 280 available_textures_.end(), texture_ids.begin(), texture_ids.end()); | |
| 281 SendPictures(); | |
| 282 } | |
| 283 | |
| 284 void VideoDecoderAdapter::RecycleTexture(uint32_t texture_id) { | |
| 285 DCHECK(RenderThreadImpl::current()); | |
| 286 if (textures_to_dismiss_.find(texture_id) != textures_to_dismiss_.end()) { | |
| 287 DismissTexture(texture_id); | |
| 288 } else if (texture_id_map_.find(texture_id) != texture_id_map_.end()) { | |
| 289 available_textures_.push_back(texture_id); | |
| 290 SendPictures(); | |
| 291 } else { | |
| 292 NOTREACHED(); | |
| 293 } | |
| 294 } | |
| 295 | |
| 296 void VideoDecoderAdapter::Flush() { | |
| 297 DCHECK(RenderThreadImpl::current()); | |
| 298 DCHECK_EQ(state_, DECODING); | |
| 299 state_ = FLUSHING; | |
| 300 } | |
| 301 | |
| 302 void VideoDecoderAdapter::Reset() { | |
| 303 DCHECK(RenderThreadImpl::current()); | |
| 304 DCHECK_EQ(state_, DECODING); | |
| 305 state_ = RESETTING; | |
| 306 media_message_loop_->PostTask( | |
| 307 FROM_HERE, | |
| 308 base::Bind(&VideoDecoderAdapter::Delegate::Reset, | |
| 309 base::Unretained(delegate_.get()))); | |
| 310 } | |
| 311 | |
| 312 void VideoDecoderAdapter::Destroy() { | |
| 313 DCHECK(RenderThreadImpl::current()); | |
| 314 DCHECK(host_); | |
| 315 host_ = NULL; | |
| 316 state_ = DESTROYED; | |
| 317 // No methods can post tasks to the delegate now. | |
| 318 weak_ptr_factory_.InvalidateWeakPtrs(); | |
| 319 // No more callbacks from the delegate will be received now. | |
| 320 | |
| 321 // The callback now holds the only reference to the delegate, which will be | |
| 322 // deleted when Stop completes. | |
| 323 media_message_loop_->PostTask(FROM_HERE, | |
| 324 base::Bind(&VideoDecoderAdapter::Delegate::Stop, | |
| 325 base::Owned(delegate_.release()))); | |
|
dmichael (off chromium)
2014/06/06 17:24:00
You convinced me that VideoDecoderAdapter::Delegat
bbudge
2014/06/07 00:31:09
We're posting a task to the media loop to Stop the
bbudge
2014/06/07 01:01:23
Ugh, there you go being right again. Yeah, since I
| |
| 326 | |
| 327 delete this; | |
| 328 } | |
| 329 | |
| 330 void VideoDecoderAdapter::OnPipelineStatus(media::PipelineStatus status) { | |
| 331 DCHECK(RenderThreadImpl::current()); | |
| 332 DCHECK(host_); | |
| 333 | |
| 334 int32_t result; | |
| 335 switch (status) { | |
| 336 case media::PIPELINE_OK: | |
| 337 result = PP_OK; | |
| 338 state_ = DECODING; | |
| 339 break; | |
| 340 case media::DECODER_ERROR_NOT_SUPPORTED: | |
| 341 result = PP_ERROR_NOTSUPPORTED; | |
| 342 break; | |
| 343 default: | |
| 344 result = PP_ERROR_FAILED; | |
| 345 break; | |
| 346 } | |
| 347 host_->OnInitializeComplete(result); | |
| 348 } | |
| 349 | |
| 350 void VideoDecoderAdapter::OnDecodeComplete(media::VideoDecoder::Status status, | |
| 351 scoped_ptr<PendingFrame> frame) { | |
| 352 DCHECK(RenderThreadImpl::current()); | |
| 353 DCHECK(host_); | |
| 354 | |
| 355 num_pending_decodes_--; | |
| 356 | |
| 357 if (!frame->argb_pixels.empty()) { | |
| 358 if (texture_size_ != frame->size) { | |
| 359 // If the size has changed, all current textures must be dismissed. Add | |
| 360 // all textures to |textures_to_dismiss_| and dismiss any that aren't in | |
| 361 // use by the plugin. We dismiss the rest as they are recycled. | |
| 362 for (TextureIdMap::const_iterator it = texture_id_map_.begin(); | |
| 363 it != texture_id_map_.end(); | |
| 364 ++it) { | |
| 365 textures_to_dismiss_.insert(it->second); | |
| 366 } | |
| 367 for (std::vector<uint32_t>::const_iterator it = | |
| 368 available_textures_.begin(); | |
| 369 it != available_textures_.end(); | |
| 370 ++it) { | |
| 371 DismissTexture(*it); | |
| 372 } | |
| 373 available_textures_.clear(); | |
| 374 FlushCommandBuffer(); | |
| 375 | |
| 376 DCHECK(pending_texture_mailboxes_.empty()); | |
| 377 const uint32_t num_textures = 8; | |
|
Ami GONE FROM CHROMIUM
2014/06/06 17:14:33
In order to saturate both the decoder and the rend
bbudge
2014/06/07 00:31:09
Done.
| |
| 378 for (uint32_t i = 0; i < num_textures; i++) | |
| 379 pending_texture_mailboxes_.push_back(gpu::Mailbox::Generate()); | |
| 380 | |
| 381 host_->RequestTextures( | |
| 382 num_textures, frame->size, GL_TEXTURE_2D, pending_texture_mailboxes_); | |
| 383 texture_size_ = frame->size; | |
| 384 } | |
| 385 | |
| 386 pending_frames_.push(linked_ptr<PendingFrame>(frame.release())); | |
| 387 SendPictures(); | |
| 388 } else { | |
| 389 host_->NotifyEndOfBitstreamBuffer(frame->decode_id); | |
| 390 } | |
| 391 | |
| 392 switch (status) { | |
| 393 case media::VideoDecoder::kOk: | |
| 394 case media::VideoDecoder::kAborted: | |
| 395 // This is not necessarily an error. | |
| 396 case media::VideoDecoder::kNotEnoughData: | |
| 397 break; | |
| 398 case media::VideoDecoder::kDecodeError: | |
| 399 host_->NotifyError(PP_ERROR_RESOURCE_FAILED); | |
| 400 break; | |
| 401 case media::VideoDecoder::kDecryptError: | |
| 402 NOTREACHED(); | |
| 403 break; | |
| 404 // No default case, to catch unhandled status values. | |
| 405 } | |
| 406 } | |
| 407 | |
| 408 void VideoDecoderAdapter::SendPictures() { | |
| 409 DCHECK(RenderThreadImpl::current()); | |
| 410 DCHECK(host_); | |
| 411 | |
| 412 while (!pending_frames_.empty() && !available_textures_.empty()) { | |
| 413 const linked_ptr<PendingFrame>& frame = pending_frames_.front(); | |
| 414 | |
| 415 uint32_t texture_id = available_textures_.back(); | |
| 416 available_textures_.pop_back(); | |
| 417 | |
| 418 uint32_t local_texture_id = texture_id_map_[texture_id]; | |
| 419 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL(); | |
| 420 gles2->ActiveTexture(GL_TEXTURE0); | |
| 421 gles2->BindTexture(GL_TEXTURE_2D, local_texture_id); | |
| 422 gles2->TexImage2D(GL_TEXTURE_2D, | |
| 423 0, | |
| 424 GL_RGBA, | |
| 425 texture_size_.width(), | |
| 426 texture_size_.height(), | |
| 427 0, | |
| 428 GL_RGBA, | |
| 429 GL_UNSIGNED_BYTE, | |
| 430 &frame->argb_pixels.front()); | |
| 431 | |
| 432 host_->NotifyEndOfBitstreamBuffer(frame->decode_id); | |
| 433 host_->PictureReady(media::Picture(texture_id, frame->decode_id)); | |
| 434 pending_frames_.pop(); | |
| 435 } | |
| 436 | |
| 437 FlushCommandBuffer(); | |
| 438 | |
| 439 if (state_ == FLUSHING && !num_pending_decodes_ && pending_frames_.empty()) { | |
| 440 state_ = DECODING; | |
| 441 host_->NotifyFlushDone(); | |
| 442 } | |
| 443 } | |
| 444 | |
| 445 void VideoDecoderAdapter::OnResetComplete() { | |
| 446 DCHECK(RenderThreadImpl::current()); | |
| 447 DCHECK(host_); | |
| 448 | |
| 449 while (!pending_frames_.empty()) { | |
| 450 const linked_ptr<PendingFrame>& frame = pending_frames_.front(); | |
| 451 host_->NotifyEndOfBitstreamBuffer(frame->decode_id); | |
| 452 pending_frames_.pop(); | |
| 453 } | |
| 454 | |
| 455 state_ = DECODING; | |
| 456 host_->NotifyResetDone(); | |
| 457 } | |
| 458 | |
| 459 void VideoDecoderAdapter::DismissTexture(uint32_t texture_id) { | |
| 460 DCHECK(host_); | |
| 461 textures_to_dismiss_.erase(texture_id); | |
| 462 DCHECK(texture_id_map_.find(texture_id) != texture_id_map_.end()); | |
| 463 DeleteTexture(texture_id_map_[texture_id]); | |
| 464 texture_id_map_.erase(texture_id); | |
| 465 host_->DismissPictureBuffer(texture_id); | |
| 466 } | |
| 467 | |
| 468 void VideoDecoderAdapter::DeleteTexture(uint32_t texture_id) { | |
| 469 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL(); | |
| 470 gles2->DeleteTextures(1, &texture_id); | |
| 471 } | |
| 472 | |
| 473 void VideoDecoderAdapter::FlushCommandBuffer() { | |
| 474 context_provider_->ContextGL()->Flush(); | |
| 475 } | |
| 476 | |
| 477 } // namespace content | |
| OLD | NEW |