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

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: passing an EOS access unit during config change 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& 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 config_changed_cb_(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();
47 eos_unit_.end_of_stream = true;
43 } 48 }
44 49
45 MediaDecoderJob::~MediaDecoderJob() {} 50 MediaDecoderJob::~MediaDecoderJob() {
51 ReleaseMediaCodecBridge();
52 }
46 53
47 void MediaDecoderJob::OnDataReceived(const DemuxerData& data) { 54 void MediaDecoderJob::OnDataReceived(const DemuxerData& data) {
48 DVLOG(1) << __FUNCTION__ << ": " << data.access_units.size() << " units"; 55 DVLOG(1) << __FUNCTION__ << ": " << data.access_units.size() << " units";
49 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 56 DCHECK(ui_task_runner_->BelongsToCurrentThread());
50 DCHECK(NoAccessUnitsRemainingInChunk(false)); 57 DCHECK(NoAccessUnitsRemainingInChunk(false));
51 58
52 TRACE_EVENT_ASYNC_END2( 59 TRACE_EVENT_ASYNC_END2(
53 "media", "MediaDecoderJob::RequestData", this, 60 "media", "MediaDecoderJob::RequestData", this,
54 "Data type", data.type == media::DemuxerStream::AUDIO ? "AUDIO" : "VIDEO", 61 "Data type", data.type == media::DemuxerStream::AUDIO ? "AUDIO" : "VIDEO",
55 "Units read", data.access_units.size()); 62 "Units read", data.access_units.size());
56 63
57 if (is_incoming_data_invalid_) { 64 if (is_incoming_data_invalid_) {
58 is_incoming_data_invalid_ = false; 65 is_incoming_data_invalid_ = false;
59 66
60 // If there is a pending callback, need to request the data again to get 67 // If there is a pending callback, need to request the data again to get
61 // valid data. 68 // valid data.
62 if (!on_data_received_cb_.is_null()) 69 if (!data_received_cb_.is_null())
63 request_data_cb_.Run(); 70 request_data_cb_.Run();
64 else 71 else
65 is_requesting_demuxer_data_ = false; 72 is_requesting_demuxer_data_ = false;
66 return; 73 return;
67 } 74 }
68 75
69 size_t next_demuxer_data_index = inactive_demuxer_data_index(); 76 size_t next_demuxer_data_index = inactive_demuxer_data_index();
70 received_data_[next_demuxer_data_index] = data; 77 received_data_[next_demuxer_data_index] = data;
71 access_unit_index_[next_demuxer_data_index] = 0; 78 access_unit_index_[next_demuxer_data_index] = 0;
72 is_requesting_demuxer_data_ = false; 79 is_requesting_demuxer_data_ = false;
73 80
74 base::Closure done_cb = base::ResetAndReturn(&on_data_received_cb_); 81 base::Closure done_cb = base::ResetAndReturn(&data_received_cb_);
75 82
76 // If this data request is for the inactive chunk, or |on_data_received_cb_| 83 // If this data request is for the inactive chunk, or |data_received_cb_|
77 // was set to null by ClearData() or Release(), do nothing. 84 // was set to null by Flush() or Release(), do nothing.
78 if (done_cb.is_null()) 85 if (done_cb.is_null())
79 return; 86 return;
80 87
81 if (stop_decode_pending_) { 88 if (stop_decode_pending_) {
82 DCHECK(is_decoding()); 89 DCHECK(is_decoding());
83 OnDecodeCompleted(MEDIA_CODEC_STOPPED, kNoTimestamp(), kNoTimestamp()); 90 OnDecodeCompleted(MEDIA_CODEC_STOPPED, kNoTimestamp(), kNoTimestamp());
84 return; 91 return;
85 } 92 }
86 93
87 done_cb.Run(); 94 done_cb.Run();
88 } 95 }
89 96
90 void MediaDecoderJob::Prefetch(const base::Closure& prefetch_cb) { 97 void MediaDecoderJob::Prefetch(const base::Closure& prefetch_cb) {
91 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 98 DCHECK(ui_task_runner_->BelongsToCurrentThread());
92 DCHECK(on_data_received_cb_.is_null()); 99 DCHECK(data_received_cb_.is_null());
93 DCHECK(decode_cb_.is_null()); 100 DCHECK(decode_cb_.is_null());
94 101
95 if (HasData()) { 102 if (HasData()) {
96 DVLOG(1) << __FUNCTION__ << " : using previously received data"; 103 DVLOG(1) << __FUNCTION__ << " : using previously received data";
97 ui_task_runner_->PostTask(FROM_HERE, prefetch_cb); 104 ui_task_runner_->PostTask(FROM_HERE, prefetch_cb);
98 return; 105 return;
99 } 106 }
100 107
101 DVLOG(1) << __FUNCTION__ << " : requesting data"; 108 DVLOG(1) << __FUNCTION__ << " : requesting data";
102 RequestData(prefetch_cb); 109 RequestData(prefetch_cb);
103 } 110 }
104 111
105 scoped_ptr<DemuxerConfigs> MediaDecoderJob::Decode( 112 bool MediaDecoderJob::Decode(
106 base::TimeTicks start_time_ticks, 113 base::TimeTicks start_time_ticks,
107 base::TimeDelta start_presentation_timestamp, 114 base::TimeDelta start_presentation_timestamp,
108 const DecoderCallback& callback) { 115 const DecoderCallback& callback) {
109 DCHECK(decode_cb_.is_null()); 116 DCHECK(decode_cb_.is_null());
110 DCHECK(on_data_received_cb_.is_null()); 117 DCHECK(data_received_cb_.is_null());
111 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 118 DCHECK(ui_task_runner_->BelongsToCurrentThread());
112 119
120 if (!media_codec_bridge_ || need_to_reconfig_decoder_job_) {
121 need_to_reconfig_decoder_job_ = !CreateMediaCodecBridge();
122 if (drain_decoder_) {
123 // Decoder has been recreated, stop draining.
124 drain_decoder_ = false;
125 input_eos_encountered_ = false;
126 output_eos_encountered_ = false;
127 access_unit_index_[current_demuxer_data_index_]++;
128 }
129 skip_eos_enqueue_ = true;
130 if (need_to_reconfig_decoder_job_)
131 return false;
132 }
133
113 decode_cb_ = callback; 134 decode_cb_ = callback;
114 135
115 if (!HasData()) { 136 if (!HasData()) {
116 RequestData(base::Bind(&MediaDecoderJob::DecodeCurrentAccessUnit, 137 RequestData(base::Bind(&MediaDecoderJob::DecodeCurrentAccessUnit,
117 base::Unretained(this), 138 base::Unretained(this),
118 start_time_ticks, 139 start_time_ticks,
119 start_presentation_timestamp)); 140 start_presentation_timestamp));
120 return scoped_ptr<DemuxerConfigs>(); 141 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 } 142 }
130 143
131 DecodeCurrentAccessUnit(start_time_ticks, start_presentation_timestamp); 144 DecodeCurrentAccessUnit(start_time_ticks, start_presentation_timestamp);
132 return scoped_ptr<DemuxerConfigs>(); 145 return true;
133 } 146 }
134 147
135 void MediaDecoderJob::StopDecode() { 148 void MediaDecoderJob::StopDecode() {
136 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 149 DCHECK(ui_task_runner_->BelongsToCurrentThread());
137 DCHECK(is_decoding()); 150 DCHECK(is_decoding());
138 stop_decode_pending_ = true; 151 stop_decode_pending_ = true;
139 } 152 }
140 153
154 bool MediaDecoderJob::OutputEOSReached() const {
155 return !drain_decoder_ && output_eos_encountered_;
156 }
157
158 void MediaDecoderJob::SetDrmBridge(MediaDrmBridge* drm_bridge) {
159 drm_bridge_ = drm_bridge;
160 need_to_reconfig_decoder_job_ = true;
161 }
162
141 void MediaDecoderJob::Flush() { 163 void MediaDecoderJob::Flush() {
164 DVLOG(1) << __FUNCTION__;
165 DCHECK(ui_task_runner_->BelongsToCurrentThread());
166 DCHECK(data_received_cb_.is_null());
142 DCHECK(decode_cb_.is_null()); 167 DCHECK(decode_cb_.is_null());
143 168
169 // Clean up the received data.
170 current_demuxer_data_index_ = 0;
171 InitializeReceivedData();
172 if (is_requesting_demuxer_data_)
173 is_incoming_data_invalid_ = true;
174 input_eos_encountered_ = false;
175 output_eos_encountered_ = false;
176 drain_decoder_ = false;
177
144 // Do nothing, flush when the next Decode() happens. 178 // Do nothing, flush when the next Decode() happens.
145 needs_flush_ = true; 179 needs_flush_ = true;
146 ClearData();
147 } 180 }
148 181
149 void MediaDecoderJob::BeginPrerolling(base::TimeDelta preroll_timestamp) { 182 void MediaDecoderJob::BeginPrerolling(base::TimeDelta preroll_timestamp) {
150 DVLOG(1) << __FUNCTION__ << "(" << preroll_timestamp.InSecondsF() << ")"; 183 DVLOG(1) << __FUNCTION__ << "(" << preroll_timestamp.InSecondsF() << ")";
151 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 184 DCHECK(ui_task_runner_->BelongsToCurrentThread());
152 DCHECK(!is_decoding()); 185 DCHECK(!is_decoding());
153 186
154 preroll_timestamp_ = preroll_timestamp; 187 preroll_timestamp_ = preroll_timestamp;
155 prerolling_ = true; 188 prerolling_ = true;
156 } 189 }
157 190
191 void MediaDecoderJob::ReleaseDecoderResources() {
192 DVLOG(1) << __FUNCTION__;
193 DCHECK(ui_task_runner_->BelongsToCurrentThread());
194 if (decode_cb_.is_null()) {
195 DCHECK(!drain_decoder_);
196 // Since the decoder job is not decoding data, we can safely destroy
197 // |media_codec_bridge_|.
198 ReleaseMediaCodecBridge();
199 return;
200 }
201
202 // Release |media_codec_bridge_| once decoding is completed.
203 release_resources_pending_ = true;
204 }
205
206 bool MediaDecoderJob::SetDemuxerConfigs(const DemuxerConfigs& configs) {
207 bool config_changed = AreDemuxerConfigsChanged(configs);
208 if (config_changed)
209 UpdateDemuxerConfigs(configs);
210 return config_changed;
211 }
212
213 base::android::ScopedJavaLocalRef<jobject> MediaDecoderJob::GetMediaCrypto() {
214 base::android::ScopedJavaLocalRef<jobject> media_crypto;
215 if (drm_bridge_)
216 media_crypto = drm_bridge_->GetMediaCrypto();
217 return media_crypto;
218 }
219
158 void MediaDecoderJob::Release() { 220 void MediaDecoderJob::Release() {
159 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 221 DCHECK(ui_task_runner_->BelongsToCurrentThread());
160 DVLOG(1) << __FUNCTION__; 222 DVLOG(1) << __FUNCTION__;
161 223
162 // If the decoder job is not waiting for data, and is still decoding, we 224 // If the decoder job is still decoding, we cannot delete the job immediately.
163 // cannot delete the job immediately. 225 destroy_pending_ = is_decoding();
164 destroy_pending_ = on_data_received_cb_.is_null() && is_decoding();
165 226
166 request_data_cb_.Reset(); 227 request_data_cb_.Reset();
167 on_data_received_cb_.Reset(); 228 data_received_cb_.Reset();
168 decode_cb_.Reset(); 229 decode_cb_.Reset();
169 230
170 if (destroy_pending_) { 231 if (destroy_pending_) {
171 DVLOG(1) << __FUNCTION__ << " : delete is pending decode completion"; 232 DVLOG(1) << __FUNCTION__ << " : delete is pending decode completion";
172 return; 233 return;
173 } 234 }
174 235
175 delete this; 236 delete this;
176 } 237 }
177 238
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 // |current_demuxer_data_index_| must be pointing to an EOS unit. 292 // |current_demuxer_data_index_| must be pointing to an EOS unit.
232 // We'll reuse this unit to flush the decoder until we hit output EOS. 293 // We'll reuse this unit to flush the decoder until we hit output EOS.
233 DCHECK(!input_eos_encountered_ || !NoAccessUnitsRemainingInChunk(true)); 294 DCHECK(!input_eos_encountered_ || !NoAccessUnitsRemainingInChunk(true));
234 return !NoAccessUnitsRemainingInChunk(true) || 295 return !NoAccessUnitsRemainingInChunk(true) ||
235 !NoAccessUnitsRemainingInChunk(false); 296 !NoAccessUnitsRemainingInChunk(false);
236 } 297 }
237 298
238 void MediaDecoderJob::RequestData(const base::Closure& done_cb) { 299 void MediaDecoderJob::RequestData(const base::Closure& done_cb) {
239 DVLOG(1) << __FUNCTION__; 300 DVLOG(1) << __FUNCTION__;
240 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 301 DCHECK(ui_task_runner_->BelongsToCurrentThread());
241 DCHECK(on_data_received_cb_.is_null()); 302 DCHECK(data_received_cb_.is_null());
242 DCHECK(!input_eos_encountered_); 303 DCHECK(!input_eos_encountered_);
243 DCHECK(NoAccessUnitsRemainingInChunk(false)); 304 DCHECK(NoAccessUnitsRemainingInChunk(false));
244 305
245 TRACE_EVENT_ASYNC_BEGIN0("media", "MediaDecoderJob::RequestData", this); 306 TRACE_EVENT_ASYNC_BEGIN0("media", "MediaDecoderJob::RequestData", this);
246 307
247 on_data_received_cb_ = done_cb; 308 data_received_cb_ = done_cb;
248 309
249 // If we are already expecting new data, just set the callback and do 310 // If we are already expecting new data, just set the callback and do
250 // nothing. 311 // nothing.
251 if (is_requesting_demuxer_data_) 312 if (is_requesting_demuxer_data_)
252 return; 313 return;
253 314
254 // The new incoming data will be stored as the next demuxer data chunk, since 315 // The new incoming data will be stored as the next demuxer data chunk, since
255 // the decoder might still be decoding the current one. 316 // the decoder might still be decoding the current one.
256 size_t next_demuxer_data_index = inactive_demuxer_data_index(); 317 size_t next_demuxer_data_index = inactive_demuxer_data_index();
257 received_data_[next_demuxer_data_index] = DemuxerData(); 318 received_data_[next_demuxer_data_index] = DemuxerData();
258 access_unit_index_[next_demuxer_data_index] = 0; 319 access_unit_index_[next_demuxer_data_index] = 0;
259 is_requesting_demuxer_data_ = true; 320 is_requesting_demuxer_data_ = true;
260 321
261 request_data_cb_.Run(); 322 request_data_cb_.Run();
262 } 323 }
263 324
264 void MediaDecoderJob::DecodeCurrentAccessUnit( 325 void MediaDecoderJob::DecodeCurrentAccessUnit(
265 base::TimeTicks start_time_ticks, 326 base::TimeTicks start_time_ticks,
266 base::TimeDelta start_presentation_timestamp) { 327 base::TimeDelta start_presentation_timestamp) {
267 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 328 DCHECK(ui_task_runner_->BelongsToCurrentThread());
268 DCHECK(!decode_cb_.is_null()); 329 DCHECK(!decode_cb_.is_null());
269 330
270 RequestCurrentChunkIfEmpty(); 331 RequestCurrentChunkIfEmpty();
271 const AccessUnit& access_unit = CurrentAccessUnit(); 332 const AccessUnit& access_unit = CurrentAccessUnit();
272 // If the first access unit is a config change, request the player to dequeue 333 if (CurrentAccessUnit().status == DemuxerStream::kConfigChanged) {
273 // the input buffer again so that it can request config data. 334 int index = CurrentReceivedDataChunkIndex();
274 if (access_unit.status == DemuxerStream::kConfigChanged) { 335 bool config_changed = SetDemuxerConfigs(
275 ui_task_runner_->PostTask(FROM_HERE, 336 received_data_[index].demuxer_configs[0]);
276 base::Bind(&MediaDecoderJob::OnDecodeCompleted, 337 if (config_changed)
277 base::Unretained(this), 338 config_changed_cb_.Run();
278 MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER, 339 if (!drain_decoder_) {
279 kNoTimestamp(), kNoTimestamp())); 340 // If we haven't decoded any data yet, just skip the current access unit
280 return; 341 // and request the MediaCodec to be recreated on next Decode().
342 if (skip_eos_enqueue_ || !config_changed) {
343 need_to_reconfig_decoder_job_ =
344 need_to_reconfig_decoder_job_ || config_changed;
345 ui_task_runner_->PostTask(FROM_HERE, base::Bind(
346 &MediaDecoderJob::OnDecodeCompleted, base::Unretained(this),
347 MEDIA_CODEC_OUTPUT_FORMAT_CHANGED, kNoTimestamp(), kNoTimestamp()));
348 return;
349 }
350 // Start draining the decoder so that all the remaining frames are
351 // rendered.
352 drain_decoder_ = true;
353 }
281 } 354 }
282 355
283 decoder_task_runner_->PostTask(FROM_HERE, base::Bind( 356 decoder_task_runner_->PostTask(FROM_HERE, base::Bind(
wolenetz 2014/06/04 00:21:46 nit: Before posting task, DCHECK(!(needs_flush_ &&
qinmin 2014/06/04 19:29:15 Done.
284 &MediaDecoderJob::DecodeInternal, base::Unretained(this), 357 &MediaDecoderJob::DecodeInternal, base::Unretained(this),
285 access_unit, 358 drain_decoder_ ? eos_unit_ : access_unit,
286 start_time_ticks, start_presentation_timestamp, needs_flush_, 359 start_time_ticks, start_presentation_timestamp, needs_flush_,
287 media::BindToCurrentLoop(base::Bind( 360 media::BindToCurrentLoop(base::Bind(
288 &MediaDecoderJob::OnDecodeCompleted, base::Unretained(this))))); 361 &MediaDecoderJob::OnDecodeCompleted, base::Unretained(this)))));
289 needs_flush_ = false; 362 needs_flush_ = false;
290 } 363 }
291 364
292 void MediaDecoderJob::DecodeInternal( 365 void MediaDecoderJob::DecodeInternal(
293 const AccessUnit& unit, 366 const AccessUnit& unit,
294 base::TimeTicks start_time_ticks, 367 base::TimeTicks start_time_ticks,
295 base::TimeDelta start_presentation_timestamp, 368 base::TimeDelta start_presentation_timestamp,
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
367 !media_codec_bridge_->GetOutputBuffers()) { 440 !media_codec_bridge_->GetOutputBuffers()) {
368 status = MEDIA_CODEC_ERROR; 441 status = MEDIA_CODEC_ERROR;
369 } 442 }
370 callback.Run(status, kNoTimestamp(), kNoTimestamp()); 443 callback.Run(status, kNoTimestamp(), kNoTimestamp());
371 return; 444 return;
372 } 445 }
373 446
374 // TODO(xhwang/qinmin): This logic is correct but strange. Clean it up. 447 // TODO(xhwang/qinmin): This logic is correct but strange. Clean it up.
375 if (output_eos_encountered_) 448 if (output_eos_encountered_)
376 status = MEDIA_CODEC_OUTPUT_END_OF_STREAM; 449 status = MEDIA_CODEC_OUTPUT_END_OF_STREAM;
377 else if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM)
378 status = 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;
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