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 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 142 bool AVDACodecAllocator::AllocateSurface(AVDACodecAllocatorClient* client, | 142 bool AVDACodecAllocator::AllocateSurface(AVDACodecAllocatorClient* client, |
| 143 int surface_id) { | 143 int surface_id) { |
| 144 DVLOG(1) << __func__ << ": " << surface_id; | 144 DVLOG(1) << __func__ << ": " << surface_id; |
| 145 DCHECK(thread_checker_.CalledOnValidThread()); | 145 DCHECK(thread_checker_.CalledOnValidThread()); |
| 146 | 146 |
| 147 if (surface_id == SurfaceManager::kNoSurfaceID) | 147 if (surface_id == SurfaceManager::kNoSurfaceID) |
| 148 return true; | 148 return true; |
| 149 | 149 |
| 150 // If it's not owned or being released, |client| now owns it. | 150 // If it's not owned or being released, |client| now owns it. |
| 151 if (!surface_owners_.count(surface_id) && | 151 if (!surface_owners_.count(surface_id) && |
| 152 !pending_codec_releases_.count(surface_id)) { | 152 !surface_view_codec_releases_.count(surface_id)) { |
| 153 surface_owners_[surface_id].owner = client; | 153 surface_owners_[surface_id].owner = client; |
| 154 return true; | 154 return true; |
| 155 } | 155 } |
| 156 | 156 |
| 157 // Otherwise |client| replaces the previous waiter (if any). | 157 // Otherwise |client| replaces the previous waiter (if any). |
| 158 OwnerRecord& record = surface_owners_[surface_id]; | 158 OwnerRecord& record = surface_owners_[surface_id]; |
| 159 if (record.waiter) | 159 if (record.waiter) |
| 160 record.waiter->OnSurfaceAvailable(false); | 160 record.waiter->OnSurfaceAvailable(false); |
| 161 record.waiter = client; | 161 record.waiter = client; |
| 162 return false; | 162 return false; |
| 163 } | 163 } |
| 164 | 164 |
| 165 void AVDACodecAllocator::DeallocateSurface(AVDACodecAllocatorClient* client, | 165 void AVDACodecAllocator::DeallocateSurface(AVDACodecAllocatorClient* client, |
| 166 int surface_id) { | 166 int surface_id) { |
| 167 DCHECK(thread_checker_.CalledOnValidThread()); | 167 DCHECK(thread_checker_.CalledOnValidThread()); |
| 168 if (surface_id == SurfaceManager::kNoSurfaceID || | 168 if (surface_id == SurfaceManager::kNoSurfaceID || |
| 169 !surface_owners_.count(surface_id)) { | 169 !surface_owners_.count(surface_id)) { |
| 170 return; | 170 return; |
| 171 } | 171 } |
| 172 | 172 |
| 173 OwnerRecord& record = surface_owners_[surface_id]; | 173 OwnerRecord& record = surface_owners_[surface_id]; |
| 174 if (record.owner == client) | 174 if (record.owner == client) |
| 175 record.owner = nullptr; | 175 record.owner = nullptr; |
| 176 else if (record.waiter == client) | 176 else if (record.waiter == client) |
| 177 record.waiter = nullptr; | 177 record.waiter = nullptr; |
| 178 | 178 |
| 179 // Promote the waiter if possible. | 179 // Promote the waiter if possible. |
| 180 if (record.waiter && !record.owner && | 180 if (record.waiter && !record.owner && |
| 181 !pending_codec_releases_.count(surface_id)) { | 181 !surface_view_codec_releases_.count(surface_id)) { |
| 182 record.owner = record.waiter; | 182 record.owner = record.waiter; |
| 183 record.waiter = nullptr; | 183 record.waiter = nullptr; |
| 184 record.owner->OnSurfaceAvailable(true); | 184 record.owner->OnSurfaceAvailable(true); |
| 185 return; | 185 return; |
| 186 } | 186 } |
| 187 | 187 |
| 188 // Remove the record if it's now unused. | 188 // Remove the record if it's now unused. |
| 189 if (!record.owner && !record.waiter) | 189 if (!record.owner && !record.waiter) |
| 190 surface_owners_.erase(surface_id); | 190 surface_owners_.erase(surface_id); |
| 191 } | 191 } |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 214 } | 214 } |
| 215 | 215 |
| 216 if (record.owner) | 216 if (record.owner) |
| 217 record.owner->OnSurfaceDestroyed(); | 217 record.owner->OnSurfaceDestroyed(); |
| 218 | 218 |
| 219 surface_owners_.erase(surface_id); | 219 surface_owners_.erase(surface_id); |
| 220 } | 220 } |
| 221 | 221 |
| 222 // The codec might have been released above in OnSurfaceDestroyed(), or was | 222 // The codec might have been released above in OnSurfaceDestroyed(), or was |
| 223 // already pending release. | 223 // already pending release. |
| 224 if (!pending_codec_releases_.count(surface_id)) | 224 if (!surface_view_codec_releases_.count(surface_id)) |
| 225 return; | 225 return; |
| 226 | 226 |
| 227 // The codec is being released so we have to wait for it here. It's a | 227 // The codec is being released so we have to wait for it here. It's a |
| 228 // TimedWait() because the MediaCodec release may hang due to framework bugs. | 228 // TimedWait() because the MediaCodec release may hang due to framework bugs. |
| 229 // And in that case we don't want to hang the browser UI thread. Android ANRs | 229 // And in that case we don't want to hang the browser UI thread. Android ANRs |
| 230 // occur when the UI thread is blocked for 5 seconds, so waiting for 2 seconds | 230 // occur when the UI thread is blocked for 5 seconds, so waiting for 2 seconds |
| 231 // gives us leeway to avoid an ANR. Verified no ANR on a Nexus 7. | 231 // gives us leeway to avoid an ANR. Verified no ANR on a Nexus 7. |
| 232 base::WaitableEvent& released = | 232 base::WaitableEvent& released = |
| 233 pending_codec_releases_.find(surface_id)->second; | 233 surface_view_codec_releases_.find(surface_id)->second; |
| 234 released.TimedWait(base::TimeDelta::FromSeconds(2)); | 234 released.TimedWait(base::TimeDelta::FromSeconds(2)); |
| 235 if (!released.IsSignaled()) | 235 if (!released.IsSignaled()) |
| 236 DLOG(WARNING) << __func__ << ": timed out waiting for MediaCodec#release()"; | 236 DLOG(WARNING) << __func__ << ": timed out waiting for MediaCodec#release()"; |
| 237 } | 237 } |
| 238 | 238 |
| 239 std::unique_ptr<VideoCodecBridge> AVDACodecAllocator::CreateMediaCodecSync( | 239 std::unique_ptr<VideoCodecBridge> AVDACodecAllocator::CreateMediaCodecSync( |
| 240 scoped_refptr<CodecConfig> codec_config) { | 240 scoped_refptr<CodecConfig> codec_config) { |
| 241 TRACE_EVENT0("media", "AVDA::CreateMediaCodecSync"); | 241 TRACE_EVENT0("media", "AVDA::CreateMediaCodecSync"); |
| 242 | 242 |
| 243 jobject media_crypto = | 243 jobject media_crypto = |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 262 base::PostTaskAndReplyWithResult( | 262 base::PostTaskAndReplyWithResult( |
| 263 TaskRunnerFor(codec_config->task_type).get(), FROM_HERE, | 263 TaskRunnerFor(codec_config->task_type).get(), FROM_HERE, |
| 264 base::Bind(&AVDACodecAllocator::CreateMediaCodecSync, | 264 base::Bind(&AVDACodecAllocator::CreateMediaCodecSync, |
| 265 base::Unretained(this), codec_config), | 265 base::Unretained(this), codec_config), |
| 266 base::Bind(&AVDACodecAllocatorClient::OnCodecConfigured, client)); | 266 base::Bind(&AVDACodecAllocatorClient::OnCodecConfigured, client)); |
| 267 } | 267 } |
| 268 | 268 |
| 269 void AVDACodecAllocator::ReleaseMediaCodec( | 269 void AVDACodecAllocator::ReleaseMediaCodec( |
| 270 std::unique_ptr<VideoCodecBridge> media_codec, | 270 std::unique_ptr<VideoCodecBridge> media_codec, |
| 271 TaskType task_type, | 271 TaskType task_type, |
| 272 int surface_id) { | 272 int surface_id, |
| 273 gl::SurfaceTexture* surface_texture) { | |
| 273 DCHECK(thread_checker_.CalledOnValidThread()); | 274 DCHECK(thread_checker_.CalledOnValidThread()); |
| 274 DCHECK(media_codec); | 275 DCHECK(media_codec); |
| 276 DCHECK(surface_id != SurfaceManager::kNoSurfaceID || surface_texture); | |
| 275 | 277 |
| 276 // No need to track the release if it's a SurfaceTexture. | 278 base::WaitableEvent* released_event = nullptr; |
| 277 if (surface_id == SurfaceManager::kNoSurfaceID) { | 279 if (surface_texture) { |
| 278 TaskRunnerFor(task_type)->PostTask( | 280 surface_texture_codec_releases_[surface_texture] = task_type; |
| 279 FROM_HERE, base::Bind(&DeleteMediaCodecAndSignal, | 281 } else { |
| 280 base::Passed(std::move(media_codec)), nullptr)); | 282 surface_view_codec_releases_.emplace( |
| 283 std::piecewise_construct, std::forward_as_tuple(surface_id), | |
| 284 std::forward_as_tuple(base::WaitableEvent::ResetPolicy::MANUAL, | |
| 285 base::WaitableEvent::InitialState::NOT_SIGNALED)); | |
| 286 released_event = &surface_view_codec_releases_.find(surface_id)->second; | |
| 287 } | |
| 288 | |
| 289 TaskRunnerFor(task_type)->PostTaskAndReply( | |
| 290 FROM_HERE, | |
| 291 base::Bind(&DeleteMediaCodecAndSignal, | |
| 292 base::Passed(std::move(media_codec)), released_event), | |
| 293 base::Bind(&AVDACodecAllocator::OnMediaCodecReleased, | |
| 294 base::Unretained(this), surface_id, | |
| 295 base::Unretained(surface_texture))); | |
| 296 } | |
| 297 | |
| 298 void AVDACodecAllocator::OnMediaCodecReleased( | |
| 299 int surface_id, | |
| 300 gl::SurfaceTexture* surface_texture) { | |
| 301 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 302 | |
| 303 if (surface_texture) { | |
| 304 surface_texture_codec_releases_.erase(surface_texture); | |
| 305 } else { | |
| 306 surface_view_codec_releases_.erase(surface_id); | |
| 307 if (!surface_owners_.count(surface_id)) | |
|
liberato (no reviews please)
2017/01/13 17:22:04
might want to use find rather than count + [] late
| |
| 308 return; | |
| 309 | |
| 310 OwnerRecord& record = surface_owners_[surface_id]; | |
| 311 if (!record.owner && record.waiter) { | |
| 312 record.owner = record.waiter; | |
| 313 record.waiter = nullptr; | |
| 314 record.owner->OnSurfaceAvailable(true); | |
| 315 } | |
| 316 } | |
| 317 } | |
| 318 | |
| 319 void AVDACodecAllocator::ReleaseSurfaceTexture( | |
| 320 scoped_refptr<gl::SurfaceTexture> surface_texture) { | |
| 321 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 322 | |
| 323 // If this SurfaceTexture is attached to a codec that's currently being | |
| 324 // released, defer the surface release until after the codec is released. | |
| 325 if (surface_texture_codec_releases_.count(surface_texture.get())) { | |
|
liberato (no reviews please)
2017/01/13 17:22:04
ditto find().
also might want to invert this to i
| |
| 326 TaskType task_type = surface_texture_codec_releases_[surface_texture.get()]; | |
| 327 TaskRunnerFor(task_type)->PostTaskAndReply( | |
| 328 FROM_HERE, base::Bind(&base::DoNothing), | |
| 329 base::Bind(&gl::SurfaceTexture::ReleaseSurfaceTexture, | |
| 330 surface_texture)); | |
| 281 return; | 331 return; |
| 282 } | 332 } |
| 283 | 333 |
| 284 pending_codec_releases_.emplace( | 334 // Otherwise we can release immediately. |
| 285 std::piecewise_construct, std::forward_as_tuple(surface_id), | 335 surface_texture->ReleaseSurfaceTexture(); |
| 286 std::forward_as_tuple(base::WaitableEvent::ResetPolicy::MANUAL, | |
| 287 base::WaitableEvent::InitialState::NOT_SIGNALED)); | |
| 288 base::WaitableEvent* released = | |
| 289 &pending_codec_releases_.find(surface_id)->second; | |
| 290 | |
| 291 TaskRunnerFor(task_type)->PostTaskAndReply( | |
| 292 FROM_HERE, base::Bind(&DeleteMediaCodecAndSignal, | |
| 293 base::Passed(std::move(media_codec)), released), | |
| 294 base::Bind(&AVDACodecAllocator::OnMediaCodecAndSurfaceReleased, | |
| 295 base::Unretained(this), surface_id)); | |
| 296 } | |
| 297 | |
| 298 void AVDACodecAllocator::OnMediaCodecAndSurfaceReleased(int surface_id) { | |
| 299 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 300 | |
| 301 pending_codec_releases_.erase(surface_id); | |
| 302 if (!surface_owners_.count(surface_id)) | |
| 303 return; | |
| 304 | |
| 305 OwnerRecord& record = surface_owners_[surface_id]; | |
| 306 if (!record.owner && record.waiter) { | |
| 307 record.owner = record.waiter; | |
| 308 record.waiter = nullptr; | |
| 309 record.owner->OnSurfaceAvailable(true); | |
| 310 } | |
| 311 } | 336 } |
| 312 | 337 |
| 313 // Returns a hint about whether the construction thread has hung for | 338 // 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 | 339 // |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 | 340 // "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. | 341 // detector will see no pending jobs in that case, so it's automatic. |
| 317 bool AVDACodecAllocator::IsThreadLikelyHung(TaskType task_type) { | 342 bool AVDACodecAllocator::IsThreadLikelyHung(TaskType task_type) { |
| 318 DCHECK(thread_checker_.CalledOnValidThread()); | 343 DCHECK(thread_checker_.CalledOnValidThread()); |
| 319 return threads_[task_type]->hang_detector.IsThreadLikelyHung(); | 344 return threads_[task_type]->hang_detector.IsThreadLikelyHung(); |
| 320 } | 345 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 360 void AVDACodecAllocator::StopThreadTask(size_t index) { | 385 void AVDACodecAllocator::StopThreadTask(size_t index) { |
| 361 threads_[index]->thread.Stop(); | 386 threads_[index]->thread.Stop(); |
| 362 // Signal the stop event after both threads are stopped. | 387 // Signal the stop event after both threads are stopped. |
| 363 if (stop_event_for_testing_ && !threads_[AUTO_CODEC]->thread.IsRunning() && | 388 if (stop_event_for_testing_ && !threads_[AUTO_CODEC]->thread.IsRunning() && |
| 364 !threads_[SW_CODEC]->thread.IsRunning()) { | 389 !threads_[SW_CODEC]->thread.IsRunning()) { |
| 365 stop_event_for_testing_->Signal(); | 390 stop_event_for_testing_->Signal(); |
| 366 } | 391 } |
| 367 } | 392 } |
| 368 | 393 |
| 369 } // namespace media | 394 } // namespace media |
| OLD | NEW |