OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 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 <CoreVideo/CoreVideo.h> | 5 #include <CoreVideo/CoreVideo.h> |
6 #include <OpenGL/CGLIOSurface.h> | 6 #include <OpenGL/CGLIOSurface.h> |
7 #include <OpenGL/gl.h> | 7 #include <OpenGL/gl.h> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/callback_helpers.h" | 10 #include "base/callback_helpers.h" |
11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
12 #include "base/sys_byteorder.h" | 12 #include "base/sys_byteorder.h" |
13 #include "base/thread_task_runner_handle.h" | 13 #include "base/thread_task_runner_handle.h" |
14 #include "content/common/gpu/media/vt_video_decode_accelerator.h" | 14 #include "content/common/gpu/media/vt_video_decode_accelerator.h" |
15 #include "content/public/common/content_switches.h" | 15 #include "content/public/common/content_switches.h" |
16 #include "media/filters/h264_parser.h" | 16 #include "media/filters/h264_parser.h" |
17 #include "ui/gl/scoped_binders.h" | 17 #include "ui/gl/scoped_binders.h" |
18 #include "ui/gl/scoped_cgl.h" | |
19 | 18 |
20 using content_common_gpu_media::kModuleVt; | 19 using content_common_gpu_media::kModuleVt; |
21 using content_common_gpu_media::InitializeStubs; | 20 using content_common_gpu_media::InitializeStubs; |
22 using content_common_gpu_media::IsVtInitialized; | 21 using content_common_gpu_media::IsVtInitialized; |
23 using content_common_gpu_media::StubPathMap; | 22 using content_common_gpu_media::StubPathMap; |
24 | 23 |
25 #define NOTIFY_STATUS(name, status) \ | 24 #define NOTIFY_STATUS(name, status) \ |
26 do { \ | 25 do { \ |
27 LOG(ERROR) << name << " failed with status " << status; \ | 26 LOG(ERROR) << name << " failed with status " << status; \ |
28 NotifyError(PLATFORM_FAILURE); \ | 27 NotifyError(PLATFORM_FAILURE); \ |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
66 VTVideoDecodeAccelerator::PendingAction::PendingAction( | 65 VTVideoDecodeAccelerator::PendingAction::PendingAction( |
67 Action action, | 66 Action action, |
68 int32_t bitstream_id) | 67 int32_t bitstream_id) |
69 : action(action), | 68 : action(action), |
70 bitstream_id(bitstream_id) { | 69 bitstream_id(bitstream_id) { |
71 } | 70 } |
72 | 71 |
73 VTVideoDecodeAccelerator::PendingAction::~PendingAction() { | 72 VTVideoDecodeAccelerator::PendingAction::~PendingAction() { |
74 } | 73 } |
75 | 74 |
76 VTVideoDecodeAccelerator::VTVideoDecodeAccelerator(CGLContextObj cgl_context) | 75 VTVideoDecodeAccelerator::VTVideoDecodeAccelerator( |
| 76 CGLContextObj cgl_context, |
| 77 const base::Callback<bool(void)>& make_context_current) |
77 : cgl_context_(cgl_context), | 78 : cgl_context_(cgl_context), |
| 79 make_context_current_(make_context_current), |
78 client_(NULL), | 80 client_(NULL), |
79 has_error_(false), | 81 has_error_(false), |
80 format_(NULL), | 82 format_(NULL), |
81 session_(NULL), | 83 session_(NULL), |
82 gpu_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 84 gpu_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
83 weak_this_factory_(this), | 85 weak_this_factory_(this), |
84 decoder_thread_("VTDecoderThread") { | 86 decoder_thread_("VTDecoderThread") { |
| 87 DCHECK(!make_context_current_.is_null()); |
85 callback_.decompressionOutputCallback = OutputThunk; | 88 callback_.decompressionOutputCallback = OutputThunk; |
86 callback_.decompressionOutputRefCon = this; | 89 callback_.decompressionOutputRefCon = this; |
87 } | 90 } |
88 | 91 |
89 VTVideoDecodeAccelerator::~VTVideoDecodeAccelerator() { | 92 VTVideoDecodeAccelerator::~VTVideoDecodeAccelerator() { |
90 } | 93 } |
91 | 94 |
92 bool VTVideoDecodeAccelerator::Initialize( | 95 bool VTVideoDecodeAccelerator::Initialize( |
93 media::VideoCodecProfile profile, | 96 media::VideoCodecProfile profile, |
94 Client* client) { | 97 Client* client) { |
(...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
526 int32_t VTVideoDecodeAccelerator::SendPictures(int32_t up_to_bitstream_id) { | 529 int32_t VTVideoDecodeAccelerator::SendPictures(int32_t up_to_bitstream_id) { |
527 DCHECK(CalledOnValidThread()); | 530 DCHECK(CalledOnValidThread()); |
528 DCHECK(!decoded_frames_.empty()); | 531 DCHECK(!decoded_frames_.empty()); |
529 | 532 |
530 // TODO(sandersd): Store the actual last sent bitstream ID? | 533 // TODO(sandersd): Store the actual last sent bitstream ID? |
531 int32_t last_sent_bitstream_id = -1; | 534 int32_t last_sent_bitstream_id = -1; |
532 | 535 |
533 if (available_picture_ids_.empty()) | 536 if (available_picture_ids_.empty()) |
534 return last_sent_bitstream_id; | 537 return last_sent_bitstream_id; |
535 | 538 |
536 gfx::ScopedCGLSetCurrentContext scoped_set_current_context(cgl_context_); | 539 if (!make_context_current_.Run()) { |
| 540 LOG(ERROR) << "Failed to make GL context current"; |
| 541 NotifyError(PLATFORM_FAILURE); |
| 542 return last_sent_bitstream_id; |
| 543 } |
| 544 |
537 glEnable(GL_TEXTURE_RECTANGLE_ARB); | 545 glEnable(GL_TEXTURE_RECTANGLE_ARB); |
538 while (!available_picture_ids_.empty() && | 546 while (!available_picture_ids_.empty() && |
539 !decoded_frames_.empty() && | 547 !decoded_frames_.empty() && |
540 last_sent_bitstream_id != up_to_bitstream_id && | 548 last_sent_bitstream_id != up_to_bitstream_id && |
541 !has_error_) { | 549 !has_error_) { |
542 // We don't pop |frame| until it is consumed, which won't happen if an | 550 // We don't pop |frame| until it is consumed, which won't happen if an |
543 // error occurs. Conveniently, this also removes some refcounting. | 551 // error occurs. Conveniently, this also removes some refcounting. |
544 const DecodedFrame& frame = decoded_frames_.front(); | 552 const DecodedFrame& frame = decoded_frames_.front(); |
545 DCHECK_EQ(pending_bitstream_ids_.front(), frame.bitstream_id); | 553 DCHECK_EQ(pending_bitstream_ids_.front(), frame.bitstream_id); |
546 | 554 |
547 // Likewise, |picture_id| won't be popped if |image_buffer| is NULL or an | 555 // Likewise, |picture_id| won't be popped if |image_buffer| is NULL or an |
548 // error occurs. | 556 // error occurs. |
549 // TODO(sandersd): Don't block waiting for a |picture_id| when | 557 // TODO(sandersd): Don't block waiting for a |picture_id| when |
550 // |image_buffer| is NULL. | 558 // |image_buffer| is NULL. |
551 int32_t picture_id = available_picture_ids_.front(); | 559 int32_t picture_id = available_picture_ids_.front(); |
552 | 560 |
553 CVImageBufferRef image_buffer = frame.image_buffer.get(); | 561 CVImageBufferRef image_buffer = frame.image_buffer.get(); |
554 if (image_buffer) { | 562 if (image_buffer) { |
555 IOSurfaceRef surface = CVPixelBufferGetIOSurface(image_buffer); | 563 IOSurfaceRef surface = CVPixelBufferGetIOSurface(image_buffer); |
556 | 564 |
557 // TODO(sandersd): Find out why this sometimes fails due to no GL context. | |
558 gfx::ScopedTextureBinder | 565 gfx::ScopedTextureBinder |
559 texture_binder(GL_TEXTURE_RECTANGLE_ARB, texture_ids_[picture_id]); | 566 texture_binder(GL_TEXTURE_RECTANGLE_ARB, texture_ids_[picture_id]); |
560 CGLError status = CGLTexImageIOSurface2D( | 567 CGLError status = CGLTexImageIOSurface2D( |
561 cgl_context_, // ctx | 568 cgl_context_, // ctx |
562 GL_TEXTURE_RECTANGLE_ARB, // target | 569 GL_TEXTURE_RECTANGLE_ARB, // target |
563 GL_RGB, // internal_format | 570 GL_RGB, // internal_format |
564 texture_size_.width(), // width | 571 texture_size_.width(), // width |
565 texture_size_.height(), // height | 572 texture_size_.height(), // height |
566 GL_YCBCR_422_APPLE, // format | 573 GL_YCBCR_422_APPLE, // format |
567 GL_UNSIGNED_SHORT_8_8_APPLE, // type | 574 GL_UNSIGNED_SHORT_8_8_APPLE, // type |
568 surface, // io_surface | 575 surface, // io_surface |
569 0); // plane | 576 0); // plane |
570 if (status != kCGLNoError) { | 577 if (status != kCGLNoError) { |
571 NOTIFY_STATUS("CGLTexImageIOSurface2D()", status); | 578 NOTIFY_STATUS("CGLTexImageIOSurface2D()", status); |
572 break; | 579 break; |
573 } | 580 } |
574 | 581 |
575 picture_bindings_[picture_id] = frame.image_buffer; | 582 picture_bindings_[picture_id] = frame.image_buffer; |
576 client_->PictureReady(media::Picture( | 583 client_->PictureReady(media::Picture( |
577 picture_id, frame.bitstream_id, gfx::Rect(texture_size_))); | 584 picture_id, frame.bitstream_id, gfx::Rect(texture_size_))); |
578 available_picture_ids_.pop(); | 585 available_picture_ids_.pop(); |
579 } | 586 } |
580 | 587 |
581 client_->NotifyEndOfBitstreamBuffer(frame.bitstream_id); | 588 client_->NotifyEndOfBitstreamBuffer(frame.bitstream_id); |
582 last_sent_bitstream_id = frame.bitstream_id; | 589 last_sent_bitstream_id = frame.bitstream_id; |
583 decoded_frames_.pop(); | 590 decoded_frames_.pop(); |
584 pending_bitstream_ids_.pop(); | 591 pending_bitstream_ids_.pop(); |
585 } | 592 } |
586 glDisable(GL_TEXTURE_RECTANGLE_ARB); | 593 glDisable(GL_TEXTURE_RECTANGLE_ARB); |
| 594 |
587 return last_sent_bitstream_id; | 595 return last_sent_bitstream_id; |
588 } | 596 } |
589 | 597 |
590 void VTVideoDecodeAccelerator::FlushTask() { | 598 void VTVideoDecodeAccelerator::FlushTask() { |
591 DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread()); | 599 DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread()); |
592 OSStatus status = VTDecompressionSessionFinishDelayedFrames(session_); | 600 OSStatus status = VTDecompressionSessionFinishDelayedFrames(session_); |
593 if (status) | 601 if (status) |
594 NOTIFY_STATUS("VTDecompressionSessionFinishDelayedFrames()", status); | 602 NOTIFY_STATUS("VTDecompressionSessionFinishDelayedFrames()", status); |
595 } | 603 } |
596 | 604 |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
653 pending_bitstream_ids_.pop(); | 661 pending_bitstream_ids_.pop(); |
654 } | 662 } |
655 QueueAction(ACTION_DESTROY); | 663 QueueAction(ACTION_DESTROY); |
656 } | 664 } |
657 | 665 |
658 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() { | 666 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() { |
659 return false; | 667 return false; |
660 } | 668 } |
661 | 669 |
662 } // namespace content | 670 } // namespace content |
OLD | NEW |