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