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

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

Issue 196133020: Reducing the IPC latency for MSE video decoding (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix clang warning Created 6 years, 9 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_player_android.h » ('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/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"
(...skipping 14 matching lines...) Expand all
25 const base::Closure& request_data_cb) 25 const base::Closure& request_data_cb)
26 : ui_task_runner_(base::MessageLoopProxy::current()), 26 : ui_task_runner_(base::MessageLoopProxy::current()),
27 decoder_task_runner_(decoder_task_runner), 27 decoder_task_runner_(decoder_task_runner),
28 media_codec_bridge_(media_codec_bridge), 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 access_unit_index_(0), 35 current_demuxer_data_index_(0),
36 input_buf_index_(-1), 36 input_buf_index_(-1),
37 stop_decode_pending_(false), 37 stop_decode_pending_(false),
38 destroy_pending_(false), 38 destroy_pending_(false),
39 weak_factory_(this) {} 39 is_requesting_demuxer_data_(false),
40 is_incoming_data_invalid_(false),
41 weak_factory_(this) {
42 InitializeReceivedData();
43 }
40 44
41 MediaDecoderJob::~MediaDecoderJob() {} 45 MediaDecoderJob::~MediaDecoderJob() {}
42 46
43 void MediaDecoderJob::OnDataReceived(const DemuxerData& data) { 47 void MediaDecoderJob::OnDataReceived(const DemuxerData& data) {
44 DVLOG(1) << __FUNCTION__ << ": " << data.access_units.size() << " units"; 48 DVLOG(1) << __FUNCTION__ << ": " << data.access_units.size() << " units";
45 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 49 DCHECK(ui_task_runner_->BelongsToCurrentThread());
46 DCHECK(!on_data_received_cb_.is_null()); 50 DCHECK(NoAccessUnitsRemainingInChunk(false));
47 51
48 TRACE_EVENT_ASYNC_END2( 52 TRACE_EVENT_ASYNC_END2(
49 "media", "MediaDecoderJob::RequestData", this, 53 "media", "MediaDecoderJob::RequestData", this,
50 "Data type", data.type == media::DemuxerStream::AUDIO ? "AUDIO" : "VIDEO", 54 "Data type", data.type == media::DemuxerStream::AUDIO ? "AUDIO" : "VIDEO",
51 "Units read", data.access_units.size()); 55 "Units read", data.access_units.size());
52 56
57 if (is_incoming_data_invalid_) {
58 is_incoming_data_invalid_ = false;
59
60 // If there is a pending callback, need to request the data again to get
61 // valid data.
62 if (!on_data_received_cb_.is_null())
63 request_data_cb_.Run();
64 else
65 is_requesting_demuxer_data_ = false;
66 return;
67 }
68
69 size_t next_demuxer_data_index = inactive_demuxer_data_index();
70 received_data_[next_demuxer_data_index] = data;
71 access_unit_index_[next_demuxer_data_index] = 0;
72 is_requesting_demuxer_data_ = false;
73
53 base::Closure done_cb = base::ResetAndReturn(&on_data_received_cb_); 74 base::Closure done_cb = base::ResetAndReturn(&on_data_received_cb_);
54
55 if (stop_decode_pending_) { 75 if (stop_decode_pending_) {
56 OnDecodeCompleted(MEDIA_CODEC_STOPPED, kNoTimestamp(), 0); 76 OnDecodeCompleted(MEDIA_CODEC_STOPPED, kNoTimestamp(), 0);
57 return; 77 return;
58 } 78 }
59 79
60 access_unit_index_ = 0; 80 if (!done_cb.is_null())
61 received_data_ = data; 81 done_cb.Run();
62 done_cb.Run();
63 } 82 }
64 83
65 void MediaDecoderJob::Prefetch(const base::Closure& prefetch_cb) { 84 void MediaDecoderJob::Prefetch(const base::Closure& prefetch_cb) {
66 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 85 DCHECK(ui_task_runner_->BelongsToCurrentThread());
67 DCHECK(on_data_received_cb_.is_null()); 86 DCHECK(on_data_received_cb_.is_null());
68 DCHECK(decode_cb_.is_null()); 87 DCHECK(decode_cb_.is_null());
69 88
70 if (HasData()) { 89 if (HasData()) {
71 DVLOG(1) << __FUNCTION__ << " : using previously received data"; 90 DVLOG(1) << __FUNCTION__ << " : using previously received data";
72 ui_task_runner_->PostTask(FROM_HERE, prefetch_cb); 91 ui_task_runner_->PostTask(FROM_HERE, prefetch_cb);
73 return; 92 return;
74 } 93 }
75 94
76 DVLOG(1) << __FUNCTION__ << " : requesting data"; 95 DVLOG(1) << __FUNCTION__ << " : requesting data";
77 RequestData(prefetch_cb); 96 RequestData(prefetch_cb);
78 } 97 }
79 98
80 bool MediaDecoderJob::Decode( 99 bool MediaDecoderJob::Decode(
81 const base::TimeTicks& start_time_ticks, 100 base::TimeTicks start_time_ticks,
82 const base::TimeDelta& start_presentation_timestamp, 101 base::TimeDelta start_presentation_timestamp,
83 const DecoderCallback& callback) { 102 const DecoderCallback& callback) {
84 DCHECK(decode_cb_.is_null()); 103 DCHECK(decode_cb_.is_null());
85 DCHECK(on_data_received_cb_.is_null()); 104 DCHECK(on_data_received_cb_.is_null());
86 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 105 DCHECK(ui_task_runner_->BelongsToCurrentThread());
87 106
88 decode_cb_ = callback; 107 decode_cb_ = callback;
89 108
90 if (!HasData()) { 109 if (!HasData()) {
91 RequestData(base::Bind(&MediaDecoderJob::DecodeNextAccessUnit, 110 RequestData(base::Bind(&MediaDecoderJob::DecodeCurrentAccessUnit,
92 base::Unretained(this), 111 base::Unretained(this),
93 start_time_ticks, 112 start_time_ticks,
94 start_presentation_timestamp)); 113 start_presentation_timestamp));
95 return true; 114 return true;
96 } 115 }
97 116
98 if (DemuxerStream::kConfigChanged == 117 if (DemuxerStream::kConfigChanged == CurrentAccessUnit().status) {
99 received_data_.access_units[access_unit_index_].status) {
100 // Clear received data because we need to handle a config change. 118 // Clear received data because we need to handle a config change.
101 decode_cb_.Reset(); 119 decode_cb_.Reset();
102 received_data_ = DemuxerData(); 120 ClearData();
103 access_unit_index_ = 0;
104 return false; 121 return false;
105 } 122 }
106 123
107 DecodeNextAccessUnit(start_time_ticks, start_presentation_timestamp); 124 DecodeCurrentAccessUnit(start_time_ticks, start_presentation_timestamp);
108 return true; 125 return true;
109 } 126 }
110 127
111 void MediaDecoderJob::StopDecode() { 128 void MediaDecoderJob::StopDecode() {
112 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 129 DCHECK(ui_task_runner_->BelongsToCurrentThread());
113 DCHECK(is_decoding()); 130 DCHECK(is_decoding());
114 stop_decode_pending_ = true; 131 stop_decode_pending_ = true;
115 } 132 }
116 133
117 void MediaDecoderJob::Flush() { 134 void MediaDecoderJob::Flush() {
118 DCHECK(decode_cb_.is_null()); 135 DCHECK(decode_cb_.is_null());
119 136
120 // Do nothing, flush when the next Decode() happens. 137 // Do nothing, flush when the next Decode() happens.
121 needs_flush_ = true; 138 needs_flush_ = true;
122 received_data_ = DemuxerData(); 139 ClearData();
123 input_eos_encountered_ = false;
124 access_unit_index_ = 0;
125 on_data_received_cb_.Reset();
126 } 140 }
127 141
128 void MediaDecoderJob::BeginPrerolling( 142 void MediaDecoderJob::BeginPrerolling(base::TimeDelta preroll_timestamp) {
129 const base::TimeDelta& preroll_timestamp) {
130 DVLOG(1) << __FUNCTION__ << "(" << preroll_timestamp.InSecondsF() << ")"; 143 DVLOG(1) << __FUNCTION__ << "(" << preroll_timestamp.InSecondsF() << ")";
131 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 144 DCHECK(ui_task_runner_->BelongsToCurrentThread());
132 DCHECK(!is_decoding()); 145 DCHECK(!is_decoding());
133 146
134 preroll_timestamp_ = preroll_timestamp; 147 preroll_timestamp_ = preroll_timestamp;
135 prerolling_ = true; 148 prerolling_ = true;
136 } 149 }
137 150
138 void MediaDecoderJob::Release() { 151 void MediaDecoderJob::Release() {
139 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 152 DCHECK(ui_task_runner_->BelongsToCurrentThread());
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
200 // In case of MEDIA_CODEC_NO_KEY, we must reuse the |input_buf_index_|. 213 // In case of MEDIA_CODEC_NO_KEY, we must reuse the |input_buf_index_|.
201 // Otherwise MediaDrm will report errors. 214 // Otherwise MediaDrm will report errors.
202 if (status == MEDIA_CODEC_NO_KEY) 215 if (status == MEDIA_CODEC_NO_KEY)
203 input_buf_index_ = input_buf_index; 216 input_buf_index_ = input_buf_index;
204 217
205 return status; 218 return status;
206 } 219 }
207 220
208 bool MediaDecoderJob::HasData() const { 221 bool MediaDecoderJob::HasData() const {
209 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 222 DCHECK(ui_task_runner_->BelongsToCurrentThread());
210 // When |input_eos_encountered_| is set, |access_units| must not be empty and 223 // When |input_eos_encountered_| is set, |access_unit_index_| and
211 // |access_unit_index_| must be pointing to an EOS unit. We'll reuse this 224 // |current_demuxer_data_index_| must be pointing to an EOS unit.
212 // unit to flush the decoder until we hit output EOS. 225 // We'll reuse this unit to flush the decoder until we hit output EOS.
213 DCHECK(!input_eos_encountered_ || 226 DCHECK(!input_eos_encountered_ || !NoAccessUnitsRemainingInChunk(true));
214 (received_data_.access_units.size() > 0 && 227 return !NoAccessUnitsRemainingInChunk(true) ||
215 access_unit_index_ < received_data_.access_units.size())) 228 !NoAccessUnitsRemainingInChunk(false);
216 << " (access_units.size(): " << received_data_.access_units.size()
217 << ", access_unit_index_: " << access_unit_index_ << ")";
218 return access_unit_index_ < received_data_.access_units.size();
219 } 229 }
220 230
221 void MediaDecoderJob::RequestData(const base::Closure& done_cb) { 231 void MediaDecoderJob::RequestData(const base::Closure& done_cb) {
222 DVLOG(1) << __FUNCTION__; 232 DVLOG(1) << __FUNCTION__;
223 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 233 DCHECK(ui_task_runner_->BelongsToCurrentThread());
224 DCHECK(on_data_received_cb_.is_null()); 234 DCHECK(on_data_received_cb_.is_null());
225 DCHECK(!input_eos_encountered_); 235 DCHECK(!input_eos_encountered_);
236 DCHECK(NoAccessUnitsRemainingInChunk(false));
226 237
227 TRACE_EVENT_ASYNC_BEGIN0("media", "MediaDecoderJob::RequestData", this); 238 TRACE_EVENT_ASYNC_BEGIN0("media", "MediaDecoderJob::RequestData", this);
228 239
229 received_data_ = DemuxerData();
230 access_unit_index_ = 0;
231 on_data_received_cb_ = done_cb; 240 on_data_received_cb_ = done_cb;
232 241
242 // If we are already expecting new data, just set the callback and do
243 // nothing.
244 if (is_requesting_demuxer_data_)
245 return;
246
247 // The new incoming data will be stored as the next demuxer data chunk, since
248 // the decoder might still be decoding the current one.
249 size_t next_demuxer_data_index = inactive_demuxer_data_index();
250 received_data_[next_demuxer_data_index] = DemuxerData();
251 access_unit_index_[next_demuxer_data_index] = 0;
252 is_requesting_demuxer_data_ = true;
253
233 request_data_cb_.Run(); 254 request_data_cb_.Run();
234 } 255 }
235 256
236 void MediaDecoderJob::DecodeNextAccessUnit( 257 void MediaDecoderJob::DecodeCurrentAccessUnit(
237 const base::TimeTicks& start_time_ticks, 258 base::TimeTicks start_time_ticks,
238 const base::TimeDelta& start_presentation_timestamp) { 259 base::TimeDelta start_presentation_timestamp) {
239 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 260 DCHECK(ui_task_runner_->BelongsToCurrentThread());
240 DCHECK(!decode_cb_.is_null()); 261 DCHECK(!decode_cb_.is_null());
241 262
263 RequestCurrentChunkIfEmpty();
264 const AccessUnit& access_unit = CurrentAccessUnit();
242 // If the first access unit is a config change, request the player to dequeue 265 // If the first access unit is a config change, request the player to dequeue
243 // the input buffer again so that it can request config data. 266 // the input buffer again so that it can request config data.
244 if (received_data_.access_units[access_unit_index_].status == 267 if (access_unit.status == DemuxerStream::kConfigChanged) {
245 DemuxerStream::kConfigChanged) {
246 ui_task_runner_->PostTask(FROM_HERE, 268 ui_task_runner_->PostTask(FROM_HERE,
247 base::Bind(&MediaDecoderJob::OnDecodeCompleted, 269 base::Bind(&MediaDecoderJob::OnDecodeCompleted,
248 base::Unretained(this), 270 base::Unretained(this),
249 MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER, 271 MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER,
250 kNoTimestamp(), 272 kNoTimestamp(),
251 0)); 273 0));
252 return; 274 return;
253 } 275 }
254 276
255 decoder_task_runner_->PostTask(FROM_HERE, base::Bind( 277 decoder_task_runner_->PostTask(FROM_HERE, base::Bind(
256 &MediaDecoderJob::DecodeInternal, base::Unretained(this), 278 &MediaDecoderJob::DecodeInternal, base::Unretained(this),
257 received_data_.access_units[access_unit_index_], 279 access_unit,
258 start_time_ticks, start_presentation_timestamp, needs_flush_, 280 start_time_ticks, start_presentation_timestamp, needs_flush_,
259 media::BindToCurrentLoop(base::Bind( 281 media::BindToCurrentLoop(base::Bind(
260 &MediaDecoderJob::OnDecodeCompleted, base::Unretained(this))))); 282 &MediaDecoderJob::OnDecodeCompleted, base::Unretained(this)))));
261 needs_flush_ = false; 283 needs_flush_ = false;
262 } 284 }
263 285
264 void MediaDecoderJob::DecodeInternal( 286 void MediaDecoderJob::DecodeInternal(
265 const AccessUnit& unit, 287 const AccessUnit& unit,
266 const base::TimeTicks& start_time_ticks, 288 base::TimeTicks start_time_ticks,
267 const base::TimeDelta& start_presentation_timestamp, 289 base::TimeDelta start_presentation_timestamp,
268 bool needs_flush, 290 bool needs_flush,
269 const MediaDecoderJob::DecoderCallback& callback) { 291 const MediaDecoderJob::DecoderCallback& callback) {
270 DVLOG(1) << __FUNCTION__; 292 DVLOG(1) << __FUNCTION__;
271 DCHECK(decoder_task_runner_->BelongsToCurrentThread()); 293 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
272 TRACE_EVENT0("media", __FUNCTION__); 294 TRACE_EVENT0("media", __FUNCTION__);
273 295
274 if (needs_flush) { 296 if (needs_flush) {
275 DVLOG(1) << "DecodeInternal needs flush."; 297 DVLOG(1) << "DecodeInternal needs flush.";
276 input_eos_encountered_ = false; 298 input_eos_encountered_ = false;
277 output_eos_encountered_ = false; 299 output_eos_encountered_ = false;
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
382 presentation_timestamp, start_presentation_timestamp); 404 presentation_timestamp, start_presentation_timestamp);
383 } else { 405 } else {
384 presentation_timestamp = kNoTimestamp(); 406 presentation_timestamp = kNoTimestamp();
385 } 407 }
386 ReleaseOutputCompletionCallback completion_callback = base::Bind( 408 ReleaseOutputCompletionCallback completion_callback = base::Bind(
387 callback, status, presentation_timestamp); 409 callback, status, presentation_timestamp);
388 ReleaseOutputBuffer(buffer_index, size, render_output, completion_callback); 410 ReleaseOutputBuffer(buffer_index, size, render_output, completion_callback);
389 } 411 }
390 412
391 void MediaDecoderJob::OnDecodeCompleted( 413 void MediaDecoderJob::OnDecodeCompleted(
392 MediaCodecStatus status, const base::TimeDelta& presentation_timestamp, 414 MediaCodecStatus status, base::TimeDelta presentation_timestamp,
393 size_t audio_output_bytes) { 415 size_t audio_output_bytes) {
394 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 416 DCHECK(ui_task_runner_->BelongsToCurrentThread());
395 417
396 if (destroy_pending_) { 418 if (destroy_pending_) {
397 DVLOG(1) << __FUNCTION__ << " : completing pending deletion"; 419 DVLOG(1) << __FUNCTION__ << " : completing pending deletion";
398 delete this; 420 delete this;
399 return; 421 return;
400 } 422 }
401 423
402 DCHECK(!decode_cb_.is_null()); 424 DCHECK(!decode_cb_.is_null());
403 425
404 // If output was queued for rendering, then we have completed prerolling. 426 // If output was queued for rendering, then we have completed prerolling.
405 if (presentation_timestamp != kNoTimestamp()) 427 if (presentation_timestamp != kNoTimestamp())
406 prerolling_ = false; 428 prerolling_ = false;
407 429
408 switch (status) { 430 switch (status) {
409 case MEDIA_CODEC_OK: 431 case MEDIA_CODEC_OK:
410 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER: 432 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER:
411 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED: 433 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED:
412 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: 434 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED:
413 case MEDIA_CODEC_OUTPUT_END_OF_STREAM: 435 case MEDIA_CODEC_OUTPUT_END_OF_STREAM:
414 if (!input_eos_encountered_) 436 if (!input_eos_encountered_)
415 access_unit_index_++; 437 access_unit_index_[current_demuxer_data_index_]++;
416 break; 438 break;
417 439
418 case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER: 440 case MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER:
419 case MEDIA_CODEC_INPUT_END_OF_STREAM: 441 case MEDIA_CODEC_INPUT_END_OF_STREAM:
420 case MEDIA_CODEC_NO_KEY: 442 case MEDIA_CODEC_NO_KEY:
421 case MEDIA_CODEC_STOPPED: 443 case MEDIA_CODEC_STOPPED:
422 case MEDIA_CODEC_ERROR: 444 case MEDIA_CODEC_ERROR:
423 // Do nothing. 445 // Do nothing.
424 break; 446 break;
425 }; 447 };
426 448
427 stop_decode_pending_ = false; 449 stop_decode_pending_ = false;
428 base::ResetAndReturn(&decode_cb_).Run(status, presentation_timestamp, 450 base::ResetAndReturn(&decode_cb_).Run(status, presentation_timestamp,
429 audio_output_bytes); 451 audio_output_bytes);
430 } 452 }
431 453
454 const AccessUnit& MediaDecoderJob::CurrentAccessUnit() const {
455 DCHECK(ui_task_runner_->BelongsToCurrentThread());
456 DCHECK(HasData());
457 int index = NoAccessUnitsRemainingInChunk(true) ?
458 inactive_demuxer_data_index() : current_demuxer_data_index_;
459 return received_data_[index].access_units[access_unit_index_[index]];
460 }
461
462 bool MediaDecoderJob::NoAccessUnitsRemainingInChunk(
463 bool is_active_chunk) const {
464 DCHECK(ui_task_runner_->BelongsToCurrentThread());
465 size_t index = is_active_chunk ? current_demuxer_data_index_ :
466 inactive_demuxer_data_index();
467 return received_data_[index].access_units.size() <= access_unit_index_[index];
468 }
469
470 void MediaDecoderJob::ClearData() {
471 DCHECK(ui_task_runner_->BelongsToCurrentThread());
472 current_demuxer_data_index_ = 0;
473 InitializeReceivedData();
474 on_data_received_cb_.Reset();
475 if (is_requesting_demuxer_data_)
476 is_incoming_data_invalid_ = true;
477 input_eos_encountered_ = false;
478 }
479
480 void MediaDecoderJob::RequestCurrentChunkIfEmpty() {
481 DCHECK(ui_task_runner_->BelongsToCurrentThread());
482 DCHECK(HasData());
483 if (!NoAccessUnitsRemainingInChunk(true))
484 return;
485
486 // Requests new data if the the last access unit of the next chunk is not EOS.
487 current_demuxer_data_index_ = inactive_demuxer_data_index();
488 const AccessUnit last_access_unit =
489 received_data_[current_demuxer_data_index_].access_units.back();
490 if (!last_access_unit.end_of_stream &&
491 last_access_unit.status != DemuxerStream::kConfigChanged &&
492 last_access_unit.status != DemuxerStream::kAborted) {
493 RequestData(base::Closure());
494 }
495 }
496
497 void MediaDecoderJob::InitializeReceivedData() {
498 for (size_t i = 0; i < 2; ++i) {
499 received_data_[i] = DemuxerData();
500 access_unit_index_[i] = 0;
501 }
502 }
503
432 } // namespace media 504 } // namespace media
OLDNEW
« no previous file with comments | « media/base/android/media_decoder_job.h ('k') | media/base/android/media_player_android.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698