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

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, 8 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();
(...skipping 15 matching lines...) Expand all
103 } 109 }
104 110
105 bool 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 true; 140 return true;
121 } 141 }
122 142
123 if (DemuxerStream::kConfigChanged == CurrentAccessUnit().status) {
124 // Clear received data because we need to handle a config change.
125 decode_cb_.Reset();
126 ClearData();
127 return false;
128 }
129
130 DecodeCurrentAccessUnit(start_time_ticks, start_presentation_timestamp); 143 DecodeCurrentAccessUnit(start_time_ticks, start_presentation_timestamp);
131 return true; 144 return true;
132 } 145 }
133 146
134 void MediaDecoderJob::StopDecode() { 147 void MediaDecoderJob::StopDecode() {
135 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 148 DCHECK(ui_task_runner_->BelongsToCurrentThread());
136 DCHECK(is_decoding()); 149 DCHECK(is_decoding());
137 stop_decode_pending_ = true; 150 stop_decode_pending_ = true;
138 } 151 }
139 152
153 bool MediaDecoderJob::OutputEOSReached() const {
154 return !drain_decoder_ && output_eos_encountered_;
155 }
156
140 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());
141 DCHECK(decode_cb_.is_null()); 161 DCHECK(decode_cb_.is_null());
142 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
143 // Do nothing, flush when the next Decode() happens. 172 // Do nothing, flush when the next Decode() happens.
144 needs_flush_ = true; 173 needs_flush_ = true;
145 ClearData();
146 } 174 }
147 175
148 void MediaDecoderJob::BeginPrerolling(base::TimeDelta preroll_timestamp) { 176 void MediaDecoderJob::BeginPrerolling(base::TimeDelta preroll_timestamp) {
149 DVLOG(1) << __FUNCTION__ << "(" << preroll_timestamp.InSecondsF() << ")"; 177 DVLOG(1) << __FUNCTION__ << "(" << preroll_timestamp.InSecondsF() << ")";
150 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 178 DCHECK(ui_task_runner_->BelongsToCurrentThread());
151 DCHECK(!is_decoding()); 179 DCHECK(!is_decoding());
152 180
153 preroll_timestamp_ = preroll_timestamp; 181 preroll_timestamp_ = preroll_timestamp;
154 prerolling_ = true; 182 prerolling_ = true;
155 } 183 }
156 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
157 void MediaDecoderJob::Release() { 214 void MediaDecoderJob::Release() {
158 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 215 DCHECK(ui_task_runner_->BelongsToCurrentThread());
159 DVLOG(1) << __FUNCTION__; 216 DVLOG(1) << __FUNCTION__;
160 217
161 // 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.
162 // cannot delete the job immediately. 219 destroy_pending_ = is_decoding();
163 destroy_pending_ = on_data_received_cb_.is_null() && is_decoding();
164 220
165 request_data_cb_.Reset(); 221 request_data_cb_.Reset();
166 on_data_received_cb_.Reset(); 222 on_data_received_cb_.Reset();
167 decode_cb_.Reset(); 223 decode_cb_.Reset();
168 224
169 if (destroy_pending_) { 225 if (destroy_pending_) {
170 DVLOG(1) << __FUNCTION__ << " : delete is pending decode completion"; 226 DVLOG(1) << __FUNCTION__ << " : delete is pending decode completion";
171 return; 227 return;
172 } 228 }
173 229
174 delete this; 230 delete this;
175 } 231 }
176 232
177 MediaCodecStatus MediaDecoderJob::QueueInputBuffer(const AccessUnit& unit) { 233 MediaCodecStatus MediaDecoderJob::QueueInputBuffer(
234 const AccessUnit& unit, bool drain_decoder) {
178 DVLOG(1) << __FUNCTION__; 235 DVLOG(1) << __FUNCTION__;
179 DCHECK(decoder_task_runner_->BelongsToCurrentThread()); 236 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
180 TRACE_EVENT0("media", __FUNCTION__); 237 TRACE_EVENT0("media", __FUNCTION__);
181 238
182 int input_buf_index = input_buf_index_; 239 int input_buf_index = input_buf_index_;
183 input_buf_index_ = -1; 240 input_buf_index_ = -1;
184 241
185 // TODO(xhwang): Hide DequeueInputBuffer() and the index in MediaCodecBridge. 242 // TODO(xhwang): Hide DequeueInputBuffer() and the index in MediaCodecBridge.
186 if (input_buf_index == -1) { 243 if (input_buf_index == -1) {
187 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds( 244 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(
188 kMediaCodecTimeoutInMilliseconds); 245 kMediaCodecTimeoutInMilliseconds);
189 MediaCodecStatus status = 246 MediaCodecStatus status =
190 media_codec_bridge_->DequeueInputBuffer(timeout, &input_buf_index); 247 media_codec_bridge_->DequeueInputBuffer(timeout, &input_buf_index);
191 if (status != MEDIA_CODEC_OK) { 248 if (status != MEDIA_CODEC_OK) {
192 DVLOG(1) << "DequeueInputBuffer fails: " << status; 249 DVLOG(1) << "DequeueInputBuffer fails: " << status;
193 return status; 250 return status;
194 } 251 }
195 } 252 }
196 253
197 // TODO(qinmin): skip frames if video is falling far behind. 254 // TODO(qinmin): skip frames if video is falling far behind.
198 DCHECK_GE(input_buf_index, 0); 255 DCHECK_GE(input_buf_index, 0);
199 if (unit.end_of_stream || unit.data.empty()) { 256 if (unit.end_of_stream || unit.data.empty()) {
200 media_codec_bridge_->QueueEOS(input_buf_index); 257 media_codec_bridge_->QueueEOS(input_buf_index);
201 return MEDIA_CODEC_INPUT_END_OF_STREAM; 258 return MEDIA_CODEC_INPUT_END_OF_STREAM;
202 } 259 }
203 260
204 if (unit.key_id.empty() || unit.iv.empty()) { 261 if (drain_decoder || unit.key_id.empty() || unit.iv.empty()) {
205 DCHECK(unit.iv.empty() || !unit.key_id.empty()); 262 DCHECK(unit.iv.empty() || !unit.key_id.empty());
206 return media_codec_bridge_->QueueInputBuffer( 263 return media_codec_bridge_->QueueInputBuffer(
207 input_buf_index, &unit.data[0], unit.data.size(), unit.timestamp); 264 input_buf_index, &unit.data[0], unit.data.size(), unit.timestamp);
208 } 265 }
209 266
210 MediaCodecStatus status = media_codec_bridge_->QueueSecureInputBuffer( 267 MediaCodecStatus status = media_codec_bridge_->QueueSecureInputBuffer(
211 input_buf_index, 268 input_buf_index,
212 &unit.data[0], unit.data.size(), 269 &unit.data[0], unit.data.size(),
213 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(),
214 reinterpret_cast<const uint8*>(&unit.iv[0]), unit.iv.size(), 271 reinterpret_cast<const uint8*>(&unit.iv[0]), unit.iv.size(),
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 316
260 request_data_cb_.Run(); 317 request_data_cb_.Run();
261 } 318 }
262 319
263 void MediaDecoderJob::DecodeCurrentAccessUnit( 320 void MediaDecoderJob::DecodeCurrentAccessUnit(
264 base::TimeTicks start_time_ticks, 321 base::TimeTicks start_time_ticks,
265 base::TimeDelta start_presentation_timestamp) { 322 base::TimeDelta start_presentation_timestamp) {
266 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 323 DCHECK(ui_task_runner_->BelongsToCurrentThread());
267 DCHECK(!decode_cb_.is_null()); 324 DCHECK(!decode_cb_.is_null());
268 325
326
269 RequestCurrentChunkIfEmpty(); 327 RequestCurrentChunkIfEmpty();
270 const AccessUnit& access_unit = CurrentAccessUnit(); 328 const AccessUnit& access_unit = CurrentAccessUnit();
271 // If the first access unit is a config change, request the player to dequeue 329 if (CurrentAccessUnit().status == DemuxerStream::kConfigChanged) {
272 // the input buffer again so that it can request config data. 330 int index = NoAccessUnitsRemainingInChunk(true) ?
273 if (access_unit.status == DemuxerStream::kConfigChanged) { 331 inactive_demuxer_data_index() : current_demuxer_data_index_;
274 ui_task_runner_->PostTask(FROM_HERE, 332 bool config_changed = SetDemuxerConfigs(
275 base::Bind(&MediaDecoderJob::OnDecodeCompleted, 333 received_data_[index].demuxer_configs[0]);
276 base::Unretained(this), 334 if (config_changed)
277 MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER, 335 on_demuxer_config_changed_cb_.Run();
278 kNoTimestamp(), kNoTimestamp())); 336 if (!drain_decoder_) {
279 return; 337 // If we haven't decoded any data yet, just skip the current access unit
338 // and request the MediaCodec to be recreated on next Decode().
339 if (skip_eos_enqueue_ || !config_changed) {
340 need_to_reconfig_decoder_job_ =
341 need_to_reconfig_decoder_job_ || config_changed;
342 ui_task_runner_->PostTask(FROM_HERE, base::Bind(
343 &MediaDecoderJob::OnDecodeCompleted, base::Unretained(this),
344 MEDIA_CODEC_OUTPUT_FORMAT_CHANGED, kNoTimestamp(), kNoTimestamp()));
345 return;
346 }
347 // Start draining the decoder so that all the remaining frames are
348 // rendered.
349 drain_decoder_ = true;
350 }
280 } 351 }
281 352
282 decoder_task_runner_->PostTask(FROM_HERE, base::Bind( 353 decoder_task_runner_->PostTask(FROM_HERE, base::Bind(
283 &MediaDecoderJob::DecodeInternal, base::Unretained(this), 354 &MediaDecoderJob::DecodeInternal, base::Unretained(this),
284 access_unit, 355 access_unit,
285 start_time_ticks, start_presentation_timestamp, needs_flush_, 356 start_time_ticks, start_presentation_timestamp, needs_flush_,
357 drain_decoder_,
286 media::BindToCurrentLoop(base::Bind( 358 media::BindToCurrentLoop(base::Bind(
287 &MediaDecoderJob::OnDecodeCompleted, base::Unretained(this))))); 359 &MediaDecoderJob::OnDecodeCompleted, base::Unretained(this)))));
288 needs_flush_ = false; 360 needs_flush_ = false;
289 } 361 }
290 362
291 void MediaDecoderJob::DecodeInternal( 363 void MediaDecoderJob::DecodeInternal(
292 const AccessUnit& unit, 364 const AccessUnit& unit,
293 base::TimeTicks start_time_ticks, 365 base::TimeTicks start_time_ticks,
294 base::TimeDelta start_presentation_timestamp, 366 base::TimeDelta start_presentation_timestamp,
295 bool needs_flush, 367 bool needs_flush,
368 bool drain_decoder,
296 const MediaDecoderJob::DecoderCallback& callback) { 369 const MediaDecoderJob::DecoderCallback& callback) {
297 DVLOG(1) << __FUNCTION__; 370 DVLOG(1) << __FUNCTION__;
298 DCHECK(decoder_task_runner_->BelongsToCurrentThread()); 371 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
299 TRACE_EVENT0("media", __FUNCTION__); 372 TRACE_EVENT0("media", __FUNCTION__);
300 373
301 if (needs_flush) { 374 if (needs_flush) {
302 DVLOG(1) << "DecodeInternal needs flush."; 375 DVLOG(1) << "DecodeInternal needs flush.";
303 input_eos_encountered_ = false; 376 input_eos_encountered_ = false;
304 output_eos_encountered_ = false; 377 output_eos_encountered_ = false;
305 MediaCodecStatus reset_status = media_codec_bridge_->Reset(); 378 MediaCodecStatus reset_status = media_codec_bridge_->Reset();
(...skipping 22 matching lines...) Expand all
328 callback.Run(MEDIA_CODEC_OUTPUT_END_OF_STREAM, kNoTimestamp(), 401 callback.Run(MEDIA_CODEC_OUTPUT_END_OF_STREAM, kNoTimestamp(),
329 kNoTimestamp()); 402 kNoTimestamp());
330 return; 403 return;
331 } 404 }
332 405
333 skip_eos_enqueue_ = false; 406 skip_eos_enqueue_ = false;
334 } 407 }
335 408
336 MediaCodecStatus input_status = MEDIA_CODEC_INPUT_END_OF_STREAM; 409 MediaCodecStatus input_status = MEDIA_CODEC_INPUT_END_OF_STREAM;
337 if (!input_eos_encountered_) { 410 if (!input_eos_encountered_) {
338 input_status = QueueInputBuffer(unit); 411 input_status = QueueInputBuffer(unit, drain_decoder);
339 if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) { 412 if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) {
340 input_eos_encountered_ = true; 413 input_eos_encountered_ = true;
341 } else if (input_status != MEDIA_CODEC_OK) { 414 } else if (input_status != MEDIA_CODEC_OK) {
342 callback.Run(input_status, kNoTimestamp(), kNoTimestamp()); 415 callback.Run(input_status, kNoTimestamp(), kNoTimestamp());
343 return; 416 return;
344 } 417 }
345 } 418 }
346 419
347 int buffer_index = 0; 420 int buffer_index = 0;
348 size_t offset = 0; 421 size_t offset = 0;
(...skipping 18 matching lines...) Expand all
367 status = MEDIA_CODEC_ERROR; 440 status = MEDIA_CODEC_ERROR;
368 } 441 }
369 callback.Run(status, kNoTimestamp(), kNoTimestamp()); 442 callback.Run(status, kNoTimestamp(), kNoTimestamp());
370 return; 443 return;
371 } 444 }
372 445
373 // TODO(xhwang/qinmin): This logic is correct but strange. Clean it up. 446 // TODO(xhwang/qinmin): This logic is correct but strange. Clean it up.
374 if (output_eos_encountered_) 447 if (output_eos_encountered_)
375 status = MEDIA_CODEC_OUTPUT_END_OF_STREAM; 448 status = MEDIA_CODEC_OUTPUT_END_OF_STREAM;
376 else if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) 449 else if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM)
377 status = MEDIA_CODEC_INPUT_END_OF_STREAM; 450 status = drain_decoder ? MEDIA_CODEC_OK : MEDIA_CODEC_INPUT_END_OF_STREAM;
378 451
379 bool render_output = presentation_timestamp >= preroll_timestamp_ && 452 bool render_output = presentation_timestamp >= preroll_timestamp_ &&
380 (status != MEDIA_CODEC_OUTPUT_END_OF_STREAM || size != 0u); 453 (status != MEDIA_CODEC_OUTPUT_END_OF_STREAM || size != 0u);
381 base::TimeDelta time_to_render; 454 base::TimeDelta time_to_render;
382 DCHECK(!start_time_ticks.is_null()); 455 DCHECK(!start_time_ticks.is_null());
383 if (render_output && ComputeTimeToRender()) { 456 if (render_output && ComputeTimeToRender()) {
384 time_to_render = presentation_timestamp - (base::TimeTicks::Now() - 457 time_to_render = presentation_timestamp - (base::TimeTicks::Now() -
385 start_time_ticks + start_presentation_timestamp); 458 start_time_ticks + start_presentation_timestamp);
386 } 459 }
387 460
388 if (time_to_render > base::TimeDelta()) { 461 if (time_to_render > base::TimeDelta()) {
389 decoder_task_runner_->PostDelayedTask( 462 decoder_task_runner_->PostDelayedTask(
390 FROM_HERE, 463 FROM_HERE,
391 base::Bind(&MediaDecoderJob::ReleaseOutputBuffer, 464 base::Bind(&MediaDecoderJob::ReleaseOutputBuffer,
392 weak_factory_.GetWeakPtr(), 465 base::Unretained(this),
393 buffer_index, 466 buffer_index,
394 size, 467 size,
395 render_output, 468 render_output,
396 presentation_timestamp, 469 presentation_timestamp,
397 base::Bind(callback, status)), 470 base::Bind(callback, status)),
398 time_to_render); 471 time_to_render);
399 return; 472 return;
400 } 473 }
401 474
402 // TODO(qinmin): The codec is lagging behind, need to recalculate the 475 // TODO(qinmin): The codec is lagging behind, need to recalculate the
(...skipping 12 matching lines...) Expand all
415 ReleaseOutputCompletionCallback completion_callback = base::Bind( 488 ReleaseOutputCompletionCallback completion_callback = base::Bind(
416 callback, status); 489 callback, status);
417 ReleaseOutputBuffer(buffer_index, size, render_output, presentation_timestamp, 490 ReleaseOutputBuffer(buffer_index, size, render_output, presentation_timestamp,
418 completion_callback); 491 completion_callback);
419 } 492 }
420 493
421 void MediaDecoderJob::OnDecodeCompleted( 494 void MediaDecoderJob::OnDecodeCompleted(
422 MediaCodecStatus status, base::TimeDelta current_presentation_timestamp, 495 MediaCodecStatus status, base::TimeDelta current_presentation_timestamp,
423 base::TimeDelta max_presentation_timestamp) { 496 base::TimeDelta max_presentation_timestamp) {
424 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 497 DCHECK(ui_task_runner_->BelongsToCurrentThread());
425
426 if (destroy_pending_) { 498 if (destroy_pending_) {
427 DVLOG(1) << __FUNCTION__ << " : completing pending deletion"; 499 DVLOG(1) << __FUNCTION__ << " : completing pending deletion";
428 delete this; 500 delete this;
429 return; 501 return;
430 } 502 }
431 503
504 if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM) {
505 output_eos_encountered_ = true;
506 }
507
432 DCHECK(!decode_cb_.is_null()); 508 DCHECK(!decode_cb_.is_null());
433 509
434 // If output was queued for rendering, then we have completed prerolling. 510 // If output was queued for rendering, then we have completed prerolling.
435 if (current_presentation_timestamp != kNoTimestamp()) 511 if (current_presentation_timestamp != kNoTimestamp())
436 prerolling_ = false; 512 prerolling_ = false;
437 513
438 switch (status) { 514 switch (status) {
439 case MEDIA_CODEC_OK: 515 case MEDIA_CODEC_OK:
440 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER: 516 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER:
441 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: 517 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED:
442 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: 518 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED:
443 case MEDIA_CODEC_OUTPUT_END_OF_STREAM: 519 case MEDIA_CODEC_OUTPUT_END_OF_STREAM:
444 if (!input_eos_encountered_) 520 if (!input_eos_encountered_) {
521 CurrentDataConsumed(
522 CurrentAccessUnit().status == DemuxerStream::kConfigChanged);
445 access_unit_index_[current_demuxer_data_index_]++; 523 access_unit_index_[current_demuxer_data_index_]++;
524 }
446 break; 525 break;
447 526
448 case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER: 527 case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER:
449 case MEDIA_CODEC_INPUT_END_OF_STREAM: 528 case MEDIA_CODEC_INPUT_END_OF_STREAM:
450 case MEDIA_CODEC_NO_KEY: 529 case MEDIA_CODEC_NO_KEY:
451 case MEDIA_CODEC_STOPPED: 530 case MEDIA_CODEC_STOPPED:
452 case MEDIA_CODEC_ERROR: 531 case MEDIA_CODEC_ERROR:
453 // Do nothing. 532 // Do nothing.
454 break; 533 break;
455 }; 534 };
456 535
536 if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM && drain_decoder_) {
537 OnDecoderDrained();
538 status = MEDIA_CODEC_OK;
539 }
540
541 if (release_resources_pending_) {
542 ReleaseMediaCodecBridge();
543 release_resources_pending_ = false;
544 if (drain_decoder_)
545 OnDecoderDrained();
546 }
547
457 stop_decode_pending_ = false; 548 stop_decode_pending_ = false;
458 base::ResetAndReturn(&decode_cb_).Run( 549 base::ResetAndReturn(&decode_cb_).Run(
459 status, current_presentation_timestamp, max_presentation_timestamp); 550 status, current_presentation_timestamp, max_presentation_timestamp);
460 } 551 }
461 552
462 const AccessUnit& MediaDecoderJob::CurrentAccessUnit() const { 553 const AccessUnit& MediaDecoderJob::CurrentAccessUnit() const {
463 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 554 DCHECK(ui_task_runner_->BelongsToCurrentThread());
464 DCHECK(HasData()); 555 DCHECK(HasData());
465 int index = NoAccessUnitsRemainingInChunk(true) ? 556 int index = NoAccessUnitsRemainingInChunk(true) ?
466 inactive_demuxer_data_index() : current_demuxer_data_index_; 557 inactive_demuxer_data_index() : current_demuxer_data_index_;
467 return received_data_[index].access_units[access_unit_index_[index]]; 558 return received_data_[index].access_units[access_unit_index_[index]];
468 } 559 }
469 560
470 bool MediaDecoderJob::NoAccessUnitsRemainingInChunk( 561 bool MediaDecoderJob::NoAccessUnitsRemainingInChunk(
471 bool is_active_chunk) const { 562 bool is_active_chunk) const {
472 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 563 DCHECK(ui_task_runner_->BelongsToCurrentThread());
473 size_t index = is_active_chunk ? current_demuxer_data_index_ : 564 size_t index = is_active_chunk ? current_demuxer_data_index_ :
474 inactive_demuxer_data_index(); 565 inactive_demuxer_data_index();
475 return received_data_[index].access_units.size() <= access_unit_index_[index]; 566 return received_data_[index].access_units.size() <= access_unit_index_[index];
476 } 567 }
477 568
478 void MediaDecoderJob::ClearData() {
479 DCHECK(ui_task_runner_->BelongsToCurrentThread());
480 current_demuxer_data_index_ = 0;
481 InitializeReceivedData();
482 on_data_received_cb_.Reset();
483 if (is_requesting_demuxer_data_)
484 is_incoming_data_invalid_ = true;
485 input_eos_encountered_ = false;
486 }
487
488 void MediaDecoderJob::RequestCurrentChunkIfEmpty() { 569 void MediaDecoderJob::RequestCurrentChunkIfEmpty() {
489 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 570 DCHECK(ui_task_runner_->BelongsToCurrentThread());
490 DCHECK(HasData()); 571 DCHECK(HasData());
491 if (!NoAccessUnitsRemainingInChunk(true)) 572 if (!NoAccessUnitsRemainingInChunk(true))
492 return; 573 return;
493 574
494 // Requests new data if the the last access unit of the next chunk is not EOS. 575 // Requests new data if the the last access unit of the next chunk is not EOS.
495 current_demuxer_data_index_ = inactive_demuxer_data_index(); 576 current_demuxer_data_index_ = inactive_demuxer_data_index();
496 const AccessUnit last_access_unit = 577 const AccessUnit last_access_unit =
497 received_data_[current_demuxer_data_index_].access_units.back(); 578 received_data_[current_demuxer_data_index_].access_units.back();
498 if (!last_access_unit.end_of_stream && 579 if (!last_access_unit.end_of_stream &&
499 last_access_unit.status != DemuxerStream::kConfigChanged &&
500 last_access_unit.status != DemuxerStream::kAborted) { 580 last_access_unit.status != DemuxerStream::kAborted) {
501 RequestData(base::Closure()); 581 RequestData(base::Closure());
502 } 582 }
503 } 583 }
504 584
505 void MediaDecoderJob::InitializeReceivedData() { 585 void MediaDecoderJob::InitializeReceivedData() {
506 for (size_t i = 0; i < 2; ++i) { 586 for (size_t i = 0; i < 2; ++i) {
507 received_data_[i] = DemuxerData(); 587 received_data_[i] = DemuxerData();
508 access_unit_index_[i] = 0; 588 access_unit_index_[i] = 0;
509 } 589 }
510 } 590 }
511 591
592 void MediaDecoderJob::OnDecoderDrained() {
593 DVLOG(1) << __FUNCTION__;
594 DCHECK(ui_task_runner_->BelongsToCurrentThread());
595 DCHECK(drain_decoder_);
596
597 input_eos_encountered_ = false;
598 output_eos_encountered_ = false;
599 drain_decoder_ = false;
600 ReleaseMediaCodecBridge();
601 // Increase the access unit index so that the new decoder will not handle
602 // the config change again.
603 access_unit_index_[current_demuxer_data_index_]++;
604 CurrentDataConsumed(true);
605 }
606
607 bool MediaDecoderJob::CreateMediaCodecBridge() {
608 DVLOG(1) << __FUNCTION__;
609 DCHECK(ui_task_runner_->BelongsToCurrentThread());
610 DCHECK(decode_cb_.is_null());
611
612 if (!HasStream()) {
613 ReleaseMediaCodecBridge();
614 return false;
615 }
616
617 // Create |media_codec_bridge_| only if config changes.
618 if (media_codec_bridge_ && !need_to_reconfig_decoder_job_)
619 return true;
620
621 base::android::ScopedJavaLocalRef<jobject> media_crypto = GetMediaCrypto();
622 if (is_content_encrypted_ && media_crypto.is_null())
623 return false;
624
625 ReleaseMediaCodecBridge();
626 DVLOG(1) << __FUNCTION__ << " : creating new media codec bridge";
627
628 return CreateMediaCodecBridgeInternal();
629 }
630
631 void MediaDecoderJob::ReleaseMediaCodecBridge() {
632 if (!media_codec_bridge_)
633 return;
634
635 media_codec_bridge_.reset();
636 OnMediaCodecBridgeReleased();
637 }
638
512 } // namespace media 639 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698