Chromium Code Reviews| 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 "media/gpu/android_video_decode_accelerator.h" | 5 #include "media/gpu/android_video_decode_accelerator.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <memory> | 9 #include <memory> |
| 10 | 10 |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 242 io_timer_.Stop(); | 242 io_timer_.Stop(); |
| 243 } | 243 } |
| 244 | 244 |
| 245 // Eventually, we should run the timer on this thread. For now, we just keep | 245 // Eventually, we should run the timer on this thread. For now, we just keep |
| 246 // it as a convenience for construction. | 246 // it as a convenience for construction. |
| 247 scoped_refptr<base::SingleThreadTaskRunner> ConstructionTaskRunner() { | 247 scoped_refptr<base::SingleThreadTaskRunner> ConstructionTaskRunner() { |
| 248 DCHECK(thread_checker_.CalledOnValidThread()); | 248 DCHECK(thread_checker_.CalledOnValidThread()); |
| 249 return construction_thread_.task_runner(); | 249 return construction_thread_.task_runner(); |
| 250 } | 250 } |
| 251 | 251 |
| 252 // |owner| would like to use |surface_id|. If it is not busy, then mark it | |
|
watk
2016/05/18 20:38:18
No "owner" any more
liberato (no reviews please)
2016/05/18 21:13:13
Done.
| |
| 253 // as busy and return true. If it is busy, then replace any existing waiter, | |
| 254 // make |owner| the current waiter, and return false. Any existing waiter | |
| 255 // is assumed to be on the way out, so we fail its allocation request. | |
| 256 bool AllocateSurface(int surface_id, AndroidVideoDecodeAccelerator* avda) { | |
| 257 SurfaceWaiterMap::iterator iter = surface_waiter_map_.find(surface_id); | |
| 258 | |
| 259 // Nobody has to wait for no surface. | |
|
DaleCurtis
2016/05/18 17:59:11
Move above find?
liberato (no reviews please)
2016/05/18 18:49:39
Done.
| |
| 260 if (surface_id == AndroidVideoDecodeAccelerator::Config::kNoSurfaceID) | |
| 261 return true; | |
| 262 | |
| 263 if (iter == surface_waiter_map_.end()) { | |
| 264 // SurfaceView isn't allocated. Succeed. | |
| 265 surface_waiter_map_[surface_id].owner = avda; | |
| 266 surface_waiter_map_[surface_id].waiter = nullptr; | |
| 267 return true; | |
| 268 } | |
| 269 | |
| 270 // SurfaceView is already allocated. | |
| 271 | |
| 272 if (iter->second.waiter != nullptr) { | |
|
DaleCurtis
2016/05/18 17:59:11
Can you explain this design choice? I.e. why would
liberato (no reviews please)
2016/05/18 18:49:39
because WMPI maintains at most one AVDA instance.
DaleCurtis
2016/05/18 18:55:49
Hmm, what about other WMPI instances?
liberato (no reviews please)
2016/05/18 19:51:18
|surface_id_| will not be the same if the surface
| |
| 273 // Some other AVDA is waiting. |avda| will replace it, so notify it | |
| 274 // that it will fail. | |
| 275 iter->second.waiter->OnSurfaceAvailable(false); | |
| 276 iter->second.waiter = nullptr; | |
| 277 } | |
| 278 | |
| 279 // |avda| is now waiting. | |
| 280 iter->second.waiter = avda; | |
| 281 return false; | |
| 282 } | |
| 283 | |
| 284 // Clear any waiting request for |surface_id| by |avda|. It is okay if | |
| 285 // |waiter| is not waiting and/or isn't the owner of |surface_id|. | |
| 286 void DeallocateSurface(int surface_id, AndroidVideoDecodeAccelerator* avda) { | |
| 287 SurfaceWaiterMap::iterator iter = surface_waiter_map_.find(surface_id); | |
| 288 if (iter == surface_waiter_map_.end()) | |
|
DaleCurtis
2016/05/18 17:59:11
Should this dcheck?
liberato (no reviews please)
2016/05/18 18:49:39
no. this way, one simply calls Deallocate uncondi
| |
| 289 return; | |
| 290 | |
| 291 // If |avda| was waiting, then remove it without OnSurfaceAvailable. | |
| 292 if (iter->second.waiter == avda) | |
| 293 iter->second.waiter = nullptr; | |
| 294 | |
| 295 // If |avda| is the owner, then let the next owner have it. | |
| 296 if (iter->second.owner == avda) { | |
|
DaleCurtis
2016/05/18 17:59:11
Use early returns instead.
liberato (no reviews please)
2016/05/18 18:49:39
Done.
| |
| 297 if (AndroidVideoDecodeAccelerator* waiter = iter->second.waiter) { | |
| 298 // Promote |waiter| to be the owner. | |
| 299 iter->second.owner = waiter; | |
| 300 iter->second.waiter = nullptr; | |
| 301 waiter->OnSurfaceAvailable(true); | |
| 302 } else { | |
| 303 // No waiter -- remove the record and return since |iter| is | |
| 304 // no longer valid. | |
| 305 surface_waiter_map_.erase(iter); | |
| 306 return; | |
| 307 } | |
| 308 } | |
| 309 } | |
| 310 | |
| 252 private: | 311 private: |
| 253 friend struct base::DefaultLazyInstanceTraits<AVDATimerManager>; | 312 friend struct base::DefaultLazyInstanceTraits<AVDATimerManager>; |
| 254 | 313 |
| 255 AVDATimerManager() : construction_thread_("AVDAThread") {} | 314 AVDATimerManager() : construction_thread_("AVDAThread") {} |
| 256 ~AVDATimerManager() { NOTREACHED(); } | 315 ~AVDATimerManager() { NOTREACHED(); } |
| 257 | 316 |
| 258 void RunTimer() { | 317 void RunTimer() { |
| 259 { | 318 { |
| 260 // Call out to all AVDA instances, some of which may attempt to remove | 319 // Call out to all AVDA instances, some of which may attempt to remove |
| 261 // themselves from the list during this operation; those removals will be | 320 // themselves from the list during this operation; those removals will be |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 273 // TODO(dalecurtis): We may want to consider chunking this if task execution | 332 // TODO(dalecurtis): We may want to consider chunking this if task execution |
| 274 // takes too long for the combined timer. | 333 // takes too long for the combined timer. |
| 275 } | 334 } |
| 276 | 335 |
| 277 // All AVDA instances that would like us to poll DoIOTask. | 336 // All AVDA instances that would like us to poll DoIOTask. |
| 278 std::set<AndroidVideoDecodeAccelerator*> timer_avda_instances_; | 337 std::set<AndroidVideoDecodeAccelerator*> timer_avda_instances_; |
| 279 | 338 |
| 280 // All AVDA instances that might like to use the construction thread. | 339 // All AVDA instances that might like to use the construction thread. |
| 281 std::set<AndroidVideoDecodeAccelerator*> thread_avda_instances_; | 340 std::set<AndroidVideoDecodeAccelerator*> thread_avda_instances_; |
| 282 | 341 |
| 342 // [surface id] = accelerator that owns the surface, or nullptr. | |
|
watk
2016/05/18 20:38:18
Comment seems out of date/wrong place
liberato (no reviews please)
2016/05/18 21:13:13
Done.
| |
| 343 struct OwnerRecord { | |
| 344 OwnerRecord() : owner(nullptr), waiter(nullptr) {} | |
|
DaleCurtis
2016/05/18 17:59:11
Constructor prevents this from being a POD type. I
liberato (no reviews please)
2016/05/18 18:49:39
hrm, i just tried brace-or-equal but that doesn't
DaleCurtis
2016/05/18 18:55:49
Dropping the constructor and not using = nullptr o
liberato (no reviews please)
2016/05/18 19:51:17
i switched to "= nullptr" in the most recent CL.
| |
| 345 AndroidVideoDecodeAccelerator* owner; | |
| 346 AndroidVideoDecodeAccelerator* waiter; | |
| 347 }; | |
| 348 using SurfaceWaiterMap = std::map<int, OwnerRecord>; | |
| 349 SurfaceWaiterMap surface_waiter_map_; | |
| 350 | |
| 283 // Since we can't delete while iterating when using a set, defer erasure until | 351 // Since we can't delete while iterating when using a set, defer erasure until |
| 284 // after iteration complete. | 352 // after iteration complete. |
| 285 bool timer_running_ = false; | 353 bool timer_running_ = false; |
| 286 std::set<AndroidVideoDecodeAccelerator*> pending_erase_; | 354 std::set<AndroidVideoDecodeAccelerator*> pending_erase_; |
| 287 | 355 |
| 288 // Repeating timer responsible for draining pending IO to the codecs. | 356 // Repeating timer responsible for draining pending IO to the codecs. |
| 289 base::RepeatingTimer io_timer_; | 357 base::RepeatingTimer io_timer_; |
| 290 | 358 |
| 291 base::Thread construction_thread_; | 359 base::Thread construction_thread_; |
| 292 | 360 |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 311 is_encrypted_(false), | 379 is_encrypted_(false), |
| 312 state_(NO_ERROR), | 380 state_(NO_ERROR), |
| 313 picturebuffers_requested_(false), | 381 picturebuffers_requested_(false), |
| 314 drain_type_(DRAIN_TYPE_NONE), | 382 drain_type_(DRAIN_TYPE_NONE), |
| 315 media_drm_bridge_cdm_context_(nullptr), | 383 media_drm_bridge_cdm_context_(nullptr), |
| 316 cdm_registration_id_(0), | 384 cdm_registration_id_(0), |
| 317 pending_input_buf_index_(-1), | 385 pending_input_buf_index_(-1), |
| 318 error_sequence_token_(0), | 386 error_sequence_token_(0), |
| 319 defer_errors_(false), | 387 defer_errors_(false), |
| 320 deferred_initialization_pending_(false), | 388 deferred_initialization_pending_(false), |
| 389 cdm_id_(0), | |
| 321 surface_id_(media::VideoDecodeAccelerator::Config::kNoSurfaceID), | 390 surface_id_(media::VideoDecodeAccelerator::Config::kNoSurfaceID), |
| 322 weak_this_factory_(this) {} | 391 weak_this_factory_(this) {} |
| 323 | 392 |
| 324 AndroidVideoDecodeAccelerator::~AndroidVideoDecodeAccelerator() { | 393 AndroidVideoDecodeAccelerator::~AndroidVideoDecodeAccelerator() { |
| 325 DCHECK(thread_checker_.CalledOnValidThread()); | 394 DCHECK(thread_checker_.CalledOnValidThread()); |
| 326 g_avda_timer.Pointer()->StopTimer(this); | 395 g_avda_timer.Pointer()->StopTimer(this); |
| 327 g_avda_timer.Pointer()->StopThread(this); | 396 g_avda_timer.Pointer()->StopThread(this); |
| 328 | 397 |
| 329 #if defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) | 398 #if defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) |
| 330 if (!media_drm_bridge_cdm_context_) | 399 if (!media_drm_bridge_cdm_context_) |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 352 return false; | 421 return false; |
| 353 } | 422 } |
| 354 | 423 |
| 355 DCHECK(client); | 424 DCHECK(client); |
| 356 client_ = client; | 425 client_ = client; |
| 357 codec_config_ = new CodecConfig(); | 426 codec_config_ = new CodecConfig(); |
| 358 codec_config_->codec_ = VideoCodecProfileToVideoCodec(config.profile); | 427 codec_config_->codec_ = VideoCodecProfileToVideoCodec(config.profile); |
| 359 codec_config_->initial_expected_coded_size_ = | 428 codec_config_->initial_expected_coded_size_ = |
| 360 config.initial_expected_coded_size; | 429 config.initial_expected_coded_size; |
| 361 is_encrypted_ = config.is_encrypted; | 430 is_encrypted_ = config.is_encrypted; |
| 431 cdm_id_ = config.cdm_id; | |
| 362 | 432 |
| 363 // We signalled that we support deferred initialization, so see if the client | 433 // We signalled that we support deferred initialization, so see if the client |
| 364 // does also. | 434 // does also. |
| 365 deferred_initialization_pending_ = config.is_deferred_initialization_allowed; | 435 deferred_initialization_pending_ = config.is_deferred_initialization_allowed; |
| 366 | 436 |
| 367 if (is_encrypted_ && !deferred_initialization_pending_) { | 437 if (is_encrypted_ && !deferred_initialization_pending_) { |
| 368 DLOG(ERROR) << "Deferred initialization must be used for encrypted streams"; | 438 DLOG(ERROR) << "Deferred initialization must be used for encrypted streams"; |
| 369 return false; | 439 return false; |
| 370 } | 440 } |
| 371 | 441 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 408 DVLOG(1) << __FUNCTION__ << ", using copy back strategy."; | 478 DVLOG(1) << __FUNCTION__ << ", using copy back strategy."; |
| 409 strategy_.reset(new AndroidCopyingBackingStrategy(this)); | 479 strategy_.reset(new AndroidCopyingBackingStrategy(this)); |
| 410 } | 480 } |
| 411 | 481 |
| 412 if (!make_context_current_cb_.Run()) { | 482 if (!make_context_current_cb_.Run()) { |
| 413 LOG(ERROR) << "Failed to make this decoder's GL context current."; | 483 LOG(ERROR) << "Failed to make this decoder's GL context current."; |
| 414 return false; | 484 return false; |
| 415 } | 485 } |
| 416 | 486 |
| 417 surface_id_ = config.surface_id; | 487 surface_id_ = config.surface_id; |
| 488 if (g_avda_timer.Pointer()->AllocateSurface(surface_id_, this)) { | |
| 489 // We have succesfully owned the surface, so finish initialization now. | |
| 490 return InitializeStrategy(); | |
| 491 } | |
| 492 | |
| 493 // We have to wait for some other AVDA instance to free up the surface. | |
| 494 // OnSurfaceAvailable will be called when it's available. | |
| 495 return true; | |
| 496 } | |
| 497 | |
| 498 void AndroidVideoDecodeAccelerator::OnSurfaceAvailable(bool success) { | |
| 499 DCHECK(deferred_initialization_pending_); | |
| 500 | |
| 501 if (!success) { | |
| 502 // Surface isn't available and/or we're being destroyed. | |
| 503 NotifyInitializationComplete(false); | |
| 504 deferred_initialization_pending_ = false; | |
| 505 return; | |
| 506 } | |
| 507 | |
| 508 if (!InitializeStrategy()) { | |
|
watk
2016/05/18 20:38:18
Could merge this block into the above with a || if
liberato (no reviews please)
2016/05/18 21:13:13
Done.
| |
| 509 NotifyInitializationComplete(false); | |
| 510 deferred_initialization_pending_ = false; | |
| 511 } | |
| 512 } | |
| 513 | |
| 514 bool AndroidVideoDecodeAccelerator::InitializeStrategy() { | |
| 418 codec_config_->surface_ = strategy_->Initialize(surface_id_); | 515 codec_config_->surface_ = strategy_->Initialize(surface_id_); |
| 419 if (codec_config_->surface_.IsEmpty()) { | 516 if (codec_config_->surface_.IsEmpty()) { |
| 420 LOG(ERROR) << "Failed to initialize the backing strategy. The returned " | 517 LOG(ERROR) << "Failed to initialize the backing strategy. The returned " |
| 421 "Java surface is empty."; | 518 "Java surface is empty."; |
| 422 return false; | 519 return false; |
| 423 } | 520 } |
| 424 | 521 |
| 425 on_destroying_surface_cb_ = | 522 on_destroying_surface_cb_ = |
| 426 base::Bind(&AndroidVideoDecodeAccelerator::OnDestroyingSurface, | 523 base::Bind(&AndroidVideoDecodeAccelerator::OnDestroyingSurface, |
| 427 weak_this_factory_.GetWeakPtr()); | 524 weak_this_factory_.GetWeakPtr()); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 438 | 535 |
| 439 // Start the thread for async configuration, even if we don't need it now. | 536 // Start the thread for async configuration, even if we don't need it now. |
| 440 // ResetCodecState might rebuild the codec later, for example. | 537 // ResetCodecState might rebuild the codec later, for example. |
| 441 if (!g_avda_timer.Pointer()->StartThread(this)) { | 538 if (!g_avda_timer.Pointer()->StartThread(this)) { |
| 442 LOG(ERROR) << "Failed to start AVDA thread"; | 539 LOG(ERROR) << "Failed to start AVDA thread"; |
| 443 return false; | 540 return false; |
| 444 } | 541 } |
| 445 | 542 |
| 446 // If we are encrypted, then we aren't able to create the codec yet. | 543 // If we are encrypted, then we aren't able to create the codec yet. |
| 447 if (is_encrypted_) { | 544 if (is_encrypted_) { |
| 448 InitializeCdm(config.cdm_id); | 545 InitializeCdm(); |
| 449 return true; | 546 return true; |
| 450 } | 547 } |
| 451 | 548 |
| 452 if (deferred_initialization_pending_) { | 549 if (deferred_initialization_pending_) { |
| 453 ConfigureMediaCodecAsynchronously(); | 550 ConfigureMediaCodecAsynchronously(); |
| 454 return true; | 551 return true; |
| 455 } | 552 } |
| 456 | 553 |
| 457 // If the client doesn't support deferred initialization (WebRTC), then we | 554 // If the client doesn't support deferred initialization (WebRTC), then we |
| 458 // should complete it now and return a meaningful result. | 555 // should complete it now and return a meaningful result. Note that it would |
| 556 // be nice if we didn't have to worry about starting codec configuration at | |
| 557 // all (::Initialize or the wrapper can do it), but then they have to remember | |
| 558 // not to start codec config if we have to wait for the cdm. It's somewhat | |
| 559 // clearer for us to handle both cases. | |
| 459 return ConfigureMediaCodecSynchronously(); | 560 return ConfigureMediaCodecSynchronously(); |
| 460 } | 561 } |
| 461 | 562 |
| 462 void AndroidVideoDecodeAccelerator::DoIOTask(bool start_timer) { | 563 void AndroidVideoDecodeAccelerator::DoIOTask(bool start_timer) { |
| 463 DCHECK(thread_checker_.CalledOnValidThread()); | 564 DCHECK(thread_checker_.CalledOnValidThread()); |
| 464 TRACE_EVENT0("media", "AVDA::DoIOTask"); | 565 TRACE_EVENT0("media", "AVDA::DoIOTask"); |
| 465 if (state_ == ERROR || state_ == WAITING_FOR_CODEC || | 566 if (state_ == ERROR || state_ == WAITING_FOR_CODEC || |
| 466 state_ == SURFACE_DESTROYED) { | 567 state_ == SURFACE_DESTROYED) { |
| 467 return; | 568 return; |
| 468 } | 569 } |
| (...skipping 728 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1197 | 1298 |
| 1198 void AndroidVideoDecodeAccelerator::ActualDestroy() { | 1299 void AndroidVideoDecodeAccelerator::ActualDestroy() { |
| 1199 DVLOG(1) << __FUNCTION__; | 1300 DVLOG(1) << __FUNCTION__; |
| 1200 DCHECK(thread_checker_.CalledOnValidThread()); | 1301 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1201 | 1302 |
| 1202 if (!on_destroying_surface_cb_.is_null()) { | 1303 if (!on_destroying_surface_cb_.is_null()) { |
| 1203 AVDASurfaceTracker::GetInstance()->UnregisterOnDestroyingSurfaceCallback( | 1304 AVDASurfaceTracker::GetInstance()->UnregisterOnDestroyingSurfaceCallback( |
| 1204 on_destroying_surface_cb_); | 1305 on_destroying_surface_cb_); |
| 1205 } | 1306 } |
| 1206 | 1307 |
| 1308 // We no longer care about |surface_id_|, in case we did before. It's okay | |
| 1309 // if we have no surface and/or weren't the owner or a waiter. | |
| 1310 g_avda_timer.Pointer()->DeallocateSurface(surface_id_, this); | |
| 1311 | |
| 1207 // Note that async codec construction might still be in progress. In that | 1312 // Note that async codec construction might still be in progress. In that |
| 1208 // case, the codec will be deleted when it completes once we invalidate all | 1313 // case, the codec will be deleted when it completes once we invalidate all |
| 1209 // our weak refs. | 1314 // our weak refs. |
| 1210 weak_this_factory_.InvalidateWeakPtrs(); | 1315 weak_this_factory_.InvalidateWeakPtrs(); |
| 1211 if (media_codec_) { | 1316 if (media_codec_) { |
| 1212 g_avda_timer.Pointer()->StopTimer(this); | 1317 g_avda_timer.Pointer()->StopTimer(this); |
| 1213 media_codec_.reset(); | 1318 media_codec_.reset(); |
| 1214 } | 1319 } |
| 1215 delete this; | 1320 delete this; |
| 1216 } | 1321 } |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1289 const ::tracked_objects::Location& from_here, | 1394 const ::tracked_objects::Location& from_here, |
| 1290 media::VideoDecodeAccelerator::Error error) { | 1395 media::VideoDecodeAccelerator::Error error) { |
| 1291 base::MessageLoop::current()->PostDelayedTask( | 1396 base::MessageLoop::current()->PostDelayedTask( |
| 1292 from_here, | 1397 from_here, |
| 1293 base::Bind(&AndroidVideoDecodeAccelerator::NotifyError, | 1398 base::Bind(&AndroidVideoDecodeAccelerator::NotifyError, |
| 1294 weak_this_factory_.GetWeakPtr(), error, error_sequence_token_), | 1399 weak_this_factory_.GetWeakPtr(), error, error_sequence_token_), |
| 1295 (defer_errors_ ? ErrorPostingDelay() : base::TimeDelta())); | 1400 (defer_errors_ ? ErrorPostingDelay() : base::TimeDelta())); |
| 1296 state_ = ERROR; | 1401 state_ = ERROR; |
| 1297 } | 1402 } |
| 1298 | 1403 |
| 1299 void AndroidVideoDecodeAccelerator::InitializeCdm(int cdm_id) { | 1404 void AndroidVideoDecodeAccelerator::InitializeCdm() { |
| 1300 DVLOG(2) << __FUNCTION__ << ": " << cdm_id; | 1405 DVLOG(2) << __FUNCTION__ << ": " << cdm_id_; |
| 1301 | 1406 |
| 1302 #if !defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) | 1407 #if !defined(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) |
| 1303 NOTIMPLEMENTED(); | 1408 NOTIMPLEMENTED(); |
| 1304 NotifyInitializationComplete(false); | 1409 NotifyInitializationComplete(false); |
| 1305 #else | 1410 #else |
| 1306 // Store the CDM to hold a reference to it. | 1411 // Store the CDM to hold a reference to it. |
| 1307 cdm_for_reference_holding_only_ = media::MojoCdmService::LegacyGetCdm(cdm_id); | 1412 cdm_for_reference_holding_only_ = |
| 1413 media::MojoCdmService::LegacyGetCdm(cdm_id_); | |
| 1308 DCHECK(cdm_for_reference_holding_only_); | 1414 DCHECK(cdm_for_reference_holding_only_); |
| 1309 | 1415 |
| 1310 // On Android platform the CdmContext must be a MediaDrmBridgeCdmContext. | 1416 // On Android platform the CdmContext must be a MediaDrmBridgeCdmContext. |
| 1311 media_drm_bridge_cdm_context_ = static_cast<media::MediaDrmBridgeCdmContext*>( | 1417 media_drm_bridge_cdm_context_ = static_cast<media::MediaDrmBridgeCdmContext*>( |
| 1312 cdm_for_reference_holding_only_->GetCdmContext()); | 1418 cdm_for_reference_holding_only_->GetCdmContext()); |
| 1313 DCHECK(media_drm_bridge_cdm_context_); | 1419 DCHECK(media_drm_bridge_cdm_context_); |
| 1314 | 1420 |
| 1315 // Register CDM callbacks. The callbacks registered will be posted back to | 1421 // Register CDM callbacks. The callbacks registered will be posted back to |
| 1316 // this thread via BindToCurrentLoop. | 1422 // this thread via BindToCurrentLoop. |
| 1317 | 1423 |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1502 if (media::MediaCodecUtil::IsSurfaceViewOutputSupported()) { | 1608 if (media::MediaCodecUtil::IsSurfaceViewOutputSupported()) { |
| 1503 capabilities.flags |= media::VideoDecodeAccelerator::Capabilities:: | 1609 capabilities.flags |= media::VideoDecodeAccelerator::Capabilities:: |
| 1504 SUPPORTS_EXTERNAL_OUTPUT_SURFACE; | 1610 SUPPORTS_EXTERNAL_OUTPUT_SURFACE; |
| 1505 } | 1611 } |
| 1506 } | 1612 } |
| 1507 | 1613 |
| 1508 return capabilities; | 1614 return capabilities; |
| 1509 } | 1615 } |
| 1510 | 1616 |
| 1511 } // namespace media | 1617 } // namespace media |
| OLD | NEW |