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

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 again Created 4 years, 11 months 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') | media/base/BUILD.gn » ('j') | 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 <stddef.h> 7 #include <stddef.h>
8 8
9 #include "base/android/build_info.h" 9 #include "base/android/build_info.h"
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
11 #include "base/command_line.h" 12 #include "base/command_line.h"
12 #include "base/logging.h" 13 #include "base/logging.h"
13 #include "base/message_loop/message_loop.h" 14 #include "base/message_loop/message_loop.h"
14 #include "base/metrics/histogram.h" 15 #include "base/metrics/histogram.h"
15 #include "base/trace_event/trace_event.h" 16 #include "base/trace_event/trace_event.h"
16 #include "content/common/gpu/gpu_channel.h" 17 #include "content/common/gpu/gpu_channel.h"
17 #include "content/common/gpu/media/android_copying_backing_strategy.h" 18 #include "content/common/gpu/media/android_copying_backing_strategy.h"
18 #include "content/common/gpu/media/android_deferred_rendering_backing_strategy.h " 19 #include "content/common/gpu/media/android_deferred_rendering_backing_strategy.h "
19 #include "content/common/gpu/media/avda_return_on_failure.h" 20 #include "content/common/gpu/media/avda_return_on_failure.h"
20 #include "gpu/command_buffer/service/gles2_cmd_decoder.h" 21 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
22 #include "media/base/bind_to_current_loop.h"
21 #include "media/base/bitstream_buffer.h" 23 #include "media/base/bitstream_buffer.h"
22 #include "media/base/limits.h" 24 #include "media/base/limits.h"
23 #include "media/base/media_switches.h" 25 #include "media/base/media_switches.h"
24 #include "media/base/timestamp_constants.h" 26 #include "media/base/timestamp_constants.h"
25 #include "media/base/video_decoder_config.h" 27 #include "media/base/video_decoder_config.h"
26 #include "media/video/picture.h" 28 #include "media/video/picture.h"
27 #include "ui/gl/android/scoped_java_surface.h" 29 #include "ui/gl/android/scoped_java_surface.h"
28 #include "ui/gl/android/surface_texture.h" 30 #include "ui/gl/android/surface_texture.h"
29 #include "ui/gl/gl_bindings.h" 31 #include "ui/gl/gl_bindings.h"
30 32
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 DISALLOW_COPY_AND_ASSIGN(OnFrameAvailableHandler); 143 DISALLOW_COPY_AND_ASSIGN(OnFrameAvailableHandler);
142 }; 144 };
143 145
144 AndroidVideoDecodeAccelerator::AndroidVideoDecodeAccelerator( 146 AndroidVideoDecodeAccelerator::AndroidVideoDecodeAccelerator(
145 const base::WeakPtr<gpu::gles2::GLES2Decoder> decoder, 147 const base::WeakPtr<gpu::gles2::GLES2Decoder> decoder,
146 const base::Callback<bool(void)>& make_context_current) 148 const base::Callback<bool(void)>& make_context_current)
147 : client_(NULL), 149 : client_(NULL),
148 make_context_current_(make_context_current), 150 make_context_current_(make_context_current),
149 codec_(media::kCodecH264), 151 codec_(media::kCodecH264),
150 is_encrypted_(false), 152 is_encrypted_(false),
153 needs_protected_surface_(false),
151 state_(NO_ERROR), 154 state_(NO_ERROR),
152 picturebuffers_requested_(false), 155 picturebuffers_requested_(false),
153 gl_decoder_(decoder), 156 gl_decoder_(decoder),
157 cdm_registration_id_(0),
154 weak_this_factory_(this) { 158 weak_this_factory_(this) {
155 if (UseDeferredRenderingStrategy()) 159 if (UseDeferredRenderingStrategy())
156 strategy_.reset(new AndroidDeferredRenderingBackingStrategy()); 160 strategy_.reset(new AndroidDeferredRenderingBackingStrategy());
157 else 161 else
158 strategy_.reset(new AndroidCopyingBackingStrategy()); 162 strategy_.reset(new AndroidCopyingBackingStrategy());
159 } 163 }
160 164
161 AndroidVideoDecodeAccelerator::~AndroidVideoDecodeAccelerator() { 165 AndroidVideoDecodeAccelerator::~AndroidVideoDecodeAccelerator() {
162 DCHECK(thread_checker_.CalledOnValidThread()); 166 DCHECK(thread_checker_.CalledOnValidThread());
167
168 #if defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS)
169 if (cdm_) {
170 DCHECK(cdm_registration_id_);
171 static_cast<media::MediaDrmBridge*>(cdm_.get())
172 ->UnregisterPlayer(cdm_registration_id_);
173 }
174 #endif // defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS)
163 } 175 }
164 176
165 bool AndroidVideoDecodeAccelerator::Initialize(const Config& config, 177 bool AndroidVideoDecodeAccelerator::Initialize(const Config& config,
166 Client* client) { 178 Client* client) {
167 DCHECK(!media_codec_); 179 DCHECK(!media_codec_);
168 DCHECK(thread_checker_.CalledOnValidThread()); 180 DCHECK(thread_checker_.CalledOnValidThread());
169 TRACE_EVENT0("media", "AVDA::Initialize"); 181 TRACE_EVENT0("media", "AVDA::Initialize");
170 182
171 DVLOG(1) << __FUNCTION__ << ": profile:" << config.profile 183 DVLOG(1) << __FUNCTION__ << ": " << config.AsHumanReadableString();
172 << " is_encrypted:" << config.is_encrypted;
173 184
185 DCHECK(client);
174 client_ = client; 186 client_ = client;
175 codec_ = VideoCodecProfileToVideoCodec(config.profile); 187 codec_ = VideoCodecProfileToVideoCodec(config.profile);
176 is_encrypted_ = config.is_encrypted; 188 is_encrypted_ = config.is_encrypted;
177 189
178 bool profile_supported = codec_ == media::kCodecVP8 || 190 bool profile_supported = codec_ == media::kCodecVP8 ||
179 codec_ == media::kCodecVP9 || 191 codec_ == media::kCodecVP9 ||
180 codec_ == media::kCodecH264; 192 codec_ == media::kCodecH264;
181 193
182 if (!profile_supported) { 194 if (!profile_supported) {
183 LOG(ERROR) << "Unsupported profile: " << config.profile; 195 LOG(ERROR) << "Unsupported profile: " << config.profile;
(...skipping 19 matching lines...) Expand all
203 LOG(ERROR) << "Failed to get gles2 decoder instance."; 215 LOG(ERROR) << "Failed to get gles2 decoder instance.";
204 return false; 216 return false;
205 } 217 }
206 218
207 strategy_->Initialize(this); 219 strategy_->Initialize(this);
208 220
209 surface_texture_ = strategy_->CreateSurfaceTexture(); 221 surface_texture_ = strategy_->CreateSurfaceTexture();
210 on_frame_available_handler_ = 222 on_frame_available_handler_ =
211 new OnFrameAvailableHandler(this, surface_texture_); 223 new OnFrameAvailableHandler(this, surface_texture_);
212 224
213 if (!ConfigureMediaCodec()) { 225 // For encrypted streams we postpone configuration until MediaCrypto is
214 LOG(ERROR) << "Failed to create MediaCodec instance."; 226 // available.
215 return false; 227 if (is_encrypted_)
216 } 228 return true;
217 229
218 return true; 230 return ConfigureMediaCodec();
219 } 231 }
220 232
221 void AndroidVideoDecodeAccelerator::SetCdm(int cdm_id) { 233 void AndroidVideoDecodeAccelerator::SetCdm(int cdm_id) {
222 DVLOG(2) << __FUNCTION__ << ": " << cdm_id; 234 DVLOG(2) << __FUNCTION__ << ": " << cdm_id;
223 235
224 #if defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) 236 #if defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS)
225 // TODO(timav): Implement CDM setting here. See http://crbug.com/542417 237 using media::MediaDrmBridge;
226 scoped_refptr<media::MediaKeys> cdm = media::MojoCdmService::GetCdm(cdm_id); 238
227 DCHECK(cdm); 239 DCHECK(client_) << "SetCdm() must be called after Initialize().";
228 #endif 240
241 if (cdm_) {
242 NOTREACHED() << "We do not support resetting CDM.";
243 NotifyCdmAttached(false);
244 return;
245 }
246
247 cdm_ = media::MojoCdmService::GetCdm(cdm_id);
248 DCHECK(cdm_);
249
250 // On Android platform the MediaKeys will be its subclass MediaDrmBridge.
251 MediaDrmBridge* drm_bridge = static_cast<MediaDrmBridge*>(cdm_.get());
252
253 // Register CDM callbacks. The callbacks registered will be posted back to
254 // this thread via BindToCurrentLoop.
255
256 // Since |this| holds a reference to the |cdm_|, by the time the CDM is
257 // destructed, UnregisterPlayer() must have been called and |this| has been
258 // destructed as well. So the |cdm_unset_cb| will never have a chance to be
259 // called.
260 // TODO(xhwang): Remove |cdm_unset_cb| after it's not used on all platforms.
261 cdm_registration_id_ =
262 drm_bridge->RegisterPlayer(media::BindToCurrentLoop(base::Bind(
263 &AndroidVideoDecodeAccelerator::OnKeyAdded,
264 weak_this_factory_.GetWeakPtr())),
265 base::Bind(&base::DoNothing));
266
267 drm_bridge->SetMediaCryptoReadyCB(media::BindToCurrentLoop(
268 base::Bind(&AndroidVideoDecodeAccelerator::OnMediaCryptoReady,
269 weak_this_factory_.GetWeakPtr())));
270
271 // Postpone NotifyCdmAttached() call till we create the MediaCodec after
272 // OnMediaCryptoReady().
273
274 #else
229 275
230 NOTIMPLEMENTED(); 276 NOTIMPLEMENTED();
231 NotifyCdmAttached(false); 277 NotifyCdmAttached(false);
278
279 #endif // !defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS)
232 } 280 }
233 281
234 void AndroidVideoDecodeAccelerator::DoIOTask() { 282 void AndroidVideoDecodeAccelerator::DoIOTask() {
235 DCHECK(thread_checker_.CalledOnValidThread()); 283 DCHECK(thread_checker_.CalledOnValidThread());
236 TRACE_EVENT0("media", "AVDA::DoIOTask"); 284 TRACE_EVENT0("media", "AVDA::DoIOTask");
237 if (state_ == ERROR) { 285 if (state_ == ERROR) {
238 return; 286 return;
239 } 287 }
240 288
241 bool did_work = QueueInput(); 289 bool did_work = QueueInput();
(...skipping 18 matching lines...) Expand all
260 DCHECK(status == media::MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER || 308 DCHECK(status == media::MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER ||
261 status == media::MEDIA_CODEC_ERROR); 309 status == media::MEDIA_CODEC_ERROR);
262 return false; 310 return false;
263 } 311 }
264 312
265 base::Time queued_time = pending_bitstream_buffers_.front().second; 313 base::Time queued_time = pending_bitstream_buffers_.front().second;
266 UMA_HISTOGRAM_TIMES("Media.AVDA.InputQueueTime", 314 UMA_HISTOGRAM_TIMES("Media.AVDA.InputQueueTime",
267 base::Time::Now() - queued_time); 315 base::Time::Now() - queued_time);
268 media::BitstreamBuffer bitstream_buffer = 316 media::BitstreamBuffer bitstream_buffer =
269 pending_bitstream_buffers_.front().first; 317 pending_bitstream_buffers_.front().first;
270 pending_bitstream_buffers_.pop();
271 TRACE_COUNTER1("media", "AVDA::PendingBitstreamBufferCount",
272 pending_bitstream_buffers_.size());
273 318
274 if (bitstream_buffer.id() == -1) { 319 if (bitstream_buffer.id() == -1) {
320 pending_bitstream_buffers_.pop();
321 TRACE_COUNTER1("media", "AVDA::PendingBitstreamBufferCount",
322 pending_bitstream_buffers_.size());
323
275 media_codec_->QueueEOS(input_buf_index); 324 media_codec_->QueueEOS(input_buf_index);
276 return true; 325 return true;
277 } 326 }
278 327
279 scoped_ptr<base::SharedMemory> shm( 328 scoped_ptr<base::SharedMemory> shm(
280 new base::SharedMemory(bitstream_buffer.handle(), true)); 329 new base::SharedMemory(bitstream_buffer.handle(), true));
281 RETURN_ON_FAILURE(this, shm->Map(bitstream_buffer.size()), 330 RETURN_ON_FAILURE(this, shm->Map(bitstream_buffer.size()),
282 "Failed to SharedMemory::Map()", UNREADABLE_INPUT, false); 331 "Failed to SharedMemory::Map()", UNREADABLE_INPUT, false);
283 332
284 const base::TimeDelta presentation_timestamp = 333 const base::TimeDelta presentation_timestamp =
(...skipping 19 matching lines...) Expand all
304 status = media_codec_->QueueInputBuffer(input_buf_index, memory, 353 status = media_codec_->QueueInputBuffer(input_buf_index, memory,
305 bitstream_buffer.size(), 354 bitstream_buffer.size(),
306 presentation_timestamp); 355 presentation_timestamp);
307 } else { 356 } else {
308 status = media_codec_->QueueSecureInputBuffer( 357 status = media_codec_->QueueSecureInputBuffer(
309 input_buf_index, memory, bitstream_buffer.size(), key_id, iv, 358 input_buf_index, memory, bitstream_buffer.size(), key_id, iv,
310 subsamples, presentation_timestamp); 359 subsamples, presentation_timestamp);
311 } 360 }
312 361
313 DVLOG(2) << __FUNCTION__ 362 DVLOG(2) << __FUNCTION__
314 << ": QueueInputBuffer: pts:" << presentation_timestamp 363 << ": Queue(Secure)InputBuffer: pts:" << presentation_timestamp
315 << " status:" << status; 364 << " status:" << status;
316 365
366 if (status == media::MEDIA_CODEC_NO_KEY) {
367 // Keep trying to enqueue the front pending buffer.
368 //
369 // TODO(timav): Figure out whether stopping the pipeline in response to
370 // this error and restarting it in OnKeyAdded() has significant benefits
371 // (e.g. saving power).
372 DVLOG(1) << "QueueSecureInputBuffer failed: NO_KEY";
373 return true;
374 }
375
376 pending_bitstream_buffers_.pop();
377 TRACE_COUNTER1("media", "AVDA::PendingBitstreamBufferCount",
378 pending_bitstream_buffers_.size());
379
317 RETURN_ON_FAILURE(this, status == media::MEDIA_CODEC_OK, 380 RETURN_ON_FAILURE(this, status == media::MEDIA_CODEC_OK,
318 "Failed to QueueInputBuffer: " << status, PLATFORM_FAILURE, 381 "Failed to QueueInputBuffer: " << status, PLATFORM_FAILURE,
319 false); 382 false);
320 383
321 // We should call NotifyEndOfBitstreamBuffer(), when no more decoded output 384 // We should call NotifyEndOfBitstreamBuffer(), when no more decoded output
322 // will be returned from the bitstream buffer. However, MediaCodec API is 385 // will be returned from the bitstream buffer. However, MediaCodec API is
323 // not enough to guarantee it. 386 // not enough to guarantee it.
324 // So, here, we calls NotifyEndOfBitstreamBuffer() in advance in order to 387 // So, here, we calls NotifyEndOfBitstreamBuffer() in advance in order to
325 // keep getting more bitstreams from the client, and throttle them by using 388 // keep getting more bitstreams from the client, and throttle them by using
326 // |bitstreams_notified_in_advance_|. 389 // |bitstreams_notified_in_advance_|.
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after
579 Decode(media::BitstreamBuffer(-1, base::SharedMemoryHandle(), 0)); 642 Decode(media::BitstreamBuffer(-1, base::SharedMemoryHandle(), 0));
580 } 643 }
581 644
582 bool AndroidVideoDecodeAccelerator::ConfigureMediaCodec() { 645 bool AndroidVideoDecodeAccelerator::ConfigureMediaCodec() {
583 DCHECK(thread_checker_.CalledOnValidThread()); 646 DCHECK(thread_checker_.CalledOnValidThread());
584 DCHECK(surface_texture_.get()); 647 DCHECK(surface_texture_.get());
585 TRACE_EVENT0("media", "AVDA::ConfigureMediaCodec"); 648 TRACE_EVENT0("media", "AVDA::ConfigureMediaCodec");
586 649
587 gfx::ScopedJavaSurface surface(surface_texture_.get()); 650 gfx::ScopedJavaSurface surface(surface_texture_.get());
588 651
652 jobject media_crypto = media_crypto_ ? media_crypto_->obj() : nullptr;
653
654 // |needs_protected_surface_| implies encrypted stream.
655 DCHECK(!needs_protected_surface_ || media_crypto);
656
589 // Pass a dummy 320x240 canvas size and let the codec signal the real size 657 // Pass a dummy 320x240 canvas size and let the codec signal the real size
590 // when it's known from the bitstream. 658 // when it's known from the bitstream.
591 media_codec_.reset(media::VideoCodecBridge::CreateDecoder( 659 media_codec_.reset(media::VideoCodecBridge::CreateDecoder(
592 codec_, false, gfx::Size(320, 240), surface.j_surface().obj(), NULL)); 660 codec_, needs_protected_surface_, gfx::Size(320, 240),
661 surface.j_surface().obj(), media_crypto));
593 strategy_->CodecChanged(media_codec_.get(), output_picture_buffers_); 662 strategy_->CodecChanged(media_codec_.get(), output_picture_buffers_);
594 if (!media_codec_) 663 if (!media_codec_) {
664 LOG(ERROR) << "Failed to create MediaCodec instance.";
595 return false; 665 return false;
666 }
596 667
597 ManageTimer(true); 668 ManageTimer(true);
598 return true; 669 return true;
599 } 670 }
600 671
601 void AndroidVideoDecodeAccelerator::ResetCodecState() { 672 void AndroidVideoDecodeAccelerator::ResetCodecState() {
602 // TODO(chcunningham): This will likely dismiss a handful of decoded frames 673 // TODO(chcunningham): This will likely dismiss a handful of decoded frames
603 // that have not yet been drawn and returned to us for re-use. Consider 674 // that have not yet been drawn and returned to us for re-use. Consider
604 // a more complicated design that would wait for these to be drawn before 675 // a more complicated design that would wait for these to be drawn before
605 // dismissing. 676 // dismissing.
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
705 776
706 void AndroidVideoDecodeAccelerator::PostError( 777 void AndroidVideoDecodeAccelerator::PostError(
707 const ::tracked_objects::Location& from_here, 778 const ::tracked_objects::Location& from_here,
708 media::VideoDecodeAccelerator::Error error) { 779 media::VideoDecodeAccelerator::Error error) {
709 base::MessageLoop::current()->PostTask( 780 base::MessageLoop::current()->PostTask(
710 from_here, base::Bind(&AndroidVideoDecodeAccelerator::NotifyError, 781 from_here, base::Bind(&AndroidVideoDecodeAccelerator::NotifyError,
711 weak_this_factory_.GetWeakPtr(), error)); 782 weak_this_factory_.GetWeakPtr(), error));
712 state_ = ERROR; 783 state_ = ERROR;
713 } 784 }
714 785
786 void AndroidVideoDecodeAccelerator::OnMediaCryptoReady(
787 media::MediaDrmBridge::JavaObjectPtr media_crypto,
788 bool needs_protected_surface) {
789 DVLOG(1) << __FUNCTION__;
790
791 if (!media_crypto) {
792 LOG(ERROR) << "MediaCrypto is not available, can't play encrypted stream.";
793 NotifyCdmAttached(false);
794 return;
795 }
796
797 DCHECK(!media_crypto->is_null());
798
799 // We assume this is a part of the initialization process, thus MediaCodec
800 // is not created yet.
801 DCHECK(!media_codec_);
802
803 media_crypto_ = std::move(media_crypto);
804 needs_protected_surface_ = needs_protected_surface;
805
806 // After receiving |media_crypto_| we can configure MediaCodec.
807 const bool success = ConfigureMediaCodec();
808 NotifyCdmAttached(success);
809 }
810
811 void AndroidVideoDecodeAccelerator::OnKeyAdded() {
812 DVLOG(1) << __FUNCTION__;
813 // TODO(timav): Figure out whether stopping the pipeline in response to
814 // NO_KEY error and restarting it here has significant benefits (e.g. saving
815 // power). Right now do nothing here.
816 }
817
715 void AndroidVideoDecodeAccelerator::NotifyCdmAttached(bool success) { 818 void AndroidVideoDecodeAccelerator::NotifyCdmAttached(bool success) {
716 client_->NotifyCdmAttached(success); 819 client_->NotifyCdmAttached(success);
717 } 820 }
718 821
719 void AndroidVideoDecodeAccelerator::NotifyPictureReady( 822 void AndroidVideoDecodeAccelerator::NotifyPictureReady(
720 const media::Picture& picture) { 823 const media::Picture& picture) {
721 client_->PictureReady(picture); 824 client_->PictureReady(picture);
722 } 825 }
723 826
724 void AndroidVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer( 827 void AndroidVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer(
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
802 905
803 if (UseDeferredRenderingStrategy()) { 906 if (UseDeferredRenderingStrategy()) {
804 capabilities.flags = media::VideoDecodeAccelerator::Capabilities:: 907 capabilities.flags = media::VideoDecodeAccelerator::Capabilities::
805 NEEDS_ALL_PICTURE_BUFFERS_TO_DECODE; 908 NEEDS_ALL_PICTURE_BUFFERS_TO_DECODE;
806 } 909 }
807 910
808 return capabilities; 911 return capabilities;
809 } 912 }
810 913
811 } // namespace content 914 } // namespace content
OLDNEW
« no previous file with comments | « content/common/gpu/media/android_video_decode_accelerator.h ('k') | media/base/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698