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

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

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

Powered by Google App Engine
This is Rietveld 408576698