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

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: Passed needs_protected_surface to codec configuration, addressed comments 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
« no previous file with comments | « content/common/gpu/media/android_video_decode_accelerator.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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__ << ": 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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « content/common/gpu/media/android_video_decode_accelerator.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698