Chromium Code Reviews| 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 17 matching lines...) Expand all Loading... | |
| 28 const int kInputBufferTimeout = 20; | 28 const int kInputBufferTimeout = 20; |
| 29 | 29 |
| 30 // Timeout for dequeuing an output buffer from MediaCodec in milliseconds. | 30 // Timeout for dequeuing an output buffer from MediaCodec in milliseconds. |
| 31 const int kOutputBufferTimeout = 20; | 31 const int kOutputBufferTimeout = 20; |
| 32 } | 32 } |
| 33 | 33 |
| 34 MediaCodecDecoder::MediaCodecDecoder( | 34 MediaCodecDecoder::MediaCodecDecoder( |
| 35 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, | 35 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, |
| 36 const base::Closure& external_request_data_cb, | 36 const base::Closure& external_request_data_cb, |
| 37 const base::Closure& starvation_cb, | 37 const base::Closure& starvation_cb, |
| 38 const base::Closure& preroll_done_cb, | |
| 38 const base::Closure& stop_done_cb, | 39 const base::Closure& stop_done_cb, |
| 39 const base::Closure& error_cb, | 40 const base::Closure& error_cb, |
| 40 const char* decoder_thread_name) | 41 const char* decoder_thread_name) |
| 41 : media_task_runner_(media_task_runner), | 42 : media_task_runner_(media_task_runner), |
| 42 decoder_thread_(decoder_thread_name), | 43 decoder_thread_(decoder_thread_name), |
| 43 needs_reconfigure_(false), | 44 needs_reconfigure_(false), |
| 44 external_request_data_cb_(external_request_data_cb), | 45 external_request_data_cb_(external_request_data_cb), |
| 45 starvation_cb_(starvation_cb), | 46 starvation_cb_(starvation_cb), |
| 47 preroll_done_cb_(preroll_done_cb), | |
| 46 stop_done_cb_(stop_done_cb), | 48 stop_done_cb_(stop_done_cb), |
| 47 error_cb_(error_cb), | 49 error_cb_(error_cb), |
| 48 state_(kStopped), | 50 state_(kStopped), |
| 49 eos_enqueued_(false), | 51 eos_enqueued_(false), |
| 50 completed_(false), | 52 completed_(false), |
| 51 last_frame_posted_(false), | 53 last_frame_posted_(false), |
| 52 is_data_request_in_progress_(false), | 54 is_data_request_in_progress_(false), |
| 53 is_incoming_data_invalid_(false), | 55 is_incoming_data_invalid_(false), |
| 54 #ifndef NDEBUG | 56 #ifndef NDEBUG |
| 55 verify_next_frame_is_key_(false), | 57 verify_next_frame_is_key_(false), |
| 56 #endif | 58 #endif |
| 57 weak_factory_(this) { | 59 weak_factory_(this) { |
| 58 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 60 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 59 | 61 |
| 60 DVLOG(1) << "Decoder::Decoder() " << decoder_thread_name; | 62 DVLOG(1) << "Decoder::Decoder() " << decoder_thread_name; |
| 61 | 63 |
| 62 internal_error_cb_ = | 64 internal_error_cb_ = |
| 63 base::Bind(&MediaCodecDecoder::OnCodecError, weak_factory_.GetWeakPtr()); | 65 base::Bind(&MediaCodecDecoder::OnCodecError, weak_factory_.GetWeakPtr()); |
| 66 internal_preroll_done_cb_ = | |
| 67 base::Bind(&MediaCodecDecoder::OnPrerollDone, weak_factory_.GetWeakPtr()); | |
| 64 request_data_cb_ = | 68 request_data_cb_ = |
| 65 base::Bind(&MediaCodecDecoder::RequestData, weak_factory_.GetWeakPtr()); | 69 base::Bind(&MediaCodecDecoder::RequestData, weak_factory_.GetWeakPtr()); |
| 66 } | 70 } |
| 67 | 71 |
| 68 MediaCodecDecoder::~MediaCodecDecoder() { | 72 MediaCodecDecoder::~MediaCodecDecoder() { |
| 69 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 73 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 70 | 74 |
| 71 DVLOG(1) << "Decoder::~Decoder()"; | 75 DVLOG(1) << "Decoder::~Decoder()"; |
| 72 | 76 |
| 73 // NB: ReleaseDecoderResources() is virtual | 77 // NB: ReleaseDecoderResources() is virtual |
| 74 ReleaseDecoderResources(); | 78 ReleaseDecoderResources(); |
| 75 } | 79 } |
| 76 | 80 |
| 77 const char* MediaCodecDecoder::class_name() const { | 81 const char* MediaCodecDecoder::class_name() const { |
| 78 return "Decoder"; | 82 return "Decoder"; |
| 79 } | 83 } |
| 80 | 84 |
| 81 void MediaCodecDecoder::ReleaseDecoderResources() { | 85 void MediaCodecDecoder::ReleaseDecoderResources() { |
| 82 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 86 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 83 | 87 |
| 84 DVLOG(1) << class_name() << "::" << __FUNCTION__; | 88 DVLOG(1) << class_name() << "::" << __FUNCTION__; |
| 85 | 89 |
| 86 // Set [kInEmergencyStop| state to block already posted ProcessNextFrame(). | 90 // Set [kInEmergencyStop| state to block already posted ProcessNextFrame(). |
| 87 SetState(kInEmergencyStop); | 91 SetState(kInEmergencyStop); |
| 88 | 92 |
| 89 decoder_thread_.Stop(); // synchronous | 93 decoder_thread_.Stop(); // synchronous |
| 90 | 94 |
| 91 SetState(kStopped); | 95 SetState(kStopped); |
| 92 media_codec_bridge_.reset(); | 96 ReleaseMediaCodec(); |
| 93 } | 97 } |
| 94 | 98 |
| 95 void MediaCodecDecoder::Flush() { | 99 void MediaCodecDecoder::Flush() { |
| 96 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 100 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 97 | 101 |
| 98 DVLOG(1) << class_name() << "::" << __FUNCTION__; | 102 DVLOG(1) << class_name() << "::" << __FUNCTION__; |
| 99 | 103 |
| 100 DCHECK_EQ(GetState(), kStopped); | 104 DCHECK_EQ(GetState(), kStopped); |
| 101 | 105 |
| 102 // Flush() is a part of the Seek request. Whenever we request a seek we need | 106 // Flush() is a part of the Seek request. Whenever we request a seek we need |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 124 DVLOG(0) << class_name() << "::" << __FUNCTION__ | 128 DVLOG(0) << class_name() << "::" << __FUNCTION__ |
| 125 << "MediaCodecBridge::Reset() failed"; | 129 << "MediaCodecBridge::Reset() failed"; |
| 126 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_); | 130 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_); |
| 127 } | 131 } |
| 128 } | 132 } |
| 129 } | 133 } |
| 130 | 134 |
| 131 void MediaCodecDecoder::ReleaseMediaCodec() { | 135 void MediaCodecDecoder::ReleaseMediaCodec() { |
| 132 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 136 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 133 | 137 |
| 134 DVLOG(1) << class_name() << "::" << __FUNCTION__; | |
| 135 | |
| 136 media_codec_bridge_.reset(); | 138 media_codec_bridge_.reset(); |
| 137 } | 139 } |
| 138 | 140 |
| 139 bool MediaCodecDecoder::IsPrefetchingOrPlaying() const { | 141 bool MediaCodecDecoder::IsPrefetchingOrPlaying() const { |
| 140 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 142 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 141 | 143 |
| 144 // Whether decoder needs to be stopped. | |
| 142 base::AutoLock lock(state_lock_); | 145 base::AutoLock lock(state_lock_); |
| 143 return state_ == kPrefetching || state_ == kRunning; | 146 switch (state_) { |
| 147 case kPrefetching: | |
| 148 case kPrefetched: | |
| 149 case kPrerolling: | |
| 150 case kPrerolled: | |
| 151 case kRunning: | |
| 152 return true; | |
| 153 case kStopped: | |
| 154 case kStopping: | |
| 155 case kInEmergencyStop: | |
| 156 case kError: | |
| 157 return false; | |
| 158 } | |
| 159 NOTREACHED(); | |
| 160 return false; | |
| 161 } | |
| 162 | |
| 163 bool MediaCodecDecoder::IsPrerollDone() const { | |
| 164 DCHECK(media_task_runner_->BelongsToCurrentThread()); | |
| 165 | |
| 166 return !HasStream() || IsCompleted() || GetState() == kPrerolled; | |
| 144 } | 167 } |
| 145 | 168 |
| 146 bool MediaCodecDecoder::IsStopped() const { | 169 bool MediaCodecDecoder::IsStopped() const { |
| 147 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 170 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 148 | 171 |
| 149 return GetState() == kStopped; | 172 return GetState() == kStopped; |
| 150 } | 173 } |
| 151 | 174 |
| 152 bool MediaCodecDecoder::IsCompleted() const { | 175 bool MediaCodecDecoder::IsCompleted() const { |
| 153 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 176 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 185 | 208 |
| 186 if (GetState() == kError) { | 209 if (GetState() == kError) { |
| 187 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state kError"; | 210 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state kError"; |
| 188 return kConfigFailure; | 211 return kConfigFailure; |
| 189 } | 212 } |
| 190 | 213 |
| 191 if (needs_reconfigure_) { | 214 if (needs_reconfigure_) { |
| 192 DVLOG(1) << class_name() << "::" << __FUNCTION__ | 215 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
| 193 << ": needs reconfigure, deleting MediaCodec"; | 216 << ": needs reconfigure, deleting MediaCodec"; |
| 194 needs_reconfigure_ = false; | 217 needs_reconfigure_ = false; |
| 195 media_codec_bridge_.reset(); | 218 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 } | 219 } |
| 202 | 220 |
| 203 MediaCodecDecoder::ConfigStatus result; | 221 MediaCodecDecoder::ConfigStatus result; |
| 204 if (media_codec_bridge_) { | 222 if (media_codec_bridge_) { |
| 205 DVLOG(1) << class_name() << "::" << __FUNCTION__ | 223 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
| 206 << ": reconfiguration is not required, ignoring"; | 224 << ": reconfiguration is not required, ignoring"; |
| 207 result = kConfigOk; | 225 result = kConfigOk; |
| 208 } else { | 226 } else { |
| 209 result = ConfigureInternal(); | 227 result = ConfigureInternal(); |
| 210 | 228 |
| 211 #ifndef NDEBUG | 229 #ifndef NDEBUG |
| 212 // We check and reset |verify_next_frame_is_key_| on Decoder thread. | 230 // We check and reset |verify_next_frame_is_key_| on Decoder thread. |
| 213 // This DCHECK ensures we won't need to lock this variable. | 231 // This DCHECK ensures we won't need to lock this variable. |
| 214 DCHECK(!decoder_thread_.IsRunning()); | 232 DCHECK(!decoder_thread_.IsRunning()); |
| 215 | 233 |
| 216 // For video the first frame after reconfiguration must be key frame. | 234 // For video the first frame after reconfiguration must be key frame. |
| 217 if (result == kConfigOk) | 235 if (result == kConfigOk) |
| 218 verify_next_frame_is_key_ = true; | 236 verify_next_frame_is_key_ = true; |
| 219 #endif | 237 #endif |
| 220 } | 238 } |
| 221 | 239 |
| 222 return result; | 240 return result; |
| 223 } | 241 } |
| 224 | 242 |
| 225 bool MediaCodecDecoder::Start(base::TimeDelta current_time) { | 243 void MediaCodecDecoder::SetPrerollTimestamp(base::TimeDelta preroll_timestamp) { |
| 244 DCHECK(media_task_runner_->BelongsToCurrentThread()); | |
| 245 DCHECK(!decoder_thread_.IsRunning()); | |
| 246 | |
| 247 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": " << preroll_timestamp; | |
| 248 | |
| 249 // Do not set preroll timestamp if it's too close to zero. | |
| 250 preroll_timestamp_ = preroll_timestamp; | |
| 251 } | |
| 252 | |
| 253 bool MediaCodecDecoder::Start(base::TimeDelta start_timestamp) { | |
| 226 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 254 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 227 | 255 |
| 228 DVLOG(1) << class_name() << "::" << __FUNCTION__ | 256 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
| 229 << " current_time:" << current_time; | 257 << " start_timestamp:" << start_timestamp; |
| 230 | 258 |
| 231 DecoderState state = GetState(); | 259 DecoderState state = GetState(); |
| 232 if (state == kRunning) { | 260 if (state == kPrerolling || state == kRunning) { |
| 233 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": already started"; | 261 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": already started"; |
| 234 return true; // already started | 262 return true; // already started |
| 235 } | 263 } |
| 236 | 264 |
| 237 if (state != kPrefetched) { | 265 if (state != kPrefetched) { |
| 238 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state " | 266 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state " |
| 239 << AsString(state) << ", ignoring"; | 267 << AsString(state) << ", ignoring"; |
| 240 return false; | 268 return false; |
| 241 } | 269 } |
| 242 | 270 |
| 243 if (!media_codec_bridge_) { | 271 if (!media_codec_bridge_) { |
| 244 DVLOG(0) << class_name() << "::" << __FUNCTION__ | 272 DVLOG(0) << class_name() << "::" << __FUNCTION__ |
| 245 << ": not configured, ignoring"; | 273 << ": not configured, ignoring"; |
| 246 return false; | 274 return false; |
| 247 } | 275 } |
| 248 | 276 |
| 249 DCHECK(!decoder_thread_.IsRunning()); | 277 DCHECK(!decoder_thread_.IsRunning()); |
| 250 | 278 |
| 279 const bool needs_preroll = (preroll_timestamp_ != base::TimeDelta()); | |
|
qinmin
2015/07/31 18:43:10
why not preroll if timestamp is 0? it will help us
Tima Vaisburd
2015/07/31 19:26:42
I think decoder initialization delay has been alre
Tima Vaisburd
2015/08/01 04:34:43
Min explained that there is internal codec initial
| |
| 280 | |
| 251 // We only synchronize video stream. | 281 // We only synchronize video stream. |
| 252 // When audio is present, the |current_time| is audio time. | 282 if (needs_preroll) |
| 253 SynchronizePTSWithTime(current_time); | 283 DissociatePTSFromTime(); // associaton will happen after preroll is done. |
| 284 else | |
| 285 AssociateCurrentTimeWithPTS(start_timestamp); | |
| 254 | 286 |
| 255 last_frame_posted_ = false; | 287 last_frame_posted_ = false; |
| 256 | 288 |
| 257 // Start the decoder thread | 289 // Start the decoder thread |
| 258 if (!decoder_thread_.Start()) { | 290 if (!decoder_thread_.Start()) { |
| 259 DVLOG(1) << class_name() << "::" << __FUNCTION__ | 291 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
| 260 << ": cannot start decoder thread"; | 292 << ": cannot start decoder thread"; |
| 261 return false; | 293 return false; |
| 262 } | 294 } |
| 263 | 295 |
| 264 SetState(kRunning); | 296 SetState(needs_preroll ? kPrerolling : kRunning); |
| 265 | 297 |
| 266 decoder_thread_.task_runner()->PostTask( | 298 decoder_thread_.task_runner()->PostTask( |
| 267 FROM_HERE, | 299 FROM_HERE, |
| 268 base::Bind(&MediaCodecDecoder::ProcessNextFrame, base::Unretained(this))); | 300 base::Bind(&MediaCodecDecoder::ProcessNextFrame, base::Unretained(this))); |
| 269 | 301 |
| 270 return true; | 302 return true; |
| 271 } | 303 } |
| 272 | 304 |
| 305 void MediaCodecDecoder::ResumeAfterPreroll() { | |
| 306 DCHECK(media_task_runner_->BelongsToCurrentThread()); | |
| 307 | |
| 308 DVLOG(1) << class_name() << "::" << __FUNCTION__; | |
| 309 | |
| 310 DCHECK(GetState() == kPrerolled); | |
| 311 DCHECK(decoder_thread_.IsRunning()); | |
| 312 | |
| 313 SetState(kRunning); | |
| 314 | |
| 315 AssociateCurrentTimeWithPTS(preroll_timestamp_); | |
| 316 preroll_timestamp_ = base::TimeDelta(); | |
| 317 | |
| 318 decoder_thread_.task_runner()->PostTask( | |
| 319 FROM_HERE, | |
| 320 base::Bind(&MediaCodecDecoder::ProcessNextFrame, base::Unretained(this))); | |
| 321 } | |
| 322 | |
| 273 void MediaCodecDecoder::SyncStop() { | 323 void MediaCodecDecoder::SyncStop() { |
| 274 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 324 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 275 | 325 |
| 276 DVLOG(1) << class_name() << "::" << __FUNCTION__; | 326 DVLOG(1) << class_name() << "::" << __FUNCTION__; |
| 277 | 327 |
| 278 if (GetState() == kError) { | 328 if (GetState() == kError) { |
| 279 DVLOG(0) << class_name() << "::" << __FUNCTION__ | 329 DVLOG(0) << class_name() << "::" << __FUNCTION__ |
| 280 << ": wrong state kError, ignoring"; | 330 << ": wrong state kError, ignoring"; |
| 281 return; | 331 return; |
| 282 } | 332 } |
| 283 | 333 |
| 284 // After this method returns, decoder thread will not be running. | 334 // After this method returns, decoder thread will not be running. |
| 285 | 335 |
| 286 // Set [kInEmergencyStop| state to block already posted ProcessNextFrame(). | 336 // Set [kInEmergencyStop| state to block already posted ProcessNextFrame(). |
| 287 SetState(kInEmergencyStop); | 337 SetState(kInEmergencyStop); |
| 288 | 338 |
| 289 decoder_thread_.Stop(); // synchronous | 339 decoder_thread_.Stop(); // synchronous |
| 290 | 340 |
| 291 SetState(kStopped); | 341 SetState(kStopped); |
| 292 | 342 |
| 293 ClearDelayedBuffers(true); // release prior to clearing |delayed_buffers_|. | 343 ReleaseDelayedBuffers(); |
| 294 } | 344 } |
| 295 | 345 |
| 296 void MediaCodecDecoder::RequestToStop() { | 346 void MediaCodecDecoder::RequestToStop() { |
| 297 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 347 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 298 | 348 |
| 299 DVLOG(1) << class_name() << "::" << __FUNCTION__; | 349 DVLOG(1) << class_name() << "::" << __FUNCTION__; |
| 300 | 350 |
| 301 DecoderState state = GetState(); | 351 DecoderState state = GetState(); |
| 302 switch (state) { | 352 switch (state) { |
| 303 case kError: | 353 case kError: |
| 304 DVLOG(0) << class_name() << "::" << __FUNCTION__ | 354 DVLOG(0) << class_name() << "::" << __FUNCTION__ |
| 305 << ": wrong state kError, ignoring"; | 355 << ": wrong state kError, ignoring"; |
| 306 break; | 356 break; |
| 307 case kRunning: | 357 case kRunning: |
| 308 SetState(kStopping); | 358 SetState(kStopping); |
| 309 break; | 359 break; |
| 360 case kPrerolling: | |
| 361 case kPrerolled: | |
| 362 DCHECK(decoder_thread_.IsRunning()); | |
| 363 // Synchronous stop. | |
| 364 decoder_thread_.Stop(); | |
| 365 SetState(kStopped); | |
| 366 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); | |
| 367 break; | |
| 310 case kStopping: | 368 case kStopping: |
| 311 break; // ignore | 369 break; // ignore |
| 312 case kStopped: | 370 case kStopped: |
| 313 case kPrefetching: | 371 case kPrefetching: |
| 314 case kPrefetched: | 372 case kPrefetched: |
| 315 // There is nothing to wait for, we can sent nofigication right away. | 373 // There is nothing to wait for, we can sent nofigication right away. |
| 316 DCHECK(!decoder_thread_.IsRunning()); | 374 DCHECK(!decoder_thread_.IsRunning()); |
| 317 SetState(kStopped); | 375 SetState(kStopped); |
| 318 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); | 376 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); |
| 319 break; | 377 break; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 330 << " completed:" << completed; | 388 << " completed:" << completed; |
| 331 | 389 |
| 332 decoder_thread_.Stop(); // synchronous | 390 decoder_thread_.Stop(); // synchronous |
| 333 | 391 |
| 334 SetState(kStopped); | 392 SetState(kStopped); |
| 335 completed_ = completed; | 393 completed_ = completed; |
| 336 | 394 |
| 337 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); | 395 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); |
| 338 } | 396 } |
| 339 | 397 |
| 398 void MediaCodecDecoder::OnPrerollDone() { | |
| 399 DCHECK(media_task_runner_->BelongsToCurrentThread()); | |
| 400 | |
| 401 DVLOG(1) << class_name() << "::" << __FUNCTION__; | |
| 402 | |
| 403 if (GetState() == kPrerolling) { | |
| 404 SetState(kPrerolled); | |
| 405 media_task_runner_->PostTask(FROM_HERE, preroll_done_cb_); | |
| 406 } | |
| 407 } | |
| 408 | |
| 340 void MediaCodecDecoder::OnDemuxerDataAvailable(const DemuxerData& data) { | 409 void MediaCodecDecoder::OnDemuxerDataAvailable(const DemuxerData& data) { |
| 341 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 410 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 342 | 411 |
| 343 // If |data| contains an aborted data, the last AU will have kAborted status. | 412 // If |data| contains an aborted data, the last AU will have kAborted status. |
| 344 bool aborted_data = | 413 bool aborted_data = |
| 345 !data.access_units.empty() && | 414 !data.access_units.empty() && |
| 346 data.access_units.back().status == DemuxerStream::kAborted; | 415 data.access_units.back().status == DemuxerStream::kAborted; |
| 347 | 416 |
| 348 #ifndef NDEBUG | 417 #ifndef NDEBUG |
| 349 const char* explain_if_skipped = | 418 const char* explain_if_skipped = |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 431 request_data_cb_.Run(); | 500 request_data_cb_.Run(); |
| 432 } | 501 } |
| 433 | 502 |
| 434 void MediaCodecDecoder::ProcessNextFrame() { | 503 void MediaCodecDecoder::ProcessNextFrame() { |
| 435 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | 504 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
| 436 | 505 |
| 437 DVLOG(2) << class_name() << "::" << __FUNCTION__; | 506 DVLOG(2) << class_name() << "::" << __FUNCTION__; |
| 438 | 507 |
| 439 DecoderState state = GetState(); | 508 DecoderState state = GetState(); |
| 440 | 509 |
| 441 if (state != kRunning && state != kStopping) { | 510 if (state != kPrerolling && state != kRunning && state != kStopping) { |
| 442 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": not running"; | 511 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": not running"; |
| 443 return; | 512 return; |
| 444 } | 513 } |
| 445 | 514 |
| 446 if (state == kStopping) { | 515 if (state == kStopping) { |
| 447 if (NumDelayedRenderTasks() == 0 && !last_frame_posted_) { | 516 if (NumDelayedRenderTasks() == 0 && !last_frame_posted_) { |
| 448 DVLOG(1) << class_name() << "::" << __FUNCTION__ | 517 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
| 449 << ": kStopping, posting OnLastFrameRendered"; | 518 << ": kStopping, posting OnLastFrameRendered"; |
| 450 media_task_runner_->PostTask( | 519 media_task_runner_->PostTask( |
| 451 FROM_HERE, base::Bind(&MediaCodecDecoder::OnLastFrameRendered, | 520 FROM_HERE, base::Bind(&MediaCodecDecoder::OnLastFrameRendered, |
| 452 weak_factory_.GetWeakPtr(), false)); | 521 weak_factory_.GetWeakPtr(), false)); |
| 453 last_frame_posted_ = true; | 522 last_frame_posted_ = true; |
| 454 } | 523 } |
| 455 | 524 |
| 456 // We can stop processing, the |au_queue_| and MediaCodec queues can freeze. | 525 // We can stop processing, the |au_queue_| and MediaCodec queues can freeze. |
| 457 // We only need to let finish the delayed rendering tasks. | 526 // We only need to let finish the delayed rendering tasks. |
| 458 return; | 527 return; |
| 459 } | 528 } |
| 460 | 529 |
| 461 DCHECK(state == kRunning); | 530 DCHECK(state == kPrerolling || state == kRunning); |
| 462 | 531 |
| 463 if (!EnqueueInputBuffer()) | 532 if (!EnqueueInputBuffer()) |
| 464 return; | 533 return; |
| 465 | 534 |
| 466 if (!DepleteOutputBufferQueue()) | 535 if (!DepleteOutputBufferQueue()) |
| 467 return; | 536 return; |
| 468 | 537 |
| 469 // We need a small delay if we want to stop this thread by | 538 // We need a small delay if we want to stop this thread by |
| 470 // decoder_thread_.Stop() reliably. | 539 // decoder_thread_.Stop() reliably. |
| 471 // The decoder thread message loop processes all pending | 540 // The decoder thread message loop processes all pending |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 593 | 662 |
| 594 DVLOG(2) << class_name() << "::" << __FUNCTION__; | 663 DVLOG(2) << class_name() << "::" << __FUNCTION__; |
| 595 | 664 |
| 596 int buffer_index = 0; | 665 int buffer_index = 0; |
| 597 size_t offset = 0; | 666 size_t offset = 0; |
| 598 size_t size = 0; | 667 size_t size = 0; |
| 599 base::TimeDelta pts; | 668 base::TimeDelta pts; |
| 600 MediaCodecStatus status; | 669 MediaCodecStatus status; |
| 601 bool eos_encountered = false; | 670 bool eos_encountered = false; |
| 602 | 671 |
| 672 RenderMode render_mode; | |
| 673 bool preroll_done = false; | |
| 674 | |
| 603 base::TimeDelta timeout = | 675 base::TimeDelta timeout = |
| 604 base::TimeDelta::FromMilliseconds(kOutputBufferTimeout); | 676 base::TimeDelta::FromMilliseconds(kOutputBufferTimeout); |
| 605 | 677 |
| 606 // Extract all output buffers that are available. | 678 // Extract all output buffers that are available. |
| 607 // Usually there will be only one, but sometimes it is preceeded by | 679 // Usually there will be only one, but sometimes it is preceeded by |
| 608 // MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED or MEDIA_CODEC_OUTPUT_FORMAT_CHANGED. | 680 // MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED or MEDIA_CODEC_OUTPUT_FORMAT_CHANGED. |
| 609 do { | 681 do { |
| 610 status = media_codec_bridge_->DequeueOutputBuffer( | 682 status = media_codec_bridge_->DequeueOutputBuffer( |
| 611 timeout, &buffer_index, &offset, &size, &pts, &eos_encountered, | 683 timeout, &buffer_index, &offset, &size, &pts, &eos_encountered, |
| 612 nullptr); | 684 nullptr); |
| 613 | 685 |
| 614 // Reset the timeout to 0 for the subsequent DequeueOutputBuffer() calls | 686 // Reset the timeout to 0 for the subsequent DequeueOutputBuffer() calls |
| 615 // to quickly break the loop after we got all currently available buffers. | 687 // to quickly break the loop after we got all currently available buffers. |
| 616 timeout = base::TimeDelta::FromMilliseconds(0); | 688 timeout = base::TimeDelta::FromMilliseconds(0); |
| 617 | 689 |
| 618 switch (status) { | 690 switch (status) { |
| 619 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: | 691 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: |
| 620 // Output buffers are replaced in MediaCodecBridge, nothing to do. | 692 // Output buffers are replaced in MediaCodecBridge, nothing to do. |
| 621 break; | 693 break; |
| 622 | 694 |
| 623 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: | 695 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: |
| 624 DVLOG(2) << class_name() << "::" << __FUNCTION__ | 696 DVLOG(2) << class_name() << "::" << __FUNCTION__ |
| 625 << " MEDIA_CODEC_OUTPUT_FORMAT_CHANGED"; | 697 << " MEDIA_CODEC_OUTPUT_FORMAT_CHANGED"; |
| 626 OnOutputFormatChanged(); | 698 OnOutputFormatChanged(); |
| 627 break; | 699 break; |
| 628 | 700 |
| 629 case MEDIA_CODEC_OK: | 701 case MEDIA_CODEC_OK: { |
| 630 // We got the decoded frame | 702 // We got the decoded frame. |
| 631 Render(buffer_index, size, true, pts, eos_encountered); | 703 |
| 632 break; | 704 if (pts < preroll_timestamp_) |
| 705 render_mode = kRenderSkip; | |
| 706 else if (GetState() == kPrerolling) | |
| 707 render_mode = kRenderAfterPreroll; | |
| 708 else | |
| 709 render_mode = kRenderNow; | |
| 710 | |
| 711 Render(buffer_index, size, render_mode, pts, eos_encountered); | |
| 712 | |
| 713 if (render_mode == kRenderAfterPreroll) { | |
| 714 media_task_runner_->PostTask(FROM_HERE, internal_preroll_done_cb_); | |
| 715 preroll_done = true; | |
|
qinmin
2015/07/31 18:43:10
why not just return false here.
Tima Vaisburd
2015/07/31 19:26:42
Done.
| |
| 716 } | |
| 717 } break; | |
|
qinmin
2015/07/31 18:43:10
move the break to a new line
Tima Vaisburd
2015/07/31 19:26:42
Done.
| |
| 633 | 718 |
| 634 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER: | 719 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER: |
| 635 // Nothing to do. | 720 // Nothing to do. |
| 636 break; | 721 break; |
| 637 | 722 |
| 638 case MEDIA_CODEC_ERROR: | 723 case MEDIA_CODEC_ERROR: |
| 639 DVLOG(0) << class_name() << "::" << __FUNCTION__ | 724 DVLOG(0) << class_name() << "::" << __FUNCTION__ |
| 640 << ": MEDIA_CODEC_ERROR from DequeueOutputBuffer"; | 725 << ": MEDIA_CODEC_ERROR from DequeueOutputBuffer"; |
| 641 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_); | 726 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_); |
| 642 break; | 727 break; |
| 643 | 728 |
| 644 default: | 729 default: |
| 645 NOTREACHED(); | 730 NOTREACHED(); |
| 646 break; | 731 break; |
| 647 } | 732 } |
| 648 | 733 |
| 649 } while (status != MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER && | 734 } while (status != MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER && |
| 650 status != MEDIA_CODEC_ERROR && !eos_encountered); | 735 status != MEDIA_CODEC_ERROR && !eos_encountered && !preroll_done); |
| 651 | 736 |
| 652 if (eos_encountered) { | 737 if (eos_encountered) { |
| 653 DVLOG(1) << class_name() << "::" << __FUNCTION__ | 738 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
| 654 << " EOS dequeued, stopping frame processing"; | 739 << " EOS dequeued, stopping frame processing"; |
| 655 return false; | 740 return false; |
| 656 } | 741 } |
| 657 | 742 |
| 743 if (preroll_done) { | |
| 744 DVLOG(1) << class_name() << "::" << __FUNCTION__ | |
| 745 << " preroll done, stopping frame processing"; | |
| 746 return false; | |
| 747 } | |
| 748 | |
| 658 if (status == MEDIA_CODEC_ERROR) { | 749 if (status == MEDIA_CODEC_ERROR) { |
| 659 DVLOG(1) << class_name() << "::" << __FUNCTION__ | 750 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
| 660 << " MediaCodec error, stopping frame processing"; | 751 << " MediaCodec error, stopping frame processing"; |
| 661 return false; | 752 return false; |
| 662 } | 753 } |
| 663 | 754 |
| 664 return true; | 755 return true; |
| 665 } | 756 } |
| 666 | 757 |
| 667 MediaCodecDecoder::DecoderState MediaCodecDecoder::GetState() const { | 758 MediaCodecDecoder::DecoderState MediaCodecDecoder::GetState() const { |
| 668 base::AutoLock lock(state_lock_); | 759 base::AutoLock lock(state_lock_); |
| 669 return state_; | 760 return state_; |
| 670 } | 761 } |
| 671 | 762 |
| 672 void MediaCodecDecoder::SetState(DecoderState state) { | 763 void MediaCodecDecoder::SetState(DecoderState state) { |
| 673 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " " << AsString(state); | 764 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " " << AsString(state); |
| 674 | 765 |
| 675 base::AutoLock lock(state_lock_); | 766 base::AutoLock lock(state_lock_); |
| 676 state_ = state; | 767 state_ = state; |
| 677 } | 768 } |
| 678 | 769 |
| 679 #undef RETURN_STRING | 770 #undef RETURN_STRING |
| 680 #define RETURN_STRING(x) \ | 771 #define RETURN_STRING(x) \ |
| 681 case x: \ | 772 case x: \ |
| 682 return #x; | 773 return #x; |
| 683 | 774 |
| 775 const char* MediaCodecDecoder::AsString(RenderMode render_mode) { | |
| 776 switch (render_mode) { | |
| 777 RETURN_STRING(kRenderSkip); | |
| 778 RETURN_STRING(kRenderAfterPreroll); | |
| 779 RETURN_STRING(kRenderNow); | |
| 780 } | |
| 781 return nullptr; // crash early | |
| 782 } | |
| 783 | |
| 684 const char* MediaCodecDecoder::AsString(DecoderState state) { | 784 const char* MediaCodecDecoder::AsString(DecoderState state) { |
| 685 switch (state) { | 785 switch (state) { |
| 686 RETURN_STRING(kStopped); | 786 RETURN_STRING(kStopped); |
| 687 RETURN_STRING(kPrefetching); | 787 RETURN_STRING(kPrefetching); |
| 688 RETURN_STRING(kPrefetched); | 788 RETURN_STRING(kPrefetched); |
| 789 RETURN_STRING(kPrerolling); | |
| 790 RETURN_STRING(kPrerolled); | |
| 689 RETURN_STRING(kRunning); | 791 RETURN_STRING(kRunning); |
| 690 RETURN_STRING(kStopping); | 792 RETURN_STRING(kStopping); |
| 691 RETURN_STRING(kInEmergencyStop); | 793 RETURN_STRING(kInEmergencyStop); |
| 692 RETURN_STRING(kError); | 794 RETURN_STRING(kError); |
| 693 default: | |
| 694 return "Unknown DecoderState"; | |
| 695 } | 795 } |
| 796 return nullptr; // crash early | |
| 696 } | 797 } |
| 697 | 798 |
| 698 #undef RETURN_STRING | 799 #undef RETURN_STRING |
| 699 | 800 |
| 700 } // namespace media | 801 } // namespace media |
| OLD | NEW |