| 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 client->OnCodecConfigured(std::move(media_codec)); |
| 265 } | 290 } |
| 266 | 291 |
| 267 void AVDACodecAllocator::ReleaseMediaCodec( | 292 void AVDACodecAllocator::ReleaseMediaCodec( |
| 268 std::unique_ptr<VideoCodecBridge> media_codec, | 293 std::unique_ptr<VideoCodecBridge> media_codec, |
| 269 TaskType task_type, | 294 TaskType task_type, |
| 270 int surface_id) { | 295 const scoped_refptr<AVDASurfaceBundle>& surface_bundle) { |
| 271 DCHECK(thread_checker_.CalledOnValidThread()); | 296 DCHECK(thread_checker_.CalledOnValidThread()); |
| 272 DCHECK(media_codec); | 297 DCHECK(media_codec); |
| 273 | 298 |
| 274 // No need to track the release if it's a SurfaceTexture. | 299 // No need to track the release if it's a SurfaceTexture. We still forward |
| 275 if (surface_id == SurfaceManager::kNoSurfaceID) { | 300 // the reference to |surface_bundle|, though, so that the SurfaceTexture |
| 276 TaskRunnerFor(task_type)->PostTask( | 301 // lasts at least as long as the codec. |
| 302 if (surface_bundle->surface_id == SurfaceManager::kNoSurfaceID) { |
| 303 TaskRunnerFor(task_type)->PostTaskAndReply( |
| 277 FROM_HERE, base::Bind(&DeleteMediaCodecAndSignal, | 304 FROM_HERE, base::Bind(&DeleteMediaCodecAndSignal, |
| 278 base::Passed(std::move(media_codec)), nullptr)); | 305 base::Passed(std::move(media_codec)), nullptr), |
| 306 base::Bind(&DropReferenceToSurfaceBundle, surface_bundle)); |
| 279 return; | 307 return; |
| 280 } | 308 } |
| 281 | 309 |
| 310 DCHECK(!surface_bundle->surface_texture); |
| 282 pending_codec_releases_.emplace( | 311 pending_codec_releases_.emplace( |
| 283 std::piecewise_construct, std::forward_as_tuple(surface_id), | 312 std::piecewise_construct, |
| 313 std::forward_as_tuple(surface_bundle->surface_id), |
| 284 std::forward_as_tuple(base::WaitableEvent::ResetPolicy::MANUAL, | 314 std::forward_as_tuple(base::WaitableEvent::ResetPolicy::MANUAL, |
| 285 base::WaitableEvent::InitialState::NOT_SIGNALED)); | 315 base::WaitableEvent::InitialState::NOT_SIGNALED)); |
| 286 base::WaitableEvent* released = | 316 base::WaitableEvent* released = |
| 287 &pending_codec_releases_.find(surface_id)->second; | 317 &pending_codec_releases_.find(surface_bundle->surface_id)->second; |
| 288 | 318 |
| 319 // Note that we forward |surface_bundle|, too, so that the surface outlasts |
| 320 // the codec. This doesn't matter so much for CVV surfaces, since they don't |
| 321 // auto-release when they're dropped. However, for surface owners, this will |
| 322 // become important, so we still handle it. Plus, it makes sense. |
| 289 TaskRunnerFor(task_type)->PostTaskAndReply( | 323 TaskRunnerFor(task_type)->PostTaskAndReply( |
| 290 FROM_HERE, base::Bind(&DeleteMediaCodecAndSignal, | 324 FROM_HERE, base::Bind(&DeleteMediaCodecAndSignal, |
| 291 base::Passed(std::move(media_codec)), released), | 325 base::Passed(std::move(media_codec)), released), |
| 292 base::Bind(&AVDACodecAllocator::OnMediaCodecAndSurfaceReleased, | 326 base::Bind(&AVDACodecAllocator::OnMediaCodecReleased, |
| 293 base::Unretained(this), surface_id)); | 327 base::Unretained(this), surface_bundle)); |
| 294 } | 328 } |
| 295 | 329 |
| 296 void AVDACodecAllocator::OnMediaCodecAndSurfaceReleased(int surface_id) { | 330 void AVDACodecAllocator::OnMediaCodecReleased( |
| 331 scoped_refptr<AVDASurfaceBundle> surface_bundle) { |
| 297 DCHECK(thread_checker_.CalledOnValidThread()); | 332 DCHECK(thread_checker_.CalledOnValidThread()); |
| 298 | 333 |
| 299 pending_codec_releases_.erase(surface_id); | 334 pending_codec_releases_.erase(surface_bundle->surface_id); |
| 300 if (!surface_owners_.count(surface_id)) | 335 if (!surface_owners_.count(surface_bundle->surface_id)) |
| 301 return; | 336 return; |
| 302 | 337 |
| 303 OwnerRecord& record = surface_owners_[surface_id]; | 338 OwnerRecord& record = surface_owners_[surface_bundle->surface_id]; |
| 304 if (!record.owner && record.waiter) { | 339 if (!record.owner && record.waiter) { |
| 305 record.owner = record.waiter; | 340 record.owner = record.waiter; |
| 306 record.waiter = nullptr; | 341 record.waiter = nullptr; |
| 307 record.owner->OnSurfaceAvailable(true); | 342 record.owner->OnSurfaceAvailable(true); |
| 308 } | 343 } |
| 344 |
| 345 // Also note that |surface_bundle| lasted at least as long as the codec. |
| 309 } | 346 } |
| 310 | 347 |
| 311 // Returns a hint about whether the construction thread has hung for | 348 // 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 | 349 // |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 | 350 // "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. | 351 // detector will see no pending jobs in that case, so it's automatic. |
| 315 bool AVDACodecAllocator::IsThreadLikelyHung(TaskType task_type) { | 352 bool AVDACodecAllocator::IsThreadLikelyHung(TaskType task_type) { |
| 316 DCHECK(thread_checker_.CalledOnValidThread()); | 353 DCHECK(thread_checker_.CalledOnValidThread()); |
| 317 return threads_[task_type]->hang_detector.IsThreadLikelyHung(); | 354 return threads_[task_type]->hang_detector.IsThreadLikelyHung(); |
| 318 } | 355 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 358 void AVDACodecAllocator::StopThreadTask(size_t index) { | 395 void AVDACodecAllocator::StopThreadTask(size_t index) { |
| 359 threads_[index]->thread.Stop(); | 396 threads_[index]->thread.Stop(); |
| 360 // Signal the stop event after both threads are stopped. | 397 // Signal the stop event after both threads are stopped. |
| 361 if (stop_event_for_testing_ && !threads_[AUTO_CODEC]->thread.IsRunning() && | 398 if (stop_event_for_testing_ && !threads_[AUTO_CODEC]->thread.IsRunning() && |
| 362 !threads_[SW_CODEC]->thread.IsRunning()) { | 399 !threads_[SW_CODEC]->thread.IsRunning()) { |
| 363 stop_event_for_testing_->Signal(); | 400 stop_event_for_testing_->Signal(); |
| 364 } | 401 } |
| 365 } | 402 } |
| 366 | 403 |
| 367 } // namespace media | 404 } // namespace media |
| OLD | NEW |