| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/base/android/media_codec_decoder.h" | 5 #include "media/base/android/media_codec_decoder.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
| 9 #include "base/callback_helpers.h" | 9 #include "base/callback_helpers.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 28 matching lines...) Expand all Loading... |
| 39 const base::Closure& error_cb, | 39 const base::Closure& error_cb, |
| 40 const char* decoder_thread_name) | 40 const char* decoder_thread_name) |
| 41 : media_task_runner_(media_task_runner), | 41 : media_task_runner_(media_task_runner), |
| 42 decoder_thread_(decoder_thread_name), | 42 decoder_thread_(decoder_thread_name), |
| 43 needs_reconfigure_(false), | 43 needs_reconfigure_(false), |
| 44 external_request_data_cb_(external_request_data_cb), | 44 external_request_data_cb_(external_request_data_cb), |
| 45 starvation_cb_(starvation_cb), | 45 starvation_cb_(starvation_cb), |
| 46 stop_done_cb_(stop_done_cb), | 46 stop_done_cb_(stop_done_cb), |
| 47 error_cb_(error_cb), | 47 error_cb_(error_cb), |
| 48 state_(kStopped), | 48 state_(kStopped), |
| 49 needs_preroll_(true), |
| 49 eos_enqueued_(false), | 50 eos_enqueued_(false), |
| 50 completed_(false), | 51 completed_(false), |
| 51 last_frame_posted_(false), | 52 last_frame_posted_(false), |
| 52 is_data_request_in_progress_(false), | 53 is_data_request_in_progress_(false), |
| 53 is_incoming_data_invalid_(false), | 54 is_incoming_data_invalid_(false), |
| 54 #ifndef NDEBUG | 55 #ifndef NDEBUG |
| 55 verify_next_frame_is_key_(false), | 56 verify_next_frame_is_key_(false), |
| 56 #endif | 57 #endif |
| 57 weak_factory_(this) { | 58 weak_factory_(this) { |
| 58 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 59 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 59 | 60 |
| 60 DVLOG(1) << "Decoder::Decoder() " << decoder_thread_name; | 61 DVLOG(1) << "Decoder::Decoder() " << decoder_thread_name; |
| 61 | 62 |
| 62 internal_error_cb_ = | 63 internal_error_cb_ = |
| 63 base::Bind(&MediaCodecDecoder::OnCodecError, weak_factory_.GetWeakPtr()); | 64 base::Bind(&MediaCodecDecoder::OnCodecError, weak_factory_.GetWeakPtr()); |
| 65 internal_preroll_done_cb_ = |
| 66 base::Bind(&MediaCodecDecoder::OnPrerollDone, weak_factory_.GetWeakPtr()); |
| 64 request_data_cb_ = | 67 request_data_cb_ = |
| 65 base::Bind(&MediaCodecDecoder::RequestData, weak_factory_.GetWeakPtr()); | 68 base::Bind(&MediaCodecDecoder::RequestData, weak_factory_.GetWeakPtr()); |
| 66 } | 69 } |
| 67 | 70 |
| 68 MediaCodecDecoder::~MediaCodecDecoder() { | 71 MediaCodecDecoder::~MediaCodecDecoder() {} |
| 69 DCHECK(media_task_runner_->BelongsToCurrentThread()); | |
| 70 | |
| 71 DVLOG(1) << "Decoder::~Decoder()"; | |
| 72 | |
| 73 // NB: ReleaseDecoderResources() is virtual | |
| 74 ReleaseDecoderResources(); | |
| 75 } | |
| 76 | 72 |
| 77 const char* MediaCodecDecoder::class_name() const { | 73 const char* MediaCodecDecoder::class_name() const { |
| 78 return "Decoder"; | 74 return "Decoder"; |
| 79 } | 75 } |
| 80 | 76 |
| 81 void MediaCodecDecoder::ReleaseDecoderResources() { | |
| 82 DCHECK(media_task_runner_->BelongsToCurrentThread()); | |
| 83 | |
| 84 DVLOG(1) << class_name() << "::" << __FUNCTION__; | |
| 85 | |
| 86 // Set [kInEmergencyStop| state to block already posted ProcessNextFrame(). | |
| 87 SetState(kInEmergencyStop); | |
| 88 | |
| 89 decoder_thread_.Stop(); // synchronous | |
| 90 | |
| 91 SetState(kStopped); | |
| 92 media_codec_bridge_.reset(); | |
| 93 } | |
| 94 | |
| 95 void MediaCodecDecoder::Flush() { | 77 void MediaCodecDecoder::Flush() { |
| 96 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 78 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 97 | 79 |
| 98 DVLOG(1) << class_name() << "::" << __FUNCTION__; | 80 DVLOG(1) << class_name() << "::" << __FUNCTION__; |
| 99 | 81 |
| 100 DCHECK_EQ(GetState(), kStopped); | 82 DCHECK_EQ(GetState(), kStopped); |
| 101 | 83 |
| 102 // Flush() is a part of the Seek request. Whenever we request a seek we need | 84 // Flush() is a part of the Seek request. Whenever we request a seek we need |
| 103 // to invalidate the current data request. | 85 // to invalidate the current data request. |
| 104 if (is_data_request_in_progress_) | 86 if (is_data_request_in_progress_) |
| 105 is_incoming_data_invalid_ = true; | 87 is_incoming_data_invalid_ = true; |
| 106 | 88 |
| 107 eos_enqueued_ = false; | 89 eos_enqueued_ = false; |
| 108 completed_ = false; | 90 completed_ = false; |
| 109 au_queue_.Flush(); | 91 au_queue_.Flush(); |
| 110 | 92 |
| 111 #ifndef NDEBUG | 93 #ifndef NDEBUG |
| 112 // We check and reset |verify_next_frame_is_key_| on Decoder thread. | 94 // We check and reset |verify_next_frame_is_key_| on Decoder thread. |
| 113 // This DCHECK ensures we won't need to lock this variable. | 95 // This DCHECK ensures we won't need to lock this variable. |
| 114 DCHECK(!decoder_thread_.IsRunning()); | 96 DCHECK(!decoder_thread_.IsRunning()); |
| 115 | 97 |
| 116 // For video the first frame after flush must be key frame. | 98 // For video the first frame after flush must be key frame. |
| 117 verify_next_frame_is_key_ = true; | 99 verify_next_frame_is_key_ = true; |
| 118 #endif | 100 #endif |
| 119 | 101 |
| 102 needs_preroll_ = true; |
| 103 |
| 120 if (media_codec_bridge_) { | 104 if (media_codec_bridge_) { |
| 121 // MediaCodecBridge::Reset() performs MediaCodecBridge.flush() | 105 // MediaCodecBridge::Reset() performs MediaCodecBridge.flush() |
| 122 MediaCodecStatus flush_status = media_codec_bridge_->Reset(); | 106 MediaCodecStatus flush_status = media_codec_bridge_->Reset(); |
| 123 if (flush_status != MEDIA_CODEC_OK) { | 107 if (flush_status != MEDIA_CODEC_OK) { |
| 124 DVLOG(0) << class_name() << "::" << __FUNCTION__ | 108 DVLOG(0) << class_name() << "::" << __FUNCTION__ |
| 125 << "MediaCodecBridge::Reset() failed"; | 109 << "MediaCodecBridge::Reset() failed"; |
| 126 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_); | 110 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_); |
| 127 } | 111 } |
| 128 } | 112 } |
| 129 } | 113 } |
| 130 | 114 |
| 131 void MediaCodecDecoder::ReleaseMediaCodec() { | 115 void MediaCodecDecoder::ReleaseMediaCodec() { |
| 132 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 116 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 133 | 117 |
| 134 DVLOG(1) << class_name() << "::" << __FUNCTION__; | 118 DVLOG(1) << class_name() << "::" << __FUNCTION__; |
| 135 | 119 |
| 136 media_codec_bridge_.reset(); | 120 media_codec_bridge_.reset(); |
| 121 needs_preroll_ = true; |
| 137 } | 122 } |
| 138 | 123 |
| 139 bool MediaCodecDecoder::IsPrefetchingOrPlaying() const { | 124 bool MediaCodecDecoder::IsPrefetchingOrPlaying() const { |
| 140 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 125 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 141 | 126 |
| 127 // Whether decoder needs to be stopped. |
| 142 base::AutoLock lock(state_lock_); | 128 base::AutoLock lock(state_lock_); |
| 143 return state_ == kPrefetching || state_ == kRunning; | 129 switch (state_) { |
| 130 case kPrefetching: |
| 131 case kPrefetched: |
| 132 case kPrerolling: |
| 133 case kPrerolled: |
| 134 case kRunning: |
| 135 return true; |
| 136 case kStopped: |
| 137 case kStopping: |
| 138 case kInEmergencyStop: |
| 139 case kError: |
| 140 return false; |
| 141 } |
| 142 NOTREACHED(); |
| 143 return false; |
| 144 } | 144 } |
| 145 | 145 |
| 146 bool MediaCodecDecoder::IsStopped() const { | 146 bool MediaCodecDecoder::IsStopped() const { |
| 147 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 147 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 148 | 148 |
| 149 return GetState() == kStopped; | 149 return GetState() == kStopped; |
| 150 } | 150 } |
| 151 | 151 |
| 152 bool MediaCodecDecoder::IsCompleted() const { | 152 bool MediaCodecDecoder::IsCompleted() const { |
| 153 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 153 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 154 | 154 |
| 155 return completed_; | 155 return completed_; |
| 156 } | 156 } |
| 157 | 157 |
| 158 bool MediaCodecDecoder::NotCompletedAndNeedsPreroll() const { |
| 159 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 160 |
| 161 return HasStream() && needs_preroll_ && !completed_; |
| 162 } |
| 163 |
| 158 base::android::ScopedJavaLocalRef<jobject> MediaCodecDecoder::GetMediaCrypto() { | 164 base::android::ScopedJavaLocalRef<jobject> MediaCodecDecoder::GetMediaCrypto() { |
| 159 base::android::ScopedJavaLocalRef<jobject> media_crypto; | 165 base::android::ScopedJavaLocalRef<jobject> media_crypto; |
| 160 | 166 |
| 161 // TODO(timav): implement DRM. | 167 // TODO(timav): implement DRM. |
| 162 // drm_bridge_ is not implemented | 168 // drm_bridge_ is not implemented |
| 163 // if (drm_bridge_) | 169 // if (drm_bridge_) |
| 164 // media_crypto = drm_bridge_->GetMediaCrypto(); | 170 // media_crypto = drm_bridge_->GetMediaCrypto(); |
| 165 return media_crypto; | 171 return media_crypto; |
| 166 } | 172 } |
| 167 | 173 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 185 | 191 |
| 186 if (GetState() == kError) { | 192 if (GetState() == kError) { |
| 187 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state kError"; | 193 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state kError"; |
| 188 return kConfigFailure; | 194 return kConfigFailure; |
| 189 } | 195 } |
| 190 | 196 |
| 191 if (needs_reconfigure_) { | 197 if (needs_reconfigure_) { |
| 192 DVLOG(1) << class_name() << "::" << __FUNCTION__ | 198 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
| 193 << ": needs reconfigure, deleting MediaCodec"; | 199 << ": needs reconfigure, deleting MediaCodec"; |
| 194 needs_reconfigure_ = false; | 200 needs_reconfigure_ = false; |
| 195 media_codec_bridge_.reset(); | 201 ReleaseMediaCodec(); |
| 196 | |
| 197 // No need to release these buffers since the MediaCodec is deleted, just | |
| 198 // remove their indexes from |delayed_buffers_|. | |
| 199 | |
| 200 ClearDelayedBuffers(false); | |
| 201 } | 202 } |
| 202 | 203 |
| 203 MediaCodecDecoder::ConfigStatus result; | 204 MediaCodecDecoder::ConfigStatus result; |
| 204 if (media_codec_bridge_) { | 205 if (media_codec_bridge_) { |
| 205 DVLOG(1) << class_name() << "::" << __FUNCTION__ | 206 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
| 206 << ": reconfiguration is not required, ignoring"; | 207 << ": reconfiguration is not required, ignoring"; |
| 207 result = kConfigOk; | 208 result = kConfigOk; |
| 208 } else { | 209 } else { |
| 209 result = ConfigureInternal(); | 210 result = ConfigureInternal(); |
| 210 | 211 |
| 211 #ifndef NDEBUG | 212 #ifndef NDEBUG |
| 212 // We check and reset |verify_next_frame_is_key_| on Decoder thread. | 213 // We check and reset |verify_next_frame_is_key_| on Decoder thread. |
| 213 // This DCHECK ensures we won't need to lock this variable. | 214 // This DCHECK ensures we won't need to lock this variable. |
| 214 DCHECK(!decoder_thread_.IsRunning()); | 215 DCHECK(!decoder_thread_.IsRunning()); |
| 215 | 216 |
| 216 // For video the first frame after reconfiguration must be key frame. | 217 // For video the first frame after reconfiguration must be key frame. |
| 217 if (result == kConfigOk) | 218 if (result == kConfigOk) |
| 218 verify_next_frame_is_key_ = true; | 219 verify_next_frame_is_key_ = true; |
| 219 #endif | 220 #endif |
| 220 } | 221 } |
| 221 | 222 |
| 222 return result; | 223 return result; |
| 223 } | 224 } |
| 224 | 225 |
| 225 bool MediaCodecDecoder::Start(base::TimeDelta current_time) { | 226 bool MediaCodecDecoder::Preroll(base::TimeDelta preroll_timestamp, |
| 227 const base::Closure& preroll_done_cb) { |
| 226 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 228 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 227 | 229 |
| 228 DVLOG(1) << class_name() << "::" << __FUNCTION__ | 230 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
| 229 << " current_time:" << current_time; | 231 << " preroll_timestamp:" << preroll_timestamp; |
| 230 | 232 |
| 231 DecoderState state = GetState(); | 233 DecoderState state = GetState(); |
| 232 if (state == kRunning) { | |
| 233 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": already started"; | |
| 234 return true; // already started | |
| 235 } | |
| 236 | |
| 237 if (state != kPrefetched) { | 234 if (state != kPrefetched) { |
| 238 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state " | 235 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state " |
| 239 << AsString(state) << ", ignoring"; | 236 << AsString(state) << ", ignoring"; |
| 240 return false; | 237 return false; |
| 241 } | 238 } |
| 242 | 239 |
| 243 if (!media_codec_bridge_) { | 240 if (!media_codec_bridge_) { |
| 244 DVLOG(0) << class_name() << "::" << __FUNCTION__ | 241 DVLOG(0) << class_name() << "::" << __FUNCTION__ |
| 245 << ": not configured, ignoring"; | 242 << ": not configured, ignoring"; |
| 246 return false; | 243 return false; |
| 247 } | 244 } |
| 248 | 245 |
| 249 DCHECK(!decoder_thread_.IsRunning()); | 246 DCHECK(!decoder_thread_.IsRunning()); |
| 247 DCHECK(needs_preroll_); |
| 248 |
| 249 preroll_done_cb_ = preroll_done_cb; |
| 250 | 250 |
| 251 // We only synchronize video stream. | 251 // We only synchronize video stream. |
| 252 // When audio is present, the |current_time| is audio time. | 252 DissociatePTSFromTime(); // associaton will happen after preroll is done. |
| 253 SynchronizePTSWithTime(current_time); | 253 preroll_timestamp_ = preroll_timestamp; |
| 254 | 254 |
| 255 last_frame_posted_ = false; | 255 last_frame_posted_ = false; |
| 256 | 256 |
| 257 // Start the decoder thread | 257 // Start the decoder thread |
| 258 if (!decoder_thread_.Start()) { | 258 if (!decoder_thread_.Start()) { |
| 259 DVLOG(0) << class_name() << "::" << __FUNCTION__ | 259 DVLOG(0) << class_name() << "::" << __FUNCTION__ |
| 260 << ": cannot start decoder thread"; | 260 << ": cannot start decoder thread"; |
| 261 return false; | 261 return false; |
| 262 } | 262 } |
| 263 | 263 |
| 264 DVLOG(0) << class_name() << "::" << __FUNCTION__ << " decoder thread started"; | 264 SetState(kPrerolling); |
| 265 |
| 266 decoder_thread_.task_runner()->PostTask( |
| 267 FROM_HERE, |
| 268 base::Bind(&MediaCodecDecoder::ProcessNextFrame, base::Unretained(this))); |
| 269 |
| 270 return true; |
| 271 } |
| 272 |
| 273 bool MediaCodecDecoder::Start(base::TimeDelta start_timestamp) { |
| 274 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 275 |
| 276 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
| 277 << " start_timestamp:" << start_timestamp; |
| 278 |
| 279 DecoderState state = GetState(); |
| 280 |
| 281 if (state != kPrefetched && state != kPrerolled) { |
| 282 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state " |
| 283 << AsString(state) << ", ignoring"; |
| 284 return false; |
| 285 } |
| 286 |
| 287 if (!media_codec_bridge_) { |
| 288 DVLOG(0) << class_name() << "::" << __FUNCTION__ |
| 289 << ": not configured, ignoring"; |
| 290 return false; |
| 291 } |
| 292 |
| 293 // We only synchronize video stream. |
| 294 AssociateCurrentTimeWithPTS(start_timestamp); |
| 295 preroll_timestamp_ = base::TimeDelta(); |
| 296 |
| 297 // Start the decoder thread |
| 298 if (!decoder_thread_.IsRunning()) { |
| 299 last_frame_posted_ = false; |
| 300 if (!decoder_thread_.Start()) { |
| 301 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
| 302 << ": cannot start decoder thread"; |
| 303 return false; |
| 304 } |
| 305 } |
| 265 | 306 |
| 266 SetState(kRunning); | 307 SetState(kRunning); |
| 267 | 308 |
| 268 decoder_thread_.task_runner()->PostTask( | 309 decoder_thread_.task_runner()->PostTask( |
| 269 FROM_HERE, | 310 FROM_HERE, |
| 270 base::Bind(&MediaCodecDecoder::ProcessNextFrame, base::Unretained(this))); | 311 base::Bind(&MediaCodecDecoder::ProcessNextFrame, base::Unretained(this))); |
| 271 | 312 |
| 272 return true; | 313 return true; |
| 273 } | 314 } |
| 274 | 315 |
| 275 void MediaCodecDecoder::SyncStop() { | 316 void MediaCodecDecoder::SyncStop() { |
| 276 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 317 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 277 | 318 |
| 278 DVLOG(1) << class_name() << "::" << __FUNCTION__; | 319 DVLOG(1) << class_name() << "::" << __FUNCTION__; |
| 279 | 320 |
| 280 if (GetState() == kError) { | 321 if (GetState() == kError) { |
| 281 DVLOG(0) << class_name() << "::" << __FUNCTION__ | 322 DVLOG(0) << class_name() << "::" << __FUNCTION__ |
| 282 << ": wrong state kError, ignoring"; | 323 << ": wrong state kError, ignoring"; |
| 283 return; | 324 return; |
| 284 } | 325 } |
| 285 | 326 |
| 286 // After this method returns, decoder thread will not be running. | 327 DoEmergencyStop(); |
| 287 | 328 |
| 288 // Set [kInEmergencyStop| state to block already posted ProcessNextFrame(). | 329 ReleaseDelayedBuffers(); |
| 289 SetState(kInEmergencyStop); | |
| 290 | |
| 291 decoder_thread_.Stop(); // synchronous | |
| 292 | |
| 293 SetState(kStopped); | |
| 294 | |
| 295 ClearDelayedBuffers(true); // release prior to clearing |delayed_buffers_|. | |
| 296 } | 330 } |
| 297 | 331 |
| 298 void MediaCodecDecoder::RequestToStop() { | 332 void MediaCodecDecoder::RequestToStop() { |
| 299 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 333 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 300 | 334 |
| 301 DVLOG(1) << class_name() << "::" << __FUNCTION__; | 335 DVLOG(1) << class_name() << "::" << __FUNCTION__; |
| 302 | 336 |
| 303 DecoderState state = GetState(); | 337 DecoderState state = GetState(); |
| 304 switch (state) { | 338 switch (state) { |
| 305 case kError: | 339 case kError: |
| 306 DVLOG(0) << class_name() << "::" << __FUNCTION__ | 340 DVLOG(0) << class_name() << "::" << __FUNCTION__ |
| 307 << ": wrong state kError, ignoring"; | 341 << ": wrong state kError, ignoring"; |
| 308 break; | 342 break; |
| 309 case kRunning: | 343 case kRunning: |
| 310 SetState(kStopping); | 344 SetState(kStopping); |
| 311 break; | 345 break; |
| 346 case kPrerolling: |
| 347 case kPrerolled: |
| 348 DCHECK(decoder_thread_.IsRunning()); |
| 349 // Synchronous stop. |
| 350 decoder_thread_.Stop(); |
| 351 SetState(kStopped); |
| 352 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); |
| 353 break; |
| 312 case kStopping: | 354 case kStopping: |
| 313 break; // ignore | 355 break; // ignore |
| 314 case kStopped: | 356 case kStopped: |
| 315 case kPrefetching: | 357 case kPrefetching: |
| 316 case kPrefetched: | 358 case kPrefetched: |
| 317 // There is nothing to wait for, we can sent nofigication right away. | 359 // There is nothing to wait for, we can sent nofigication right away. |
| 318 DCHECK(!decoder_thread_.IsRunning()); | 360 DCHECK(!decoder_thread_.IsRunning()); |
| 319 SetState(kStopped); | 361 SetState(kStopped); |
| 320 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); | 362 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); |
| 321 break; | 363 break; |
| 322 default: | 364 default: |
| 323 NOTREACHED(); | 365 NOTREACHED(); |
| 324 break; | 366 break; |
| 325 } | 367 } |
| 326 } | 368 } |
| 327 | 369 |
| 328 void MediaCodecDecoder::OnLastFrameRendered(bool completed) { | 370 void MediaCodecDecoder::OnLastFrameRendered(bool completed) { |
| 329 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 371 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 330 | 372 |
| 331 DVLOG(0) << class_name() << "::" << __FUNCTION__ | 373 DVLOG(0) << class_name() << "::" << __FUNCTION__ |
| 332 << " completed:" << completed; | 374 << " completed:" << completed; |
| 333 | 375 |
| 334 decoder_thread_.Stop(); // synchronous | 376 decoder_thread_.Stop(); // synchronous |
| 335 | 377 |
| 336 SetState(kStopped); | 378 SetState(kStopped); |
| 337 completed_ = completed; | 379 completed_ = completed; |
| 338 | 380 |
| 381 if (completed_ && !preroll_done_cb_.is_null()) |
| 382 media_task_runner_->PostTask(FROM_HERE, |
| 383 base::ResetAndReturn(&preroll_done_cb_)); |
| 384 |
| 339 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); | 385 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); |
| 340 } | 386 } |
| 341 | 387 |
| 388 void MediaCodecDecoder::OnPrerollDone() { |
| 389 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 390 |
| 391 DVLOG(1) << class_name() << "::" << __FUNCTION__; |
| 392 |
| 393 if (GetState() == kPrerolling) { |
| 394 SetState(kPrerolled); |
| 395 needs_preroll_ = false; |
| 396 media_task_runner_->PostTask(FROM_HERE, |
| 397 base::ResetAndReturn(&preroll_done_cb_)); |
| 398 } |
| 399 } |
| 400 |
| 342 void MediaCodecDecoder::OnDemuxerDataAvailable(const DemuxerData& data) { | 401 void MediaCodecDecoder::OnDemuxerDataAvailable(const DemuxerData& data) { |
| 343 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 402 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 344 | 403 |
| 345 // If |data| contains an aborted data, the last AU will have kAborted status. | 404 // If |data| contains an aborted data, the last AU will have kAborted status. |
| 346 bool aborted_data = | 405 bool aborted_data = |
| 347 !data.access_units.empty() && | 406 !data.access_units.empty() && |
| 348 data.access_units.back().status == DemuxerStream::kAborted; | 407 data.access_units.back().status == DemuxerStream::kAborted; |
| 349 | 408 |
| 350 #ifndef NDEBUG | 409 #ifndef NDEBUG |
| 351 const char* explain_if_skipped = | 410 const char* explain_if_skipped = |
| (...skipping 12 matching lines...) Expand all Loading... |
| 364 | 423 |
| 365 is_incoming_data_invalid_ = false; | 424 is_incoming_data_invalid_ = false; |
| 366 is_data_request_in_progress_ = false; | 425 is_data_request_in_progress_ = false; |
| 367 | 426 |
| 368 // Do not request data if we got kAborted. There is no point to request the | 427 // Do not request data if we got kAborted. There is no point to request the |
| 369 // data after kAborted and before the OnDemuxerSeekDone. | 428 // data after kAborted and before the OnDemuxerSeekDone. |
| 370 if (GetState() == kPrefetching && !aborted_data) | 429 if (GetState() == kPrefetching && !aborted_data) |
| 371 PrefetchNextChunk(); | 430 PrefetchNextChunk(); |
| 372 } | 431 } |
| 373 | 432 |
| 433 bool MediaCodecDecoder::IsPrerollingForTests() const { |
| 434 // UI task runner. |
| 435 return GetState() == kPrerolling; |
| 436 } |
| 437 |
| 374 int MediaCodecDecoder::NumDelayedRenderTasks() const { | 438 int MediaCodecDecoder::NumDelayedRenderTasks() const { |
| 375 return 0; | 439 return 0; |
| 376 } | 440 } |
| 377 | 441 |
| 442 void MediaCodecDecoder::DoEmergencyStop() { |
| 443 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 444 DVLOG(1) << class_name() << "::" << __FUNCTION__; |
| 445 |
| 446 // After this method returns, decoder thread will not be running. |
| 447 |
| 448 // Set [kInEmergencyStop| state to block already posted ProcessNextFrame(). |
| 449 SetState(kInEmergencyStop); |
| 450 |
| 451 decoder_thread_.Stop(); // synchronous |
| 452 |
| 453 SetState(kStopped); |
| 454 } |
| 455 |
| 378 void MediaCodecDecoder::CheckLastFrame(bool eos_encountered, | 456 void MediaCodecDecoder::CheckLastFrame(bool eos_encountered, |
| 379 bool has_delayed_tasks) { | 457 bool has_delayed_tasks) { |
| 380 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | 458 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
| 381 | 459 |
| 382 bool last_frame_when_stopping = GetState() == kStopping && !has_delayed_tasks; | 460 bool last_frame_when_stopping = GetState() == kStopping && !has_delayed_tasks; |
| 383 | 461 |
| 384 if (last_frame_when_stopping || eos_encountered) { | 462 if (last_frame_when_stopping || eos_encountered) { |
| 385 media_task_runner_->PostTask( | 463 media_task_runner_->PostTask( |
| 386 FROM_HERE, base::Bind(&MediaCodecDecoder::OnLastFrameRendered, | 464 FROM_HERE, base::Bind(&MediaCodecDecoder::OnLastFrameRendered, |
| 387 weak_factory_.GetWeakPtr(), eos_encountered)); | 465 weak_factory_.GetWeakPtr(), eos_encountered)); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 433 request_data_cb_.Run(); | 511 request_data_cb_.Run(); |
| 434 } | 512 } |
| 435 | 513 |
| 436 void MediaCodecDecoder::ProcessNextFrame() { | 514 void MediaCodecDecoder::ProcessNextFrame() { |
| 437 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | 515 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
| 438 | 516 |
| 439 DVLOG(2) << class_name() << "::" << __FUNCTION__; | 517 DVLOG(2) << class_name() << "::" << __FUNCTION__; |
| 440 | 518 |
| 441 DecoderState state = GetState(); | 519 DecoderState state = GetState(); |
| 442 | 520 |
| 443 if (state != kRunning && state != kStopping) { | 521 if (state != kPrerolling && state != kRunning && state != kStopping) { |
| 444 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": not running"; | 522 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": not running"; |
| 445 return; | 523 return; |
| 446 } | 524 } |
| 447 | 525 |
| 448 if (state == kStopping) { | 526 if (state == kStopping) { |
| 449 if (NumDelayedRenderTasks() == 0 && !last_frame_posted_) { | 527 if (NumDelayedRenderTasks() == 0 && !last_frame_posted_) { |
| 450 DVLOG(1) << class_name() << "::" << __FUNCTION__ | 528 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
| 451 << ": kStopping, posting OnLastFrameRendered"; | 529 << ": kStopping, posting OnLastFrameRendered"; |
| 452 media_task_runner_->PostTask( | 530 media_task_runner_->PostTask( |
| 453 FROM_HERE, base::Bind(&MediaCodecDecoder::OnLastFrameRendered, | 531 FROM_HERE, base::Bind(&MediaCodecDecoder::OnLastFrameRendered, |
| 454 weak_factory_.GetWeakPtr(), false)); | 532 weak_factory_.GetWeakPtr(), false)); |
| 455 last_frame_posted_ = true; | 533 last_frame_posted_ = true; |
| 456 } | 534 } |
| 457 | 535 |
| 458 // We can stop processing, the |au_queue_| and MediaCodec queues can freeze. | 536 // We can stop processing, the |au_queue_| and MediaCodec queues can freeze. |
| 459 // We only need to let finish the delayed rendering tasks. | 537 // We only need to let finish the delayed rendering tasks. |
| 460 return; | 538 return; |
| 461 } | 539 } |
| 462 | 540 |
| 463 DCHECK(state == kRunning); | 541 DCHECK(state == kPrerolling || state == kRunning); |
| 464 | 542 |
| 465 if (!EnqueueInputBuffer()) | 543 if (!EnqueueInputBuffer()) |
| 466 return; | 544 return; |
| 467 | 545 |
| 468 if (!DepleteOutputBufferQueue()) | 546 if (!DepleteOutputBufferQueue()) |
| 469 return; | 547 return; |
| 470 | 548 |
| 471 // We need a small delay if we want to stop this thread by | 549 // We need a small delay if we want to stop this thread by |
| 472 // decoder_thread_.Stop() reliably. | 550 // decoder_thread_.Stop() reliably. |
| 473 // The decoder thread message loop processes all pending | 551 // The decoder thread message loop processes all pending |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 598 | 676 |
| 599 DVLOG(2) << class_name() << "::" << __FUNCTION__; | 677 DVLOG(2) << class_name() << "::" << __FUNCTION__; |
| 600 | 678 |
| 601 int buffer_index = 0; | 679 int buffer_index = 0; |
| 602 size_t offset = 0; | 680 size_t offset = 0; |
| 603 size_t size = 0; | 681 size_t size = 0; |
| 604 base::TimeDelta pts; | 682 base::TimeDelta pts; |
| 605 MediaCodecStatus status; | 683 MediaCodecStatus status; |
| 606 bool eos_encountered = false; | 684 bool eos_encountered = false; |
| 607 | 685 |
| 686 RenderMode render_mode; |
| 687 |
| 608 base::TimeDelta timeout = | 688 base::TimeDelta timeout = |
| 609 base::TimeDelta::FromMilliseconds(kOutputBufferTimeout); | 689 base::TimeDelta::FromMilliseconds(kOutputBufferTimeout); |
| 610 | 690 |
| 611 // Extract all output buffers that are available. | 691 // Extract all output buffers that are available. |
| 612 // Usually there will be only one, but sometimes it is preceeded by | 692 // Usually there will be only one, but sometimes it is preceeded by |
| 613 // MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED or MEDIA_CODEC_OUTPUT_FORMAT_CHANGED. | 693 // MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED or MEDIA_CODEC_OUTPUT_FORMAT_CHANGED. |
| 614 do { | 694 do { |
| 615 status = media_codec_bridge_->DequeueOutputBuffer( | 695 status = media_codec_bridge_->DequeueOutputBuffer( |
| 616 timeout, &buffer_index, &offset, &size, &pts, &eos_encountered, | 696 timeout, &buffer_index, &offset, &size, &pts, &eos_encountered, |
| 617 nullptr); | 697 nullptr); |
| 618 | 698 |
| 619 // Reset the timeout to 0 for the subsequent DequeueOutputBuffer() calls | 699 // Reset the timeout to 0 for the subsequent DequeueOutputBuffer() calls |
| 620 // to quickly break the loop after we got all currently available buffers. | 700 // to quickly break the loop after we got all currently available buffers. |
| 621 timeout = base::TimeDelta::FromMilliseconds(0); | 701 timeout = base::TimeDelta::FromMilliseconds(0); |
| 622 | 702 |
| 623 switch (status) { | 703 switch (status) { |
| 624 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: | 704 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: |
| 625 // Output buffers are replaced in MediaCodecBridge, nothing to do. | 705 // Output buffers are replaced in MediaCodecBridge, nothing to do. |
| 626 break; | 706 break; |
| 627 | 707 |
| 628 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: | 708 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: |
| 629 DVLOG(2) << class_name() << "::" << __FUNCTION__ | 709 DVLOG(2) << class_name() << "::" << __FUNCTION__ |
| 630 << " MEDIA_CODEC_OUTPUT_FORMAT_CHANGED"; | 710 << " MEDIA_CODEC_OUTPUT_FORMAT_CHANGED"; |
| 631 OnOutputFormatChanged(); | 711 OnOutputFormatChanged(); |
| 632 break; | 712 break; |
| 633 | 713 |
| 634 case MEDIA_CODEC_OK: | 714 case MEDIA_CODEC_OK: |
| 635 // We got the decoded frame | 715 // We got the decoded frame. |
| 636 Render(buffer_index, offset, size, true, pts, eos_encountered); | 716 |
| 717 if (pts < preroll_timestamp_) |
| 718 render_mode = kRenderSkip; |
| 719 else if (GetState() == kPrerolling) |
| 720 render_mode = kRenderAfterPreroll; |
| 721 else |
| 722 render_mode = kRenderNow; |
| 723 |
| 724 Render(buffer_index, offset, size, render_mode, pts, eos_encountered); |
| 725 |
| 726 if (render_mode == kRenderAfterPreroll) { |
| 727 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " pts:" << pts |
| 728 << " preroll done, stopping frame processing"; |
| 729 media_task_runner_->PostTask(FROM_HERE, internal_preroll_done_cb_); |
| 730 return false; |
| 731 } |
| 637 break; | 732 break; |
| 638 | 733 |
| 639 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER: | 734 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER: |
| 640 // Nothing to do. | 735 // Nothing to do. |
| 641 break; | 736 break; |
| 642 | 737 |
| 643 case MEDIA_CODEC_ERROR: | 738 case MEDIA_CODEC_ERROR: |
| 644 DVLOG(0) << class_name() << "::" << __FUNCTION__ | 739 DVLOG(0) << class_name() << "::" << __FUNCTION__ |
| 645 << ": MEDIA_CODEC_ERROR from DequeueOutputBuffer"; | 740 << ": MEDIA_CODEC_ERROR from DequeueOutputBuffer"; |
| 646 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_); | 741 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 679 | 774 |
| 680 base::AutoLock lock(state_lock_); | 775 base::AutoLock lock(state_lock_); |
| 681 state_ = state; | 776 state_ = state; |
| 682 } | 777 } |
| 683 | 778 |
| 684 #undef RETURN_STRING | 779 #undef RETURN_STRING |
| 685 #define RETURN_STRING(x) \ | 780 #define RETURN_STRING(x) \ |
| 686 case x: \ | 781 case x: \ |
| 687 return #x; | 782 return #x; |
| 688 | 783 |
| 784 const char* MediaCodecDecoder::AsString(RenderMode render_mode) { |
| 785 switch (render_mode) { |
| 786 RETURN_STRING(kRenderSkip); |
| 787 RETURN_STRING(kRenderAfterPreroll); |
| 788 RETURN_STRING(kRenderNow); |
| 789 } |
| 790 return nullptr; // crash early |
| 791 } |
| 792 |
| 689 const char* MediaCodecDecoder::AsString(DecoderState state) { | 793 const char* MediaCodecDecoder::AsString(DecoderState state) { |
| 690 switch (state) { | 794 switch (state) { |
| 691 RETURN_STRING(kStopped); | 795 RETURN_STRING(kStopped); |
| 692 RETURN_STRING(kPrefetching); | 796 RETURN_STRING(kPrefetching); |
| 693 RETURN_STRING(kPrefetched); | 797 RETURN_STRING(kPrefetched); |
| 798 RETURN_STRING(kPrerolling); |
| 799 RETURN_STRING(kPrerolled); |
| 694 RETURN_STRING(kRunning); | 800 RETURN_STRING(kRunning); |
| 695 RETURN_STRING(kStopping); | 801 RETURN_STRING(kStopping); |
| 696 RETURN_STRING(kInEmergencyStop); | 802 RETURN_STRING(kInEmergencyStop); |
| 697 RETURN_STRING(kError); | 803 RETURN_STRING(kError); |
| 698 default: | |
| 699 return "Unknown DecoderState"; | |
| 700 } | 804 } |
| 805 return nullptr; // crash early |
| 701 } | 806 } |
| 702 | 807 |
| 703 #undef RETURN_STRING | 808 #undef RETURN_STRING |
| 704 | 809 |
| 705 } // namespace media | 810 } // namespace media |
| OLD | NEW |