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

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: cl feedback. Created 4 years, 5 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
« no previous file with comments | « media/gpu/android_video_decode_accelerator.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 { kMaxConcurrentCodecAutodetections = 4 };
121
118 static inline void RecordFormatChangedMetric(FormatChangedValue value) { 122 static inline void RecordFormatChangedMetric(FormatChangedValue value) {
119 UMA_HISTOGRAM_BOOLEAN("Media.AVDA.MissingFormatChanged", !!value); 123 UMA_HISTOGRAM_BOOLEAN("Media.AVDA.MissingFormatChanged", !!value);
120 } 124 }
121 125
122 // Handle OnFrameAvailable callbacks safely. Since they occur asynchronously, 126 // Handle OnFrameAvailable callbacks safely. Since they occur asynchronously,
123 // we take care that the AVDA that wants them still exists. A WeakPtr to 127 // 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 128 // the AVDA would be preferable, except that OnFrameAvailable callbacks can
125 // occur off the gpu main thread. We also can't guarantee when the 129 // occur off the gpu main thread. We also can't guarantee when the
126 // SurfaceTexture will quit sending callbacks to coordinate with the 130 // 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. 131 // 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 182 // 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 183 // 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 184 // 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. 185 // time out or keep polling forever in some common cases.
182 class AVDATimerManager { 186 class AVDATimerManager {
183 public: 187 public:
184 // Make sure that the construction thread is started for |avda_instance|. 188 // Make sure that the construction thread is started for |avda_instance|.
185 bool StartThread(AndroidVideoDecodeAccelerator* avda_instance) { 189 bool StartThread(AndroidVideoDecodeAccelerator* avda_instance) {
186 DCHECK(thread_checker_.CalledOnValidThread()); 190 DCHECK(thread_checker_.CalledOnValidThread());
187 191
188 if (thread_avda_instances_.empty()) { 192 // If we chose not to shut it down due to pending codec constructions, then
193 // the thread might already be started even if there are no avda instances.
194 // Plus, sometimes we just fail to start the thread.
195 if (!construction_thread_.IsRunning()) {
189 if (!construction_thread_.Start()) { 196 if (!construction_thread_.Start()) {
190 LOG(ERROR) << "Failed to start construction thread."; 197 LOG(ERROR) << "Failed to start construction thread.";
191 return false; 198 return false;
192 } 199 }
193 } 200 }
194 201
195 thread_avda_instances_.insert(avda_instance); 202 thread_avda_instances_.insert(avda_instance);
196 return true; 203 return true;
197 } 204 }
198 205
199 // |avda_instance| will no longer need the construction thread. Stop the 206 // |avda_instance| will no longer need the construction thread. Stop the
200 // thread if this is the last instance. 207 // thread if this is the last instance.
201 void StopThread(AndroidVideoDecodeAccelerator* avda_instance) { 208 void StopThread(AndroidVideoDecodeAccelerator* avda_instance) {
202 DCHECK(thread_checker_.CalledOnValidThread()); 209 DCHECK(thread_checker_.CalledOnValidThread());
203 210
204 thread_avda_instances_.erase(avda_instance); 211 thread_avda_instances_.erase(avda_instance);
205 if (thread_avda_instances_.empty()) 212 if (!thread_avda_instances_.empty())
206 construction_thread_.Stop(); 213 return;
214
215 // Don't stop the thread if there are outstanding requests, since they
216 // might be hung. They also might simply be incomplete, and the thread
217 // will stay running until we try to shut it down again.
218 base::AutoLock auto_lock(autodetection_info_.lock_);
219 if (autodetection_info_.outstanding_)
220 return;
221
222 construction_thread_.Stop();
207 } 223 }
208 224
209 // Request periodic callback of |avda_instance|->DoIOTask(). Does nothing if 225 // Request periodic callback of |avda_instance|->DoIOTask(). Does nothing if
210 // the instance is already registered and the timer started. The first request 226 // the instance is already registered and the timer started. The first request
211 // will start the repeating timer on an interval of DecodePollDelay(). 227 // will start the repeating timer on an interval of DecodePollDelay().
212 void StartTimer(AndroidVideoDecodeAccelerator* avda_instance) { 228 void StartTimer(AndroidVideoDecodeAccelerator* avda_instance) {
213 DCHECK(thread_checker_.CalledOnValidThread()); 229 DCHECK(thread_checker_.CalledOnValidThread());
214 230
215 timer_avda_instances_.insert(avda_instance); 231 timer_avda_instances_.insert(avda_instance);
216 232
(...skipping 25 matching lines...) Expand all
242 io_timer_.Stop(); 258 io_timer_.Stop();
243 } 259 }
244 260
245 // Eventually, we should run the timer on this thread. For now, we just keep 261 // Eventually, we should run the timer on this thread. For now, we just keep
246 // it as a convenience for construction. 262 // it as a convenience for construction.
247 scoped_refptr<base::SingleThreadTaskRunner> ConstructionTaskRunner() { 263 scoped_refptr<base::SingleThreadTaskRunner> ConstructionTaskRunner() {
248 DCHECK(thread_checker_.CalledOnValidThread()); 264 DCHECK(thread_checker_.CalledOnValidThread());
249 return construction_thread_.task_runner(); 265 return construction_thread_.task_runner();
250 } 266 }
251 267
268 // Called on the main thread when codec autodetection starts. There may be
269 // several calls to this before any call to OnAsyncCodecAutodetectionComplete.
270 void OnAsyncCodecAutodetectionStarted() {
271 base::AutoLock auto_lock(autodetection_info_.lock_);
272 ++autodetection_info_.outstanding_;
273 }
274
275 // Called on any thread when a codec is constructed with autodetection. This
276 // assumes that requests are ordered, so please don't mix sync and async codec
277 // construction here. This may be called on any thread.
278 void OnAsyncCodecAutodetectionComplete() {
279 base::AutoLock auto_lock_l(autodetection_info_.lock_);
280 DCHECK_GT(autodetection_info_.outstanding_, 0);
281 --autodetection_info_.outstanding_;
282 }
283
284 // Return a hint about whether autodetecting the codec type is safe or not.
285 bool IsCodecAutodetectionProbablySafe() {
286 base::AutoLock auto_lock_l(autodetection_info_.lock_);
287
288 return autodetection_info_.outstanding_ < kMaxConcurrentCodecAutodetections;
289 }
290
252 // |avda| would like to use |surface_id|. If it is not busy, then mark it 291 // |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, 292 // 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 293 // 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. 294 // is assumed to be on the way out, so we fail its allocation request.
256 bool AllocateSurface(int surface_id, AndroidVideoDecodeAccelerator* avda) { 295 bool AllocateSurface(int surface_id, AndroidVideoDecodeAccelerator* avda) {
257 // Nobody has to wait for no surface. 296 // Nobody has to wait for no surface.
258 if (surface_id == AndroidVideoDecodeAccelerator::Config::kNoSurfaceID) 297 if (surface_id == AndroidVideoDecodeAccelerator::Config::kNoSurfaceID)
259 return true; 298 return true;
260 299
261 auto iter = surface_waiter_map_.find(surface_id); 300 auto iter = surface_waiter_map_.find(surface_id);
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
347 SurfaceWaiterMap surface_waiter_map_; 386 SurfaceWaiterMap surface_waiter_map_;
348 387
349 // Since we can't delete while iterating when using a set, defer erasure until 388 // Since we can't delete while iterating when using a set, defer erasure until
350 // after iteration complete. 389 // after iteration complete.
351 bool timer_running_ = false; 390 bool timer_running_ = false;
352 std::set<AndroidVideoDecodeAccelerator*> pending_erase_; 391 std::set<AndroidVideoDecodeAccelerator*> pending_erase_;
353 392
354 // Repeating timer responsible for draining pending IO to the codecs. 393 // Repeating timer responsible for draining pending IO to the codecs.
355 base::RepeatingTimer io_timer_; 394 base::RepeatingTimer io_timer_;
356 395
396 // Data for determining if codec creation is hanging.
397 struct {
398 // Lock that protects other members of this struct.
399 base::Lock lock_;
400
401 // Number of currently pending autodetection requests.
402 int outstanding_ = 0;
403 } autodetection_info_;
404
357 base::Thread construction_thread_; 405 base::Thread construction_thread_;
358 406
359 base::ThreadChecker thread_checker_; 407 base::ThreadChecker thread_checker_;
360 408
361 DISALLOW_COPY_AND_ASSIGN(AVDATimerManager); 409 DISALLOW_COPY_AND_ASSIGN(AVDATimerManager);
362 }; 410 };
363 411
364 static base::LazyInstance<AVDATimerManager>::Leaky g_avda_timer = 412 static base::LazyInstance<AVDATimerManager>::Leaky g_avda_timer =
365 LAZY_INSTANCE_INITIALIZER; 413 LAZY_INSTANCE_INITIALIZER;
366 414
(...skipping 673 matching lines...) Expand 10 before | Expand all | Expand 10 after
1040 // Tell the strategy that we're changing codecs. The codec itself could be 1088 // 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 1089 // 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 1090 // 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 1091 // might access that surface while the main thread is drawing. Telling the
1044 // strategy to forget the codec avoids this. 1092 // strategy to forget the codec avoids this.
1045 if (media_codec_) { 1093 if (media_codec_) {
1046 media_codec_.reset(); 1094 media_codec_.reset();
1047 strategy_->CodecChanged(nullptr); 1095 strategy_->CodecChanged(nullptr);
1048 } 1096 }
1049 1097
1098 // Choose whether to autodetect the codec type.
1099 codec_config_->allow_autodetection_ =
1100 g_avda_timer.Pointer()->IsCodecAutodetectionProbablySafe();
1101 codec_config_->notify_completion_ = codec_config_->allow_autodetection_;
1102 if (codec_config_->allow_autodetection_)
1103 g_avda_timer.Pointer()->OnAsyncCodecAutodetectionStarted();
1104
1105 // If we're not trying autodetection, then use the main thread. The original
1106 // might be blocked.
1050 scoped_refptr<base::SingleThreadTaskRunner> task_runner = 1107 scoped_refptr<base::SingleThreadTaskRunner> task_runner =
1051 g_avda_timer.Pointer()->ConstructionTaskRunner(); 1108 codec_config_->allow_autodetection_
1109 ? g_avda_timer.Pointer()->ConstructionTaskRunner()
1110 : base::ThreadTaskRunnerHandle::Get();
1052 CHECK(task_runner); 1111 CHECK(task_runner);
1053 1112
1054 base::PostTaskAndReplyWithResult( 1113 base::PostTaskAndReplyWithResult(
1055 task_runner.get(), FROM_HERE, 1114 task_runner.get(), FROM_HERE,
1056 base::Bind(&AndroidVideoDecodeAccelerator::ConfigureMediaCodecOnAnyThread, 1115 base::Bind(&AndroidVideoDecodeAccelerator::ConfigureMediaCodecOnAnyThread,
1057 codec_config_), 1116 codec_config_),
1058 base::Bind(&AndroidVideoDecodeAccelerator::OnCodecConfigured, 1117 base::Bind(&AndroidVideoDecodeAccelerator::OnCodecConfigured,
1059 weak_this_factory_.GetWeakPtr())); 1118 weak_this_factory_.GetWeakPtr()));
1060 } 1119 }
1061 1120
1062 bool AndroidVideoDecodeAccelerator::ConfigureMediaCodecSynchronously() { 1121 bool AndroidVideoDecodeAccelerator::ConfigureMediaCodecSynchronously() {
1063 state_ = WAITING_FOR_CODEC; 1122 state_ = WAITING_FOR_CODEC;
1123
1124 // Decide whether to allow autodetection or not. Since we're on the main
1125 // thread, and this request is unordered with respect to pending async config
1126 // attempts, don't record it. It may break book-keeping, and there's not
1127 // much we can do anyway.
1128 codec_config_->allow_autodetection_ =
1129 g_avda_timer.Pointer()->IsCodecAutodetectionProbablySafe();
1130 codec_config_->notify_completion_ = false;
1131
1064 std::unique_ptr<VideoCodecBridge> media_codec = 1132 std::unique_ptr<VideoCodecBridge> media_codec =
1065 ConfigureMediaCodecOnAnyThread(codec_config_); 1133 ConfigureMediaCodecOnAnyThread(codec_config_);
1066 OnCodecConfigured(std::move(media_codec)); 1134 OnCodecConfigured(std::move(media_codec));
1067 return !!media_codec_; 1135 return !!media_codec_;
1068 } 1136 }
1069 1137
1070 std::unique_ptr<VideoCodecBridge> 1138 std::unique_ptr<VideoCodecBridge>
1071 AndroidVideoDecodeAccelerator::ConfigureMediaCodecOnAnyThread( 1139 AndroidVideoDecodeAccelerator::ConfigureMediaCodecOnAnyThread(
1072 scoped_refptr<CodecConfig> codec_config) { 1140 scoped_refptr<CodecConfig> codec_config) {
1073 TRACE_EVENT0("media", "AVDA::ConfigureMediaCodec"); 1141 TRACE_EVENT0("media", "AVDA::ConfigureMediaCodec");
1074 1142
1075 jobject media_crypto = codec_config->media_crypto_ 1143 jobject media_crypto = codec_config->media_crypto_
1076 ? codec_config->media_crypto_->obj() 1144 ? codec_config->media_crypto_->obj()
1077 : nullptr; 1145 : nullptr;
1078 1146
1079 // |needs_protected_surface_| implies encrypted stream. 1147 // |needs_protected_surface_| implies encrypted stream.
1080 DCHECK(!codec_config->needs_protected_surface_ || media_crypto); 1148 DCHECK(!codec_config->needs_protected_surface_ || media_crypto);
1081 1149
1082 return std::unique_ptr<VideoCodecBridge>(VideoCodecBridge::CreateDecoder( 1150 const bool require_software_codec = !codec_config->allow_autodetection_;
1151
1152 std::unique_ptr<VideoCodecBridge> codec(VideoCodecBridge::CreateDecoder(
1083 codec_config->codec_, codec_config->needs_protected_surface_, 1153 codec_config->codec_, codec_config->needs_protected_surface_,
1084 codec_config->initial_expected_coded_size_, 1154 codec_config->initial_expected_coded_size_,
1085 codec_config->surface_.j_surface().obj(), media_crypto, true)); 1155 codec_config->surface_.j_surface().obj(), media_crypto, true,
1156 require_software_codec));
1157
1158 // If we successfully completed after an autodetect, then let the other
1159 // instances know that we didn't get stuck.
1160 if (codec_config->notify_completion_)
1161 g_avda_timer.Pointer()->OnAsyncCodecAutodetectionComplete();
1162
1163 return codec;
1086 } 1164 }
1087 1165
1088 void AndroidVideoDecodeAccelerator::OnCodecConfigured( 1166 void AndroidVideoDecodeAccelerator::OnCodecConfigured(
1089 std::unique_ptr<VideoCodecBridge> media_codec) { 1167 std::unique_ptr<VideoCodecBridge> media_codec) {
1090 DCHECK(thread_checker_.CalledOnValidThread()); 1168 DCHECK(thread_checker_.CalledOnValidThread());
1091 DCHECK(state_ == WAITING_FOR_CODEC || state_ == SURFACE_DESTROYED); 1169 DCHECK(state_ == WAITING_FOR_CODEC || state_ == SURFACE_DESTROYED);
1092 1170
1093 // Record one instance of the codec being initialized. 1171 // Record one instance of the codec being initialized.
1094 RecordFormatChangedMetric(FormatChangedValue::CodecInitialized); 1172 RecordFormatChangedMetric(FormatChangedValue::CodecInitialized);
1095 1173
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
1315 1393
1316 void AndroidVideoDecodeAccelerator::ActualDestroy() { 1394 void AndroidVideoDecodeAccelerator::ActualDestroy() {
1317 DVLOG(1) << __FUNCTION__; 1395 DVLOG(1) << __FUNCTION__;
1318 DCHECK(thread_checker_.CalledOnValidThread()); 1396 DCHECK(thread_checker_.CalledOnValidThread());
1319 1397
1320 if (!on_destroying_surface_cb_.is_null()) { 1398 if (!on_destroying_surface_cb_.is_null()) {
1321 AVDASurfaceTracker::GetInstance()->UnregisterOnDestroyingSurfaceCallback( 1399 AVDASurfaceTracker::GetInstance()->UnregisterOnDestroyingSurfaceCallback(
1322 on_destroying_surface_cb_); 1400 on_destroying_surface_cb_);
1323 } 1401 }
1324 1402
1403 AVDATimerManager* manager = g_avda_timer.Pointer();
1404
1325 // We no longer care about |surface_id|, in case we did before. It's okay 1405 // We no longer care about |surface_id|, in case we did before. It's okay
1326 // if we have no surface and/or weren't the owner or a waiter. 1406 // if we have no surface and/or weren't the owner or a waiter.
1327 g_avda_timer.Pointer()->DeallocateSurface(config_.surface_id, this); 1407 manager->DeallocateSurface(config_.surface_id, this);
1328 1408
1329 // Note that async codec construction might still be in progress. In that 1409 // Note that async codec construction might still be in progress. In that
1330 // case, the codec will be deleted when it completes once we invalidate all 1410 // case, the codec will be deleted when it completes once we invalidate all
1331 // our weak refs. 1411 // our weak refs.
1332 weak_this_factory_.InvalidateWeakPtrs(); 1412 weak_this_factory_.InvalidateWeakPtrs();
1333 if (media_codec_) { 1413 if (media_codec_) {
1334 g_avda_timer.Pointer()->StopTimer(this); 1414 manager->StopTimer(this);
1335 media_codec_.reset(); 1415 // If codec construction is broken, then we can't release this codec if it's
1416 // backed by hardware, else it may hang too. Post it to the construction
1417 // thread, and it'll get freed if things start working. If things are
1418 // already working, then it'll be freed soon.
1419 if (media_codec_->IsSoftwareCodec()) {
1420 media_codec_.reset();
1421 } else {
1422 manager->ConstructionTaskRunner()->DeleteSoon(FROM_HERE,
1423 media_codec_.release());
1424 }
1336 } 1425 }
1337 delete this; 1426 delete this;
1338 } 1427 }
1339 1428
1340 bool AndroidVideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread( 1429 bool AndroidVideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread(
1341 const base::WeakPtr<Client>& decode_client, 1430 const base::WeakPtr<Client>& decode_client,
1342 const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) { 1431 const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) {
1343 return false; 1432 return false;
1344 } 1433 }
1345 1434
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after
1651 if (MediaCodecUtil::IsSurfaceViewOutputSupported()) { 1740 if (MediaCodecUtil::IsSurfaceViewOutputSupported()) {
1652 capabilities.flags |= VideoDecodeAccelerator::Capabilities:: 1741 capabilities.flags |= VideoDecodeAccelerator::Capabilities::
1653 SUPPORTS_EXTERNAL_OUTPUT_SURFACE; 1742 SUPPORTS_EXTERNAL_OUTPUT_SURFACE;
1654 } 1743 }
1655 } 1744 }
1656 1745
1657 return capabilities; 1746 return capabilities;
1658 } 1747 }
1659 1748
1660 } // namespace media 1749 } // namespace media
OLDNEW
« no previous file with comments | « media/gpu/android_video_decode_accelerator.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698