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_proxy.h" | |
| 10 | |
| 11 #include "base/bind.h" | |
| 12 #include "content/public/renderer/render_thread.h" | |
| 13 #include "content/renderer/pepper/pepper_video_decoder_host.h" | |
| 14 #include "content/renderer/render_thread_impl.h" | |
| 15 #include "gpu/command_buffer/client/gles2_implementation.h" | |
| 16 #include "media/base/decoder_buffer.h" | |
| 17 #include "media/filters/ffmpeg_video_decoder.h" | |
| 18 #include "media/video/picture.h" | |
| 19 #include "media/video/video_decode_accelerator.h" | |
| 20 #include "ppapi/c/pp_errors.h" | |
| 21 #include "third_party/libyuv/include/libyuv.h" | |
| 22 #include "webkit/common/gpu/context_provider_web_context.h" | |
| 23 | |
| 24 namespace content { | |
| 25 | |
| 26 VideoDecoderProxy::PendingDecode::PendingDecode( | |
| 27 uint32_t decode_id, | |
| 28 const scoped_refptr<media::DecoderBuffer>& buffer) | |
| 29 : decode_id(decode_id), buffer(buffer) { | |
| 30 } | |
| 31 | |
| 32 VideoDecoderProxy::PendingDecode::~PendingDecode() { | |
| 33 } | |
| 34 | |
| 35 VideoDecoderProxy::PendingFrame::PendingFrame(uint32_t decode_id, | |
| 36 const gfx::Size& size) | |
| 37 : decode_id(decode_id), | |
| 38 size(size), | |
| 39 pixels(size.width() * size.height() * 4) { | |
| 40 } | |
| 41 | |
| 42 VideoDecoderProxy::PendingFrame::~PendingFrame() { | |
| 43 } | |
| 44 | |
| 45 VideoDecoderProxy::Delegate::Delegate( | |
| 46 const base::WeakPtr<VideoDecoderProxy>& proxy) | |
| 47 : proxy_(proxy), main_message_loop_(base::MessageLoopProxy::current()) { | |
| 48 } | |
| 49 | |
| 50 VideoDecoderProxy::Delegate::~Delegate() { | |
| 51 DCHECK(pending_decodes_.empty()); | |
|
Ami GONE FROM CHROMIUM
2014/06/05 00:06:24
what guarantees this?
I think you might be relying
bbudge
2014/06/06 02:03:45
Done.
| |
| 52 } | |
| 53 | |
| 54 void VideoDecoderProxy::Delegate::Initialize( | |
| 55 scoped_ptr<media::VideoDecoder> decoder, | |
| 56 media::VideoDecoderConfig config) { | |
| 57 DCHECK(!decoder_); | |
| 58 decoder_.reset(decoder.release()); | |
|
dmichael (off chromium)
2014/06/05 23:00:43
tiny nit: I think I would write this as decoder_ =
bbudge
2014/06/06 02:03:45
This is no longer an argument.
| |
| 59 decoder_->Initialize( | |
| 60 config, | |
| 61 true /* low_delay */, | |
| 62 base::Bind(&VideoDecoderProxy::Delegate::OnPipelineStatus, | |
| 63 base::Unretained(this))); | |
|
Ami GONE FROM CHROMIUM
2014/06/05 00:06:24
I guess the only reason this isn't a UAF waiting t
bbudge
2014/06/06 02:03:45
Done.
| |
| 64 } | |
| 65 | |
| 66 void VideoDecoderProxy::Delegate::OnPipelineStatus( | |
| 67 media::PipelineStatus status) { | |
| 68 main_message_loop_->PostTask( | |
| 69 FROM_HERE, | |
| 70 base::Bind(&VideoDecoderProxy::OnPipelineStatus, proxy_, status)); | |
| 71 } | |
| 72 | |
| 73 void VideoDecoderProxy::Delegate::ReceiveBuffer( | |
| 74 uint32_t decode_id, | |
| 75 scoped_refptr<media::DecoderBuffer> buffer) { | |
| 76 bool decoder_busy = !pending_decodes_.empty(); | |
| 77 pending_decodes_.push(PendingDecode(decode_id, buffer)); | |
| 78 if (!decoder_busy) | |
|
Ami GONE FROM CHROMIUM
2014/06/05 00:06:24
FWIW can drop decoder_busy if you do
if (pending_d
Ami GONE FROM CHROMIUM
2014/06/05 00:06:24
AFAICT a client that never calls Reset() can never
bbudge
2014/06/06 02:03:44
I changed this and now call VD::GetMaxDecodeReques
bbudge
2014/06/06 02:03:45
It happens at startup and on reset. In the steady
| |
| 79 Decode(); | |
| 80 } | |
| 81 | |
| 82 void VideoDecoderProxy::Delegate::Decode() { | |
| 83 DCHECK(!pending_decodes_.empty()); | |
| 84 PendingDecode& next_decode = pending_decodes_.front(); | |
|
Ami GONE FROM CHROMIUM
2014/06/05 00:06:24
const& is less surprising
bbudge
2014/06/06 02:03:45
Done.
| |
| 85 decoder_->Decode(next_decode.buffer, | |
| 86 base::Bind(&VideoDecoderProxy::Delegate::ConvertFrame, | |
| 87 base::Unretained(this), | |
| 88 next_decode.decode_id)); | |
| 89 pending_decodes_.pop(); | |
| 90 } | |
| 91 | |
| 92 void VideoDecoderProxy::Delegate::ConvertFrame( | |
| 93 uint32_t decode_id, | |
| 94 media::VideoDecoder::Status status, | |
| 95 const scoped_refptr<media::VideoFrame>& frame) { | |
| 96 scoped_ptr<PendingFrame> pending_frame( | |
| 97 new PendingFrame(decode_id, gfx::Size())); | |
| 98 if (frame) { | |
|
Ami GONE FROM CHROMIUM
2014/06/05 00:06:24
You're using frame!=NULL as a proxy for status==kO
bbudge
2014/06/06 02:03:45
So:
if (status == kOk && frame && !frame->end_of_s
| |
| 99 pending_frame->size = frame->coded_size(); | |
| 100 pending_frame->pixels.resize(frame->coded_size().width() * | |
|
Ami GONE FROM CHROMIUM
2014/06/05 00:06:24
It's strange that you do the w*h*4 calc here _and_
bbudge
2014/06/06 02:03:45
Added a ctor to create an empty frame, and defer c
| |
| 101 frame->coded_size().height() * 4); | |
| 102 // Convert the decoded frame to ARGB pixels. | |
| 103 libyuv::I420ToARGB(frame->data(media::VideoFrame::kYPlane), | |
| 104 frame->stride(media::VideoFrame::kYPlane), | |
| 105 frame->data(media::VideoFrame::kUPlane), | |
| 106 frame->stride(media::VideoFrame::kUPlane), | |
| 107 frame->data(media::VideoFrame::kVPlane), | |
| 108 frame->stride(media::VideoFrame::kVPlane), | |
| 109 &pending_frame->pixels.front(), | |
| 110 frame->coded_size().width() * 4, | |
| 111 frame->coded_size().width(), | |
| 112 frame->coded_size().height()); | |
| 113 } | |
| 114 | |
| 115 main_message_loop_->PostTask(FROM_HERE, | |
| 116 base::Bind(&VideoDecoderProxy::ReceiveFrame, | |
| 117 proxy_, | |
| 118 status, | |
| 119 base::Passed(&pending_frame))); | |
| 120 | |
| 121 if (!pending_decodes_.empty()) | |
|
Ami GONE FROM CHROMIUM
2014/06/05 00:06:24
per comment at l.78, can this arise in the absence
bbudge
2014/06/06 02:03:45
Stop() and Reset() now clear pending frames first,
| |
| 122 Decode(); | |
| 123 } | |
| 124 | |
| 125 void VideoDecoderProxy::Delegate::Reset() { | |
| 126 decoder_->Reset(base::Bind(&VideoDecoderProxy::Delegate::OnResetComplete, | |
|
Ami GONE FROM CHROMIUM
2014/06/05 00:06:24
set some state so that decodes that arrive from no
bbudge
2014/06/06 02:03:44
No decodes can arrive until Reset completes becaus
| |
| 127 base::Unretained(this))); | |
| 128 } | |
| 129 | |
| 130 void VideoDecoderProxy::Delegate::OnResetComplete() { | |
| 131 // Cancel all remaining decodes, and notify the host so it can free the shm | |
|
Ami GONE FROM CHROMIUM
2014/06/05 00:06:24
is it obvious why this shouldn't have been done in
bbudge
2014/06/06 02:03:44
No, it should be done in Reset() as you point out.
| |
| 132 // buffers. We'll clear pending frames on the main thread. | |
| 133 while (!pending_decodes_.empty()) { | |
| 134 PendingDecode& next_decode = pending_decodes_.front(); | |
| 135 scoped_ptr<PendingFrame> pending_frame( | |
| 136 new PendingFrame(next_decode.decode_id, gfx::Size())); | |
| 137 main_message_loop_->PostTask(FROM_HERE, | |
| 138 base::Bind(&VideoDecoderProxy::ReceiveFrame, | |
| 139 proxy_, | |
| 140 media::VideoDecoder::kAborted, | |
| 141 base::Passed(&pending_frame))); | |
|
dmichael (off chromium)
2014/06/05 23:00:43
Any reason you can't pass a null pointer instead o
bbudge
2014/06/06 02:03:44
The frame has the decode_id, which is used to iden
| |
| 142 pending_decodes_.pop(); | |
| 143 } | |
| 144 main_message_loop_->PostTask( | |
| 145 FROM_HERE, base::Bind(&VideoDecoderProxy::OnResetComplete, proxy_)); | |
| 146 } | |
| 147 | |
| 148 void VideoDecoderProxy::Delegate::Destroy() { | |
| 149 DCHECK(decoder_); | |
| 150 decoder_->Stop(); | |
|
dmichael (off chromium)
2014/06/05 23:00:43
Would it be safe to instead put this in the destru
bbudge
2014/06/06 02:03:45
Stop can cause callbacks to run, and I'd rather no
| |
| 151 // By now, our owning VideoDecoderProxy has invalidated our weak_ptr to it. | |
| 152 } | |
| 153 | |
| 154 VideoDecoderProxy::VideoDecoderProxy(PepperVideoDecoderHost* host) | |
| 155 : state_(UNINITIALIZED), | |
| 156 host_(host), | |
| 157 media_message_loop_( | |
| 158 RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy()), | |
| 159 context_provider_( | |
| 160 RenderThreadImpl::current()->SharedMainThreadContextProvider()), | |
| 161 num_pending_decodes_(0), | |
|
Ami GONE FROM CHROMIUM
2014/06/05 00:06:24
the logic around this member requires that Decode(
bbudge
2014/06/06 02:03:44
Done.
| |
| 162 weak_ptr_factory_(this) { | |
| 163 DCHECK(host_); | |
| 164 DCHECK(media_message_loop_); | |
| 165 DCHECK(context_provider_); | |
| 166 delegate_.reset(new Delegate(weak_ptr_factory_.GetWeakPtr())); | |
| 167 } | |
| 168 | |
| 169 VideoDecoderProxy::~VideoDecoderProxy() { | |
| 170 DCHECK(RenderThreadImpl::current()); | |
| 171 DCHECK(!host_); | |
| 172 // Delete any remaining video frames. | |
| 173 while (!pending_frames_.empty()) { | |
| 174 delete pending_frames_.front(); | |
| 175 pending_frames_.pop(); | |
| 176 } | |
| 177 // Delete any remaining textures. | |
| 178 TextureIdMap::iterator it = texture_id_map_.begin(); | |
| 179 for (; it != texture_id_map_.end(); ++it) | |
| 180 DeleteTexture(it->second); | |
| 181 | |
|
Ami GONE FROM CHROMIUM
2014/06/05 00:06:24
clear the map once done?
bbudge
2014/06/06 02:03:44
It will be destroyed once we exit the body.
| |
| 182 FlushCommandBuffer(); | |
| 183 } | |
| 184 | |
| 185 void VideoDecoderProxy::Initialize(media::VideoCodecProfile profile) { | |
| 186 DCHECK(RenderThreadImpl::current()); | |
| 187 DCHECK_EQ(state_, UNINITIALIZED); | |
| 188 media::VideoCodec codec = media::kUnknownVideoCodec; | |
| 189 if (profile <= media::H264PROFILE_MAX) | |
| 190 codec = media::kCodecH264; | |
| 191 else if (profile <= media::VP8PROFILE_MAX) | |
| 192 codec = media::kCodecVP8; | |
| 193 DCHECK_NE(codec, media::kUnknownVideoCodec); | |
| 194 | |
| 195 media::VideoDecoderConfig config( | |
| 196 codec, | |
| 197 profile, | |
| 198 media::VideoFrame::YV12, | |
| 199 gfx::Size(32, 24), // Small sizes that won't fail. | |
| 200 gfx::Rect(32, 24), | |
| 201 gfx::Size(32, 24), | |
| 202 NULL /* extra_data */, | |
|
Ami GONE FROM CHROMIUM
2014/06/05 00:06:24
durr, does this really work?
e.g. does the h264 te
bbudge
2014/06/06 02:03:45
I don't know. I'll have to try it. I have no idea
| |
| 203 0 /* extra_data_size */, | |
| 204 false /* decryption */); | |
| 205 | |
| 206 scoped_ptr<media::VideoDecoder> decoder( | |
| 207 new media::FFmpegVideoDecoder(media_message_loop_)); | |
|
Ami GONE FROM CHROMIUM
2014/06/05 00:06:24
Why not VpxVideoDecoder (for VP9) or one of the de
bbudge
2014/06/06 02:03:45
You're right. I moved VideoDecoder construction in
| |
| 208 | |
| 209 media_message_loop_->PostTask( | |
| 210 FROM_HERE, | |
| 211 base::Bind(&VideoDecoderProxy::Delegate::Initialize, | |
| 212 base::Unretained(delegate_.get()), | |
| 213 base::Passed(&decoder), | |
| 214 config)); | |
| 215 state_ = DECODING; | |
|
Ami GONE FROM CHROMIUM
2014/06/05 00:06:24
shouldn't this transition only happen in the OK ca
bbudge
2014/06/06 02:03:45
Yep.
| |
| 216 } | |
| 217 | |
| 218 void VideoDecoderProxy::Decode(uint32_t decode_id, | |
| 219 const uint8_t* buffer, | |
| 220 uint32_t size) { | |
| 221 DCHECK(RenderThreadImpl::current()); | |
| 222 DCHECK_EQ(state_, DECODING); | |
| 223 | |
| 224 num_pending_decodes_++; | |
| 225 | |
| 226 media_message_loop_->PostTask( | |
| 227 FROM_HERE, | |
| 228 base::Bind(&VideoDecoderProxy::Delegate::ReceiveBuffer, | |
| 229 base::Unretained(delegate_.get()), | |
| 230 decode_id, | |
| 231 media::DecoderBuffer::CopyFrom(buffer, size))); | |
| 232 } | |
| 233 | |
| 234 void VideoDecoderProxy::AssignTextures( | |
| 235 const std::vector<uint32_t>& texture_ids) { | |
| 236 DCHECK(RenderThreadImpl::current()); | |
| 237 DCHECK_EQ(state_, DECODING); | |
| 238 DCHECK(texture_ids.size()); | |
|
Ami GONE FROM CHROMIUM
2014/06/05 00:06:24
DCHECK(texture_id_map_.empty());
?
dmichael (off chromium)
2014/06/05 23:00:44
With a "!", of course :)
bbudge
2014/06/06 02:03:45
I don't think so. We AssignTextures when the video
| |
| 239 DCHECK_EQ(texture_ids.size(), pending_texture_mailboxes_.size()); | |
| 240 uint32_t num_textures = static_cast<GLuint>(texture_ids.size()); | |
|
Ami GONE FROM CHROMIUM
2014/06/05 00:06:24
checked_cast to avoid silent overflow
bbudge
2014/06/06 02:03:45
Done.
| |
| 241 std::vector<uint32_t> local_texture_ids(num_textures); | |
| 242 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL(); | |
| 243 gles2->GenTextures(num_textures, &local_texture_ids.front()); | |
| 244 for (uint32_t i = 0; i < num_textures; i++) { | |
| 245 gles2->ActiveTexture(GL_TEXTURE0); | |
| 246 gles2->BindTexture(GL_TEXTURE_2D, local_texture_ids[i]); | |
| 247 gles2->ConsumeTextureCHROMIUM(GL_TEXTURE_2D, | |
| 248 pending_texture_mailboxes_[i].name); | |
| 249 // Map the plugin texture id to the local texture id. | |
| 250 texture_id_map_.insert( | |
| 251 std::make_pair(texture_ids[i], local_texture_ids[i])); | |
|
Ami GONE FROM CHROMIUM
2014/06/05 00:06:24
since you're ignoring return value you may as well
bbudge
2014/06/06 02:03:44
Done.
| |
| 252 } | |
| 253 pending_texture_mailboxes_.clear(); | |
| 254 available_textures_.insert( | |
| 255 available_textures_.end(), texture_ids.begin(), texture_ids.end()); | |
| 256 SendPictures(); | |
| 257 } | |
| 258 | |
| 259 void VideoDecoderProxy::RecycleTexture(uint32_t texture_id) { | |
| 260 DCHECK(RenderThreadImpl::current()); | |
| 261 if (textures_to_dismiss_.find(texture_id) != textures_to_dismiss_.end()) { | |
| 262 DismissTexture(texture_id); | |
| 263 } else if (texture_id_map_.find(texture_id) != texture_id_map_.end()) { | |
| 264 available_textures_.push_back(texture_id); | |
| 265 SendPictures(); | |
| 266 } else { | |
| 267 NOTREACHED(); | |
| 268 } | |
| 269 } | |
| 270 | |
| 271 void VideoDecoderProxy::Flush() { | |
| 272 DCHECK(RenderThreadImpl::current()); | |
| 273 DCHECK_EQ(state_, DECODING); | |
| 274 state_ = FLUSHING; | |
| 275 } | |
| 276 | |
| 277 void VideoDecoderProxy::Reset() { | |
| 278 DCHECK(RenderThreadImpl::current()); | |
| 279 DCHECK_EQ(state_, DECODING); | |
| 280 state_ = RESETTING; | |
| 281 media_message_loop_->PostTask(FROM_HERE, | |
| 282 base::Bind(&VideoDecoderProxy::Delegate::Reset, | |
| 283 base::Unretained(delegate_.get()))); | |
| 284 } | |
| 285 | |
| 286 void VideoDecoderProxy::Destroy() { | |
| 287 DCHECK(RenderThreadImpl::current()); | |
| 288 DCHECK(host_); | |
| 289 host_ = NULL; | |
| 290 // Cut the delegate loose. | |
| 291 weak_ptr_factory_.InvalidateWeakPtrs(); | |
| 292 media_message_loop_->PostTask( | |
| 293 FROM_HERE, | |
| 294 base::Bind(&VideoDecoderProxy::Delegate::Destroy, | |
| 295 base::Owned(delegate_.release()))); | |
| 296 | |
| 297 delete this; | |
|
dmichael (off chromium)
2014/06/05 23:00:43
Can we just do all this in a destructor? (aside fr
bbudge
2014/06/06 02:03:44
That's too late. There might be pending callbacks
| |
| 298 } | |
| 299 | |
| 300 void VideoDecoderProxy::OnPipelineStatus(media::PipelineStatus status) { | |
| 301 DCHECK(RenderThreadImpl::current()); | |
| 302 DCHECK(host_); | |
| 303 | |
| 304 int32_t result; | |
| 305 switch (status) { | |
| 306 case media::PIPELINE_OK: | |
| 307 result = PP_OK; | |
| 308 break; | |
| 309 case media::DECODER_ERROR_NOT_SUPPORTED: | |
| 310 result = PP_ERROR_NOTSUPPORTED; | |
| 311 break; | |
| 312 default: | |
| 313 result = PP_ERROR_FAILED; | |
| 314 break; | |
| 315 } | |
| 316 host_->OnInitializeComplete(result); | |
| 317 } | |
| 318 | |
| 319 void VideoDecoderProxy::ReceiveFrame(media::VideoDecoder::Status status, | |
| 320 scoped_ptr<PendingFrame> frame) { | |
| 321 DCHECK(RenderThreadImpl::current()); | |
| 322 DCHECK(host_); | |
| 323 | |
| 324 num_pending_decodes_--; | |
| 325 | |
| 326 if (frame->pixels.size()) { | |
| 327 if (texture_size_ != frame->size) { | |
| 328 // If the size has changed, all current textures must be dismissed. Add | |
| 329 // all textures to |textures_to_dismiss_| and dismiss any that aren't in | |
| 330 // use by the plugin. We dismiss the rest as they are recycled. | |
| 331 for (TextureIdMap::const_iterator it = texture_id_map_.begin(); | |
| 332 it != texture_id_map_.end(); | |
| 333 ++it) { | |
| 334 textures_to_dismiss_.insert(it->second); | |
| 335 } | |
| 336 for (std::vector<uint32_t>::const_iterator it = | |
| 337 available_textures_.begin(); | |
| 338 it != available_textures_.end(); | |
| 339 ++it) { | |
| 340 DismissTexture(*it); | |
| 341 } | |
| 342 available_textures_.clear(); | |
| 343 FlushCommandBuffer(); | |
| 344 | |
| 345 DCHECK(pending_texture_mailboxes_.empty()); | |
| 346 const uint32_t num_textures = 8; | |
|
Ami GONE FROM CHROMIUM
2014/06/05 00:06:24
o rly 8?
bbudge
2014/06/06 02:03:44
Yeah, this is just a guess. It seems like 1 might
| |
| 347 for (uint32_t i = 0; i < num_textures; i++) | |
| 348 pending_texture_mailboxes_.push_back(gpu::Mailbox::Generate()); | |
| 349 | |
| 350 host_->RequestTextures( | |
| 351 num_textures, frame->size, GL_TEXTURE_2D, pending_texture_mailboxes_); | |
| 352 texture_size_ = frame->size; | |
| 353 } | |
| 354 | |
| 355 pending_frames_.push(frame.release()); | |
| 356 SendPictures(); | |
| 357 } else { | |
| 358 host_->NotifyEndOfBitstreamBuffer(frame->decode_id); | |
|
Ami GONE FROM CHROMIUM
2014/06/05 00:06:24
In case of error this is wrong.
bbudge
2014/06/06 02:03:44
I don't see why. With VideoDecodeAccelerator we no
| |
| 359 } | |
| 360 | |
| 361 switch (status) { | |
| 362 case media::VideoDecoder::kOk: | |
| 363 case media::VideoDecoder::kAborted: | |
| 364 // This is not necessarily an error. | |
| 365 case media::VideoDecoder::kNotEnoughData: | |
| 366 break; | |
| 367 case media::VideoDecoder::kDecodeError: | |
| 368 case media::VideoDecoder::kDecryptError: | |
|
Ami GONE FROM CHROMIUM
2014/06/05 00:06:24
_decrypt_ error should be unreachable, right?
bbudge
2014/06/06 02:03:44
Done.
| |
| 369 host_->NotifyError(PP_ERROR_RESOURCE_FAILED); | |
| 370 break; | |
| 371 // No default case, to catch unhandled status values. | |
| 372 } | |
| 373 } | |
| 374 | |
| 375 void VideoDecoderProxy::SendPictures() { | |
| 376 DCHECK(RenderThreadImpl::current()); | |
| 377 DCHECK(host_); | |
| 378 | |
| 379 while (!pending_frames_.empty() && !available_textures_.empty()) { | |
| 380 scoped_ptr<PendingFrame> frame(pending_frames_.front()); | |
| 381 pending_frames_.pop(); | |
| 382 | |
| 383 uint32_t texture_id = available_textures_.back(); | |
| 384 available_textures_.pop_back(); | |
| 385 | |
| 386 uint32_t local_texture_id = texture_id_map_[texture_id]; | |
| 387 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL(); | |
| 388 gles2->ActiveTexture(GL_TEXTURE0); | |
| 389 gles2->BindTexture(GL_TEXTURE_2D, local_texture_id); | |
| 390 gles2->TexImage2D(GL_TEXTURE_2D, | |
| 391 0, | |
| 392 GL_RGBA, | |
| 393 texture_size_.width(), | |
| 394 texture_size_.height(), | |
| 395 0, | |
| 396 GL_RGBA, | |
| 397 GL_UNSIGNED_BYTE, | |
| 398 &frame->pixels.front()); | |
| 399 | |
| 400 host_->NotifyEndOfBitstreamBuffer(frame->decode_id); | |
| 401 host_->PictureReady(media::Picture(texture_id, frame->decode_id)); | |
| 402 } | |
| 403 | |
| 404 FlushCommandBuffer(); | |
| 405 | |
| 406 if (state_ == FLUSHING && !num_pending_decodes_ && pending_frames_.empty()) { | |
| 407 state_ = DECODING; | |
| 408 host_->NotifyFlushDone(); | |
| 409 } | |
| 410 } | |
| 411 | |
| 412 void VideoDecoderProxy::OnResetComplete() { | |
| 413 DCHECK(RenderThreadImpl::current()); | |
| 414 DCHECK(host_); | |
| 415 | |
| 416 while (!pending_frames_.empty()) { | |
| 417 scoped_ptr<PendingFrame> frame(pending_frames_.front()); | |
| 418 host_->NotifyEndOfBitstreamBuffer(frame->decode_id); | |
|
Ami GONE FROM CHROMIUM
2014/06/05 00:06:24
Not sure this is necessary, FWIW.
bbudge
2014/06/06 02:03:44
It makes it a little simpler in the host, since I
| |
| 419 pending_frames_.pop(); | |
| 420 } | |
| 421 | |
| 422 state_ = DECODING; | |
| 423 host_->NotifyResetDone(); | |
| 424 } | |
| 425 | |
| 426 void VideoDecoderProxy::DismissTexture(uint32_t texture_id) { | |
| 427 DCHECK(host_); | |
| 428 textures_to_dismiss_.erase(texture_id); | |
| 429 DCHECK(texture_id_map_.find(texture_id) != texture_id_map_.end()); | |
| 430 DeleteTexture(texture_id_map_[texture_id]); | |
| 431 texture_id_map_.erase(texture_id); | |
| 432 host_->DismissPictureBuffer(texture_id); | |
| 433 } | |
| 434 | |
| 435 void VideoDecoderProxy::DeleteTexture(uint32_t texture_id) { | |
| 436 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL(); | |
| 437 gles2->DeleteTextures(1, &texture_id); | |
| 438 } | |
| 439 | |
| 440 void VideoDecoderProxy::FlushCommandBuffer() { | |
| 441 DCHECK(RenderThreadImpl::current()); | |
| 442 context_provider_->ContextGL()->Flush(); | |
| 443 } | |
| 444 | |
| 445 } // namespace content | |
| OLD | NEW |