| 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/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
| 10 #include "media/base/android/media_codec_bridge.h" | 10 #include "media/base/android/media_codec_bridge.h" |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 46 if (stop_decode_pending_) { | 46 if (stop_decode_pending_) { |
| 47 OnDecodeCompleted(MEDIA_CODEC_STOPPED, kNoTimestamp(), 0); | 47 OnDecodeCompleted(MEDIA_CODEC_STOPPED, kNoTimestamp(), 0); |
| 48 return; | 48 return; |
| 49 } | 49 } |
| 50 | 50 |
| 51 access_unit_index_ = 0; | 51 access_unit_index_ = 0; |
| 52 received_data_ = data; | 52 received_data_ = data; |
| 53 done_cb.Run(); | 53 done_cb.Run(); |
| 54 } | 54 } |
| 55 | 55 |
| 56 bool MediaDecoderJob::HasData() const { | |
| 57 DCHECK(ui_loop_->BelongsToCurrentThread()); | |
| 58 return access_unit_index_ < received_data_.access_units.size(); | |
| 59 } | |
| 60 | |
| 61 void MediaDecoderJob::Prefetch(const base::Closure& prefetch_cb) { | 56 void MediaDecoderJob::Prefetch(const base::Closure& prefetch_cb) { |
| 62 DCHECK(ui_loop_->BelongsToCurrentThread()); | 57 DCHECK(ui_loop_->BelongsToCurrentThread()); |
| 63 DCHECK(on_data_received_cb_.is_null()); | 58 DCHECK(on_data_received_cb_.is_null()); |
| 64 DCHECK(decode_cb_.is_null()); | 59 DCHECK(decode_cb_.is_null()); |
| 65 | 60 |
| 66 if (HasData()) { | 61 if (HasData()) { |
| 67 ui_loop_->PostTask(FROM_HERE, prefetch_cb); | 62 ui_loop_->PostTask(FROM_HERE, prefetch_cb); |
| 68 return; | 63 return; |
| 69 } | 64 } |
| 70 | 65 |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 149 media_codec_bridge_->DequeueInputBuffer(timeout, &input_buf_index); | 144 media_codec_bridge_->DequeueInputBuffer(timeout, &input_buf_index); |
| 150 if (status != MEDIA_CODEC_OK) { | 145 if (status != MEDIA_CODEC_OK) { |
| 151 DVLOG(1) << "DequeueInputBuffer fails: " << status; | 146 DVLOG(1) << "DequeueInputBuffer fails: " << status; |
| 152 return status; | 147 return status; |
| 153 } | 148 } |
| 154 } | 149 } |
| 155 | 150 |
| 156 // TODO(qinmin): skip frames if video is falling far behind. | 151 // TODO(qinmin): skip frames if video is falling far behind. |
| 157 DCHECK_GE(input_buf_index, 0); | 152 DCHECK_GE(input_buf_index, 0); |
| 158 if (unit.end_of_stream || unit.data.empty()) { | 153 if (unit.end_of_stream || unit.data.empty()) { |
| 159 media_codec_bridge_->QueueEOS(input_buf_index_); | 154 media_codec_bridge_->QueueEOS(input_buf_index); |
| 160 return MEDIA_CODEC_INPUT_END_OF_STREAM; | 155 return MEDIA_CODEC_INPUT_END_OF_STREAM; |
| 161 } | 156 } |
| 162 | 157 |
| 163 if (unit.key_id.empty()) { | 158 if (unit.key_id.empty()) { |
| 164 return media_codec_bridge_->QueueInputBuffer( | 159 return media_codec_bridge_->QueueInputBuffer( |
| 165 input_buf_index, &unit.data[0], unit.data.size(), unit.timestamp); | 160 input_buf_index, &unit.data[0], unit.data.size(), unit.timestamp); |
| 166 } | 161 } |
| 167 | 162 |
| 168 if (unit.iv.empty() || unit.subsamples.empty()) { | 163 if (unit.iv.empty() || unit.subsamples.empty()) { |
| 169 DVLOG(1) << "The access unit doesn't have iv or subsamples while it " | 164 DVLOG(1) << "The access unit doesn't have iv or subsamples while it " |
| 170 << "has key IDs!"; | 165 << "has key IDs!"; |
| 171 return MEDIA_CODEC_ERROR; | 166 return MEDIA_CODEC_ERROR; |
| 172 } | 167 } |
| 173 | 168 |
| 174 MediaCodecStatus status = media_codec_bridge_->QueueSecureInputBuffer( | 169 MediaCodecStatus status = media_codec_bridge_->QueueSecureInputBuffer( |
| 175 input_buf_index, &unit.data[0], unit.data.size(), | 170 input_buf_index, &unit.data[0], unit.data.size(), |
| 176 reinterpret_cast<const uint8*>(&unit.key_id[0]), unit.key_id.size(), | 171 reinterpret_cast<const uint8*>(&unit.key_id[0]), unit.key_id.size(), |
| 177 reinterpret_cast<const uint8*>(&unit.iv[0]), unit.iv.size(), | 172 reinterpret_cast<const uint8*>(&unit.iv[0]), unit.iv.size(), |
| 178 &unit.subsamples[0], unit.subsamples.size(), unit.timestamp); | 173 &unit.subsamples[0], unit.subsamples.size(), unit.timestamp); |
| 179 | 174 |
| 180 // In case of MEDIA_CODEC_NO_KEY, we must reuse the |input_buf_index_|. | 175 // In case of MEDIA_CODEC_NO_KEY, we must reuse the |input_buf_index_|. |
| 181 // Otherwise MediaDrm will report errors. | 176 // Otherwise MediaDrm will report errors. |
| 182 if (status == MEDIA_CODEC_NO_KEY) | 177 if (status == MEDIA_CODEC_NO_KEY) |
| 183 input_buf_index_ = input_buf_index; | 178 input_buf_index_ = input_buf_index; |
| 184 | 179 |
| 185 return status; | 180 return status; |
| 186 } | 181 } |
| 187 | 182 |
| 183 bool MediaDecoderJob::HasData() const { |
| 184 DCHECK(ui_loop_->BelongsToCurrentThread()); |
| 185 DCHECK(!input_eos_encountered_ || |
| 186 (received_data_.access_units.size() > 0 && |
| 187 access_unit_index_ < received_data_.access_units.size())) |
| 188 << "access_unit_index_.size() " << received_data_.access_units.size() |
| 189 << " access_unit_index_ " << access_unit_index_; |
| 190 return access_unit_index_ < received_data_.access_units.size() || |
| 191 input_eos_encountered_; |
| 192 } |
| 193 |
| 188 void MediaDecoderJob::RequestData(const base::Closure& done_cb) { | 194 void MediaDecoderJob::RequestData(const base::Closure& done_cb) { |
| 189 DVLOG(1) << __FUNCTION__; | 195 DVLOG(1) << __FUNCTION__; |
| 190 DCHECK(ui_loop_->BelongsToCurrentThread()); | 196 DCHECK(ui_loop_->BelongsToCurrentThread()); |
| 191 DCHECK(on_data_received_cb_.is_null()); | 197 DCHECK(on_data_received_cb_.is_null()); |
| 198 DCHECK(!input_eos_encountered_); |
| 192 | 199 |
| 193 received_data_ = DemuxerData(); | 200 received_data_ = DemuxerData(); |
| 194 access_unit_index_ = 0; | 201 access_unit_index_ = 0; |
| 195 on_data_received_cb_ = done_cb; | 202 on_data_received_cb_ = done_cb; |
| 196 | 203 |
| 197 request_data_cb_.Run(); | 204 request_data_cb_.Run(); |
| 198 } | 205 } |
| 199 | 206 |
| 200 void MediaDecoderJob::DecodeNextAccessUnit( | 207 void MediaDecoderJob::DecodeNextAccessUnit( |
| 201 const base::TimeTicks& start_time_ticks, | 208 const base::TimeTicks& start_time_ticks, |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 245 bool output_eos_encountered = false; | 252 bool output_eos_encountered = false; |
| 246 | 253 |
| 247 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds( | 254 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds( |
| 248 kMediaCodecTimeoutInMilliseconds); | 255 kMediaCodecTimeoutInMilliseconds); |
| 249 | 256 |
| 250 MediaCodecStatus status = media_codec_bridge_->DequeueOutputBuffer( | 257 MediaCodecStatus status = media_codec_bridge_->DequeueOutputBuffer( |
| 251 timeout, &buffer_index, &offset, &size, &presentation_timestamp, | 258 timeout, &buffer_index, &offset, &size, &presentation_timestamp, |
| 252 &output_eos_encountered); | 259 &output_eos_encountered); |
| 253 | 260 |
| 254 if (status != MEDIA_CODEC_OK) { | 261 if (status != MEDIA_CODEC_OK) { |
| 255 DCHECK(!(status == MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED || | |
| 256 status == MEDIA_CODEC_OUTPUT_FORMAT_CHANGED) || | |
| 257 (input_status != MEDIA_CODEC_INPUT_END_OF_STREAM)); | |
| 258 | |
| 259 if (status == MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED) { | 262 if (status == MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED) { |
| 260 media_codec_bridge_->GetOutputBuffers(); | 263 media_codec_bridge_->GetOutputBuffers(); |
| 261 status = MEDIA_CODEC_OK; | 264 status = MEDIA_CODEC_OK; |
| 262 } | 265 } |
| 263 callback.Run(status, start_presentation_timestamp, 0); | 266 callback.Run(status, start_presentation_timestamp, 0); |
| 264 return; | 267 return; |
| 265 } | 268 } |
| 266 | 269 |
| 267 // TODO(xhwang/qinmin): This logic is correct but strange. Clean it up. | 270 // TODO(xhwang/qinmin): This logic is correct but strange. Clean it up. |
| 268 if (output_eos_encountered) | 271 if (output_eos_encountered) |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 300 size_t audio_output_bytes) { | 303 size_t audio_output_bytes) { |
| 301 DCHECK(ui_loop_->BelongsToCurrentThread()); | 304 DCHECK(ui_loop_->BelongsToCurrentThread()); |
| 302 DCHECK(status != MEDIA_CODEC_STOPPED || received_data_.access_units.empty()); | 305 DCHECK(status != MEDIA_CODEC_STOPPED || received_data_.access_units.empty()); |
| 303 | 306 |
| 304 if (destroy_pending_) { | 307 if (destroy_pending_) { |
| 305 delete this; | 308 delete this; |
| 306 return; | 309 return; |
| 307 } | 310 } |
| 308 | 311 |
| 309 DCHECK(!decode_cb_.is_null()); | 312 DCHECK(!decode_cb_.is_null()); |
| 313 switch (status) { |
| 314 case MEDIA_CODEC_OK: |
| 315 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER: |
| 316 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: |
| 317 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: |
| 318 case MEDIA_CODEC_OUTPUT_END_OF_STREAM: |
| 319 if (!input_eos_encountered_) |
| 320 access_unit_index_++; |
| 321 break; |
| 310 | 322 |
| 311 if (status != MEDIA_CODEC_ERROR && | 323 case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER: |
| 312 status != MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER && | 324 case MEDIA_CODEC_INPUT_END_OF_STREAM: |
| 313 status != MEDIA_CODEC_INPUT_END_OF_STREAM && | 325 case MEDIA_CODEC_NO_KEY: |
| 314 status != MEDIA_CODEC_NO_KEY && | 326 case MEDIA_CODEC_STOPPED: |
| 315 status != MEDIA_CODEC_STOPPED) { | 327 case MEDIA_CODEC_ERROR: |
| 316 access_unit_index_++; | 328 // Do nothing. |
| 317 } | 329 break; |
| 330 }; |
| 318 | 331 |
| 319 stop_decode_pending_ = false; | 332 stop_decode_pending_ = false; |
| 320 base::ResetAndReturn(&decode_cb_).Run(status, presentation_timestamp, | 333 base::ResetAndReturn(&decode_cb_).Run(status, presentation_timestamp, |
| 321 audio_output_bytes); | 334 audio_output_bytes); |
| 322 } | 335 } |
| 323 | 336 |
| 324 } // namespace media | 337 } // namespace media |
| OLD | NEW |