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__ << ": " << config.AsHumanReadableString(); |
102 << " is_encrypted:" << config.is_encrypted; | |
103 | 114 |
| 115 DCHECK(client); |
104 client_ = client; | 116 client_ = client; |
105 codec_ = VideoCodecProfileToVideoCodec(config.profile); | 117 codec_ = VideoCodecProfileToVideoCodec(config.profile); |
106 is_encrypted_ = config.is_encrypted; | 118 is_encrypted_ = config.is_encrypted; |
107 | 119 |
108 bool profile_supported = codec_ == media::kCodecVP8; | 120 bool profile_supported = codec_ == media::kCodecVP8; |
109 #if defined(ENABLE_MEDIA_PIPELINE_ON_ANDROID) | 121 #if defined(ENABLE_MEDIA_PIPELINE_ON_ANDROID) |
110 profile_supported |= | 122 profile_supported |= |
111 (codec_ == media::kCodecVP9 || codec_ == media::kCodecH264); | 123 (codec_ == media::kCodecVP9 || codec_ == media::kCodecH264); |
112 #endif | 124 #endif |
113 | 125 |
(...skipping 19 matching lines...) Expand all Loading... |
133 | 145 |
134 if (!gl_decoder_) { | 146 if (!gl_decoder_) { |
135 LOG(ERROR) << "Failed to get gles2 decoder instance."; | 147 LOG(ERROR) << "Failed to get gles2 decoder instance."; |
136 return false; | 148 return false; |
137 } | 149 } |
138 | 150 |
139 strategy_->Initialize(this); | 151 strategy_->Initialize(this); |
140 | 152 |
141 surface_texture_ = strategy_->CreateSurfaceTexture(); | 153 surface_texture_ = strategy_->CreateSurfaceTexture(); |
142 | 154 |
143 if (!ConfigureMediaCodec()) { | 155 // For encrypted streams we postpone configuration until MediaCrypto is |
144 LOG(ERROR) << "Failed to create MediaCodec instance."; | 156 // available. |
145 return false; | 157 if (is_encrypted_) |
146 } | 158 return true; |
147 | 159 |
148 return true; | 160 return ConfigureMediaCodec(); |
149 } | 161 } |
150 | 162 |
151 void AndroidVideoDecodeAccelerator::SetCdm(int cdm_id) { | 163 void AndroidVideoDecodeAccelerator::SetCdm(int cdm_id) { |
152 DVLOG(2) << __FUNCTION__ << ": " << cdm_id; | 164 DVLOG(2) << __FUNCTION__ << ": " << cdm_id; |
153 | 165 |
154 #if defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) | 166 #if defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) |
155 // TODO(timav): Implement CDM setting here. See http://crbug.com/542417 | 167 using media::MediaDrmBridge; |
156 scoped_refptr<media::MediaKeys> cdm = media::MojoCdmService::GetCdm(cdm_id); | 168 |
157 DCHECK(cdm); | 169 DCHECK(client_) << "SetCdm() must be called after Initialize()."; |
158 #endif | 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)); |
| 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 // Keep trying to enqueue the front pending buffer. |
| 296 // |
| 297 // TODO(timav): Figure out whether stopping the pipeline in response to |
| 298 // this error and restarting it in OnKeyAdded() has significant benefits |
| 299 // (e.g. saving power). |
| 300 DVLOG(1) << "QueueSecureInputBuffer failed: NO_KEY"; |
| 301 return; |
| 302 } |
| 303 |
| 304 pending_bitstream_buffers_.pop(); |
| 305 TRACE_COUNTER1("media", "AVDA::PendingBitstreamBufferCount", |
| 306 pending_bitstream_buffers_.size()); |
| 307 |
245 RETURN_ON_FAILURE(this, status == media::MEDIA_CODEC_OK, | 308 RETURN_ON_FAILURE(this, status == media::MEDIA_CODEC_OK, |
246 "Failed to QueueInputBuffer: " << status, PLATFORM_FAILURE); | 309 "Failed to QueueInputBuffer: " << status, PLATFORM_FAILURE); |
247 | 310 |
248 // We should call NotifyEndOfBitstreamBuffer(), when no more decoded output | 311 // We should call NotifyEndOfBitstreamBuffer(), when no more decoded output |
249 // will be returned from the bitstream buffer. However, MediaCodec API is | 312 // will be returned from the bitstream buffer. However, MediaCodec API is |
250 // not enough to guarantee it. | 313 // not enough to guarantee it. |
251 // So, here, we calls NotifyEndOfBitstreamBuffer() in advance in order to | 314 // So, here, we calls NotifyEndOfBitstreamBuffer() in advance in order to |
252 // keep getting more bitstreams from the client, and throttle them by using | 315 // keep getting more bitstreams from the client, and throttle them by using |
253 // |bitstreams_notified_in_advance_|. | 316 // |bitstreams_notified_in_advance_|. |
254 // TODO(dwkang): check if there is a way to remove this workaround. | 317 // 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)); | 561 Decode(media::BitstreamBuffer(-1, base::SharedMemoryHandle(), 0)); |
499 } | 562 } |
500 | 563 |
501 bool AndroidVideoDecodeAccelerator::ConfigureMediaCodec() { | 564 bool AndroidVideoDecodeAccelerator::ConfigureMediaCodec() { |
502 DCHECK(thread_checker_.CalledOnValidThread()); | 565 DCHECK(thread_checker_.CalledOnValidThread()); |
503 DCHECK(surface_texture_.get()); | 566 DCHECK(surface_texture_.get()); |
504 TRACE_EVENT0("media", "AVDA::ConfigureMediaCodec"); | 567 TRACE_EVENT0("media", "AVDA::ConfigureMediaCodec"); |
505 | 568 |
506 gfx::ScopedJavaSurface surface(surface_texture_.get()); | 569 gfx::ScopedJavaSurface surface(surface_texture_.get()); |
507 | 570 |
| 571 jobject media_crypto = media_crypto_ ? media_crypto_->obj() : nullptr; |
| 572 |
| 573 // |needs_protected_surface_| implies encrypted stream. |
| 574 DCHECK(!needs_protected_surface_ || media_crypto); |
| 575 |
508 // Pass a dummy 320x240 canvas size and let the codec signal the real size | 576 // Pass a dummy 320x240 canvas size and let the codec signal the real size |
509 // when it's known from the bitstream. | 577 // when it's known from the bitstream. |
510 media_codec_.reset(media::VideoCodecBridge::CreateDecoder( | 578 media_codec_.reset(media::VideoCodecBridge::CreateDecoder( |
511 codec_, false, gfx::Size(320, 240), surface.j_surface().obj(), NULL)); | 579 codec_, needs_protected_surface_, gfx::Size(320, 240), |
| 580 surface.j_surface().obj(), media_crypto)); |
512 strategy_->CodecChanged(media_codec_.get(), output_picture_buffers_); | 581 strategy_->CodecChanged(media_codec_.get(), output_picture_buffers_); |
513 if (!media_codec_) | 582 if (!media_codec_) { |
| 583 LOG(ERROR) << "Failed to create MediaCodec instance."; |
514 return false; | 584 return false; |
| 585 } |
515 | 586 |
516 io_timer_.Start(FROM_HERE, | 587 io_timer_.Start(FROM_HERE, |
517 DecodePollDelay(), | 588 DecodePollDelay(), |
518 this, | 589 this, |
519 &AndroidVideoDecodeAccelerator::DoIOTask); | 590 &AndroidVideoDecodeAccelerator::DoIOTask); |
520 return true; | 591 return true; |
521 } | 592 } |
522 | 593 |
523 void AndroidVideoDecodeAccelerator::Reset() { | 594 void AndroidVideoDecodeAccelerator::Reset() { |
524 DCHECK(thread_checker_.CalledOnValidThread()); | 595 DCHECK(thread_checker_.CalledOnValidThread()); |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
599 | 670 |
600 void AndroidVideoDecodeAccelerator::PostError( | 671 void AndroidVideoDecodeAccelerator::PostError( |
601 const ::tracked_objects::Location& from_here, | 672 const ::tracked_objects::Location& from_here, |
602 media::VideoDecodeAccelerator::Error error) { | 673 media::VideoDecodeAccelerator::Error error) { |
603 base::MessageLoop::current()->PostTask( | 674 base::MessageLoop::current()->PostTask( |
604 from_here, base::Bind(&AndroidVideoDecodeAccelerator::NotifyError, | 675 from_here, base::Bind(&AndroidVideoDecodeAccelerator::NotifyError, |
605 weak_this_factory_.GetWeakPtr(), error)); | 676 weak_this_factory_.GetWeakPtr(), error)); |
606 state_ = ERROR; | 677 state_ = ERROR; |
607 } | 678 } |
608 | 679 |
| 680 void AndroidVideoDecodeAccelerator::OnMediaCryptoReady( |
| 681 media::MediaDrmBridge::JavaObjectPtr media_crypto, |
| 682 bool needs_protected_surface) { |
| 683 DVLOG(1) << __FUNCTION__; |
| 684 |
| 685 if (!media_crypto) { |
| 686 LOG(ERROR) << "MediaCrypto is not available, can't play encrypted stream."; |
| 687 NotifyCdmAttached(false); |
| 688 return; |
| 689 } |
| 690 |
| 691 DCHECK(!media_crypto->is_null()); |
| 692 |
| 693 // We assume this is a part of the initialization process, thus MediaCodec |
| 694 // is not created yet. |
| 695 DCHECK(!media_codec_); |
| 696 |
| 697 media_crypto_ = std::move(media_crypto); |
| 698 needs_protected_surface_ = needs_protected_surface; |
| 699 |
| 700 // After receiving |media_crypto_| we can configure MediaCodec. |
| 701 const bool success = ConfigureMediaCodec(); |
| 702 NotifyCdmAttached(success); |
| 703 } |
| 704 |
| 705 void AndroidVideoDecodeAccelerator::OnKeyAdded() { |
| 706 DVLOG(1) << __FUNCTION__; |
| 707 // TODO(timav): Figure out whether stopping the pipeline in response to |
| 708 // NO_KEY error and restarting it here has significant benefits (e.g. saving |
| 709 // power). Right now do nothing here. |
| 710 } |
| 711 |
609 void AndroidVideoDecodeAccelerator::NotifyCdmAttached(bool success) { | 712 void AndroidVideoDecodeAccelerator::NotifyCdmAttached(bool success) { |
610 client_->NotifyCdmAttached(success); | 713 client_->NotifyCdmAttached(success); |
611 } | 714 } |
612 | 715 |
613 void AndroidVideoDecodeAccelerator::NotifyPictureReady( | 716 void AndroidVideoDecodeAccelerator::NotifyPictureReady( |
614 const media::Picture& picture) { | 717 const media::Picture& picture) { |
615 client_->PictureReady(picture); | 718 client_->PictureReady(picture); |
616 } | 719 } |
617 | 720 |
618 void AndroidVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer( | 721 void AndroidVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer( |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
666 // software fallback for H264 on Android anyway. | 769 // software fallback for H264 on Android anyway. |
667 profile.max_resolution.SetSize(3840, 2160); | 770 profile.max_resolution.SetSize(3840, 2160); |
668 profiles.push_back(profile); | 771 profiles.push_back(profile); |
669 } | 772 } |
670 #endif | 773 #endif |
671 | 774 |
672 return profiles; | 775 return profiles; |
673 } | 776 } |
674 | 777 |
675 } // namespace content | 778 } // namespace content |
OLD | NEW |