Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(21)

Side by Side Diff: media/base/android/media_decoder_job.cc

Issue 254473010: Refactor MSE implementation on Android to simplify the logic and improve the performance (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: addressing comments Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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"
11 #include "media/base/android/media_codec_bridge.h" 11 #include "media/base/android/media_codec_bridge.h"
12 #include "media/base/android/media_drm_bridge.h"
12 #include "media/base/bind_to_current_loop.h" 13 #include "media/base/bind_to_current_loop.h"
13 #include "media/base/buffers.h" 14 #include "media/base/buffers.h"
14 15
15 namespace media { 16 namespace media {
16 17
17 // Timeout value for media codec operations. Because the first 18 // Timeout value for media codec operations. Because the first
18 // DequeInputBuffer() can take about 150 milliseconds, use 250 milliseconds 19 // DequeInputBuffer() can take about 150 milliseconds, use 250 milliseconds
19 // here. See http://b/9357571. 20 // here. See http://b/9357571.
20 static const int kMediaCodecTimeoutInMilliseconds = 250; 21 static const int kMediaCodecTimeoutInMilliseconds = 250;
21 22
22 MediaDecoderJob::MediaDecoderJob( 23 MediaDecoderJob::MediaDecoderJob(
23 const scoped_refptr<base::SingleThreadTaskRunner>& decoder_task_runner, 24 const scoped_refptr<base::SingleThreadTaskRunner>& decoder_task_runner,
24 MediaCodecBridge* media_codec_bridge, 25 const base::Closure& request_data_cb,
25 const base::Closure& request_data_cb) 26 const base::Closure& on_demuxer_config_changed_cb)
26 : ui_task_runner_(base::MessageLoopProxy::current()), 27 : ui_task_runner_(base::MessageLoopProxy::current()),
27 decoder_task_runner_(decoder_task_runner), 28 decoder_task_runner_(decoder_task_runner),
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 on_demuxer_config_changed_cb_(on_demuxer_config_changed_cb),
35 current_demuxer_data_index_(0), 36 current_demuxer_data_index_(0),
36 input_buf_index_(-1), 37 input_buf_index_(-1),
38 is_content_encrypted_(false),
37 stop_decode_pending_(false), 39 stop_decode_pending_(false),
38 destroy_pending_(false), 40 destroy_pending_(false),
39 is_requesting_demuxer_data_(false), 41 is_requesting_demuxer_data_(false),
40 is_incoming_data_invalid_(false), 42 is_incoming_data_invalid_(false),
41 weak_factory_(this) { 43 release_resources_pending_(false),
44 drm_bridge_(NULL),
45 drain_decoder_(false) {
42 InitializeReceivedData(); 46 InitializeReceivedData();
43 } 47 }
44 48
45 MediaDecoderJob::~MediaDecoderJob() {} 49 MediaDecoderJob::~MediaDecoderJob() {
50 ReleaseMediaCodecBridge();
51 }
46 52
47 void MediaDecoderJob::OnDataReceived(const DemuxerData& data) { 53 void MediaDecoderJob::OnDataReceived(const DemuxerData& data) {
48 DVLOG(1) << __FUNCTION__ << ": " << data.access_units.size() << " units"; 54 DVLOG(1) << __FUNCTION__ << ": " << data.access_units.size() << " units";
49 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 55 DCHECK(ui_task_runner_->BelongsToCurrentThread());
50 DCHECK(NoAccessUnitsRemainingInChunk(false)); 56 DCHECK(NoAccessUnitsRemainingInChunk(false));
51 57
52 TRACE_EVENT_ASYNC_END2( 58 TRACE_EVENT_ASYNC_END2(
53 "media", "MediaDecoderJob::RequestData", this, 59 "media", "MediaDecoderJob::RequestData", this,
54 "Data type", data.type == media::DemuxerStream::AUDIO ? "AUDIO" : "VIDEO", 60 "Data type", data.type == media::DemuxerStream::AUDIO ? "AUDIO" : "VIDEO",
55 "Units read", data.access_units.size()); 61 "Units read", data.access_units.size());
(...skipping 11 matching lines...) Expand all
67 } 73 }
68 74
69 size_t next_demuxer_data_index = inactive_demuxer_data_index(); 75 size_t next_demuxer_data_index = inactive_demuxer_data_index();
70 received_data_[next_demuxer_data_index] = data; 76 received_data_[next_demuxer_data_index] = data;
71 access_unit_index_[next_demuxer_data_index] = 0; 77 access_unit_index_[next_demuxer_data_index] = 0;
72 is_requesting_demuxer_data_ = false; 78 is_requesting_demuxer_data_ = false;
73 79
74 base::Closure done_cb = base::ResetAndReturn(&on_data_received_cb_); 80 base::Closure done_cb = base::ResetAndReturn(&on_data_received_cb_);
75 81
76 // If this data request is for the inactive chunk, or |on_data_received_cb_| 82 // If this data request is for the inactive chunk, or |on_data_received_cb_|
77 // was set to null by ClearData() or Release(), do nothing. 83 // was set to null by Flush() or Release(), do nothing.
78 if (done_cb.is_null()) 84 if (done_cb.is_null())
79 return; 85 return;
80 86
81 if (stop_decode_pending_) { 87 if (stop_decode_pending_) {
82 DCHECK(is_decoding()); 88 DCHECK(is_decoding());
83 OnDecodeCompleted(MEDIA_CODEC_STOPPED, kNoTimestamp(), kNoTimestamp()); 89 OnDecodeCompleted(MEDIA_CODEC_STOPPED, kNoTimestamp(), kNoTimestamp());
84 return; 90 return;
85 } 91 }
86 92
87 done_cb.Run(); 93 done_cb.Run();
88 } 94 }
89 95
90 void MediaDecoderJob::Prefetch(const base::Closure& prefetch_cb) { 96 void MediaDecoderJob::Prefetch(const base::Closure& prefetch_cb) {
91 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 97 DCHECK(ui_task_runner_->BelongsToCurrentThread());
92 DCHECK(on_data_received_cb_.is_null()); 98 DCHECK(on_data_received_cb_.is_null());
93 DCHECK(decode_cb_.is_null()); 99 DCHECK(decode_cb_.is_null());
94 100
95 if (HasData()) { 101 if (HasData()) {
96 DVLOG(1) << __FUNCTION__ << " : using previously received data"; 102 DVLOG(1) << __FUNCTION__ << " : using previously received data";
97 ui_task_runner_->PostTask(FROM_HERE, prefetch_cb); 103 ui_task_runner_->PostTask(FROM_HERE, prefetch_cb);
98 return; 104 return;
99 } 105 }
100 106
101 DVLOG(1) << __FUNCTION__ << " : requesting data"; 107 DVLOG(1) << __FUNCTION__ << " : requesting data";
102 RequestData(prefetch_cb); 108 RequestData(prefetch_cb);
103 } 109 }
104 110
105 scoped_ptr<DemuxerConfigs> MediaDecoderJob::Decode( 111 bool MediaDecoderJob::Decode(
106 base::TimeTicks start_time_ticks, 112 base::TimeTicks start_time_ticks,
107 base::TimeDelta start_presentation_timestamp, 113 base::TimeDelta start_presentation_timestamp,
108 const DecoderCallback& callback) { 114 const DecoderCallback& callback) {
109 DCHECK(decode_cb_.is_null()); 115 DCHECK(decode_cb_.is_null());
110 DCHECK(on_data_received_cb_.is_null()); 116 DCHECK(on_data_received_cb_.is_null());
111 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 117 DCHECK(ui_task_runner_->BelongsToCurrentThread());
112 118
119 if (!media_codec_bridge_ || need_to_reconfig_decoder_job_) {
120 need_to_reconfig_decoder_job_ = !CreateMediaCodecBridge();
121 if (drain_decoder_) {
122 // Decoder has been recreated, stop draining.
123 drain_decoder_ = false;
124 input_eos_encountered_ = false;
125 output_eos_encountered_ = false;
126 access_unit_index_[current_demuxer_data_index_]++;
127 }
128 skip_eos_enqueue_ = true;
129 if (need_to_reconfig_decoder_job_)
130 return false;
131 }
132
113 decode_cb_ = callback; 133 decode_cb_ = callback;
114 134
115 if (!HasData()) { 135 if (!HasData()) {
116 RequestData(base::Bind(&MediaDecoderJob::DecodeCurrentAccessUnit, 136 RequestData(base::Bind(&MediaDecoderJob::DecodeCurrentAccessUnit,
117 base::Unretained(this), 137 base::Unretained(this),
118 start_time_ticks, 138 start_time_ticks,
119 start_presentation_timestamp)); 139 start_presentation_timestamp));
120 return scoped_ptr<DemuxerConfigs>(); 140 return true;
121 }
122
123 if (DemuxerStream::kConfigChanged == CurrentAccessUnit().status) {
124 decode_cb_.Reset();
125 size_t index = CurrentReceivedDataChunkIndex();
126 CHECK_EQ(1u, received_data_[index].demuxer_configs.size());
127 return scoped_ptr<DemuxerConfigs>(new DemuxerConfigs(
128 received_data_[index].demuxer_configs[0]));
129 } 141 }
130 142
131 DecodeCurrentAccessUnit(start_time_ticks, start_presentation_timestamp); 143 DecodeCurrentAccessUnit(start_time_ticks, start_presentation_timestamp);
132 return scoped_ptr<DemuxerConfigs>(); 144 return true;
133 } 145 }
134 146
135 void MediaDecoderJob::StopDecode() { 147 void MediaDecoderJob::StopDecode() {
136 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 148 DCHECK(ui_task_runner_->BelongsToCurrentThread());
137 DCHECK(is_decoding()); 149 DCHECK(is_decoding());
138 stop_decode_pending_ = true; 150 stop_decode_pending_ = true;
139 } 151 }
140 152
153 bool MediaDecoderJob::OutputEOSReached() const {
154 return !drain_decoder_ && output_eos_encountered_;
155 }
156
141 void MediaDecoderJob::Flush() { 157 void MediaDecoderJob::Flush() {
158 DVLOG(1) << __FUNCTION__;
159 DCHECK(ui_task_runner_->BelongsToCurrentThread());
160 DCHECK(on_data_received_cb_.is_null());
142 DCHECK(decode_cb_.is_null()); 161 DCHECK(decode_cb_.is_null());
143 162
163 // Clean up the received data.
164 current_demuxer_data_index_ = 0;
165 InitializeReceivedData();
166 if (is_requesting_demuxer_data_)
167 is_incoming_data_invalid_ = true;
168 input_eos_encountered_ = false;
169 output_eos_encountered_ = false;
170 drain_decoder_ = false;
171
144 // Do nothing, flush when the next Decode() happens. 172 // Do nothing, flush when the next Decode() happens.
145 needs_flush_ = true; 173 needs_flush_ = true;
146 ClearData();
147 } 174 }
148 175
149 void MediaDecoderJob::BeginPrerolling(base::TimeDelta preroll_timestamp) { 176 void MediaDecoderJob::BeginPrerolling(base::TimeDelta preroll_timestamp) {
150 DVLOG(1) << __FUNCTION__ << "(" << preroll_timestamp.InSecondsF() << ")"; 177 DVLOG(1) << __FUNCTION__ << "(" << preroll_timestamp.InSecondsF() << ")";
151 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 178 DCHECK(ui_task_runner_->BelongsToCurrentThread());
152 DCHECK(!is_decoding()); 179 DCHECK(!is_decoding());
153 180
154 preroll_timestamp_ = preroll_timestamp; 181 preroll_timestamp_ = preroll_timestamp;
155 prerolling_ = true; 182 prerolling_ = true;
156 } 183 }
157 184
185 void MediaDecoderJob::ReleaseDecoderResources() {
186 DVLOG(1) << __FUNCTION__;
187 DCHECK(ui_task_runner_->BelongsToCurrentThread());
188 if (decode_cb_.is_null()) {
189 DCHECK(!drain_decoder_);
190 // Since the decoder job is not decoding data, we can safely destroy
191 // |media_codec_bridge_|.
192 ReleaseMediaCodecBridge();
193 return;
194 }
195
196 // Release |media_codec_bridge_| once decoding is completed.
197 release_resources_pending_ = true;
198 }
199
200 bool MediaDecoderJob::SetDemuxerConfigs(const DemuxerConfigs& configs) {
201 bool config_changed = IsDemuxerConfigChanged(configs);
202 if (config_changed)
203 UpdateDemuxerConfigs(configs);
204 return config_changed;
205 }
206
207 base::android::ScopedJavaLocalRef<jobject> MediaDecoderJob::GetMediaCrypto() {
208 base::android::ScopedJavaLocalRef<jobject> media_crypto;
209 if (drm_bridge_)
210 media_crypto = drm_bridge_->GetMediaCrypto();
211 return media_crypto;
212 }
213
158 void MediaDecoderJob::Release() { 214 void MediaDecoderJob::Release() {
159 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 215 DCHECK(ui_task_runner_->BelongsToCurrentThread());
160 DVLOG(1) << __FUNCTION__; 216 DVLOG(1) << __FUNCTION__;
161 217
162 // If the decoder job is not waiting for data, and is still decoding, we 218 // If the decoder job is still decoding, we cannot delete the job immediately.
163 // cannot delete the job immediately. 219 destroy_pending_ = is_decoding();
164 destroy_pending_ = on_data_received_cb_.is_null() && is_decoding();
165 220
166 request_data_cb_.Reset(); 221 request_data_cb_.Reset();
167 on_data_received_cb_.Reset(); 222 on_data_received_cb_.Reset();
168 decode_cb_.Reset(); 223 decode_cb_.Reset();
169 224
170 if (destroy_pending_) { 225 if (destroy_pending_) {
171 DVLOG(1) << __FUNCTION__ << " : delete is pending decode completion"; 226 DVLOG(1) << __FUNCTION__ << " : delete is pending decode completion";
172 return; 227 return;
173 } 228 }
174 229
175 delete this; 230 delete this;
176 } 231 }
177 232
178 MediaCodecStatus MediaDecoderJob::QueueInputBuffer(const AccessUnit& unit) { 233 MediaCodecStatus MediaDecoderJob::QueueInputBuffer(
234 const AccessUnit& unit, bool drain_decoder) {
179 DVLOG(1) << __FUNCTION__; 235 DVLOG(1) << __FUNCTION__;
180 DCHECK(decoder_task_runner_->BelongsToCurrentThread()); 236 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
181 TRACE_EVENT0("media", __FUNCTION__); 237 TRACE_EVENT0("media", __FUNCTION__);
182 238
183 int input_buf_index = input_buf_index_; 239 int input_buf_index = input_buf_index_;
184 input_buf_index_ = -1; 240 input_buf_index_ = -1;
185 241
186 // TODO(xhwang): Hide DequeueInputBuffer() and the index in MediaCodecBridge. 242 // TODO(xhwang): Hide DequeueInputBuffer() and the index in MediaCodecBridge.
187 if (input_buf_index == -1) { 243 if (input_buf_index == -1) {
188 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds( 244 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(
189 kMediaCodecTimeoutInMilliseconds); 245 kMediaCodecTimeoutInMilliseconds);
190 MediaCodecStatus status = 246 MediaCodecStatus status =
191 media_codec_bridge_->DequeueInputBuffer(timeout, &input_buf_index); 247 media_codec_bridge_->DequeueInputBuffer(timeout, &input_buf_index);
192 if (status != MEDIA_CODEC_OK) { 248 if (status != MEDIA_CODEC_OK) {
193 DVLOG(1) << "DequeueInputBuffer fails: " << status; 249 DVLOG(1) << "DequeueInputBuffer fails: " << status;
194 return status; 250 return status;
195 } 251 }
196 } 252 }
197 253
198 // TODO(qinmin): skip frames if video is falling far behind. 254 // TODO(qinmin): skip frames if video is falling far behind.
199 DCHECK_GE(input_buf_index, 0); 255 DCHECK_GE(input_buf_index, 0);
200 if (unit.end_of_stream || unit.data.empty()) { 256 if (unit.end_of_stream || unit.data.empty()) {
201 media_codec_bridge_->QueueEOS(input_buf_index); 257 media_codec_bridge_->QueueEOS(input_buf_index);
202 return MEDIA_CODEC_INPUT_END_OF_STREAM; 258 return MEDIA_CODEC_INPUT_END_OF_STREAM;
203 } 259 }
204 260
205 if (unit.key_id.empty() || unit.iv.empty()) { 261 if (drain_decoder || unit.key_id.empty() || unit.iv.empty()) {
206 DCHECK(unit.iv.empty() || !unit.key_id.empty()); 262 DCHECK(unit.iv.empty() || !unit.key_id.empty());
207 return media_codec_bridge_->QueueInputBuffer( 263 return media_codec_bridge_->QueueInputBuffer(
208 input_buf_index, &unit.data[0], unit.data.size(), unit.timestamp); 264 input_buf_index, &unit.data[0], unit.data.size(), unit.timestamp);
209 } 265 }
210 266
211 MediaCodecStatus status = media_codec_bridge_->QueueSecureInputBuffer( 267 MediaCodecStatus status = media_codec_bridge_->QueueSecureInputBuffer(
212 input_buf_index, 268 input_buf_index,
213 &unit.data[0], unit.data.size(), 269 &unit.data[0], unit.data.size(),
214 reinterpret_cast<const uint8*>(&unit.key_id[0]), unit.key_id.size(), 270 reinterpret_cast<const uint8*>(&unit.key_id[0]), unit.key_id.size(),
215 reinterpret_cast<const uint8*>(&unit.iv[0]), unit.iv.size(), 271 reinterpret_cast<const uint8*>(&unit.iv[0]), unit.iv.size(),
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 } 318 }
263 319
264 void MediaDecoderJob::DecodeCurrentAccessUnit( 320 void MediaDecoderJob::DecodeCurrentAccessUnit(
265 base::TimeTicks start_time_ticks, 321 base::TimeTicks start_time_ticks,
266 base::TimeDelta start_presentation_timestamp) { 322 base::TimeDelta start_presentation_timestamp) {
267 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 323 DCHECK(ui_task_runner_->BelongsToCurrentThread());
268 DCHECK(!decode_cb_.is_null()); 324 DCHECK(!decode_cb_.is_null());
269 325
270 RequestCurrentChunkIfEmpty(); 326 RequestCurrentChunkIfEmpty();
271 const AccessUnit& access_unit = CurrentAccessUnit(); 327 const AccessUnit& access_unit = CurrentAccessUnit();
272 // If the first access unit is a config change, request the player to dequeue 328 if (CurrentAccessUnit().status == DemuxerStream::kConfigChanged) {
273 // the input buffer again so that it can request config data. 329 int index = CurrentReceivedDataChunkIndex();
274 if (access_unit.status == DemuxerStream::kConfigChanged) { 330 bool config_changed = SetDemuxerConfigs(
275 ui_task_runner_->PostTask(FROM_HERE, 331 received_data_[index].demuxer_configs[0]);
276 base::Bind(&MediaDecoderJob::OnDecodeCompleted, 332 if (config_changed)
277 base::Unretained(this), 333 on_demuxer_config_changed_cb_.Run();
278 MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER, 334 if (!drain_decoder_) {
279 kNoTimestamp(), kNoTimestamp())); 335 // If we haven't decoded any data yet, just skip the current access unit
280 return; 336 // and request the MediaCodec to be recreated on next Decode().
337 if (skip_eos_enqueue_ || !config_changed) {
338 need_to_reconfig_decoder_job_ =
339 need_to_reconfig_decoder_job_ || config_changed;
340 ui_task_runner_->PostTask(FROM_HERE, base::Bind(
341 &MediaDecoderJob::OnDecodeCompleted, base::Unretained(this),
342 MEDIA_CODEC_OUTPUT_FORMAT_CHANGED, kNoTimestamp(), kNoTimestamp()));
343 return;
344 }
345 // Start draining the decoder so that all the remaining frames are
346 // rendered.
347 drain_decoder_ = true;
348 }
281 } 349 }
282 350
283 decoder_task_runner_->PostTask(FROM_HERE, base::Bind( 351 decoder_task_runner_->PostTask(FROM_HERE, base::Bind(
284 &MediaDecoderJob::DecodeInternal, base::Unretained(this), 352 &MediaDecoderJob::DecodeInternal, base::Unretained(this),
285 access_unit, 353 access_unit,
286 start_time_ticks, start_presentation_timestamp, needs_flush_, 354 start_time_ticks, start_presentation_timestamp, needs_flush_,
355 drain_decoder_,
287 media::BindToCurrentLoop(base::Bind( 356 media::BindToCurrentLoop(base::Bind(
288 &MediaDecoderJob::OnDecodeCompleted, base::Unretained(this))))); 357 &MediaDecoderJob::OnDecodeCompleted, base::Unretained(this)))));
289 needs_flush_ = false; 358 needs_flush_ = false;
290 } 359 }
291 360
292 void MediaDecoderJob::DecodeInternal( 361 void MediaDecoderJob::DecodeInternal(
293 const AccessUnit& unit, 362 const AccessUnit& unit,
294 base::TimeTicks start_time_ticks, 363 base::TimeTicks start_time_ticks,
295 base::TimeDelta start_presentation_timestamp, 364 base::TimeDelta start_presentation_timestamp,
296 bool needs_flush, 365 bool needs_flush,
366 bool drain_decoder,
297 const MediaDecoderJob::DecoderCallback& callback) { 367 const MediaDecoderJob::DecoderCallback& callback) {
298 DVLOG(1) << __FUNCTION__; 368 DVLOG(1) << __FUNCTION__;
299 DCHECK(decoder_task_runner_->BelongsToCurrentThread()); 369 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
370 DCHECK(!(needs_flush && drain_decoder));
300 TRACE_EVENT0("media", __FUNCTION__); 371 TRACE_EVENT0("media", __FUNCTION__);
301 372
302 if (needs_flush) { 373 if (needs_flush) {
303 DVLOG(1) << "DecodeInternal needs flush."; 374 DVLOG(1) << "DecodeInternal needs flush.";
304 input_eos_encountered_ = false; 375 input_eos_encountered_ = false;
305 output_eos_encountered_ = false; 376 output_eos_encountered_ = false;
306 MediaCodecStatus reset_status = media_codec_bridge_->Reset(); 377 MediaCodecStatus reset_status = media_codec_bridge_->Reset();
307 if (MEDIA_CODEC_OK != reset_status) { 378 if (MEDIA_CODEC_OK != reset_status) {
308 callback.Run(reset_status, kNoTimestamp(), kNoTimestamp()); 379 callback.Run(reset_status, kNoTimestamp(), kNoTimestamp());
309 return; 380 return;
(...skipping 19 matching lines...) Expand all
329 callback.Run(MEDIA_CODEC_OUTPUT_END_OF_STREAM, kNoTimestamp(), 400 callback.Run(MEDIA_CODEC_OUTPUT_END_OF_STREAM, kNoTimestamp(),
330 kNoTimestamp()); 401 kNoTimestamp());
331 return; 402 return;
332 } 403 }
333 404
334 skip_eos_enqueue_ = false; 405 skip_eos_enqueue_ = false;
335 } 406 }
336 407
337 MediaCodecStatus input_status = MEDIA_CODEC_INPUT_END_OF_STREAM; 408 MediaCodecStatus input_status = MEDIA_CODEC_INPUT_END_OF_STREAM;
338 if (!input_eos_encountered_) { 409 if (!input_eos_encountered_) {
339 input_status = QueueInputBuffer(unit); 410 input_status = QueueInputBuffer(unit, drain_decoder);
340 if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) { 411 if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) {
341 input_eos_encountered_ = true; 412 input_eos_encountered_ = true;
342 } else if (input_status != MEDIA_CODEC_OK) { 413 } else if (input_status != MEDIA_CODEC_OK) {
343 callback.Run(input_status, kNoTimestamp(), kNoTimestamp()); 414 callback.Run(input_status, kNoTimestamp(), kNoTimestamp());
344 return; 415 return;
345 } 416 }
346 } 417 }
347 418
348 int buffer_index = 0; 419 int buffer_index = 0;
349 size_t offset = 0; 420 size_t offset = 0;
(...skipping 18 matching lines...) Expand all
368 status = MEDIA_CODEC_ERROR; 439 status = MEDIA_CODEC_ERROR;
369 } 440 }
370 callback.Run(status, kNoTimestamp(), kNoTimestamp()); 441 callback.Run(status, kNoTimestamp(), kNoTimestamp());
371 return; 442 return;
372 } 443 }
373 444
374 // TODO(xhwang/qinmin): This logic is correct but strange. Clean it up. 445 // TODO(xhwang/qinmin): This logic is correct but strange. Clean it up.
375 if (output_eos_encountered_) 446 if (output_eos_encountered_)
376 status = MEDIA_CODEC_OUTPUT_END_OF_STREAM; 447 status = MEDIA_CODEC_OUTPUT_END_OF_STREAM;
377 else if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) 448 else if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM)
378 status = MEDIA_CODEC_INPUT_END_OF_STREAM; 449 status = drain_decoder ? MEDIA_CODEC_OK : MEDIA_CODEC_INPUT_END_OF_STREAM;
379 450
380 bool render_output = presentation_timestamp >= preroll_timestamp_ && 451 bool render_output = presentation_timestamp >= preroll_timestamp_ &&
381 (status != MEDIA_CODEC_OUTPUT_END_OF_STREAM || size != 0u); 452 (status != MEDIA_CODEC_OUTPUT_END_OF_STREAM || size != 0u);
382 base::TimeDelta time_to_render; 453 base::TimeDelta time_to_render;
383 DCHECK(!start_time_ticks.is_null()); 454 DCHECK(!start_time_ticks.is_null());
384 if (render_output && ComputeTimeToRender()) { 455 if (render_output && ComputeTimeToRender()) {
385 time_to_render = presentation_timestamp - (base::TimeTicks::Now() - 456 time_to_render = presentation_timestamp - (base::TimeTicks::Now() -
386 start_time_ticks + start_presentation_timestamp); 457 start_time_ticks + start_presentation_timestamp);
387 } 458 }
388 459
389 if (time_to_render > base::TimeDelta()) { 460 if (time_to_render > base::TimeDelta()) {
390 decoder_task_runner_->PostDelayedTask( 461 decoder_task_runner_->PostDelayedTask(
391 FROM_HERE, 462 FROM_HERE,
392 base::Bind(&MediaDecoderJob::ReleaseOutputBuffer, 463 base::Bind(&MediaDecoderJob::ReleaseOutputBuffer,
393 weak_factory_.GetWeakPtr(), 464 base::Unretained(this),
394 buffer_index, 465 buffer_index,
395 size, 466 size,
396 render_output, 467 render_output,
397 presentation_timestamp, 468 presentation_timestamp,
398 base::Bind(callback, status)), 469 base::Bind(callback, status)),
399 time_to_render); 470 time_to_render);
400 return; 471 return;
401 } 472 }
402 473
403 // TODO(qinmin): The codec is lagging behind, need to recalculate the 474 // TODO(qinmin): The codec is lagging behind, need to recalculate the
(...skipping 19 matching lines...) Expand all
423 MediaCodecStatus status, base::TimeDelta current_presentation_timestamp, 494 MediaCodecStatus status, base::TimeDelta current_presentation_timestamp,
424 base::TimeDelta max_presentation_timestamp) { 495 base::TimeDelta max_presentation_timestamp) {
425 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 496 DCHECK(ui_task_runner_->BelongsToCurrentThread());
426 497
427 if (destroy_pending_) { 498 if (destroy_pending_) {
428 DVLOG(1) << __FUNCTION__ << " : completing pending deletion"; 499 DVLOG(1) << __FUNCTION__ << " : completing pending deletion";
429 delete this; 500 delete this;
430 return; 501 return;
431 } 502 }
432 503
504 if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM)
505 output_eos_encountered_ = true;
506
433 DCHECK(!decode_cb_.is_null()); 507 DCHECK(!decode_cb_.is_null());
434 508
435 // If output was queued for rendering, then we have completed prerolling. 509 // If output was queued for rendering, then we have completed prerolling.
436 if (current_presentation_timestamp != kNoTimestamp()) 510 if (current_presentation_timestamp != kNoTimestamp())
437 prerolling_ = false; 511 prerolling_ = false;
438 512
439 switch (status) { 513 switch (status) {
440 case MEDIA_CODEC_OK: 514 case MEDIA_CODEC_OK:
441 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER: 515 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER:
442 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: 516 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED:
443 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: 517 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED:
444 case MEDIA_CODEC_OUTPUT_END_OF_STREAM: 518 case MEDIA_CODEC_OUTPUT_END_OF_STREAM:
445 if (!input_eos_encountered_) 519 if (!input_eos_encountered_) {
520 CurrentDataConsumed(
521 CurrentAccessUnit().status == DemuxerStream::kConfigChanged);
446 access_unit_index_[current_demuxer_data_index_]++; 522 access_unit_index_[current_demuxer_data_index_]++;
523 }
447 break; 524 break;
448 525
449 case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER: 526 case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER:
450 case MEDIA_CODEC_INPUT_END_OF_STREAM: 527 case MEDIA_CODEC_INPUT_END_OF_STREAM:
451 case MEDIA_CODEC_NO_KEY: 528 case MEDIA_CODEC_NO_KEY:
452 case MEDIA_CODEC_STOPPED: 529 case MEDIA_CODEC_STOPPED:
453 case MEDIA_CODEC_ERROR: 530 case MEDIA_CODEC_ERROR:
454 // Do nothing. 531 // Do nothing.
455 break; 532 break;
456 }; 533 };
457 534
535 if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM && drain_decoder_) {
536 OnDecoderDrained();
537 status = MEDIA_CODEC_OK;
538 }
539
540 if (release_resources_pending_) {
541 ReleaseMediaCodecBridge();
542 release_resources_pending_ = false;
543 if (drain_decoder_)
544 OnDecoderDrained();
545 }
546
458 stop_decode_pending_ = false; 547 stop_decode_pending_ = false;
459 base::ResetAndReturn(&decode_cb_).Run( 548 base::ResetAndReturn(&decode_cb_).Run(
460 status, current_presentation_timestamp, max_presentation_timestamp); 549 status, current_presentation_timestamp, max_presentation_timestamp);
461 } 550 }
462 551
463 const AccessUnit& MediaDecoderJob::CurrentAccessUnit() const { 552 const AccessUnit& MediaDecoderJob::CurrentAccessUnit() const {
464 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 553 DCHECK(ui_task_runner_->BelongsToCurrentThread());
465 DCHECK(HasData()); 554 DCHECK(HasData());
466 size_t index = CurrentReceivedDataChunkIndex(); 555 size_t index = CurrentReceivedDataChunkIndex();
467 return received_data_[index].access_units[access_unit_index_[index]]; 556 return received_data_[index].access_units[access_unit_index_[index]];
468 } 557 }
469 558
470 size_t MediaDecoderJob::CurrentReceivedDataChunkIndex() const { 559 size_t MediaDecoderJob::CurrentReceivedDataChunkIndex() const {
471 return NoAccessUnitsRemainingInChunk(true) ? 560 return NoAccessUnitsRemainingInChunk(true) ?
472 inactive_demuxer_data_index() : current_demuxer_data_index_; 561 inactive_demuxer_data_index() : current_demuxer_data_index_;
473 } 562 }
474 563
475 bool MediaDecoderJob::NoAccessUnitsRemainingInChunk( 564 bool MediaDecoderJob::NoAccessUnitsRemainingInChunk(
476 bool is_active_chunk) const { 565 bool is_active_chunk) const {
477 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 566 DCHECK(ui_task_runner_->BelongsToCurrentThread());
478 size_t index = is_active_chunk ? current_demuxer_data_index_ : 567 size_t index = is_active_chunk ? current_demuxer_data_index_ :
479 inactive_demuxer_data_index(); 568 inactive_demuxer_data_index();
480 return received_data_[index].access_units.size() <= access_unit_index_[index]; 569 return received_data_[index].access_units.size() <= access_unit_index_[index];
481 } 570 }
482 571
483 void MediaDecoderJob::ClearData() {
484 DCHECK(ui_task_runner_->BelongsToCurrentThread());
485 current_demuxer_data_index_ = 0;
486 InitializeReceivedData();
487 on_data_received_cb_.Reset();
488 if (is_requesting_demuxer_data_)
489 is_incoming_data_invalid_ = true;
490 input_eos_encountered_ = false;
491 }
492
493 void MediaDecoderJob::RequestCurrentChunkIfEmpty() { 572 void MediaDecoderJob::RequestCurrentChunkIfEmpty() {
494 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 573 DCHECK(ui_task_runner_->BelongsToCurrentThread());
495 DCHECK(HasData()); 574 DCHECK(HasData());
496 if (!NoAccessUnitsRemainingInChunk(true)) 575 if (!NoAccessUnitsRemainingInChunk(true))
497 return; 576 return;
498 577
499 // Requests new data if the the last access unit of the next chunk is not EOS. 578 // Requests new data if the the last access unit of the next chunk is not EOS.
500 current_demuxer_data_index_ = inactive_demuxer_data_index(); 579 current_demuxer_data_index_ = inactive_demuxer_data_index();
501 const AccessUnit last_access_unit = 580 const AccessUnit last_access_unit =
502 received_data_[current_demuxer_data_index_].access_units.back(); 581 received_data_[current_demuxer_data_index_].access_units.back();
503 if (!last_access_unit.end_of_stream && 582 if (!last_access_unit.end_of_stream &&
504 last_access_unit.status != DemuxerStream::kConfigChanged &&
505 last_access_unit.status != DemuxerStream::kAborted) { 583 last_access_unit.status != DemuxerStream::kAborted) {
506 RequestData(base::Closure()); 584 RequestData(base::Closure());
507 } 585 }
508 } 586 }
509 587
510 void MediaDecoderJob::InitializeReceivedData() { 588 void MediaDecoderJob::InitializeReceivedData() {
511 for (size_t i = 0; i < 2; ++i) { 589 for (size_t i = 0; i < 2; ++i) {
512 received_data_[i] = DemuxerData(); 590 received_data_[i] = DemuxerData();
513 access_unit_index_[i] = 0; 591 access_unit_index_[i] = 0;
514 } 592 }
515 } 593 }
516 594
595 void MediaDecoderJob::OnDecoderDrained() {
596 DVLOG(1) << __FUNCTION__;
597 DCHECK(ui_task_runner_->BelongsToCurrentThread());
598 DCHECK(drain_decoder_);
599
600 input_eos_encountered_ = false;
601 output_eos_encountered_ = false;
602 drain_decoder_ = false;
603 ReleaseMediaCodecBridge();
604 // Increase the access unit index so that the new decoder will not handle
605 // the config change again.
606 access_unit_index_[current_demuxer_data_index_]++;
607 CurrentDataConsumed(true);
608 }
609
610 bool MediaDecoderJob::CreateMediaCodecBridge() {
611 DVLOG(1) << __FUNCTION__;
612 DCHECK(ui_task_runner_->BelongsToCurrentThread());
613 DCHECK(decode_cb_.is_null());
614
615 if (!HasStream()) {
616 ReleaseMediaCodecBridge();
617 return false;
618 }
619
620 // Create |media_codec_bridge_| only if config changes.
621 if (media_codec_bridge_ && !need_to_reconfig_decoder_job_)
622 return true;
623
624 base::android::ScopedJavaLocalRef<jobject> media_crypto = GetMediaCrypto();
625 if (is_content_encrypted_ && media_crypto.is_null())
626 return false;
xhwang 2014/05/30 21:58:07 Will this trigger decode error?
qinmin 2014/05/30 23:43:33 for video we won't. Decoding will stall indefinite
xhwang 2014/06/02 23:07:11 I see. So the latest PS will make it consistent fo
qinmin 2014/06/03 00:41:03 Yes, no error will be thrown for both audio and vi
627
628 ReleaseMediaCodecBridge();
629 DVLOG(1) << __FUNCTION__ << " : creating new media codec bridge";
630
631 return CreateMediaCodecBridgeInternal();
632 }
633
634 void MediaDecoderJob::ReleaseMediaCodecBridge() {
635 if (!media_codec_bridge_)
636 return;
637
638 media_codec_bridge_.reset();
639 OnMediaCodecBridgeReleased();
640 }
641
517 } // namespace media 642 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698