OLD | NEW |
---|---|
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 "content/common/gpu/media/android_video_decode_accelerator.h" | 5 #include "content/common/gpu/media/android_video_decode_accelerator.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
11 #include "base/trace_event/trace_event.h" | 11 #include "base/trace_event/trace_event.h" |
12 #include "content/common/gpu/gpu_channel.h" | 12 #include "content/common/gpu/gpu_channel.h" |
13 #include "content/common/gpu/media/avda_return_on_failure.h" | 13 #include "content/common/gpu/media/avda_return_on_failure.h" |
14 #include "gpu/command_buffer/service/gles2_cmd_decoder.h" | 14 #include "gpu/command_buffer/service/gles2_cmd_decoder.h" |
15 #include "media/base/bind_to_current_loop.h" | |
15 #include "media/base/bitstream_buffer.h" | 16 #include "media/base/bitstream_buffer.h" |
16 #include "media/base/limits.h" | 17 #include "media/base/limits.h" |
17 #include "media/base/timestamp_constants.h" | 18 #include "media/base/timestamp_constants.h" |
18 #include "media/base/video_decoder_config.h" | 19 #include "media/base/video_decoder_config.h" |
19 #include "media/video/picture.h" | 20 #include "media/video/picture.h" |
20 #include "ui/gl/android/scoped_java_surface.h" | 21 #include "ui/gl/android/scoped_java_surface.h" |
21 #include "ui/gl/android/surface_texture.h" | 22 #include "ui/gl/android/surface_texture.h" |
22 #include "ui/gl/gl_bindings.h" | 23 #include "ui/gl/gl_bindings.h" |
23 | 24 |
24 #if defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) | 25 #if defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
79 const base::Callback<bool(void)>& make_context_current, | 80 const base::Callback<bool(void)>& make_context_current, |
80 scoped_ptr<BackingStrategy> strategy) | 81 scoped_ptr<BackingStrategy> strategy) |
81 : client_(NULL), | 82 : client_(NULL), |
82 make_context_current_(make_context_current), | 83 make_context_current_(make_context_current), |
83 codec_(media::kCodecH264), | 84 codec_(media::kCodecH264), |
84 is_encrypted_(false), | 85 is_encrypted_(false), |
85 state_(NO_ERROR), | 86 state_(NO_ERROR), |
86 picturebuffers_requested_(false), | 87 picturebuffers_requested_(false), |
87 gl_decoder_(decoder), | 88 gl_decoder_(decoder), |
88 strategy_(strategy.Pass()), | 89 strategy_(strategy.Pass()), |
90 cdm_registration_id_(0), | |
89 weak_this_factory_(this) {} | 91 weak_this_factory_(this) {} |
90 | 92 |
91 AndroidVideoDecodeAccelerator::~AndroidVideoDecodeAccelerator() { | 93 AndroidVideoDecodeAccelerator::~AndroidVideoDecodeAccelerator() { |
92 DCHECK(thread_checker_.CalledOnValidThread()); | 94 DCHECK(thread_checker_.CalledOnValidThread()); |
95 | |
96 #if defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) | |
97 if (cdm_) { | |
98 DCHECK(cdm_registration_id_); | |
99 static_cast<media::MediaDrmBridge*>(cdm_.get()) | |
100 ->UnregisterPlayer(cdm_registration_id_); | |
101 } | |
102 #endif // defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) | |
93 } | 103 } |
94 | 104 |
95 bool AndroidVideoDecodeAccelerator::Initialize(const Config& config, | 105 bool AndroidVideoDecodeAccelerator::Initialize(const Config& config, |
96 Client* client) { | 106 Client* client) { |
97 DCHECK(!media_codec_); | 107 DCHECK(!media_codec_); |
98 DCHECK(thread_checker_.CalledOnValidThread()); | 108 DCHECK(thread_checker_.CalledOnValidThread()); |
99 TRACE_EVENT0("media", "AVDA::Initialize"); | 109 TRACE_EVENT0("media", "AVDA::Initialize"); |
100 | 110 |
101 DVLOG(1) << __FUNCTION__ << ": profile:" << config.profile | 111 DVLOG(1) << __FUNCTION__ << ": profile:" << config.profile |
102 << " is_encrypted:" << config.is_encrypted; | 112 << " is_encrypted:" << config.is_encrypted; |
103 | 113 |
114 DCHECK(client); | |
104 client_ = client; | 115 client_ = client; |
105 codec_ = VideoCodecProfileToVideoCodec(config.profile); | 116 codec_ = VideoCodecProfileToVideoCodec(config.profile); |
106 is_encrypted_ = config.is_encrypted; | 117 is_encrypted_ = config.is_encrypted; |
107 | 118 |
108 bool profile_supported = codec_ == media::kCodecVP8; | 119 bool profile_supported = codec_ == media::kCodecVP8; |
109 #if defined(ENABLE_MEDIA_PIPELINE_ON_ANDROID) | 120 #if defined(ENABLE_MEDIA_PIPELINE_ON_ANDROID) |
110 profile_supported |= | 121 profile_supported |= |
111 (codec_ == media::kCodecVP9 || codec_ == media::kCodecH264); | 122 (codec_ == media::kCodecVP9 || codec_ == media::kCodecH264); |
112 #endif | 123 #endif |
113 | 124 |
(...skipping 19 matching lines...) Expand all Loading... | |
133 | 144 |
134 if (!gl_decoder_) { | 145 if (!gl_decoder_) { |
135 LOG(ERROR) << "Failed to get gles2 decoder instance."; | 146 LOG(ERROR) << "Failed to get gles2 decoder instance."; |
136 return false; | 147 return false; |
137 } | 148 } |
138 | 149 |
139 strategy_->Initialize(this); | 150 strategy_->Initialize(this); |
140 | 151 |
141 surface_texture_ = strategy_->CreateSurfaceTexture(); | 152 surface_texture_ = strategy_->CreateSurfaceTexture(); |
142 | 153 |
143 if (!ConfigureMediaCodec()) { | 154 // For encrypted streams we postpone configuration until MediaCrypto is |
144 LOG(ERROR) << "Failed to create MediaCodec instance."; | 155 // available. |
145 return false; | 156 if (is_encrypted_) |
146 } | 157 return true; |
147 | 158 |
148 return true; | 159 return ConfigureMediaCodec(); |
149 } | 160 } |
150 | 161 |
151 void AndroidVideoDecodeAccelerator::SetCdm(int cdm_id) { | 162 void AndroidVideoDecodeAccelerator::SetCdm(int cdm_id) { |
152 DVLOG(2) << __FUNCTION__ << ": " << cdm_id; | 163 DVLOG(2) << __FUNCTION__ << ": " << cdm_id; |
153 | 164 |
154 #if defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) | 165 #if defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) |
155 // TODO(timav): Implement CDM setting here. See http://crbug.com/542417 | 166 using media::MediaDrmBridge; |
156 scoped_refptr<media::MediaKeys> cdm = media::MojoCdmService::GetCdm(cdm_id); | 167 |
157 DCHECK(cdm); | 168 // This medhod must be called after Initialize(). |
158 #endif | 169 DCHECK(client_); |
xhwang
2015/12/04 23:24:09
Put the comment in the DCHECK statement:
DCHECK(c
Tima Vaisburd
2015/12/05 01:35:25
Done.
| |
170 | |
171 if (cdm_) { | |
172 NOTREACHED() << "We do not support resetting CDM."; | |
173 NotifyCdmAttached(false); | |
174 return; | |
175 } | |
176 | |
177 cdm_ = media::MojoCdmService::GetCdm(cdm_id); | |
178 DCHECK(cdm_); | |
179 | |
180 // On Android platform the MediaKeys will be its subclass MediaDrmBridge. | |
181 MediaDrmBridge* drm_bridge = static_cast<MediaDrmBridge*>(cdm_.get()); | |
182 | |
183 // Register CDM callbacks. The callbacks registered will be posted back to | |
184 // this thread via BindToCurrentLoop. | |
185 | |
186 // Since |this| holds a reference to the |cdm_|, by the time the CDM is | |
187 // destructed, UnregisterPlayer() must have been called and |this| has been | |
188 // destructed as well. So the |cdm_unset_cb| will never have a chance to be | |
189 // called. | |
190 // TODO(xhwang): Remove |cdm_unset_cb| after it's not used on all platforms. | |
191 cdm_registration_id_ = | |
192 drm_bridge->RegisterPlayer(media::BindToCurrentLoop(base::Bind( | |
193 &AndroidVideoDecodeAccelerator::OnKeyAdded, | |
194 weak_this_factory_.GetWeakPtr())), | |
195 base::Bind(&base::DoNothing)); | |
xhwang
2015/12/04 23:24:09
add include for DoNothing()?
Tima Vaisburd
2015/12/05 01:35:25
Done.
| |
196 | |
197 drm_bridge->SetMediaCryptoReadyCB(media::BindToCurrentLoop( | |
198 base::Bind(&AndroidVideoDecodeAccelerator::OnMediaCryptoReady, | |
199 weak_this_factory_.GetWeakPtr()))); | |
200 | |
201 // Postpone NotifyCdmAttached() call till we create the MediaCodec after | |
202 // OnMediaCryptoReady(). | |
203 | |
204 #else | |
159 | 205 |
160 NOTIMPLEMENTED(); | 206 NOTIMPLEMENTED(); |
161 NotifyCdmAttached(false); | 207 NotifyCdmAttached(false); |
208 | |
209 #endif // !defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) | |
162 } | 210 } |
163 | 211 |
164 void AndroidVideoDecodeAccelerator::DoIOTask() { | 212 void AndroidVideoDecodeAccelerator::DoIOTask() { |
165 DCHECK(thread_checker_.CalledOnValidThread()); | 213 DCHECK(thread_checker_.CalledOnValidThread()); |
166 TRACE_EVENT0("media", "AVDA::DoIOTask"); | 214 TRACE_EVENT0("media", "AVDA::DoIOTask"); |
167 if (state_ == ERROR) { | 215 if (state_ == ERROR) { |
168 return; | 216 return; |
169 } | 217 } |
170 | 218 |
171 QueueInput(); | 219 QueueInput(); |
(...skipping 16 matching lines...) Expand all Loading... | |
188 DCHECK(status == media::MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER || | 236 DCHECK(status == media::MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER || |
189 status == media::MEDIA_CODEC_ERROR); | 237 status == media::MEDIA_CODEC_ERROR); |
190 return; | 238 return; |
191 } | 239 } |
192 | 240 |
193 base::Time queued_time = pending_bitstream_buffers_.front().second; | 241 base::Time queued_time = pending_bitstream_buffers_.front().second; |
194 UMA_HISTOGRAM_TIMES("Media.AVDA.InputQueueTime", | 242 UMA_HISTOGRAM_TIMES("Media.AVDA.InputQueueTime", |
195 base::Time::Now() - queued_time); | 243 base::Time::Now() - queued_time); |
196 media::BitstreamBuffer bitstream_buffer = | 244 media::BitstreamBuffer bitstream_buffer = |
197 pending_bitstream_buffers_.front().first; | 245 pending_bitstream_buffers_.front().first; |
198 pending_bitstream_buffers_.pop(); | |
199 TRACE_COUNTER1("media", "AVDA::PendingBitstreamBufferCount", | |
200 pending_bitstream_buffers_.size()); | |
201 | 246 |
202 if (bitstream_buffer.id() == -1) { | 247 if (bitstream_buffer.id() == -1) { |
248 pending_bitstream_buffers_.pop(); | |
249 TRACE_COUNTER1("media", "AVDA::PendingBitstreamBufferCount", | |
250 pending_bitstream_buffers_.size()); | |
251 | |
203 media_codec_->QueueEOS(input_buf_index); | 252 media_codec_->QueueEOS(input_buf_index); |
204 return; | 253 return; |
205 } | 254 } |
206 | 255 |
207 scoped_ptr<base::SharedMemory> shm( | 256 scoped_ptr<base::SharedMemory> shm( |
208 new base::SharedMemory(bitstream_buffer.handle(), true)); | 257 new base::SharedMemory(bitstream_buffer.handle(), true)); |
209 RETURN_ON_FAILURE(this, shm->Map(bitstream_buffer.size()), | 258 RETURN_ON_FAILURE(this, shm->Map(bitstream_buffer.size()), |
210 "Failed to SharedMemory::Map()", UNREADABLE_INPUT); | 259 "Failed to SharedMemory::Map()", UNREADABLE_INPUT); |
211 | 260 |
212 const base::TimeDelta presentation_timestamp = | 261 const base::TimeDelta presentation_timestamp = |
(...skipping 19 matching lines...) Expand all Loading... | |
232 status = media_codec_->QueueInputBuffer(input_buf_index, memory, | 281 status = media_codec_->QueueInputBuffer(input_buf_index, memory, |
233 bitstream_buffer.size(), | 282 bitstream_buffer.size(), |
234 presentation_timestamp); | 283 presentation_timestamp); |
235 } else { | 284 } else { |
236 status = media_codec_->QueueSecureInputBuffer( | 285 status = media_codec_->QueueSecureInputBuffer( |
237 input_buf_index, memory, bitstream_buffer.size(), key_id, iv, | 286 input_buf_index, memory, bitstream_buffer.size(), key_id, iv, |
238 subsamples, presentation_timestamp); | 287 subsamples, presentation_timestamp); |
239 } | 288 } |
240 | 289 |
241 DVLOG(2) << __FUNCTION__ | 290 DVLOG(2) << __FUNCTION__ |
242 << ": QueueInputBuffer: pts:" << presentation_timestamp | 291 << ": Queue(Secure)InputBuffer: pts:" << presentation_timestamp |
243 << " status:" << status; | 292 << " status:" << status; |
244 | 293 |
294 if (status == media::MEDIA_CODEC_NO_KEY) | |
295 return; // keep trying to enqueue the front pending buffer | |
296 | |
297 pending_bitstream_buffers_.pop(); | |
298 TRACE_COUNTER1("media", "AVDA::PendingBitstreamBufferCount", | |
299 pending_bitstream_buffers_.size()); | |
300 | |
245 RETURN_ON_FAILURE(this, status == media::MEDIA_CODEC_OK, | 301 RETURN_ON_FAILURE(this, status == media::MEDIA_CODEC_OK, |
246 "Failed to QueueInputBuffer: " << status, PLATFORM_FAILURE); | 302 "Failed to QueueInputBuffer: " << status, PLATFORM_FAILURE); |
247 | 303 |
248 // We should call NotifyEndOfBitstreamBuffer(), when no more decoded output | 304 // We should call NotifyEndOfBitstreamBuffer(), when no more decoded output |
249 // will be returned from the bitstream buffer. However, MediaCodec API is | 305 // will be returned from the bitstream buffer. However, MediaCodec API is |
250 // not enough to guarantee it. | 306 // not enough to guarantee it. |
251 // So, here, we calls NotifyEndOfBitstreamBuffer() in advance in order to | 307 // So, here, we calls NotifyEndOfBitstreamBuffer() in advance in order to |
252 // keep getting more bitstreams from the client, and throttle them by using | 308 // keep getting more bitstreams from the client, and throttle them by using |
253 // |bitstreams_notified_in_advance_|. | 309 // |bitstreams_notified_in_advance_|. |
254 // TODO(dwkang): check if there is a way to remove this workaround. | 310 // TODO(dwkang): check if there is a way to remove this workaround. |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
498 Decode(media::BitstreamBuffer(-1, base::SharedMemoryHandle(), 0)); | 554 Decode(media::BitstreamBuffer(-1, base::SharedMemoryHandle(), 0)); |
499 } | 555 } |
500 | 556 |
501 bool AndroidVideoDecodeAccelerator::ConfigureMediaCodec() { | 557 bool AndroidVideoDecodeAccelerator::ConfigureMediaCodec() { |
502 DCHECK(thread_checker_.CalledOnValidThread()); | 558 DCHECK(thread_checker_.CalledOnValidThread()); |
503 DCHECK(surface_texture_.get()); | 559 DCHECK(surface_texture_.get()); |
504 TRACE_EVENT0("media", "AVDA::ConfigureMediaCodec"); | 560 TRACE_EVENT0("media", "AVDA::ConfigureMediaCodec"); |
505 | 561 |
506 gfx::ScopedJavaSurface surface(surface_texture_.get()); | 562 gfx::ScopedJavaSurface surface(surface_texture_.get()); |
507 | 563 |
564 jobject media_crypto = media_crypto_ ? media_crypto_->obj() : nullptr; | |
565 | |
508 // Pass a dummy 320x240 canvas size and let the codec signal the real size | 566 // Pass a dummy 320x240 canvas size and let the codec signal the real size |
509 // when it's known from the bitstream. | 567 // when it's known from the bitstream. |
510 media_codec_.reset(media::VideoCodecBridge::CreateDecoder( | 568 media_codec_.reset(media::VideoCodecBridge::CreateDecoder( |
511 codec_, false, gfx::Size(320, 240), surface.j_surface().obj(), NULL)); | 569 codec_, false, gfx::Size(320, 240), surface.j_surface().obj(), |
570 media_crypto)); | |
512 strategy_->CodecChanged(media_codec_.get(), output_picture_buffers_); | 571 strategy_->CodecChanged(media_codec_.get(), output_picture_buffers_); |
513 if (!media_codec_) | 572 if (!media_codec_) { |
573 LOG(ERROR) << "Failed to create MediaCodec instance."; | |
514 return false; | 574 return false; |
575 } | |
515 | 576 |
516 io_timer_.Start(FROM_HERE, | 577 io_timer_.Start(FROM_HERE, |
517 DecodePollDelay(), | 578 DecodePollDelay(), |
518 this, | 579 this, |
519 &AndroidVideoDecodeAccelerator::DoIOTask); | 580 &AndroidVideoDecodeAccelerator::DoIOTask); |
520 return true; | 581 return true; |
521 } | 582 } |
522 | 583 |
523 void AndroidVideoDecodeAccelerator::Reset() { | 584 void AndroidVideoDecodeAccelerator::Reset() { |
524 DCHECK(thread_checker_.CalledOnValidThread()); | 585 DCHECK(thread_checker_.CalledOnValidThread()); |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
599 | 660 |
600 void AndroidVideoDecodeAccelerator::PostError( | 661 void AndroidVideoDecodeAccelerator::PostError( |
601 const ::tracked_objects::Location& from_here, | 662 const ::tracked_objects::Location& from_here, |
602 media::VideoDecodeAccelerator::Error error) { | 663 media::VideoDecodeAccelerator::Error error) { |
603 base::MessageLoop::current()->PostTask( | 664 base::MessageLoop::current()->PostTask( |
604 from_here, base::Bind(&AndroidVideoDecodeAccelerator::NotifyError, | 665 from_here, base::Bind(&AndroidVideoDecodeAccelerator::NotifyError, |
605 weak_this_factory_.GetWeakPtr(), error)); | 666 weak_this_factory_.GetWeakPtr(), error)); |
606 state_ = ERROR; | 667 state_ = ERROR; |
607 } | 668 } |
608 | 669 |
670 void AndroidVideoDecodeAccelerator::OnMediaCryptoReady( | |
671 media::MediaDrmBridge::JavaObjectPtr media_crypto, | |
672 bool needs_protected_surface) { | |
673 DVLOG(1) << __FUNCTION__; | |
674 | |
675 if (!media_crypto) { | |
676 LOG(ERROR) << "MediaCrypto is not available, can't play encrypted stream."; | |
677 NotifyCdmAttached(false); | |
678 return; | |
679 } | |
680 | |
681 DCHECK(!media_crypto->is_null()); | |
682 | |
683 // We assume this is a part of the initialization process, thus MediaCodec | |
684 // is not created yet. | |
685 DCHECK(!media_codec_); | |
686 | |
687 if (needs_protected_surface) { | |
688 LOG(ERROR) << "Protected surface is not supported."; | |
xhwang
2015/12/04 23:24:09
Is this NOTIMPLEMENTED() as well?
Tima Vaisburd
2015/12/05 01:35:25
Yes, and actually, the codec part is easy to imple
| |
689 NotifyCdmAttached(false); | |
690 return; | |
691 } | |
692 | |
693 media_crypto_ = media_crypto.Pass(); | |
694 | |
695 // After receiving |media_crypto_| we can configure MediaCodec. | |
696 const bool success = ConfigureMediaCodec(); | |
697 NotifyCdmAttached(success); | |
698 } | |
699 | |
700 void AndroidVideoDecodeAccelerator::OnKeyAdded() { | |
701 DVLOG(1) << __FUNCTION__; | |
702 } | |
703 | |
609 void AndroidVideoDecodeAccelerator::NotifyCdmAttached(bool success) { | 704 void AndroidVideoDecodeAccelerator::NotifyCdmAttached(bool success) { |
610 client_->NotifyCdmAttached(success); | 705 client_->NotifyCdmAttached(success); |
611 } | 706 } |
612 | 707 |
613 void AndroidVideoDecodeAccelerator::NotifyPictureReady( | 708 void AndroidVideoDecodeAccelerator::NotifyPictureReady( |
614 const media::Picture& picture) { | 709 const media::Picture& picture) { |
615 client_->PictureReady(picture); | 710 client_->PictureReady(picture); |
616 } | 711 } |
617 | 712 |
618 void AndroidVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer( | 713 void AndroidVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer( |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
666 // software fallback for H264 on Android anyway. | 761 // software fallback for H264 on Android anyway. |
667 profile.max_resolution.SetSize(3840, 2160); | 762 profile.max_resolution.SetSize(3840, 2160); |
668 profiles.push_back(profile); | 763 profiles.push_back(profile); |
669 } | 764 } |
670 #endif | 765 #endif |
671 | 766 |
672 return profiles; | 767 return profiles; |
673 } | 768 } |
674 | 769 |
675 } // namespace content | 770 } // namespace content |
OLD | NEW |