Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(491)

Side by Side Diff: media/filters/gpu_video_decoder.cc

Issue 239893002: Allow multiple concurrent Decode() requests in VideoDecoder interface. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 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 "media/filters/gpu_video_decoder.h" 5 #include "media/filters/gpu_video_decoder.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/callback_helpers.h" 10 #include "base/callback_helpers.h"
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
73 73
74 void GpuVideoDecoder::Reset(const base::Closure& closure) { 74 void GpuVideoDecoder::Reset(const base::Closure& closure) {
75 DVLOG(3) << "Reset()"; 75 DVLOG(3) << "Reset()";
76 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); 76 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
77 77
78 if (state_ == kDrainingDecoder) { 78 if (state_ == kDrainingDecoder) {
79 base::MessageLoop::current()->PostTask( 79 base::MessageLoop::current()->PostTask(
80 FROM_HERE, 80 FROM_HERE,
81 base::Bind( 81 base::Bind(
82 &GpuVideoDecoder::Reset, weak_factory_.GetWeakPtr(), closure)); 82 &GpuVideoDecoder::Reset, weak_factory_.GetWeakPtr(), closure));
83 // NOTE: if we're deferring Reset() until a Flush() completes, return
84 // queued pictures to the VDA so they can be used to finish that Flush().
85 if (pending_decode_cb_.is_null())
86 ready_video_frames_.clear();
87 return; 83 return;
88 } 84 }
89 85
90 // Throw away any already-decoded, not-yet-delivered frames.
91 ready_video_frames_.clear();
92
93 if (!vda_) { 86 if (!vda_) {
94 base::MessageLoop::current()->PostTask(FROM_HERE, closure); 87 base::MessageLoop::current()->PostTask(FROM_HERE, closure);
95 return; 88 return;
96 } 89 }
97 90
98 if (!pending_decode_cb_.is_null()) 91 while (!pending_decode_callbacks_.empty()) {
99 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEOSFrame()); 92 DeliverFrame(VideoFrame::CreateEOSFrame());
93 }
100 94
101 DCHECK(pending_reset_cb_.is_null()); 95 DCHECK(pending_reset_cb_.is_null());
102 pending_reset_cb_ = BindToCurrentLoop(closure); 96 pending_reset_cb_ = BindToCurrentLoop(closure);
103 97
104 vda_->Reset(); 98 vda_->Reset();
105 } 99 }
106 100
107 void GpuVideoDecoder::Stop() { 101 void GpuVideoDecoder::Stop() {
108 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); 102 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
109 if (vda_) 103 if (vda_)
110 DestroyVDA(); 104 DestroyVDA();
111 if (!pending_decode_cb_.is_null()) 105 while (!pending_decode_callbacks_.empty()) {
112 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEOSFrame()); 106 DeliverFrame(VideoFrame::CreateEOSFrame());
107 }
113 if (!pending_reset_cb_.is_null()) 108 if (!pending_reset_cb_.is_null())
114 base::ResetAndReturn(&pending_reset_cb_).Run(); 109 base::ResetAndReturn(&pending_reset_cb_).Run();
115 } 110 }
116 111
117 static bool IsCodedSizeSupported(const gfx::Size& coded_size) { 112 static bool IsCodedSizeSupported(const gfx::Size& coded_size) {
118 // Only non-Windows, Ivy Bridge+ platforms can support more than 1920x1080. 113 // Only non-Windows, Ivy Bridge+ platforms can support more than 1920x1080.
119 // We test against 1088 to account for 16x16 macroblocks. 114 // We test against 1088 to account for 16x16 macroblocks.
120 if (coded_size.width() <= 1920 && coded_size.height() <= 1088) 115 if (coded_size.width() <= 1920 && coded_size.height() <= 1088)
121 return true; 116 return true;
122 117
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
215 ++it) { 210 ++it) {
216 assigned_picture_buffers_.erase(it->first); 211 assigned_picture_buffers_.erase(it->first);
217 } 212 }
218 DestroyPictureBuffers(&assigned_picture_buffers_); 213 DestroyPictureBuffers(&assigned_picture_buffers_);
219 } 214 }
220 215
221 void GpuVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, 216 void GpuVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
222 const DecodeCB& decode_cb) { 217 const DecodeCB& decode_cb) {
223 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); 218 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
224 DCHECK(pending_reset_cb_.is_null()); 219 DCHECK(pending_reset_cb_.is_null());
225 DCHECK(pending_decode_cb_.is_null());
226
227 pending_decode_cb_ = BindToCurrentLoop(decode_cb);
228 220
229 if (state_ == kError || !vda_) { 221 if (state_ == kError || !vda_) {
230 base::ResetAndReturn(&pending_decode_cb_).Run(kDecodeError, NULL); 222 decode_cb.Run(kDecodeError, NULL);
231 return; 223 return;
232 } 224 }
233 225
234 switch (state_) { 226 switch (state_) {
235 case kDecoderDrained: 227 case kDecoderDrained:
236 if (!ready_video_frames_.empty()) {
237 EnqueueFrameAndTriggerFrameDelivery(NULL);
238 return;
239 }
240 state_ = kNormal; 228 state_ = kNormal;
241 // Fall-through. 229 // Fall-through.
242 case kNormal: 230 case kNormal:
243 break; 231 break;
244 case kDrainingDecoder: 232 case kDrainingDecoder:
245 DCHECK(buffer->end_of_stream()); 233 DCHECK(buffer->end_of_stream());
246 // Do nothing. Will be satisfied either by a PictureReady or 234 // Do nothing. Will be satisfied either by a PictureReady or
247 // NotifyFlushDone below. 235 // NotifyFlushDone below.
248 return; 236 return;
249 case kError: 237 case kError:
250 NOTREACHED(); 238 NOTREACHED();
251 return; 239 return;
252 } 240 }
253 241
254 if (buffer->end_of_stream()) { 242 if (buffer->end_of_stream()) {
255 if (state_ == kNormal) { 243 if (state_ == kNormal) {
256 state_ = kDrainingDecoder; 244 state_ = kDrainingDecoder;
245 pending_decode_callbacks_.push_back(BindToCurrentLoop(decode_cb));
246 DCHECK_LE(static_cast<int>(pending_decode_callbacks_.size()),
247 kMaxInFlightDecodes);
257 vda_->Flush(); 248 vda_->Flush();
258 // If we have ready frames, go ahead and process them to ensure that the
259 // Flush operation does not block in the VDA due to lack of picture
260 // buffers.
261 if (!ready_video_frames_.empty())
262 EnqueueFrameAndTriggerFrameDelivery(NULL);
263 } 249 }
264 return; 250 return;
265 } 251 }
266 252
267 size_t size = buffer->data_size(); 253 size_t size = buffer->data_size();
268 SHMBuffer* shm_buffer = GetSHM(size); 254 SHMBuffer* shm_buffer = GetSHM(size);
269 if (!shm_buffer) { 255 if (!shm_buffer) {
270 base::ResetAndReturn(&pending_decode_cb_).Run(kDecodeError, NULL); 256 decode_cb.Run(kDecodeError, NULL);
271 return; 257 return;
272 } 258 }
273 259
260 pending_decode_callbacks_.push_back(BindToCurrentLoop(decode_cb));
261 DCHECK_LE(static_cast<int>(pending_decode_callbacks_.size()),
262 kMaxInFlightDecodes);
263
274 memcpy(shm_buffer->shm->memory(), buffer->data(), size); 264 memcpy(shm_buffer->shm->memory(), buffer->data(), size);
275 BitstreamBuffer bitstream_buffer( 265 BitstreamBuffer bitstream_buffer(
276 next_bitstream_buffer_id_, shm_buffer->shm->handle(), size); 266 next_bitstream_buffer_id_, shm_buffer->shm->handle(), size);
277 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer. 267 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer.
278 next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF; 268 next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF;
279 bool inserted = bitstream_buffers_in_decoder_.insert(std::make_pair( 269 bool inserted = bitstream_buffers_in_decoder_.insert(std::make_pair(
280 bitstream_buffer.id(), BufferPair(shm_buffer, buffer))).second; 270 bitstream_buffer.id(), BufferPair(shm_buffer, buffer))).second;
281 DCHECK(inserted); 271 DCHECK(inserted);
282 RecordBufferData(bitstream_buffer, *buffer.get()); 272 RecordBufferData(bitstream_buffer, *buffer.get());
283 273
284 vda_->Decode(bitstream_buffer); 274 vda_->Decode(bitstream_buffer);
285
286 if (!ready_video_frames_.empty()) {
287 EnqueueFrameAndTriggerFrameDelivery(NULL);
288 return;
289 }
290
291 if (CanMoreDecodeWorkBeDone())
292 base::ResetAndReturn(&pending_decode_cb_).Run(kNotEnoughData, NULL);
293 }
294
295 bool GpuVideoDecoder::CanMoreDecodeWorkBeDone() {
296 return bitstream_buffers_in_decoder_.size() < kMaxInFlightDecodes;
297 } 275 }
298 276
299 void GpuVideoDecoder::RecordBufferData(const BitstreamBuffer& bitstream_buffer, 277 void GpuVideoDecoder::RecordBufferData(const BitstreamBuffer& bitstream_buffer,
300 const DecoderBuffer& buffer) { 278 const DecoderBuffer& buffer) {
301 input_buffer_data_.push_front(BufferData(bitstream_buffer.id(), 279 input_buffer_data_.push_front(BufferData(bitstream_buffer.id(),
302 buffer.timestamp(), 280 buffer.timestamp(),
303 config_.visible_rect(), 281 config_.visible_rect(),
304 config_.natural_size())); 282 config_.natural_size()));
305 // Why this value? Because why not. avformat.h:MAX_REORDER_DELAY is 16, but 283 // Why this value? Because why not. avformat.h:MAX_REORDER_DELAY is 16, but
306 // that's too small for some pathological B-frame test videos. The cost of 284 // that's too small for some pathological B-frame test videos. The cost of
(...skipping 28 matching lines...) Expand all
335 313
336 bool GpuVideoDecoder::NeedsBitstreamConversion() const { 314 bool GpuVideoDecoder::NeedsBitstreamConversion() const {
337 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); 315 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
338 return needs_bitstream_conversion_; 316 return needs_bitstream_conversion_;
339 } 317 }
340 318
341 bool GpuVideoDecoder::CanReadWithoutStalling() const { 319 bool GpuVideoDecoder::CanReadWithoutStalling() const {
342 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); 320 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
343 return 321 return
344 next_picture_buffer_id_ == 0 || // Decode() will ProvidePictureBuffers(). 322 next_picture_buffer_id_ == 0 || // Decode() will ProvidePictureBuffers().
345 available_pictures_ > 0 || !ready_video_frames_.empty(); 323 available_pictures_ > 0;
324 }
325
326 int GpuVideoDecoder::GetMaxDecodeRequests() const {
327 return kMaxInFlightDecodes;
xhwang 2014/04/17 01:06:47 [not related to this CL] fischman: Do you know wh
Sergey Ulanov 2014/04/23 02:44:21 per e-mail thread VDA decoder shouldn't have any d
346 } 328 }
347 329
348 void GpuVideoDecoder::NotifyInitializeDone() { 330 void GpuVideoDecoder::NotifyInitializeDone() {
349 NOTREACHED() << "GpuVideoDecodeAcceleratorHost::Initialize is synchronous!"; 331 NOTREACHED() << "GpuVideoDecodeAcceleratorHost::Initialize is synchronous!";
350 } 332 }
351 333
352 void GpuVideoDecoder::ProvidePictureBuffers(uint32 count, 334 void GpuVideoDecoder::ProvidePictureBuffers(uint32 count,
353 const gfx::Size& size, 335 const gfx::Size& size,
354 uint32 texture_target) { 336 uint32 texture_target) {
355 DVLOG(3) << "ProvidePictureBuffers(" << count << ", " 337 DVLOG(3) << "ProvidePictureBuffers(" << count << ", "
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
472 timestamp, 454 timestamp,
473 base::Bind(&ReadPixelsSync, factories_, pb.texture_id(), visible_rect))); 455 base::Bind(&ReadPixelsSync, factories_, pb.texture_id(), visible_rect)));
474 CHECK_GT(available_pictures_, 0); 456 CHECK_GT(available_pictures_, 0);
475 --available_pictures_; 457 --available_pictures_;
476 bool inserted = 458 bool inserted =
477 picture_buffers_at_display_.insert(std::make_pair( 459 picture_buffers_at_display_.insert(std::make_pair(
478 picture.picture_buffer_id(), 460 picture.picture_buffer_id(),
479 pb.texture_id())).second; 461 pb.texture_id())).second;
480 DCHECK(inserted); 462 DCHECK(inserted);
481 463
482 EnqueueFrameAndTriggerFrameDelivery(frame); 464 DeliverFrame(frame);
483 } 465 }
484 466
485 void GpuVideoDecoder::EnqueueFrameAndTriggerFrameDelivery( 467 void GpuVideoDecoder::DeliverFrame(
486 const scoped_refptr<VideoFrame>& frame) { 468 const scoped_refptr<VideoFrame>& frame) {
487 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); 469 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
488 470
489 // During a pending vda->Reset(), we don't accumulate frames. Drop it on the 471 // During a pending vda->Reset(), we don't accumulate frames. Drop it on the
490 // floor and return. 472 // floor and return.
491 if (!pending_reset_cb_.is_null()) 473 if (!pending_reset_cb_.is_null())
492 return; 474 return;
493 475
494 if (frame.get()) 476 CHECK(!pending_decode_callbacks_.empty());
xhwang 2014/04/17 01:06:47 This is catching a coding error, use DCHECK?
Sergey Ulanov 2014/04/23 02:44:21 Done.
495 ready_video_frames_.push_back(frame);
496 else
497 DCHECK(!ready_video_frames_.empty());
498 477
499 if (pending_decode_cb_.is_null()) 478 DecodeCB decode_cb = pending_decode_callbacks_.front();
500 return; 479 pending_decode_callbacks_.pop_front();
501 480
502 base::ResetAndReturn(&pending_decode_cb_) 481 decode_cb.Run(kOk, frame);
503 .Run(kOk, ready_video_frames_.front());
504 ready_video_frames_.pop_front();
505 } 482 }
506 483
507 // static 484 // static
508 void GpuVideoDecoder::ReleaseMailbox( 485 void GpuVideoDecoder::ReleaseMailbox(
509 base::WeakPtr<GpuVideoDecoder> decoder, 486 base::WeakPtr<GpuVideoDecoder> decoder,
510 const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories, 487 const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories,
511 int64 picture_buffer_id, 488 int64 picture_buffer_id,
512 uint32 texture_id, 489 uint32 texture_id,
513 scoped_ptr<gpu::MailboxHolder> mailbox_holder) { 490 scoped_ptr<gpu::MailboxHolder> mailbox_holder) {
514 DCHECK(factories->GetTaskRunner()->BelongsToCurrentThread()); 491 DCHECK(factories->GetTaskRunner()->BelongsToCurrentThread());
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
575 std::map<int32, BufferPair>::iterator it = 552 std::map<int32, BufferPair>::iterator it =
576 bitstream_buffers_in_decoder_.find(id); 553 bitstream_buffers_in_decoder_.find(id);
577 if (it == bitstream_buffers_in_decoder_.end()) { 554 if (it == bitstream_buffers_in_decoder_.end()) {
578 NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE); 555 NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE);
579 NOTREACHED() << "Missing bitstream buffer: " << id; 556 NOTREACHED() << "Missing bitstream buffer: " << id;
580 return; 557 return;
581 } 558 }
582 559
583 PutSHM(it->second.shm_buffer); 560 PutSHM(it->second.shm_buffer);
584 bitstream_buffers_in_decoder_.erase(it); 561 bitstream_buffers_in_decoder_.erase(it);
585
586 if (pending_reset_cb_.is_null() && state_ != kDrainingDecoder &&
587 CanMoreDecodeWorkBeDone() && !pending_decode_cb_.is_null()) {
588 base::ResetAndReturn(&pending_decode_cb_).Run(kNotEnoughData, NULL);
589 }
xhwang 2014/04/17 01:06:47 Kudos for removing this logic!
590 } 562 }
591 563
592 GpuVideoDecoder::~GpuVideoDecoder() { 564 GpuVideoDecoder::~GpuVideoDecoder() {
593 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); 565 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
594 // Stop should have been already called. 566 // Stop should have been already called.
595 DCHECK(!vda_.get() && assigned_picture_buffers_.empty()); 567 DCHECK(!vda_.get() && assigned_picture_buffers_.empty());
596 DCHECK(pending_decode_cb_.is_null()); 568 DCHECK(pending_decode_callbacks_.empty());
597 for (size_t i = 0; i < available_shm_segments_.size(); ++i) { 569 for (size_t i = 0; i < available_shm_segments_.size(); ++i) {
598 available_shm_segments_[i]->shm->Close(); 570 available_shm_segments_[i]->shm->Close();
599 delete available_shm_segments_[i]; 571 delete available_shm_segments_[i];
600 } 572 }
601 available_shm_segments_.clear(); 573 available_shm_segments_.clear();
602 for (std::map<int32, BufferPair>::iterator it = 574 for (std::map<int32, BufferPair>::iterator it =
603 bitstream_buffers_in_decoder_.begin(); 575 bitstream_buffers_in_decoder_.begin();
604 it != bitstream_buffers_in_decoder_.end(); ++it) { 576 it != bitstream_buffers_in_decoder_.end(); ++it) {
605 it->second.shm_buffer->shm->Close(); 577 it->second.shm_buffer->shm->Close();
606 } 578 }
607 bitstream_buffers_in_decoder_.clear(); 579 bitstream_buffers_in_decoder_.clear();
608 } 580 }
609 581
610 void GpuVideoDecoder::NotifyFlushDone() { 582 void GpuVideoDecoder::NotifyFlushDone() {
611 DVLOG(3) << "NotifyFlushDone()"; 583 DVLOG(3) << "NotifyFlushDone()";
612 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); 584 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
613 DCHECK_EQ(state_, kDrainingDecoder); 585 DCHECK_EQ(state_, kDrainingDecoder);
614 state_ = kDecoderDrained; 586 state_ = kDecoderDrained;
615 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEOSFrame()); 587 DeliverFrame(VideoFrame::CreateEOSFrame());
xhwang 2014/04/17 01:06:47 I suspect that after FlushDone, we'll still have u
Sergey Ulanov 2014/04/23 02:44:21 Added DCHECK_EQ(pending_decode_callbacks_.size(),
616 } 588 }
617 589
618 void GpuVideoDecoder::NotifyResetDone() { 590 void GpuVideoDecoder::NotifyResetDone() {
619 DVLOG(3) << "NotifyResetDone()"; 591 DVLOG(3) << "NotifyResetDone()";
620 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); 592 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
621 DCHECK(ready_video_frames_.empty()); 593 DCHECK(pending_decode_callbacks_.empty());
622 594
623 // This needs to happen after the Reset() on vda_ is done to ensure pictures 595 // This needs to happen after the Reset() on vda_ is done to ensure pictures
624 // delivered during the reset can find their time data. 596 // delivered during the reset can find their time data.
625 input_buffer_data_.clear(); 597 input_buffer_data_.clear();
626 598
627 if (!pending_reset_cb_.is_null()) 599 if (!pending_reset_cb_.is_null())
628 base::ResetAndReturn(&pending_reset_cb_).Run(); 600 base::ResetAndReturn(&pending_reset_cb_).Run();
629
630 if (!pending_decode_cb_.is_null())
631 EnqueueFrameAndTriggerFrameDelivery(VideoFrame::CreateEOSFrame());
632 } 601 }
633 602
634 void GpuVideoDecoder::NotifyError(media::VideoDecodeAccelerator::Error error) { 603 void GpuVideoDecoder::NotifyError(media::VideoDecodeAccelerator::Error error) {
635 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); 604 DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
636 if (!vda_) 605 if (!vda_)
637 return; 606 return;
638 607
639 DLOG(ERROR) << "VDA Error: " << error; 608 DLOG(ERROR) << "VDA Error: " << error;
640 DestroyVDA(); 609 DestroyVDA();
641 610
642 state_ = kError; 611 state_ = kError;
643 612
644 if (!pending_decode_cb_.is_null()) { 613 while (!pending_decode_callbacks_.empty()) {
645 base::ResetAndReturn(&pending_decode_cb_).Run(kDecodeError, NULL); 614 pending_decode_callbacks_.front().Run(kDecodeError, NULL);
646 return; 615 pending_decode_callbacks_.pop_front();
647 } 616 }
648 } 617 }
649 618
650 void GpuVideoDecoder::DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent() 619 void GpuVideoDecoder::DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent()
651 const { 620 const {
652 DCHECK(factories_->GetTaskRunner()->BelongsToCurrentThread()); 621 DCHECK(factories_->GetTaskRunner()->BelongsToCurrentThread());
653 } 622 }
654 623
655 } // namespace media 624 } // namespace media
OLDNEW
« media/filters/gpu_video_decoder.h ('K') | « media/filters/gpu_video_decoder.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698