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