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 11 matching lines...) Expand all Loading... |
22 MediaCodecBridge* media_codec_bridge, | 22 MediaCodecBridge* media_codec_bridge, |
23 const base::Closure& request_data_cb) | 23 const base::Closure& request_data_cb) |
24 : ui_loop_(base::MessageLoopProxy::current()), | 24 : ui_loop_(base::MessageLoopProxy::current()), |
25 decoder_loop_(decoder_loop), | 25 decoder_loop_(decoder_loop), |
26 media_codec_bridge_(media_codec_bridge), | 26 media_codec_bridge_(media_codec_bridge), |
27 needs_flush_(false), | 27 needs_flush_(false), |
28 input_eos_encountered_(false), | 28 input_eos_encountered_(false), |
29 weak_this_(this), | 29 weak_this_(this), |
30 request_data_cb_(request_data_cb), | 30 request_data_cb_(request_data_cb), |
31 access_unit_index_(0), | 31 access_unit_index_(0), |
| 32 input_buf_index_(-1), |
32 stop_decode_pending_(false), | 33 stop_decode_pending_(false), |
33 destroy_pending_(false) { | 34 destroy_pending_(false) { |
34 } | 35 } |
35 | 36 |
36 MediaDecoderJob::~MediaDecoderJob() {} | 37 MediaDecoderJob::~MediaDecoderJob() {} |
37 | 38 |
38 void MediaDecoderJob::OnDataReceived(const DemuxerData& data) { | 39 void MediaDecoderJob::OnDataReceived(const DemuxerData& data) { |
| 40 DVLOG(1) << __FUNCTION__ << ": " << data.access_units.size() << " units"; |
39 DCHECK(ui_loop_->BelongsToCurrentThread()); | 41 DCHECK(ui_loop_->BelongsToCurrentThread()); |
40 DCHECK(!on_data_received_cb_.is_null()); | 42 DCHECK(!on_data_received_cb_.is_null()); |
41 | 43 |
42 base::Closure done_cb = base::ResetAndReturn(&on_data_received_cb_); | 44 base::Closure done_cb = base::ResetAndReturn(&on_data_received_cb_); |
43 | 45 |
44 if (stop_decode_pending_) { | 46 if (stop_decode_pending_) { |
45 OnDecodeCompleted(MEDIA_CODEC_STOPPED, kNoTimestamp(), 0); | 47 OnDecodeCompleted(MEDIA_CODEC_STOPPED, kNoTimestamp(), 0); |
46 return; | 48 return; |
47 } | 49 } |
48 | 50 |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 request_data_cb_.Reset(); | 127 request_data_cb_.Reset(); |
126 on_data_received_cb_.Reset(); | 128 on_data_received_cb_.Reset(); |
127 decode_cb_.Reset(); | 129 decode_cb_.Reset(); |
128 | 130 |
129 if (destroy_pending_) | 131 if (destroy_pending_) |
130 return; | 132 return; |
131 | 133 |
132 delete this; | 134 delete this; |
133 } | 135 } |
134 | 136 |
135 MediaCodecStatus MediaDecoderJob::QueueInputBuffer( | 137 MediaCodecStatus MediaDecoderJob::QueueInputBuffer(const AccessUnit& unit) { |
136 const AccessUnit& unit) { | 138 DVLOG(1) << __FUNCTION__; |
137 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds( | 139 DCHECK(decoder_loop_->BelongsToCurrentThread()); |
138 kMediaCodecTimeoutInMilliseconds); | 140 |
139 int input_buf_index = 0; | 141 int input_buf_index = input_buf_index_; |
140 MediaCodecStatus status = | 142 input_buf_index_ = -1; |
141 media_codec_bridge_->DequeueInputBuffer(timeout, &input_buf_index); | 143 |
142 if (status != MEDIA_CODEC_OK) | 144 // TODO(xhwang): Hide DequeueInputBuffer() and the index in MediaCodecBridge. |
143 return status; | 145 if (input_buf_index == -1) { |
| 146 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds( |
| 147 kMediaCodecTimeoutInMilliseconds); |
| 148 MediaCodecStatus status = |
| 149 media_codec_bridge_->DequeueInputBuffer(timeout, &input_buf_index); |
| 150 if (status != MEDIA_CODEC_OK) { |
| 151 DVLOG(1) << "DequeueInputBuffer fails: " << status; |
| 152 return status; |
| 153 } |
| 154 } |
144 | 155 |
145 // TODO(qinmin): skip frames if video is falling far behind. | 156 // TODO(qinmin): skip frames if video is falling far behind. |
146 DCHECK_GE(input_buf_index, 0); | 157 DCHECK_GE(input_buf_index, 0); |
147 if (unit.end_of_stream || unit.data.empty()) { | 158 if (unit.end_of_stream || unit.data.empty()) { |
148 media_codec_bridge_->QueueEOS(input_buf_index); | 159 media_codec_bridge_->QueueEOS(input_buf_index_); |
149 return MEDIA_CODEC_INPUT_END_OF_STREAM; | 160 return MEDIA_CODEC_INPUT_END_OF_STREAM; |
150 } | 161 } |
151 | 162 |
152 if (unit.key_id.empty()) { | 163 if (unit.key_id.empty()) { |
153 media_codec_bridge_->QueueInputBuffer( | 164 return media_codec_bridge_->QueueInputBuffer( |
154 input_buf_index, &unit.data[0], unit.data.size(), unit.timestamp); | 165 input_buf_index, &unit.data[0], unit.data.size(), unit.timestamp); |
155 return MEDIA_CODEC_OK; | |
156 } | 166 } |
157 | 167 |
158 if (unit.iv.empty() || unit.subsamples.empty()) { | 168 if (unit.iv.empty() || unit.subsamples.empty()) { |
159 LOG(ERROR) << "The access unit doesn't have iv or subsamples while it " | 169 DVLOG(1) << "The access unit doesn't have iv or subsamples while it " |
160 << "has key IDs!"; | 170 << "has key IDs!"; |
161 return MEDIA_CODEC_ERROR; | 171 return MEDIA_CODEC_ERROR; |
162 } | 172 } |
163 | 173 |
164 media_codec_bridge_->QueueSecureInputBuffer( | 174 MediaCodecStatus status = media_codec_bridge_->QueueSecureInputBuffer( |
165 input_buf_index, &unit.data[0], unit.data.size(), | 175 input_buf_index, &unit.data[0], unit.data.size(), |
166 reinterpret_cast<const uint8*>(&unit.key_id[0]), unit.key_id.size(), | 176 reinterpret_cast<const uint8*>(&unit.key_id[0]), unit.key_id.size(), |
167 reinterpret_cast<const uint8*>(&unit.iv[0]), unit.iv.size(), | 177 reinterpret_cast<const uint8*>(&unit.iv[0]), unit.iv.size(), |
168 &unit.subsamples[0], unit.subsamples.size(), unit.timestamp); | 178 &unit.subsamples[0], unit.subsamples.size(), unit.timestamp); |
169 return MEDIA_CODEC_OK; | 179 |
| 180 // In case of MEDIA_CODEC_NO_KEY, we must reuse the |input_buf_index_|. |
| 181 // Otherwise MediaDrm will report errors. |
| 182 if (status == MEDIA_CODEC_NO_KEY) |
| 183 input_buf_index_ = input_buf_index; |
| 184 |
| 185 return status; |
170 } | 186 } |
171 | 187 |
172 void MediaDecoderJob::RequestData(const base::Closure& done_cb) { | 188 void MediaDecoderJob::RequestData(const base::Closure& done_cb) { |
| 189 DVLOG(1) << __FUNCTION__; |
173 DCHECK(ui_loop_->BelongsToCurrentThread()); | 190 DCHECK(ui_loop_->BelongsToCurrentThread()); |
174 DCHECK(on_data_received_cb_.is_null()); | 191 DCHECK(on_data_received_cb_.is_null()); |
175 | 192 |
176 received_data_ = DemuxerData(); | 193 received_data_ = DemuxerData(); |
177 access_unit_index_ = 0; | 194 access_unit_index_ = 0; |
178 on_data_received_cb_ = done_cb; | 195 on_data_received_cb_ = done_cb; |
179 | 196 |
180 request_data_cb_.Run(); | 197 request_data_cb_.Run(); |
181 } | 198 } |
182 | 199 |
(...skipping 11 matching lines...) Expand all Loading... |
194 &MediaDecoderJob::OnDecodeCompleted, base::Unretained(this))))); | 211 &MediaDecoderJob::OnDecodeCompleted, base::Unretained(this))))); |
195 needs_flush_ = false; | 212 needs_flush_ = false; |
196 } | 213 } |
197 | 214 |
198 void MediaDecoderJob::DecodeInternal( | 215 void MediaDecoderJob::DecodeInternal( |
199 const AccessUnit& unit, | 216 const AccessUnit& unit, |
200 const base::TimeTicks& start_time_ticks, | 217 const base::TimeTicks& start_time_ticks, |
201 const base::TimeDelta& start_presentation_timestamp, | 218 const base::TimeDelta& start_presentation_timestamp, |
202 bool needs_flush, | 219 bool needs_flush, |
203 const MediaDecoderJob::DecoderCallback& callback) { | 220 const MediaDecoderJob::DecoderCallback& callback) { |
| 221 DVLOG(1) << __FUNCTION__; |
| 222 DCHECK(decoder_loop_->BelongsToCurrentThread()); |
| 223 |
204 if (needs_flush) { | 224 if (needs_flush) { |
205 DVLOG(1) << "DecodeInternal needs flush."; | 225 DVLOG(1) << "DecodeInternal needs flush."; |
206 input_eos_encountered_ = false; | 226 input_eos_encountered_ = false; |
207 media_codec_bridge_->Reset(); | 227 media_codec_bridge_->Reset(); |
208 } | 228 } |
209 | 229 |
210 MediaCodecStatus input_status = MEDIA_CODEC_INPUT_END_OF_STREAM; | 230 MediaCodecStatus input_status = MEDIA_CODEC_INPUT_END_OF_STREAM; |
211 if (!input_eos_encountered_) { | 231 if (!input_eos_encountered_) { |
212 input_status = QueueInputBuffer(unit); | 232 input_status = QueueInputBuffer(unit); |
213 if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) { | 233 if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
252 | 272 |
253 base::TimeDelta time_to_render; | 273 base::TimeDelta time_to_render; |
254 DCHECK(!start_time_ticks.is_null()); | 274 DCHECK(!start_time_ticks.is_null()); |
255 if (ComputeTimeToRender()) { | 275 if (ComputeTimeToRender()) { |
256 time_to_render = presentation_timestamp - (base::TimeTicks::Now() - | 276 time_to_render = presentation_timestamp - (base::TimeTicks::Now() - |
257 start_time_ticks + start_presentation_timestamp); | 277 start_time_ticks + start_presentation_timestamp); |
258 } | 278 } |
259 | 279 |
260 // TODO(acolwell): Change to > since the else will never run for audio. | 280 // TODO(acolwell): Change to > since the else will never run for audio. |
261 if (time_to_render >= base::TimeDelta()) { | 281 if (time_to_render >= base::TimeDelta()) { |
262 base::MessageLoop::current()->PostDelayedTask( | 282 decoder_loop_->PostDelayedTask( |
263 FROM_HERE, | 283 FROM_HERE, |
264 base::Bind(&MediaDecoderJob::ReleaseOutputBuffer, | 284 base::Bind(&MediaDecoderJob::ReleaseOutputBuffer, |
265 weak_this_.GetWeakPtr(), buffer_index, size, | 285 weak_this_.GetWeakPtr(), buffer_index, size, |
266 presentation_timestamp, callback, status), | 286 presentation_timestamp, callback, status), |
267 time_to_render); | 287 time_to_render); |
268 return; | 288 return; |
269 } | 289 } |
270 | 290 |
271 // TODO(qinmin): The codec is lagging behind, need to recalculate the | 291 // TODO(qinmin): The codec is lagging behind, need to recalculate the |
272 // |start_presentation_timestamp_| and |start_time_ticks_|. | 292 // |start_presentation_timestamp_| and |start_time_ticks_|. |
273 DVLOG(1) << "codec is lagging behind :" << time_to_render.InMicroseconds(); | 293 DVLOG(1) << "codec is lagging behind :" << time_to_render.InMicroseconds(); |
274 ReleaseOutputBuffer(buffer_index, size, presentation_timestamp, | 294 ReleaseOutputBuffer(buffer_index, size, presentation_timestamp, |
275 callback, status); | 295 callback, status); |
276 } | 296 } |
277 | 297 |
278 void MediaDecoderJob::OnDecodeCompleted( | 298 void MediaDecoderJob::OnDecodeCompleted( |
279 MediaCodecStatus status, const base::TimeDelta& presentation_timestamp, | 299 MediaCodecStatus status, const base::TimeDelta& presentation_timestamp, |
280 size_t audio_output_bytes) { | 300 size_t audio_output_bytes) { |
281 DCHECK(ui_loop_->BelongsToCurrentThread()); | 301 DCHECK(ui_loop_->BelongsToCurrentThread()); |
282 DCHECK(status != MEDIA_CODEC_STOPPED || received_data_.access_units.empty()); | 302 DCHECK(status != MEDIA_CODEC_STOPPED || received_data_.access_units.empty()); |
283 | 303 |
284 if (destroy_pending_) { | 304 if (destroy_pending_) { |
285 delete this; | 305 delete this; |
286 return; | 306 return; |
287 } | 307 } |
288 | 308 |
289 DCHECK(!decode_cb_.is_null()); | 309 DCHECK(!decode_cb_.is_null()); |
290 | 310 |
291 if (status != MEDIA_CODEC_ERROR && | 311 if (status != MEDIA_CODEC_ERROR && |
292 status != MEDIA_CODEC_ENQUEUE_INPUT_AGAIN_LATER && | 312 status != MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER && |
293 status != MEDIA_CODEC_INPUT_END_OF_STREAM && | 313 status != MEDIA_CODEC_INPUT_END_OF_STREAM && |
| 314 status != MEDIA_CODEC_NO_KEY && |
294 status != MEDIA_CODEC_STOPPED) { | 315 status != MEDIA_CODEC_STOPPED) { |
295 access_unit_index_++; | 316 access_unit_index_++; |
296 } | 317 } |
297 | 318 |
298 stop_decode_pending_ = false; | 319 stop_decode_pending_ = false; |
299 base::ResetAndReturn(&decode_cb_).Run(status, presentation_timestamp, | 320 base::ResetAndReturn(&decode_cb_).Run(status, presentation_timestamp, |
300 audio_output_bytes); | 321 audio_output_bytes); |
301 } | 322 } |
302 | 323 |
303 } // namespace media | 324 } // namespace media |
OLD | NEW |