Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 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/base/android/media_decoder_job.h" | 5 #include "media/base/android/media_decoder_job.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
| 9 #include "base/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
| 10 #include "base/message_loop/message_loop_proxy.h" | 10 #include "base/message_loop/message_loop_proxy.h" |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 26 : ui_task_runner_(base::MessageLoopProxy::current()), | 26 : ui_task_runner_(base::MessageLoopProxy::current()), |
| 27 decoder_task_runner_(decoder_task_runner), | 27 decoder_task_runner_(decoder_task_runner), |
| 28 media_codec_bridge_(media_codec_bridge), | 28 media_codec_bridge_(media_codec_bridge), |
| 29 needs_flush_(false), | 29 needs_flush_(false), |
| 30 input_eos_encountered_(false), | 30 input_eos_encountered_(false), |
| 31 output_eos_encountered_(false), | 31 output_eos_encountered_(false), |
| 32 skip_eos_enqueue_(true), | 32 skip_eos_enqueue_(true), |
| 33 prerolling_(true), | 33 prerolling_(true), |
| 34 weak_this_(this), | 34 weak_this_(this), |
| 35 request_data_cb_(request_data_cb), | 35 request_data_cb_(request_data_cb), |
| 36 access_unit_index_(0), | 36 current_demuxer_data_index_(0), |
| 37 input_buf_index_(-1), | 37 input_buf_index_(-1), |
| 38 stop_decode_pending_(false), | 38 stop_decode_pending_(false), |
| 39 destroy_pending_(false) { | 39 destroy_pending_(false), |
| 40 is_requesting_demuxer_data_(false), | |
| 41 is_incoming_data_invalid_(false) { | |
| 42 InitializeReceivedData(); | |
| 40 } | 43 } |
| 41 | 44 |
| 42 MediaDecoderJob::~MediaDecoderJob() {} | 45 MediaDecoderJob::~MediaDecoderJob() {} |
| 43 | 46 |
| 44 void MediaDecoderJob::OnDataReceived(const DemuxerData& data) { | 47 void MediaDecoderJob::OnDataReceived(const DemuxerData& data) { |
| 45 DVLOG(1) << __FUNCTION__ << ": " << data.access_units.size() << " units"; | 48 DVLOG(1) << __FUNCTION__ << ": " << data.access_units.size() << " units"; |
| 46 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 49 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 47 DCHECK(!on_data_received_cb_.is_null()); | 50 DCHECK(IsDemuxerDataEmpty(false)); |
| 48 | 51 |
| 49 TRACE_EVENT_ASYNC_END2( | 52 TRACE_EVENT_ASYNC_END2( |
| 50 "media", "MediaDecoderJob::RequestData", this, | 53 "media", "MediaDecoderJob::RequestData", this, |
| 51 "Data type", data.type == media::DemuxerStream::AUDIO ? "AUDIO" : "VIDEO", | 54 "Data type", data.type == media::DemuxerStream::AUDIO ? "AUDIO" : "VIDEO", |
| 52 "Units read", data.access_units.size()); | 55 "Units read", data.access_units.size()); |
| 53 | 56 |
| 57 if (is_incoming_data_invalid_) { | |
| 58 is_incoming_data_invalid_ = false; | |
| 59 // If there is a pending callback, need to request the data again to get | |
|
wolenetz
2014/03/18 21:14:47
nit: insert line before comment?
qinmin
2014/03/19 02:45:22
Done.
| |
| 60 // valid data. | |
| 61 if (!on_data_received_cb_.is_null()) | |
| 62 request_data_cb_.Run(); | |
| 63 else | |
| 64 is_requesting_demuxer_data_ = false; | |
| 65 return; | |
| 66 } | |
| 67 | |
| 68 size_t next_demuxer_data_index = inactive_demuxer_data_index(); | |
| 69 received_data_[next_demuxer_data_index] = data; | |
| 70 access_unit_index_[next_demuxer_data_index] = 0; | |
| 71 is_requesting_demuxer_data_ = false; | |
| 72 | |
| 54 base::Closure done_cb = base::ResetAndReturn(&on_data_received_cb_); | 73 base::Closure done_cb = base::ResetAndReturn(&on_data_received_cb_); |
| 55 | |
| 56 if (stop_decode_pending_) { | 74 if (stop_decode_pending_) { |
| 57 OnDecodeCompleted(MEDIA_CODEC_STOPPED, kNoTimestamp(), 0); | 75 OnDecodeCompleted(MEDIA_CODEC_STOPPED, kNoTimestamp(), 0); |
| 58 return; | 76 return; |
| 59 } | 77 } |
| 60 | 78 |
| 61 access_unit_index_ = 0; | 79 if (!done_cb.is_null()) |
| 62 received_data_ = data; | 80 done_cb.Run(); |
| 63 done_cb.Run(); | |
| 64 } | 81 } |
| 65 | 82 |
| 66 void MediaDecoderJob::Prefetch(const base::Closure& prefetch_cb) { | 83 void MediaDecoderJob::Prefetch(const base::Closure& prefetch_cb) { |
| 67 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 84 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 68 DCHECK(on_data_received_cb_.is_null()); | 85 DCHECK(on_data_received_cb_.is_null()); |
| 69 DCHECK(decode_cb_.is_null()); | 86 DCHECK(decode_cb_.is_null()); |
| 70 | 87 |
| 71 if (HasData()) { | 88 if (HasData()) { |
| 72 DVLOG(1) << __FUNCTION__ << " : using previously received data"; | 89 DVLOG(1) << __FUNCTION__ << " : using previously received data"; |
| 73 ui_task_runner_->PostTask(FROM_HERE, prefetch_cb); | 90 ui_task_runner_->PostTask(FROM_HERE, prefetch_cb); |
| 74 return; | 91 return; |
| 75 } | 92 } |
| 76 | 93 |
| 77 DVLOG(1) << __FUNCTION__ << " : requesting data"; | 94 DVLOG(1) << __FUNCTION__ << " : requesting data"; |
| 78 RequestData(prefetch_cb); | 95 RequestData(prefetch_cb); |
| 79 } | 96 } |
| 80 | 97 |
| 81 bool MediaDecoderJob::Decode( | 98 bool MediaDecoderJob::Decode( |
| 82 const base::TimeTicks& start_time_ticks, | 99 base::TimeTicks start_time_ticks, |
| 83 const base::TimeDelta& start_presentation_timestamp, | 100 base::TimeDelta start_presentation_timestamp, |
| 84 const DecoderCallback& callback) { | 101 const DecoderCallback& callback) { |
| 85 DCHECK(decode_cb_.is_null()); | 102 DCHECK(decode_cb_.is_null()); |
| 86 DCHECK(on_data_received_cb_.is_null()); | 103 DCHECK(on_data_received_cb_.is_null()); |
| 87 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 104 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 88 | 105 |
| 89 decode_cb_ = callback; | 106 decode_cb_ = callback; |
| 90 | 107 |
| 91 if (!HasData()) { | 108 if (!HasData()) { |
| 92 RequestData(base::Bind(&MediaDecoderJob::DecodeNextAccessUnit, | 109 RequestData(base::Bind(&MediaDecoderJob::DecodeCurrentAccessUnit, |
| 93 base::Unretained(this), | 110 base::Unretained(this), |
| 94 start_time_ticks, | 111 start_time_ticks, |
| 95 start_presentation_timestamp)); | 112 start_presentation_timestamp)); |
| 96 return true; | 113 return true; |
| 97 } | 114 } |
| 98 | 115 |
| 99 if (DemuxerStream::kConfigChanged == | 116 if (DemuxerStream::kConfigChanged == CurrentAccessUnit().status) { |
| 100 received_data_.access_units[access_unit_index_].status) { | |
| 101 // Clear received data because we need to handle a config change. | 117 // Clear received data because we need to handle a config change. |
| 102 decode_cb_.Reset(); | 118 decode_cb_.Reset(); |
| 103 received_data_ = DemuxerData(); | 119 ClearData(); |
| 104 access_unit_index_ = 0; | |
| 105 return false; | 120 return false; |
| 106 } | 121 } |
| 107 | 122 |
| 108 DecodeNextAccessUnit(start_time_ticks, start_presentation_timestamp); | 123 DecodeCurrentAccessUnit(start_time_ticks, start_presentation_timestamp); |
| 109 return true; | 124 return true; |
| 110 } | 125 } |
| 111 | 126 |
| 112 void MediaDecoderJob::StopDecode() { | 127 void MediaDecoderJob::StopDecode() { |
| 113 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 128 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 114 DCHECK(is_decoding()); | 129 DCHECK(is_decoding()); |
| 115 stop_decode_pending_ = true; | 130 stop_decode_pending_ = true; |
| 116 } | 131 } |
| 117 | 132 |
| 118 void MediaDecoderJob::Flush() { | 133 void MediaDecoderJob::Flush() { |
| 119 DCHECK(decode_cb_.is_null()); | 134 DCHECK(decode_cb_.is_null()); |
| 120 | 135 |
| 121 // Do nothing, flush when the next Decode() happens. | 136 // Do nothing, flush when the next Decode() happens. |
| 122 needs_flush_ = true; | 137 needs_flush_ = true; |
| 123 received_data_ = DemuxerData(); | 138 ClearData(); |
| 124 input_eos_encountered_ = false; | |
| 125 access_unit_index_ = 0; | |
| 126 on_data_received_cb_.Reset(); | |
| 127 } | 139 } |
| 128 | 140 |
| 129 void MediaDecoderJob::BeginPrerolling( | 141 void MediaDecoderJob::BeginPrerolling(base::TimeDelta preroll_timestamp) { |
| 130 const base::TimeDelta& preroll_timestamp) { | |
| 131 DVLOG(1) << __FUNCTION__ << "(" << preroll_timestamp.InSecondsF() << ")"; | 142 DVLOG(1) << __FUNCTION__ << "(" << preroll_timestamp.InSecondsF() << ")"; |
| 132 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 143 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 133 DCHECK(!is_decoding()); | 144 DCHECK(!is_decoding()); |
| 134 | 145 |
| 135 preroll_timestamp_ = preroll_timestamp; | 146 preroll_timestamp_ = preroll_timestamp; |
| 136 prerolling_ = true; | 147 prerolling_ = true; |
| 137 } | 148 } |
| 138 | 149 |
| 139 void MediaDecoderJob::Release() { | 150 void MediaDecoderJob::Release() { |
| 140 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 151 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 201 // In case of MEDIA_CODEC_NO_KEY, we must reuse the |input_buf_index_|. | 212 // In case of MEDIA_CODEC_NO_KEY, we must reuse the |input_buf_index_|. |
| 202 // Otherwise MediaDrm will report errors. | 213 // Otherwise MediaDrm will report errors. |
| 203 if (status == MEDIA_CODEC_NO_KEY) | 214 if (status == MEDIA_CODEC_NO_KEY) |
| 204 input_buf_index_ = input_buf_index; | 215 input_buf_index_ = input_buf_index; |
| 205 | 216 |
| 206 return status; | 217 return status; |
| 207 } | 218 } |
| 208 | 219 |
| 209 bool MediaDecoderJob::HasData() const { | 220 bool MediaDecoderJob::HasData() const { |
| 210 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 221 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 211 // When |input_eos_encountered_| is set, |access_units| must not be empty and | 222 // When |input_eos_encountered_| is set, |access_unit_index_| and |
| 212 // |access_unit_index_| must be pointing to an EOS unit. We'll reuse this | 223 // |current_demuxer_data_index_| must be pointing to an EOS unit. |
| 213 // unit to flush the decoder until we hit output EOS. | 224 // We'll reuse this unit to flush the decoder until we hit outpu EOS. |
|
wolenetz
2014/03/18 21:14:47
nit: s/outpu/output/
qinmin
2014/03/19 02:45:22
Done.
| |
| 214 DCHECK(!input_eos_encountered_ || | 225 DCHECK(!input_eos_encountered_ || !IsDemuxerDataEmpty(true)); |
| 215 (received_data_.access_units.size() > 0 && | 226 return !IsDemuxerDataEmpty(true) || !IsDemuxerDataEmpty(false); |
| 216 access_unit_index_ < received_data_.access_units.size())) | |
| 217 << " (access_units.size(): " << received_data_.access_units.size() | |
| 218 << ", access_unit_index_: " << access_unit_index_ << ")"; | |
| 219 return access_unit_index_ < received_data_.access_units.size() || | |
| 220 input_eos_encountered_; | |
| 221 } | 227 } |
| 222 | 228 |
| 223 void MediaDecoderJob::RequestData(const base::Closure& done_cb) { | 229 void MediaDecoderJob::RequestData(const base::Closure& done_cb) { |
| 224 DVLOG(1) << __FUNCTION__; | 230 DVLOG(1) << __FUNCTION__; |
| 225 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 231 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 226 DCHECK(on_data_received_cb_.is_null()); | 232 DCHECK(on_data_received_cb_.is_null()); |
| 227 DCHECK(!input_eos_encountered_); | 233 DCHECK(!input_eos_encountered_); |
| 234 DCHECK(IsDemuxerDataEmpty(false)); | |
| 228 | 235 |
| 229 TRACE_EVENT_ASYNC_BEGIN0("media", "MediaDecoderJob::RequestData", this); | 236 TRACE_EVENT_ASYNC_BEGIN0("media", "MediaDecoderJob::RequestData", this); |
| 230 | 237 |
| 231 received_data_ = DemuxerData(); | |
| 232 access_unit_index_ = 0; | |
| 233 on_data_received_cb_ = done_cb; | 238 on_data_received_cb_ = done_cb; |
| 234 | 239 |
| 240 // If we are already expecting new data, just set the callback and do | |
| 241 // nothing. | |
| 242 if (is_requesting_demuxer_data_) | |
| 243 return; | |
| 244 | |
| 245 // The new incoming data will be stored as the next demuxer data chunk, since | |
| 246 // the decoder might still be decoding the current one. | |
| 247 size_t next_demuxer_data_index = inactive_demuxer_data_index(); | |
| 248 received_data_[next_demuxer_data_index] = DemuxerData(); | |
| 249 access_unit_index_[next_demuxer_data_index] = 0; | |
| 250 is_requesting_demuxer_data_ = true; | |
| 251 | |
| 235 request_data_cb_.Run(); | 252 request_data_cb_.Run(); |
| 236 } | 253 } |
| 237 | 254 |
| 238 void MediaDecoderJob::DecodeNextAccessUnit( | 255 void MediaDecoderJob::DecodeCurrentAccessUnit( |
| 239 const base::TimeTicks& start_time_ticks, | 256 base::TimeTicks start_time_ticks, |
| 240 const base::TimeDelta& start_presentation_timestamp) { | 257 base::TimeDelta start_presentation_timestamp) { |
| 241 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 258 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 242 DCHECK(!decode_cb_.is_null()); | 259 DCHECK(!decode_cb_.is_null()); |
| 243 | 260 |
| 261 RequestCurrentChunkIfEmpty(); | |
| 262 const AccessUnit& access_unit = CurrentAccessUnit(); | |
| 244 // If the first access unit is a config change, request the player to dequeue | 263 // If the first access unit is a config change, request the player to dequeue |
| 245 // the input buffer again so that it can request config data. | 264 // the input buffer again so that it can request config data. |
| 246 if (received_data_.access_units[access_unit_index_].status == | 265 if (access_unit.status == DemuxerStream::kConfigChanged) { |
| 247 DemuxerStream::kConfigChanged) { | |
| 248 ui_task_runner_->PostTask(FROM_HERE, | 266 ui_task_runner_->PostTask(FROM_HERE, |
| 249 base::Bind(&MediaDecoderJob::OnDecodeCompleted, | 267 base::Bind(&MediaDecoderJob::OnDecodeCompleted, |
| 250 base::Unretained(this), | 268 base::Unretained(this), |
| 251 MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER, | 269 MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER, |
| 252 kNoTimestamp(), | 270 kNoTimestamp(), |
| 253 0)); | 271 0)); |
| 254 return; | 272 return; |
| 255 } | 273 } |
| 256 | 274 |
| 257 decoder_task_runner_->PostTask(FROM_HERE, base::Bind( | 275 decoder_task_runner_->PostTask(FROM_HERE, base::Bind( |
| 258 &MediaDecoderJob::DecodeInternal, base::Unretained(this), | 276 &MediaDecoderJob::DecodeInternal, base::Unretained(this), |
| 259 received_data_.access_units[access_unit_index_], | 277 access_unit, |
| 260 start_time_ticks, start_presentation_timestamp, needs_flush_, | 278 start_time_ticks, start_presentation_timestamp, needs_flush_, |
| 261 media::BindToCurrentLoop(base::Bind( | 279 media::BindToCurrentLoop(base::Bind( |
| 262 &MediaDecoderJob::OnDecodeCompleted, base::Unretained(this))))); | 280 &MediaDecoderJob::OnDecodeCompleted, base::Unretained(this))))); |
| 263 needs_flush_ = false; | 281 needs_flush_ = false; |
| 264 } | 282 } |
| 265 | 283 |
| 266 void MediaDecoderJob::DecodeInternal( | 284 void MediaDecoderJob::DecodeInternal( |
| 267 const AccessUnit& unit, | 285 const AccessUnit& unit, |
| 268 const base::TimeTicks& start_time_ticks, | 286 base::TimeTicks start_time_ticks, |
| 269 const base::TimeDelta& start_presentation_timestamp, | 287 base::TimeDelta start_presentation_timestamp, |
| 270 bool needs_flush, | 288 bool needs_flush, |
| 271 const MediaDecoderJob::DecoderCallback& callback) { | 289 const MediaDecoderJob::DecoderCallback& callback) { |
| 272 DVLOG(1) << __FUNCTION__; | 290 DVLOG(1) << __FUNCTION__; |
| 273 DCHECK(decoder_task_runner_->BelongsToCurrentThread()); | 291 DCHECK(decoder_task_runner_->BelongsToCurrentThread()); |
| 274 TRACE_EVENT0("media", __FUNCTION__); | 292 TRACE_EVENT0("media", __FUNCTION__); |
| 275 | 293 |
| 276 if (needs_flush) { | 294 if (needs_flush) { |
| 277 DVLOG(1) << "DecodeInternal needs flush."; | 295 DVLOG(1) << "DecodeInternal needs flush."; |
| 278 input_eos_encountered_ = false; | 296 input_eos_encountered_ = false; |
| 279 output_eos_encountered_ = false; | 297 output_eos_encountered_ = false; |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 381 presentation_timestamp, start_presentation_timestamp); | 399 presentation_timestamp, start_presentation_timestamp); |
| 382 } else { | 400 } else { |
| 383 presentation_timestamp = kNoTimestamp(); | 401 presentation_timestamp = kNoTimestamp(); |
| 384 } | 402 } |
| 385 ReleaseOutputCompletionCallback completion_callback = base::Bind( | 403 ReleaseOutputCompletionCallback completion_callback = base::Bind( |
| 386 callback, status, presentation_timestamp); | 404 callback, status, presentation_timestamp); |
| 387 ReleaseOutputBuffer(buffer_index, size, render_output, completion_callback); | 405 ReleaseOutputBuffer(buffer_index, size, render_output, completion_callback); |
| 388 } | 406 } |
| 389 | 407 |
| 390 void MediaDecoderJob::OnDecodeCompleted( | 408 void MediaDecoderJob::OnDecodeCompleted( |
| 391 MediaCodecStatus status, const base::TimeDelta& presentation_timestamp, | 409 MediaCodecStatus status, base::TimeDelta presentation_timestamp, |
| 392 size_t audio_output_bytes) { | 410 size_t audio_output_bytes) { |
| 393 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | 411 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 394 | 412 |
| 395 if (destroy_pending_) { | 413 if (destroy_pending_) { |
| 396 DVLOG(1) << __FUNCTION__ << " : completing pending deletion"; | 414 DVLOG(1) << __FUNCTION__ << " : completing pending deletion"; |
| 397 delete this; | 415 delete this; |
| 398 return; | 416 return; |
| 399 } | 417 } |
| 400 | 418 |
| 401 DCHECK(!decode_cb_.is_null()); | 419 DCHECK(!decode_cb_.is_null()); |
| 402 | 420 |
| 403 // If output was queued for rendering, then we have completed prerolling. | 421 // If output was queued for rendering, then we have completed prerolling. |
| 404 if (presentation_timestamp != kNoTimestamp()) | 422 if (presentation_timestamp != kNoTimestamp()) |
| 405 prerolling_ = false; | 423 prerolling_ = false; |
| 406 | 424 |
| 407 switch (status) { | 425 switch (status) { |
| 408 case MEDIA_CODEC_OK: | 426 case MEDIA_CODEC_OK: |
| 409 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER: | 427 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER: |
| 410 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: | 428 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: |
| 411 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: | 429 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: |
| 412 case MEDIA_CODEC_OUTPUT_END_OF_STREAM: | 430 case MEDIA_CODEC_OUTPUT_END_OF_STREAM: |
| 413 if (!input_eos_encountered_) | 431 if (!input_eos_encountered_) |
| 414 access_unit_index_++; | 432 access_unit_index_[current_demuxer_data_index_]++; |
| 415 break; | 433 break; |
| 416 | 434 |
| 417 case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER: | 435 case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER: |
| 418 case MEDIA_CODEC_INPUT_END_OF_STREAM: | 436 case MEDIA_CODEC_INPUT_END_OF_STREAM: |
| 419 case MEDIA_CODEC_NO_KEY: | 437 case MEDIA_CODEC_NO_KEY: |
| 420 case MEDIA_CODEC_STOPPED: | 438 case MEDIA_CODEC_STOPPED: |
| 421 case MEDIA_CODEC_ERROR: | 439 case MEDIA_CODEC_ERROR: |
| 422 // Do nothing. | 440 // Do nothing. |
| 423 break; | 441 break; |
| 424 }; | 442 }; |
| 425 | 443 |
| 426 stop_decode_pending_ = false; | 444 stop_decode_pending_ = false; |
| 427 base::ResetAndReturn(&decode_cb_).Run(status, presentation_timestamp, | 445 base::ResetAndReturn(&decode_cb_).Run(status, presentation_timestamp, |
| 428 audio_output_bytes); | 446 audio_output_bytes); |
| 429 } | 447 } |
| 430 | 448 |
| 449 const AccessUnit& MediaDecoderJob::CurrentAccessUnit() const { | |
| 450 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
| 451 DCHECK(HasData()); | |
| 452 int index = IsDemuxerDataEmpty(true) ? inactive_demuxer_data_index() : | |
| 453 current_demuxer_data_index_; | |
| 454 return received_data_[index].access_units[access_unit_index_[index]]; | |
| 455 } | |
| 456 | |
| 457 bool MediaDecoderJob::IsDemuxerDataEmpty(bool current_chunk) const { | |
|
wolenetz
2014/03/18 21:14:47
nit: I'm not too sure this is the best name. Maybe
qinmin
2014/03/19 02:45:22
renamed to NoAccessUnitsRemainingInChunk.
On 2014/
| |
| 458 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
| 459 size_t index = current_chunk ? current_demuxer_data_index_ : | |
| 460 inactive_demuxer_data_index(); | |
| 461 return received_data_[index].access_units.size() <= access_unit_index_[index]; | |
| 462 } | |
| 463 | |
| 464 void MediaDecoderJob::ClearData() { | |
| 465 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
| 466 current_demuxer_data_index_ = 0; | |
| 467 InitializeReceivedData(); | |
| 468 on_data_received_cb_.Reset(); | |
| 469 if (is_requesting_demuxer_data_) | |
| 470 is_incoming_data_invalid_ = true; | |
| 471 input_eos_encountered_ = false; | |
| 472 } | |
| 473 | |
| 474 void MediaDecoderJob::RequestCurrentChunkIfEmpty() { | |
| 475 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
| 476 DCHECK(HasData()); | |
| 477 if (!IsDemuxerDataEmpty(true)) | |
| 478 return; | |
| 479 | |
| 480 // Requests new data if the the last access unit of the next chunk is not EOS. | |
| 481 current_demuxer_data_index_ = inactive_demuxer_data_index(); | |
| 482 const AccessUnit last_access_unit = | |
| 483 received_data_[current_demuxer_data_index_].access_units.back(); | |
| 484 if (!last_access_unit.end_of_stream && | |
| 485 last_access_unit.status != DemuxerStream::kConfigChanged && | |
| 486 last_access_unit.status != DemuxerStream::kAborted) { | |
| 487 RequestData(base::Closure()); | |
| 488 } | |
| 489 } | |
| 490 | |
| 491 void MediaDecoderJob::InitializeReceivedData() { | |
| 492 for (size_t i = 0; i < 2; ++i) { | |
| 493 received_data_[i] = DemuxerData(); | |
| 494 access_unit_index_[i] = 0; | |
| 495 } | |
| 496 } | |
| 497 | |
| 431 } // namespace media | 498 } // namespace media |
| OLD | NEW |