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

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: rebase after recent config IPC change Created 6 years, 7 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());
300 TRACE_EVENT0("media", __FUNCTION__); 370 TRACE_EVENT0("media", __FUNCTION__);
301 371
302 if (needs_flush) { 372 if (needs_flush) {
303 DVLOG(1) << "DecodeInternal needs flush."; 373 DVLOG(1) << "DecodeInternal needs flush.";
304 input_eos_encountered_ = false; 374 input_eos_encountered_ = false;
305 output_eos_encountered_ = false; 375 output_eos_encountered_ = false;
306 MediaCodecStatus reset_status = media_codec_bridge_->Reset(); 376 MediaCodecStatus reset_status = media_codec_bridge_->Reset();
(...skipping 22 matching lines...) Expand all
329 callback.Run(MEDIA_CODEC_OUTPUT_END_OF_STREAM, kNoTimestamp(), 399 callback.Run(MEDIA_CODEC_OUTPUT_END_OF_STREAM, kNoTimestamp(),
330 kNoTimestamp()); 400 kNoTimestamp());
331 return; 401 return;
332 } 402 }
333 403
334 skip_eos_enqueue_ = false; 404 skip_eos_enqueue_ = false;
335 } 405 }
336 406
337 MediaCodecStatus input_status = MEDIA_CODEC_INPUT_END_OF_STREAM; 407 MediaCodecStatus input_status = MEDIA_CODEC_INPUT_END_OF_STREAM;
338 if (!input_eos_encountered_) { 408 if (!input_eos_encountered_) {
339 input_status = QueueInputBuffer(unit); 409 input_status = QueueInputBuffer(unit, drain_decoder);
340 if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) { 410 if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) {
341 input_eos_encountered_ = true; 411 input_eos_encountered_ = true;
342 } else if (input_status != MEDIA_CODEC_OK) { 412 } else if (input_status != MEDIA_CODEC_OK) {
343 callback.Run(input_status, kNoTimestamp(), kNoTimestamp()); 413 callback.Run(input_status, kNoTimestamp(), kNoTimestamp());
344 return; 414 return;
345 } 415 }
346 } 416 }
347 417
348 int buffer_index = 0; 418 int buffer_index = 0;
349 size_t offset = 0; 419 size_t offset = 0;
(...skipping 18 matching lines...) Expand all
368 status = MEDIA_CODEC_ERROR; 438 status = MEDIA_CODEC_ERROR;
369 } 439 }
370 callback.Run(status, kNoTimestamp(), kNoTimestamp()); 440 callback.Run(status, kNoTimestamp(), kNoTimestamp());
371 return; 441 return;
372 } 442 }
373 443
374 // TODO(xhwang/qinmin): This logic is correct but strange. Clean it up. 444 // TODO(xhwang/qinmin): This logic is correct but strange. Clean it up.
375 if (output_eos_encountered_) 445 if (output_eos_encountered_)
376 status = MEDIA_CODEC_OUTPUT_END_OF_STREAM; 446 status = MEDIA_CODEC_OUTPUT_END_OF_STREAM;
377 else if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM) 447 else if (input_status == MEDIA_CODEC_INPUT_END_OF_STREAM)
378 status = MEDIA_CODEC_INPUT_END_OF_STREAM; 448 status = drain_decoder ? MEDIA_CODEC_OK : MEDIA_CODEC_INPUT_END_OF_STREAM;
379 449
380 bool render_output = presentation_timestamp >= preroll_timestamp_ && 450 bool render_output = presentation_timestamp >= preroll_timestamp_ &&
381 (status != MEDIA_CODEC_OUTPUT_END_OF_STREAM || size != 0u); 451 (status != MEDIA_CODEC_OUTPUT_END_OF_STREAM || size != 0u);
382 base::TimeDelta time_to_render; 452 base::TimeDelta time_to_render;
383 DCHECK(!start_time_ticks.is_null()); 453 DCHECK(!start_time_ticks.is_null());
384 if (render_output && ComputeTimeToRender()) { 454 if (render_output && ComputeTimeToRender()) {
385 time_to_render = presentation_timestamp - (base::TimeTicks::Now() - 455 time_to_render = presentation_timestamp - (base::TimeTicks::Now() -
386 start_time_ticks + start_presentation_timestamp); 456 start_time_ticks + start_presentation_timestamp);
387 } 457 }
388 458
389 if (time_to_render > base::TimeDelta()) { 459 if (time_to_render > base::TimeDelta()) {
390 decoder_task_runner_->PostDelayedTask( 460 decoder_task_runner_->PostDelayedTask(
391 FROM_HERE, 461 FROM_HERE,
392 base::Bind(&MediaDecoderJob::ReleaseOutputBuffer, 462 base::Bind(&MediaDecoderJob::ReleaseOutputBuffer,
393 weak_factory_.GetWeakPtr(), 463 base::Unretained(this),
394 buffer_index, 464 buffer_index,
395 size, 465 size,
396 render_output, 466 render_output,
397 presentation_timestamp, 467 presentation_timestamp,
398 base::Bind(callback, status)), 468 base::Bind(callback, status)),
399 time_to_render); 469 time_to_render);
400 return; 470 return;
401 } 471 }
402 472
403 // TODO(qinmin): The codec is lagging behind, need to recalculate the 473 // 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, 493 MediaCodecStatus status, base::TimeDelta current_presentation_timestamp,
424 base::TimeDelta max_presentation_timestamp) { 494 base::TimeDelta max_presentation_timestamp) {
425 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 495 DCHECK(ui_task_runner_->BelongsToCurrentThread());
426 496
427 if (destroy_pending_) { 497 if (destroy_pending_) {
428 DVLOG(1) << __FUNCTION__ << " : completing pending deletion"; 498 DVLOG(1) << __FUNCTION__ << " : completing pending deletion";
429 delete this; 499 delete this;
430 return; 500 return;
431 } 501 }
432 502
503 if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM)
504 output_eos_encountered_ = true;
505
433 DCHECK(!decode_cb_.is_null()); 506 DCHECK(!decode_cb_.is_null());
434 507
435 // If output was queued for rendering, then we have completed prerolling. 508 // If output was queued for rendering, then we have completed prerolling.
436 if (current_presentation_timestamp != kNoTimestamp()) 509 if (current_presentation_timestamp != kNoTimestamp())
437 prerolling_ = false; 510 prerolling_ = false;
438 511
439 switch (status) { 512 switch (status) {
440 case MEDIA_CODEC_OK: 513 case MEDIA_CODEC_OK:
441 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER: 514 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER:
442 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: 515 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED:
443 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: 516 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED:
444 case MEDIA_CODEC_OUTPUT_END_OF_STREAM: 517 case MEDIA_CODEC_OUTPUT_END_OF_STREAM:
445 if (!input_eos_encountered_) 518 if (!input_eos_encountered_) {
519 CurrentDataConsumed(
520 CurrentAccessUnit().status == DemuxerStream::kConfigChanged);
446 access_unit_index_[current_demuxer_data_index_]++; 521 access_unit_index_[current_demuxer_data_index_]++;
522 }
447 break; 523 break;
448 524
449 case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER: 525 case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER:
450 case MEDIA_CODEC_INPUT_END_OF_STREAM: 526 case MEDIA_CODEC_INPUT_END_OF_STREAM:
451 case MEDIA_CODEC_NO_KEY: 527 case MEDIA_CODEC_NO_KEY:
452 case MEDIA_CODEC_STOPPED: 528 case MEDIA_CODEC_STOPPED:
453 case MEDIA_CODEC_ERROR: 529 case MEDIA_CODEC_ERROR:
454 // Do nothing. 530 // Do nothing.
455 break; 531 break;
456 }; 532 };
457 533
534 if (status == MEDIA_CODEC_OUTPUT_END_OF_STREAM && drain_decoder_) {
535 OnDecoderDrained();
536 status = MEDIA_CODEC_OK;
537 }
538
539 if (release_resources_pending_) {
wolenetz 2014/05/21 00:48:04 In this case (release_resources_pending_ was true)
qinmin 2014/05/22 00:35:55 We should leave it as it is. For example, if |stat
540 ReleaseMediaCodecBridge();
541 release_resources_pending_ = false;
542 if (drain_decoder_)
543 OnDecoderDrained();
wolenetz 2014/05/21 00:48:04 nit: CurrentDataConsumed(...) is called twice if l
qinmin 2014/05/22 00:35:55 OnDecoderDrained() will set drain_decoder_ to fals
544 }
545
458 stop_decode_pending_ = false; 546 stop_decode_pending_ = false;
459 base::ResetAndReturn(&decode_cb_).Run( 547 base::ResetAndReturn(&decode_cb_).Run(
460 status, current_presentation_timestamp, max_presentation_timestamp); 548 status, current_presentation_timestamp, max_presentation_timestamp);
461 } 549 }
462 550
463 const AccessUnit& MediaDecoderJob::CurrentAccessUnit() const { 551 const AccessUnit& MediaDecoderJob::CurrentAccessUnit() const {
464 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 552 DCHECK(ui_task_runner_->BelongsToCurrentThread());
465 DCHECK(HasData()); 553 DCHECK(HasData());
466 size_t index = CurrentReceivedDataChunkIndex(); 554 size_t index = CurrentReceivedDataChunkIndex();
467 return received_data_[index].access_units[access_unit_index_[index]]; 555 return received_data_[index].access_units[access_unit_index_[index]];
468 } 556 }
469 557
470 size_t MediaDecoderJob::CurrentReceivedDataChunkIndex() const { 558 size_t MediaDecoderJob::CurrentReceivedDataChunkIndex() const {
471 return NoAccessUnitsRemainingInChunk(true) ? 559 return NoAccessUnitsRemainingInChunk(true) ?
472 inactive_demuxer_data_index() : current_demuxer_data_index_; 560 inactive_demuxer_data_index() : current_demuxer_data_index_;
473 } 561 }
474 562
475 bool MediaDecoderJob::NoAccessUnitsRemainingInChunk( 563 bool MediaDecoderJob::NoAccessUnitsRemainingInChunk(
476 bool is_active_chunk) const { 564 bool is_active_chunk) const {
477 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 565 DCHECK(ui_task_runner_->BelongsToCurrentThread());
478 size_t index = is_active_chunk ? current_demuxer_data_index_ : 566 size_t index = is_active_chunk ? current_demuxer_data_index_ :
479 inactive_demuxer_data_index(); 567 inactive_demuxer_data_index();
480 return received_data_[index].access_units.size() <= access_unit_index_[index]; 568 return received_data_[index].access_units.size() <= access_unit_index_[index];
481 } 569 }
482 570
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() { 571 void MediaDecoderJob::RequestCurrentChunkIfEmpty() {
494 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 572 DCHECK(ui_task_runner_->BelongsToCurrentThread());
495 DCHECK(HasData()); 573 DCHECK(HasData());
496 if (!NoAccessUnitsRemainingInChunk(true)) 574 if (!NoAccessUnitsRemainingInChunk(true))
497 return; 575 return;
498 576
499 // Requests new data if the the last access unit of the next chunk is not EOS. 577 // 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(); 578 current_demuxer_data_index_ = inactive_demuxer_data_index();
501 const AccessUnit last_access_unit = 579 const AccessUnit last_access_unit =
502 received_data_[current_demuxer_data_index_].access_units.back(); 580 received_data_[current_demuxer_data_index_].access_units.back();
503 if (!last_access_unit.end_of_stream && 581 if (!last_access_unit.end_of_stream &&
504 last_access_unit.status != DemuxerStream::kConfigChanged &&
505 last_access_unit.status != DemuxerStream::kAborted) { 582 last_access_unit.status != DemuxerStream::kAborted) {
506 RequestData(base::Closure()); 583 RequestData(base::Closure());
507 } 584 }
508 } 585 }
509 586
510 void MediaDecoderJob::InitializeReceivedData() { 587 void MediaDecoderJob::InitializeReceivedData() {
511 for (size_t i = 0; i < 2; ++i) { 588 for (size_t i = 0; i < 2; ++i) {
512 received_data_[i] = DemuxerData(); 589 received_data_[i] = DemuxerData();
513 access_unit_index_[i] = 0; 590 access_unit_index_[i] = 0;
514 } 591 }
515 } 592 }
516 593
594 void MediaDecoderJob::OnDecoderDrained() {
595 DVLOG(1) << __FUNCTION__;
596 DCHECK(ui_task_runner_->BelongsToCurrentThread());
597 DCHECK(drain_decoder_);
598
599 input_eos_encountered_ = false;
600 output_eos_encountered_ = false;
601 drain_decoder_ = false;
602 ReleaseMediaCodecBridge();
603 // Increase the access unit index so that the new decoder will not handle
604 // the config change again.
605 access_unit_index_[current_demuxer_data_index_]++;
606 CurrentDataConsumed(true);
607 }
608
609 bool MediaDecoderJob::CreateMediaCodecBridge() {
610 DVLOG(1) << __FUNCTION__;
611 DCHECK(ui_task_runner_->BelongsToCurrentThread());
612 DCHECK(decode_cb_.is_null());
613
614 if (!HasStream()) {
615 ReleaseMediaCodecBridge();
616 return false;
617 }
618
619 // Create |media_codec_bridge_| only if config changes.
620 if (media_codec_bridge_ && !need_to_reconfig_decoder_job_)
621 return true;
622
623 base::android::ScopedJavaLocalRef<jobject> media_crypto = GetMediaCrypto();
624 if (is_content_encrypted_ && media_crypto.is_null())
625 return false;
626
627 ReleaseMediaCodecBridge();
628 DVLOG(1) << __FUNCTION__ << " : creating new media codec bridge";
629
630 return CreateMediaCodecBridgeInternal();
631 }
632
633 void MediaDecoderJob::ReleaseMediaCodecBridge() {
634 if (!media_codec_bridge_)
635 return;
636
637 media_codec_bridge_.reset();
638 OnMediaCodecBridgeReleased();
639 }
640
517 } // namespace media 641 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698