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

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

Issue 2084143002: Make AVDA fall back to software decoding if needed. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: symbolic constants, coments. Created 4 years, 6 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 (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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/android_video_decode_accelerator.h" 5 #include "media/gpu/android_video_decode_accelerator.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <memory> 9 #include <memory>
10 10
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
108 static inline const base::TimeDelta ErrorPostingDelay() { 108 static inline const base::TimeDelta ErrorPostingDelay() {
109 return base::TimeDelta::FromSeconds(2); 109 return base::TimeDelta::FromSeconds(2);
110 } 110 }
111 111
112 // For RecordFormatChangedMetric. 112 // For RecordFormatChangedMetric.
113 enum FormatChangedValue { 113 enum FormatChangedValue {
114 CodecInitialized = false, 114 CodecInitialized = false,
115 MissingFormatChanged = true 115 MissingFormatChanged = true
116 }; 116 };
117 117
118 // Maximum number of concurrent, incomplete codec creations that we'll allow
119 // before turning off autodection of codec type.
120 enum { kMaxOutstandingCodecAutodetections = 4 };
121
122 static inline const base::TimeDelta CodecConstructionTimeout() {
123 return base::TimeDelta::FromSeconds(1);
124 }
125
118 static inline void RecordFormatChangedMetric(FormatChangedValue value) { 126 static inline void RecordFormatChangedMetric(FormatChangedValue value) {
119 UMA_HISTOGRAM_BOOLEAN("Media.AVDA.MissingFormatChanged", !!value); 127 UMA_HISTOGRAM_BOOLEAN("Media.AVDA.MissingFormatChanged", !!value);
120 } 128 }
121 129
122 // Handle OnFrameAvailable callbacks safely. Since they occur asynchronously, 130 // Handle OnFrameAvailable callbacks safely. Since they occur asynchronously,
123 // we take care that the AVDA that wants them still exists. A WeakPtr to 131 // we take care that the AVDA that wants them still exists. A WeakPtr to
124 // the AVDA would be preferable, except that OnFrameAvailable callbacks can 132 // the AVDA would be preferable, except that OnFrameAvailable callbacks can
125 // occur off the gpu main thread. We also can't guarantee when the 133 // occur off the gpu main thread. We also can't guarantee when the
126 // SurfaceTexture will quit sending callbacks to coordinate with the 134 // SurfaceTexture will quit sending callbacks to coordinate with the
127 // destruction of the AVDA, so we have a separate object that the cb can own. 135 // destruction of the AVDA, so we have a separate object that the cb can own.
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 // buffer to MediaCodec). This is inherently a race, since we don't know if 186 // buffer to MediaCodec). This is inherently a race, since we don't know if
179 // MediaCodec is broken or just slow. Since the MediaCodec API doesn't let 187 // MediaCodec is broken or just slow. Since the MediaCodec API doesn't let
180 // us wait on MediaCodec state changes prior to L, we more or less have to 188 // us wait on MediaCodec state changes prior to L, we more or less have to
181 // time out or keep polling forever in some common cases. 189 // time out or keep polling forever in some common cases.
182 class AVDATimerManager { 190 class AVDATimerManager {
183 public: 191 public:
184 // Make sure that the construction thread is started for |avda_instance|. 192 // Make sure that the construction thread is started for |avda_instance|.
185 bool StartThread(AndroidVideoDecodeAccelerator* avda_instance) { 193 bool StartThread(AndroidVideoDecodeAccelerator* avda_instance) {
186 DCHECK(thread_checker_.CalledOnValidThread()); 194 DCHECK(thread_checker_.CalledOnValidThread());
187 195
188 if (thread_avda_instances_.empty()) { 196 // The thread might already be started even if there are no avda instances,
DaleCurtis 2016/06/21 21:17:56 remove ,
liberato (no reviews please) 2016/06/22 17:56:13 i restructured the sentence a litt.e
197 // if we chose not to shut it down due to pending codec constructions.
198 // Plus, sometimes we just fail to start the thread.
199 if (!construction_thread_.IsRunning()) {
189 if (!construction_thread_.Start()) { 200 if (!construction_thread_.Start()) {
190 LOG(ERROR) << "Failed to start construction thread."; 201 LOG(ERROR) << "Failed to start construction thread.";
191 return false; 202 return false;
192 } 203 }
193 } 204 }
194 205
195 thread_avda_instances_.insert(avda_instance); 206 thread_avda_instances_.insert(avda_instance);
196 return true; 207 return true;
197 } 208 }
198 209
199 // |avda_instance| will no longer need the construction thread. Stop the 210 // |avda_instance| will no longer need the construction thread. Stop the
200 // thread if this is the last instance. 211 // thread if this is the last instance.
201 void StopThread(AndroidVideoDecodeAccelerator* avda_instance) { 212 void StopThread(AndroidVideoDecodeAccelerator* avda_instance) {
202 DCHECK(thread_checker_.CalledOnValidThread()); 213 DCHECK(thread_checker_.CalledOnValidThread());
203 214
204 thread_avda_instances_.erase(avda_instance); 215 thread_avda_instances_.erase(avda_instance);
205 if (thread_avda_instances_.empty()) 216 if (!thread_avda_instances_.empty())
206 construction_thread_.Stop(); 217 return;
218
219 // Don't stop the thread if there are outstanding requests, since they
220 // might be hung. They also might simply be incomplete, and the thread
221 // will stay running until we try to shut it down again.
222 base::AutoLock _l(autodetection_info_.lock_);
223 if (autodetection_info_.outstanding_)
224 return;
225
226 construction_thread_.Stop();
207 } 227 }
208 228
209 // Request periodic callback of |avda_instance|->DoIOTask(). Does nothing if 229 // Request periodic callback of |avda_instance|->DoIOTask(). Does nothing if
210 // the instance is already registered and the timer started. The first request 230 // the instance is already registered and the timer started. The first request
211 // will start the repeating timer on an interval of DecodePollDelay(). 231 // will start the repeating timer on an interval of DecodePollDelay().
212 void StartTimer(AndroidVideoDecodeAccelerator* avda_instance) { 232 void StartTimer(AndroidVideoDecodeAccelerator* avda_instance) {
213 DCHECK(thread_checker_.CalledOnValidThread()); 233 DCHECK(thread_checker_.CalledOnValidThread());
214 234
215 timer_avda_instances_.insert(avda_instance); 235 timer_avda_instances_.insert(avda_instance);
216 236
(...skipping 25 matching lines...) Expand all
242 io_timer_.Stop(); 262 io_timer_.Stop();
243 } 263 }
244 264
245 // Eventually, we should run the timer on this thread. For now, we just keep 265 // Eventually, we should run the timer on this thread. For now, we just keep
246 // it as a convenience for construction. 266 // it as a convenience for construction.
247 scoped_refptr<base::SingleThreadTaskRunner> ConstructionTaskRunner() { 267 scoped_refptr<base::SingleThreadTaskRunner> ConstructionTaskRunner() {
248 DCHECK(thread_checker_.CalledOnValidThread()); 268 DCHECK(thread_checker_.CalledOnValidThread());
249 return construction_thread_.task_runner(); 269 return construction_thread_.task_runner();
250 } 270 }
251 271
272 scoped_refptr<base::SingleThreadTaskRunner> BackupTaskRunner() {
DaleCurtis 2016/06/21 21:17:56 Instead of this, should we just stop using async c
liberato (no reviews please) 2016/06/22 17:56:13 Done, except the UMA stat. i'm still trying to fi
273 DCHECK(thread_checker_.CalledOnValidThread());
274 // Try to start the backup thread if needed. Note that we never bother to
275 // stop this once it starts.
276 if (!backup_thread_.IsRunning())
DaleCurtis 2016/06/21 21:17:56 Collapse to ternary if not deleting.
liberato (no reviews please) 2016/06/22 17:56:13 Done.
277 if (!backup_thread_.Start())
278 return nullptr;
279 return backup_thread_.task_runner();
280 }
281
282 // Called on the main thread when codec autodetection starts. There may be
DaleCurtis 2016/06/21 21:17:56 I think this is a bit more complicated than necess
liberato (no reviews please) 2016/06/22 17:56:13 keeping codec construction off the main thread is
283 // several calls to this before any call to OnAnyThread.
284 void OnAsyncCodecAutodetectionStarted() {
285 base::AutoLock _l(autodetection_info_.lock_);
286 if (!autodetection_info_.outstanding_)
287 autodetection_info_.current_start_ = base::TimeTicks::Now();
288 ++autodetection_info_.outstanding_;
289 }
290
291 // Called on any thread when a codec is constructed with autodetection. This
292 // assumes that requests are ordered, so please don't mix sync and async codec
293 // construction here. This may be called on any thread.
294 void OnAsyncCodecAutodetectionComplete() {
295 base::AutoLock _l(autodetection_info_.lock_);
296 DCHECK(autodetection_info_.outstanding_ > 0);
297 --autodetection_info_.outstanding_;
298
299 // The next request, if any, will start approximately now.
300 autodetection_info_.current_start_ = base::TimeTicks::Now();
301 }
302
303 // Return a hint about whether autodetecting the codec type is safe or not.
304 bool IsCodecAutodetectionProbablySafe() {
305 base::AutoLock _l(autodetection_info_.lock_);
306
307 // If there are no outstanding autodetections, then assume that it's okay
308 // to try one.
309 if (autodetection_info_.outstanding_ == 0)
310 return true;
311
312 // Hard-limit the number of outstanding autodetections, to try to prevent
313 // falling back to software on an autodetect. This seems to be when
314 // things start to cause problems. While this doesn't limit the number of
315 // hardware decoders that are in use concurrently, it might help during
316 // initial page load if there are a lot of tags.
317 if (autodetection_info_.outstanding_ >= kMaxOutstandingCodecAutodetections)
318 return false;
319
320 // Make sure that we've made progress recently.
321 base::TimeTicks now = base::TimeTicks::Now();
322 return (now - autodetection_info_.current_start_) <
323 CodecConstructionTimeout();
324 }
325
252 // |avda| would like to use |surface_id|. If it is not busy, then mark it 326 // |avda| would like to use |surface_id|. If it is not busy, then mark it
253 // as busy and return true. If it is busy, then replace any existing waiter, 327 // as busy and return true. If it is busy, then replace any existing waiter,
254 // make |avda| the current waiter, and return false. Any existing waiter 328 // make |avda| the current waiter, and return false. Any existing waiter
255 // is assumed to be on the way out, so we fail its allocation request. 329 // is assumed to be on the way out, so we fail its allocation request.
256 bool AllocateSurface(int surface_id, AndroidVideoDecodeAccelerator* avda) { 330 bool AllocateSurface(int surface_id, AndroidVideoDecodeAccelerator* avda) {
257 // Nobody has to wait for no surface. 331 // Nobody has to wait for no surface.
258 if (surface_id == AndroidVideoDecodeAccelerator::Config::kNoSurfaceID) 332 if (surface_id == AndroidVideoDecodeAccelerator::Config::kNoSurfaceID)
259 return true; 333 return true;
260 334
261 auto iter = surface_waiter_map_.find(surface_id); 335 auto iter = surface_waiter_map_.find(surface_id);
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 377
304 // Promote |waiter| to be the owner. 378 // Promote |waiter| to be the owner.
305 iter->second.owner = waiter; 379 iter->second.owner = waiter;
306 iter->second.waiter = nullptr; 380 iter->second.waiter = nullptr;
307 waiter->OnSurfaceAvailable(true); 381 waiter->OnSurfaceAvailable(true);
308 } 382 }
309 383
310 private: 384 private:
311 friend struct base::DefaultLazyInstanceTraits<AVDATimerManager>; 385 friend struct base::DefaultLazyInstanceTraits<AVDATimerManager>;
312 386
313 AVDATimerManager() : construction_thread_("AVDAThread") {} 387 AVDATimerManager()
388 : construction_thread_("AVDAThread"),
389 backup_thread_("AVDABackupThread") {}
314 ~AVDATimerManager() { NOTREACHED(); } 390 ~AVDATimerManager() { NOTREACHED(); }
315 391
316 void RunTimer() { 392 void RunTimer() {
317 { 393 {
318 // Call out to all AVDA instances, some of which may attempt to remove 394 // Call out to all AVDA instances, some of which may attempt to remove
319 // themselves from the list during this operation; those removals will be 395 // themselves from the list during this operation; those removals will be
320 // deferred until after all iterations are complete. 396 // deferred until after all iterations are complete.
321 base::AutoReset<bool> scoper(&timer_running_, true); 397 base::AutoReset<bool> scoper(&timer_running_, true);
322 for (auto* avda : timer_avda_instances_) 398 for (auto* avda : timer_avda_instances_)
323 avda->DoIOTask(false); 399 avda->DoIOTask(false);
(...skipping 23 matching lines...) Expand all
347 SurfaceWaiterMap surface_waiter_map_; 423 SurfaceWaiterMap surface_waiter_map_;
348 424
349 // Since we can't delete while iterating when using a set, defer erasure until 425 // Since we can't delete while iterating when using a set, defer erasure until
350 // after iteration complete. 426 // after iteration complete.
351 bool timer_running_ = false; 427 bool timer_running_ = false;
352 std::set<AndroidVideoDecodeAccelerator*> pending_erase_; 428 std::set<AndroidVideoDecodeAccelerator*> pending_erase_;
353 429
354 // Repeating timer responsible for draining pending IO to the codecs. 430 // Repeating timer responsible for draining pending IO to the codecs.
355 base::RepeatingTimer io_timer_; 431 base::RepeatingTimer io_timer_;
356 432
433 // Data for determining if codec creation is hanging.
434 struct {
435 // Lock that protects other members of this struct.
436 base::Lock lock_;
437
438 // Number of currently pending autodetection requests.
439 int outstanding_ = 0;
440
441 // Time at which the most recent autodetection started.
442 base::TimeTicks current_start_;
443 } autodetection_info_;
444
357 base::Thread construction_thread_; 445 base::Thread construction_thread_;
446 base::Thread backup_thread_;
358 447
359 base::ThreadChecker thread_checker_; 448 base::ThreadChecker thread_checker_;
360 449
361 DISALLOW_COPY_AND_ASSIGN(AVDATimerManager); 450 DISALLOW_COPY_AND_ASSIGN(AVDATimerManager);
362 }; 451 };
363 452
364 static base::LazyInstance<AVDATimerManager>::Leaky g_avda_timer = 453 static base::LazyInstance<AVDATimerManager>::Leaky g_avda_timer =
365 LAZY_INSTANCE_INITIALIZER; 454 LAZY_INSTANCE_INITIALIZER;
366 455
367 AndroidVideoDecodeAccelerator::CodecConfig::CodecConfig() {} 456 AndroidVideoDecodeAccelerator::CodecConfig::CodecConfig() {}
(...skipping 672 matching lines...) Expand 10 before | Expand all | Expand 10 after
1040 // Tell the strategy that we're changing codecs. The codec itself could be 1129 // Tell the strategy that we're changing codecs. The codec itself could be
1041 // used normally, since we don't replace it until we're back on the main 1130 // used normally, since we don't replace it until we're back on the main
1042 // thread. However, if we're using an output surface, then the incoming codec 1131 // thread. However, if we're using an output surface, then the incoming codec
1043 // might access that surface while the main thread is drawing. Telling the 1132 // might access that surface while the main thread is drawing. Telling the
1044 // strategy to forget the codec avoids this. 1133 // strategy to forget the codec avoids this.
1045 if (media_codec_) { 1134 if (media_codec_) {
1046 media_codec_.reset(); 1135 media_codec_.reset();
1047 strategy_->CodecChanged(nullptr); 1136 strategy_->CodecChanged(nullptr);
1048 } 1137 }
1049 1138
1139 // Choose whether to autodetect the codec type.
1140 codec_config_->allow_autodetection_ =
1141 g_avda_timer.Pointer()->IsCodecAutodetectionProbablySafe();
1142 codec_config_->notify_completion_ = codec_config_->allow_autodetection_;
1143 if (codec_config_->allow_autodetection_)
1144 g_avda_timer.Pointer()->OnAsyncCodecAutodetectionStarted();
1145
1146 // If we're not trying autodetection, then also use the backup thread. The
1147 // main one might be blocked.
1050 scoped_refptr<base::SingleThreadTaskRunner> task_runner = 1148 scoped_refptr<base::SingleThreadTaskRunner> task_runner =
1051 g_avda_timer.Pointer()->ConstructionTaskRunner(); 1149 codec_config_->allow_autodetection_
1052 CHECK(task_runner); 1150 ? g_avda_timer.Pointer()->ConstructionTaskRunner()
1151 : g_avda_timer.Pointer()->BackupTaskRunner();
1152 if (!task_runner) {
1153 // If we don't have a thread, then just fail.
1154 OnCodecConfigured(nullptr);
1155 return;
1156 }
1053 1157
1054 base::PostTaskAndReplyWithResult( 1158 base::PostTaskAndReplyWithResult(
1055 task_runner.get(), FROM_HERE, 1159 task_runner.get(), FROM_HERE,
1056 base::Bind(&AndroidVideoDecodeAccelerator::ConfigureMediaCodecOnAnyThread, 1160 base::Bind(&AndroidVideoDecodeAccelerator::ConfigureMediaCodecOnAnyThread,
1057 codec_config_), 1161 codec_config_),
1058 base::Bind(&AndroidVideoDecodeAccelerator::OnCodecConfigured, 1162 base::Bind(&AndroidVideoDecodeAccelerator::OnCodecConfigured,
1059 weak_this_factory_.GetWeakPtr())); 1163 weak_this_factory_.GetWeakPtr()));
1060 } 1164 }
1061 1165
1062 bool AndroidVideoDecodeAccelerator::ConfigureMediaCodecSynchronously() { 1166 bool AndroidVideoDecodeAccelerator::ConfigureMediaCodecSynchronously() {
1063 state_ = WAITING_FOR_CODEC; 1167 state_ = WAITING_FOR_CODEC;
1168
1169 // Decide whether to allow autodetection or not. Since we're on the main
1170 // thread, and this request is unordered with respect to pending async config
1171 // attempts, don't record it. It may break book-keeping, and there's not
1172 // much we can do anyway.
1173 codec_config_->allow_autodetection_ =
1174 g_avda_timer.Pointer()->IsCodecAutodetectionProbablySafe();
1175 codec_config_->notify_completion_ = false;
1176
1064 std::unique_ptr<VideoCodecBridge> media_codec = 1177 std::unique_ptr<VideoCodecBridge> media_codec =
1065 ConfigureMediaCodecOnAnyThread(codec_config_); 1178 ConfigureMediaCodecOnAnyThread(codec_config_);
1066 OnCodecConfigured(std::move(media_codec)); 1179 OnCodecConfigured(std::move(media_codec));
1067 return !!media_codec_; 1180 return !!media_codec_;
1068 } 1181 }
1069 1182
1070 std::unique_ptr<VideoCodecBridge> 1183 std::unique_ptr<VideoCodecBridge>
1071 AndroidVideoDecodeAccelerator::ConfigureMediaCodecOnAnyThread( 1184 AndroidVideoDecodeAccelerator::ConfigureMediaCodecOnAnyThread(
1072 scoped_refptr<CodecConfig> codec_config) { 1185 scoped_refptr<CodecConfig> codec_config) {
1073 TRACE_EVENT0("media", "AVDA::ConfigureMediaCodec"); 1186 TRACE_EVENT0("media", "AVDA::ConfigureMediaCodec");
1074 1187
1075 jobject media_crypto = codec_config->media_crypto_ 1188 jobject media_crypto = codec_config->media_crypto_
1076 ? codec_config->media_crypto_->obj() 1189 ? codec_config->media_crypto_->obj()
1077 : nullptr; 1190 : nullptr;
1078 1191
1079 // |needs_protected_surface_| implies encrypted stream. 1192 // |needs_protected_surface_| implies encrypted stream.
1080 DCHECK(!codec_config->needs_protected_surface_ || media_crypto); 1193 DCHECK(!codec_config->needs_protected_surface_ || media_crypto);
1081 1194
1082 return std::unique_ptr<VideoCodecBridge>(VideoCodecBridge::CreateDecoder( 1195 const bool require_software = !codec_config->allow_autodetection_;
1196
1197 std::unique_ptr<VideoCodecBridge> codec(VideoCodecBridge::CreateDecoder(
1083 codec_config->codec_, codec_config->needs_protected_surface_, 1198 codec_config->codec_, codec_config->needs_protected_surface_,
1084 codec_config->initial_expected_coded_size_, 1199 codec_config->initial_expected_coded_size_,
1085 codec_config->surface_.j_surface().obj(), media_crypto, true)); 1200 codec_config->surface_.j_surface().obj(), media_crypto, true,
1201 require_software));
1202
1203 // If we successfully completed after an autodetect, then reset the timer so
1204 // that other instances know that autodetection is okay.
1205 if (codec_config->notify_completion_)
1206 g_avda_timer.Pointer()->OnAsyncCodecAutodetectionComplete();
1207
1208 return codec;
1086 } 1209 }
1087 1210
1088 void AndroidVideoDecodeAccelerator::OnCodecConfigured( 1211 void AndroidVideoDecodeAccelerator::OnCodecConfigured(
1089 std::unique_ptr<VideoCodecBridge> media_codec) { 1212 std::unique_ptr<VideoCodecBridge> media_codec) {
1090 DCHECK(thread_checker_.CalledOnValidThread()); 1213 DCHECK(thread_checker_.CalledOnValidThread());
1091 DCHECK(state_ == WAITING_FOR_CODEC || state_ == SURFACE_DESTROYED); 1214 DCHECK(state_ == WAITING_FOR_CODEC || state_ == SURFACE_DESTROYED);
1092 1215
1093 // Record one instance of the codec being initialized. 1216 // Record one instance of the codec being initialized.
1094 RecordFormatChangedMetric(FormatChangedValue::CodecInitialized); 1217 RecordFormatChangedMetric(FormatChangedValue::CodecInitialized);
1095 1218
(...skipping 555 matching lines...) Expand 10 before | Expand all | Expand 10 after
1651 if (MediaCodecUtil::IsSurfaceViewOutputSupported()) { 1774 if (MediaCodecUtil::IsSurfaceViewOutputSupported()) {
1652 capabilities.flags |= VideoDecodeAccelerator::Capabilities:: 1775 capabilities.flags |= VideoDecodeAccelerator::Capabilities::
1653 SUPPORTS_EXTERNAL_OUTPUT_SURFACE; 1776 SUPPORTS_EXTERNAL_OUTPUT_SURFACE;
1654 } 1777 }
1655 } 1778 }
1656 1779
1657 return capabilities; 1780 return capabilities;
1658 } 1781 }
1659 1782
1660 } // namespace media 1783 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698