Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |