Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(61)

Side by Side Diff: media/gpu/avda_codec_allocator.cc

Issue 2629223003: media: Ensure MediaCodecs are released before attached SurfaceTextures (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698