| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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/avda_codec_allocator.h" | 5 #include "media/gpu/avda_codec_allocator.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <memory> | 9 #include <memory> |
| 10 | 10 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 base::TimeDelta::FromMilliseconds(800); | 34 base::TimeDelta::FromMilliseconds(800); |
| 35 | 35 |
| 36 // Delete |codec| and signal |done_event| if it's not null. | 36 // Delete |codec| and signal |done_event| if it's not null. |
| 37 void DeleteMediaCodecAndSignal(std::unique_ptr<MediaCodecBridge> codec, | 37 void DeleteMediaCodecAndSignal(std::unique_ptr<MediaCodecBridge> codec, |
| 38 base::WaitableEvent* done_event) { | 38 base::WaitableEvent* done_event) { |
| 39 codec.reset(); | 39 codec.reset(); |
| 40 if (done_event) | 40 if (done_event) |
| 41 done_event->Signal(); | 41 done_event->Signal(); |
| 42 } | 42 } |
| 43 | 43 |
| 44 void DropReferenceToSurfaceBundle( |
| 45 scoped_refptr<AVDASurfaceBundle> surface_bundle) { |
| 46 // Do nothing. Let |surface_bundle| go out of scope. |
| 47 } |
| 48 |
| 44 } // namespace | 49 } // namespace |
| 45 | 50 |
| 46 CodecConfig::CodecConfig() {} | 51 CodecConfig::CodecConfig() {} |
| 47 CodecConfig::~CodecConfig() {} | 52 CodecConfig::~CodecConfig() {} |
| 48 | 53 |
| 49 AVDACodecAllocator::HangDetector::HangDetector(base::TickClock* tick_clock) | 54 AVDACodecAllocator::HangDetector::HangDetector(base::TickClock* tick_clock) |
| 50 : tick_clock_(tick_clock) {} | 55 : tick_clock_(tick_clock) {} |
| 51 | 56 |
| 52 void AVDACodecAllocator::HangDetector::WillProcessTask( | 57 void AVDACodecAllocator::HangDetector::WillProcessTask( |
| 53 const base::PendingTask& pending_task) { | 58 const base::PendingTask& pending_task) { |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 242 codec_config->media_crypto ? codec_config->media_crypto->obj() : nullptr; | 247 codec_config->media_crypto ? codec_config->media_crypto->obj() : nullptr; |
| 243 | 248 |
| 244 // |needs_protected_surface| implies encrypted stream. | 249 // |needs_protected_surface| implies encrypted stream. |
| 245 DCHECK(!codec_config->needs_protected_surface || media_crypto); | 250 DCHECK(!codec_config->needs_protected_surface || media_crypto); |
| 246 | 251 |
| 247 const bool require_software_codec = codec_config->task_type == SW_CODEC; | 252 const bool require_software_codec = codec_config->task_type == SW_CODEC; |
| 248 std::unique_ptr<MediaCodecBridge> codec( | 253 std::unique_ptr<MediaCodecBridge> codec( |
| 249 MediaCodecBridgeImpl::CreateVideoDecoder( | 254 MediaCodecBridgeImpl::CreateVideoDecoder( |
| 250 codec_config->codec, codec_config->needs_protected_surface, | 255 codec_config->codec, codec_config->needs_protected_surface, |
| 251 codec_config->initial_expected_coded_size, | 256 codec_config->initial_expected_coded_size, |
| 252 codec_config->surface.j_surface().obj(), media_crypto, | 257 codec_config->surface_bundle->surface.j_surface().obj(), media_crypto, |
| 253 codec_config->csd0, codec_config->csd1, true, | 258 codec_config->csd0, codec_config->csd1, true, |
| 254 require_software_codec)); | 259 require_software_codec)); |
| 255 | 260 |
| 256 return codec; | 261 return codec; |
| 257 } | 262 } |
| 258 | 263 |
| 259 void AVDACodecAllocator::CreateMediaCodecAsync( | 264 void AVDACodecAllocator::CreateMediaCodecAsync( |
| 260 base::WeakPtr<AVDACodecAllocatorClient> client, | 265 base::WeakPtr<AVDACodecAllocatorClient> client, |
| 261 scoped_refptr<CodecConfig> codec_config) { | 266 scoped_refptr<CodecConfig> codec_config) { |
| 267 // Allocate the codec on the appropriate thread, and reply to this one with |
| 268 // the result. If |client| is gone by then, we handle cleanup. |
| 262 base::PostTaskAndReplyWithResult( | 269 base::PostTaskAndReplyWithResult( |
| 263 TaskRunnerFor(codec_config->task_type).get(), FROM_HERE, | 270 TaskRunnerFor(codec_config->task_type).get(), FROM_HERE, |
| 264 base::Bind(&AVDACodecAllocator::CreateMediaCodecSync, | 271 base::Bind(&AVDACodecAllocator::CreateMediaCodecSync, |
| 265 base::Unretained(this), codec_config), | 272 base::Unretained(this), codec_config), |
| 266 base::Bind(&AVDACodecAllocatorClient::OnCodecConfigured, client)); | 273 base::Bind(&AVDACodecAllocator::ForwardOrDropCodec, |
| 274 base::Unretained(this), client, codec_config->task_type, |
| 275 codec_config->surface_bundle)); |
| 276 } |
| 277 |
| 278 void AVDACodecAllocator::ForwardOrDropCodec( |
| 279 base::WeakPtr<AVDACodecAllocatorClient> client, |
| 280 TaskType task_type, |
| 281 scoped_refptr<AVDASurfaceBundle> surface_bundle, |
| 282 std::unique_ptr<MediaCodecBridge> media_codec) { |
| 283 if (!client) { |
| 284 // |client| has been destroyed. Free |media_codec| on the right thread. |
| 285 // Note that this also preserves |surface_bundle| until |media_codec| has |
| 286 // been released, in case our ref to it is the last one. |
| 287 ReleaseMediaCodec(std::move(media_codec), task_type, surface_bundle); |
| 288 return; |
| 289 } |
| 290 |
| 291 client->OnCodecConfigured(std::move(media_codec)); |
| 267 } | 292 } |
| 268 | 293 |
| 269 void AVDACodecAllocator::ReleaseMediaCodec( | 294 void AVDACodecAllocator::ReleaseMediaCodec( |
| 270 std::unique_ptr<MediaCodecBridge> media_codec, | 295 std::unique_ptr<MediaCodecBridge> media_codec, |
| 271 TaskType task_type, | 296 TaskType task_type, |
| 272 int surface_id) { | 297 const scoped_refptr<AVDASurfaceBundle>& surface_bundle) { |
| 273 DCHECK(thread_checker_.CalledOnValidThread()); | 298 DCHECK(thread_checker_.CalledOnValidThread()); |
| 274 DCHECK(media_codec); | 299 DCHECK(media_codec); |
| 275 | 300 |
| 276 // No need to track the release if it's a SurfaceTexture. | 301 // No need to track the release if it's a SurfaceTexture. We still forward |
| 277 if (surface_id == SurfaceManager::kNoSurfaceID) { | 302 // the reference to |surface_bundle|, though, so that the SurfaceTexture |
| 278 TaskRunnerFor(task_type)->PostTask( | 303 // lasts at least as long as the codec. |
| 279 FROM_HERE, base::Bind(&DeleteMediaCodecAndSignal, | 304 if (surface_bundle->surface_id == SurfaceManager::kNoSurfaceID) { |
| 280 base::Passed(std::move(media_codec)), nullptr)); | 305 TaskRunnerFor(task_type)->PostTaskAndReply( |
| 306 FROM_HERE, |
| 307 base::Bind(&DeleteMediaCodecAndSignal, |
| 308 base::Passed(std::move(media_codec)), nullptr), |
| 309 base::Bind(&DropReferenceToSurfaceBundle, surface_bundle)); |
| 281 return; | 310 return; |
| 282 } | 311 } |
| 283 | 312 |
| 313 DCHECK(!surface_bundle->surface_texture); |
| 284 pending_codec_releases_.emplace( | 314 pending_codec_releases_.emplace( |
| 285 std::piecewise_construct, std::forward_as_tuple(surface_id), | 315 std::piecewise_construct, |
| 316 std::forward_as_tuple(surface_bundle->surface_id), |
| 286 std::forward_as_tuple(base::WaitableEvent::ResetPolicy::MANUAL, | 317 std::forward_as_tuple(base::WaitableEvent::ResetPolicy::MANUAL, |
| 287 base::WaitableEvent::InitialState::NOT_SIGNALED)); | 318 base::WaitableEvent::InitialState::NOT_SIGNALED)); |
| 288 base::WaitableEvent* released = | 319 base::WaitableEvent* released = |
| 289 &pending_codec_releases_.find(surface_id)->second; | 320 &pending_codec_releases_.find(surface_bundle->surface_id)->second; |
| 290 | 321 |
| 322 // Note that we forward |surface_bundle|, too, so that the surface outlasts |
| 323 // the codec. This doesn't matter so much for CVV surfaces, since they don't |
| 324 // auto-release when they're dropped. However, for surface owners, this will |
| 325 // become important, so we still handle it. Plus, it makes sense. |
| 291 TaskRunnerFor(task_type)->PostTaskAndReply( | 326 TaskRunnerFor(task_type)->PostTaskAndReply( |
| 292 FROM_HERE, base::Bind(&DeleteMediaCodecAndSignal, | 327 FROM_HERE, |
| 293 base::Passed(std::move(media_codec)), released), | 328 base::Bind(&DeleteMediaCodecAndSignal, |
| 294 base::Bind(&AVDACodecAllocator::OnMediaCodecAndSurfaceReleased, | 329 base::Passed(std::move(media_codec)), released), |
| 295 base::Unretained(this), surface_id)); | 330 base::Bind(&AVDACodecAllocator::OnMediaCodecReleased, |
| 331 base::Unretained(this), surface_bundle)); |
| 296 } | 332 } |
| 297 | 333 |
| 298 void AVDACodecAllocator::OnMediaCodecAndSurfaceReleased(int surface_id) { | 334 void AVDACodecAllocator::OnMediaCodecReleased( |
| 335 scoped_refptr<AVDASurfaceBundle> surface_bundle) { |
| 299 DCHECK(thread_checker_.CalledOnValidThread()); | 336 DCHECK(thread_checker_.CalledOnValidThread()); |
| 300 | 337 |
| 301 pending_codec_releases_.erase(surface_id); | 338 pending_codec_releases_.erase(surface_bundle->surface_id); |
| 302 if (!surface_owners_.count(surface_id)) | 339 if (!surface_owners_.count(surface_bundle->surface_id)) |
| 303 return; | 340 return; |
| 304 | 341 |
| 305 OwnerRecord& record = surface_owners_[surface_id]; | 342 OwnerRecord& record = surface_owners_[surface_bundle->surface_id]; |
| 306 if (!record.owner && record.waiter) { | 343 if (!record.owner && record.waiter) { |
| 307 record.owner = record.waiter; | 344 record.owner = record.waiter; |
| 308 record.waiter = nullptr; | 345 record.waiter = nullptr; |
| 309 record.owner->OnSurfaceAvailable(true); | 346 record.owner->OnSurfaceAvailable(true); |
| 310 } | 347 } |
| 348 |
| 349 // Also note that |surface_bundle| lasted at least as long as the codec. |
| 311 } | 350 } |
| 312 | 351 |
| 313 // Returns a hint about whether the construction thread has hung for | 352 // Returns a hint about whether the construction thread has hung for |
| 314 // |task_type|. Note that if a thread isn't started, then we'll just return | 353 // |task_type|. Note that if a thread isn't started, then we'll just return |
| 315 // "not hung", since it'll run on the current thread anyway. The hang | 354 // "not hung", since it'll run on the current thread anyway. The hang |
| 316 // detector will see no pending jobs in that case, so it's automatic. | 355 // detector will see no pending jobs in that case, so it's automatic. |
| 317 bool AVDACodecAllocator::IsThreadLikelyHung(TaskType task_type) { | 356 bool AVDACodecAllocator::IsThreadLikelyHung(TaskType task_type) { |
| 318 DCHECK(thread_checker_.CalledOnValidThread()); | 357 DCHECK(thread_checker_.CalledOnValidThread()); |
| 319 return threads_[task_type]->hang_detector.IsThreadLikelyHung(); | 358 return threads_[task_type]->hang_detector.IsThreadLikelyHung(); |
| 320 } | 359 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 360 void AVDACodecAllocator::StopThreadTask(size_t index) { | 399 void AVDACodecAllocator::StopThreadTask(size_t index) { |
| 361 threads_[index]->thread.Stop(); | 400 threads_[index]->thread.Stop(); |
| 362 // Signal the stop event after both threads are stopped. | 401 // Signal the stop event after both threads are stopped. |
| 363 if (stop_event_for_testing_ && !threads_[AUTO_CODEC]->thread.IsRunning() && | 402 if (stop_event_for_testing_ && !threads_[AUTO_CODEC]->thread.IsRunning() && |
| 364 !threads_[SW_CODEC]->thread.IsRunning()) { | 403 !threads_[SW_CODEC]->thread.IsRunning()) { |
| 365 stop_event_for_testing_->Signal(); | 404 stop_event_for_testing_->Signal(); |
| 366 } | 405 } |
| 367 } | 406 } |
| 368 | 407 |
| 369 } // namespace media | 408 } // namespace media |
| OLD | NEW |