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

Side by Side Diff: content/common/gpu/media/android_video_decode_accelerator.cc

Issue 1469353010: Configure MediaCodec with CDM in ADVA (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase, used std::move, added VDA::Config::AsHumanReadableString Created 5 years 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
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698