Chromium Code Reviews| 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<VideoCodecBridge> codec, | 37 void DeleteMediaCodecAndSignal(std::unique_ptr<VideoCodecBridge> 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 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 241 jobject media_crypto = | 246 jobject media_crypto = |
| 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<VideoCodecBridge> codec(VideoCodecBridge::CreateDecoder( | 253 std::unique_ptr<VideoCodecBridge> codec(VideoCodecBridge::CreateDecoder( |
| 249 codec_config->codec, codec_config->needs_protected_surface, | 254 codec_config->codec, codec_config->needs_protected_surface, |
| 250 codec_config->initial_expected_coded_size, | 255 codec_config->initial_expected_coded_size, |
| 251 codec_config->surface.j_surface().obj(), media_crypto, codec_config->csd0, | 256 codec_config->surface_bundle->surface.j_surface().obj(), media_crypto, |
| 252 codec_config->csd1, true, require_software_codec)); | 257 codec_config->csd0, codec_config->csd1, true, require_software_codec)); |
| 253 | 258 |
| 254 return codec; | 259 return codec; |
| 255 } | 260 } |
| 256 | 261 |
| 257 void AVDACodecAllocator::CreateMediaCodecAsync( | 262 void AVDACodecAllocator::CreateMediaCodecAsync( |
| 258 base::WeakPtr<AVDACodecAllocatorClient> client, | 263 base::WeakPtr<AVDACodecAllocatorClient> client, |
| 259 scoped_refptr<CodecConfig> codec_config) { | 264 scoped_refptr<CodecConfig> codec_config) { |
| 265 // Allocate the codec on the appropriate thread, and reply to this one with | |
| 266 // the result. If |client| is gone by then, we handle cleanup. | |
| 260 base::PostTaskAndReplyWithResult( | 267 base::PostTaskAndReplyWithResult( |
| 261 TaskRunnerFor(codec_config->task_type).get(), FROM_HERE, | 268 TaskRunnerFor(codec_config->task_type).get(), FROM_HERE, |
| 262 base::Bind(&AVDACodecAllocator::CreateMediaCodecSync, | 269 base::Bind(&AVDACodecAllocator::CreateMediaCodecSync, |
| 263 base::Unretained(this), codec_config), | 270 base::Unretained(this), codec_config), |
| 264 base::Bind(&AVDACodecAllocatorClient::OnCodecConfigured, client)); | 271 base::Bind(&AVDACodecAllocator::ForwardOrDropCodec, |
| 272 base::Unretained(this), client, codec_config->task_type, | |
| 273 codec_config->surface_bundle)); | |
| 274 } | |
| 275 | |
| 276 void AVDACodecAllocator::ForwardOrDropCodec( | |
| 277 base::WeakPtr<AVDACodecAllocatorClient> client, | |
| 278 TaskType task_type, | |
| 279 scoped_refptr<AVDASurfaceBundle> surface_bundle, | |
| 280 std::unique_ptr<VideoCodecBridge> media_codec) { | |
| 281 if (!client) { | |
| 282 // |client| has been destroyed. Free |media_codec| on the right thread. | |
| 283 // Note that this also preserves |surface_bundle| until |media_codec| has | |
| 284 // been released, in case our ref to it is the last one. | |
| 285 ReleaseMediaCodec(std::move(media_codec), task_type, surface_bundle); | |
| 286 return; | |
| 287 } | |
| 288 | |
| 289 // The client is still around, so (presumably) it has a reference to | |
| 290 // |surface_bundle| already. | |
|
watk
2017/02/22 20:38:56
This comment seems out of place. It seems to be ju
liberato (no reviews please)
2017/02/23 18:18:46
Done.
| |
| 291 client->OnCodecConfigured(std::move(media_codec)); | |
| 265 } | 292 } |
| 266 | 293 |
| 267 void AVDACodecAllocator::ReleaseMediaCodec( | 294 void AVDACodecAllocator::ReleaseMediaCodec( |
| 268 std::unique_ptr<VideoCodecBridge> media_codec, | 295 std::unique_ptr<VideoCodecBridge> media_codec, |
| 269 TaskType task_type, | 296 TaskType task_type, |
| 270 int surface_id) { | 297 const scoped_refptr<AVDASurfaceBundle>& surface_bundle) { |
| 271 DCHECK(thread_checker_.CalledOnValidThread()); | 298 DCHECK(thread_checker_.CalledOnValidThread()); |
| 272 DCHECK(media_codec); | 299 DCHECK(media_codec); |
| 273 | 300 |
| 274 // 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 |
| 275 if (surface_id == SurfaceManager::kNoSurfaceID) { | 302 // the reference to |surface_bundle|, though, so that the SurfaceTexture |
| 276 TaskRunnerFor(task_type)->PostTask( | 303 // lasts at least as long as the codec. |
| 304 if (surface_bundle->surface_id == SurfaceManager::kNoSurfaceID) { | |
| 305 TaskRunnerFor(task_type)->PostTaskAndReply( | |
| 277 FROM_HERE, base::Bind(&DeleteMediaCodecAndSignal, | 306 FROM_HERE, base::Bind(&DeleteMediaCodecAndSignal, |
| 278 base::Passed(std::move(media_codec)), nullptr)); | 307 base::Passed(std::move(media_codec)), nullptr), |
| 308 base::Bind(&DropReferenceToSurfaceBundle, surface_bundle)); | |
| 279 return; | 309 return; |
| 280 } | 310 } |
| 281 | 311 |
| 312 DCHECK(!surface_bundle->surface_texture); | |
| 282 pending_codec_releases_.emplace( | 313 pending_codec_releases_.emplace( |
| 283 std::piecewise_construct, std::forward_as_tuple(surface_id), | 314 std::piecewise_construct, |
| 315 std::forward_as_tuple(surface_bundle->surface_id), | |
| 284 std::forward_as_tuple(base::WaitableEvent::ResetPolicy::MANUAL, | 316 std::forward_as_tuple(base::WaitableEvent::ResetPolicy::MANUAL, |
| 285 base::WaitableEvent::InitialState::NOT_SIGNALED)); | 317 base::WaitableEvent::InitialState::NOT_SIGNALED)); |
| 286 base::WaitableEvent* released = | 318 base::WaitableEvent* released = |
| 287 &pending_codec_releases_.find(surface_id)->second; | 319 &pending_codec_releases_.find(surface_bundle->surface_id)->second; |
| 288 | 320 |
| 321 // Note that we forward |surface_bundle|, too, so that the surface outlasts | |
| 322 // the codec. This doesn't matter so much for CVV surfaces, since they don't | |
| 323 // auto-release when they're dropped. However, for surface owners, this will | |
| 324 // become important, so we still handle it. Plus, it makes sense. | |
| 289 TaskRunnerFor(task_type)->PostTaskAndReply( | 325 TaskRunnerFor(task_type)->PostTaskAndReply( |
| 290 FROM_HERE, base::Bind(&DeleteMediaCodecAndSignal, | 326 FROM_HERE, base::Bind(&DeleteMediaCodecAndSignal, |
| 291 base::Passed(std::move(media_codec)), released), | 327 base::Passed(std::move(media_codec)), released), |
| 292 base::Bind(&AVDACodecAllocator::OnMediaCodecAndSurfaceReleased, | 328 base::Bind(&AVDACodecAllocator::OnMediaCodecAndSurfaceReleased, |
| 293 base::Unretained(this), surface_id)); | 329 base::Unretained(this), surface_bundle)); |
| 294 } | 330 } |
| 295 | 331 |
| 296 void AVDACodecAllocator::OnMediaCodecAndSurfaceReleased(int surface_id) { | 332 void AVDACodecAllocator::OnMediaCodecAndSurfaceReleased( |
| 333 scoped_refptr<AVDASurfaceBundle> surface_bundle) { | |
| 297 DCHECK(thread_checker_.CalledOnValidThread()); | 334 DCHECK(thread_checker_.CalledOnValidThread()); |
| 298 | 335 |
| 299 pending_codec_releases_.erase(surface_id); | 336 pending_codec_releases_.erase(surface_bundle->surface_id); |
| 300 if (!surface_owners_.count(surface_id)) | 337 if (!surface_owners_.count(surface_bundle->surface_id)) |
| 301 return; | 338 return; |
| 302 | 339 |
| 303 OwnerRecord& record = surface_owners_[surface_id]; | 340 OwnerRecord& record = surface_owners_[surface_bundle->surface_id]; |
| 304 if (!record.owner && record.waiter) { | 341 if (!record.owner && record.waiter) { |
| 305 record.owner = record.waiter; | 342 record.owner = record.waiter; |
| 306 record.waiter = nullptr; | 343 record.waiter = nullptr; |
| 307 record.owner->OnSurfaceAvailable(true); | 344 record.owner->OnSurfaceAvailable(true); |
| 308 } | 345 } |
| 346 | |
| 347 // Also note that |surface_bundle| lasted at least as long as the codec. | |
| 309 } | 348 } |
| 310 | 349 |
| 311 // Returns a hint about whether the construction thread has hung for | 350 // Returns a hint about whether the construction thread has hung for |
| 312 // |task_type|. Note that if a thread isn't started, then we'll just return | 351 // |task_type|. Note that if a thread isn't started, then we'll just return |
| 313 // "not hung", since it'll run on the current thread anyway. The hang | 352 // "not hung", since it'll run on the current thread anyway. The hang |
| 314 // detector will see no pending jobs in that case, so it's automatic. | 353 // detector will see no pending jobs in that case, so it's automatic. |
| 315 bool AVDACodecAllocator::IsThreadLikelyHung(TaskType task_type) { | 354 bool AVDACodecAllocator::IsThreadLikelyHung(TaskType task_type) { |
| 316 DCHECK(thread_checker_.CalledOnValidThread()); | 355 DCHECK(thread_checker_.CalledOnValidThread()); |
| 317 return threads_[task_type]->hang_detector.IsThreadLikelyHung(); | 356 return threads_[task_type]->hang_detector.IsThreadLikelyHung(); |
| 318 } | 357 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 358 void AVDACodecAllocator::StopThreadTask(size_t index) { | 397 void AVDACodecAllocator::StopThreadTask(size_t index) { |
| 359 threads_[index]->thread.Stop(); | 398 threads_[index]->thread.Stop(); |
| 360 // Signal the stop event after both threads are stopped. | 399 // Signal the stop event after both threads are stopped. |
| 361 if (stop_event_for_testing_ && !threads_[AUTO_CODEC]->thread.IsRunning() && | 400 if (stop_event_for_testing_ && !threads_[AUTO_CODEC]->thread.IsRunning() && |
| 362 !threads_[SW_CODEC]->thread.IsRunning()) { | 401 !threads_[SW_CODEC]->thread.IsRunning()) { |
| 363 stop_event_for_testing_->Signal(); | 402 stop_event_for_testing_->Signal(); |
| 364 } | 403 } |
| 365 } | 404 } |
| 366 | 405 |
| 367 } // namespace media | 406 } // namespace media |
| OLD | NEW |