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

Side by Side Diff: media/filters/adaptive_demuxer.cc

Issue 7044008: Initial implementation of stream switching in AdaptiveDemuxer. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: _ Created 9 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 (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 "base/bind.h" 5 #include "base/bind.h"
6 #include "base/logging.h" 6 #include "base/logging.h"
7 #include "base/message_loop.h"
7 #include "base/string_number_conversions.h" 8 #include "base/string_number_conversions.h"
8 #include "base/string_split.h" 9 #include "base/string_split.h"
9 #include "base/string_util.h" 10 #include "base/string_util.h"
11 #include "media/ffmpeg/ffmpeg_common.h"
10 #include "media/filters/adaptive_demuxer.h" 12 #include "media/filters/adaptive_demuxer.h"
11 13
12 namespace media { 14 namespace media {
13 15
16 static const int64 kSwitchTimerPeriod = 5000; // In milliseconds.
17
18 class StreamSwitchManager
19 : public base::RefCountedThreadSafe<StreamSwitchManager> {
20
21 public:
22 StreamSwitchManager();
23 ~StreamSwitchManager();
24
25 void Init(AdaptiveDemuxer* demuxer);
26
27 void Play();
28 void Pause();
29 void Stop();
30
31 private:
32 void OnSwitchTimer();
33 void OnSwitchDone(PipelineStatus status);
34 void StartSwitchTimer_Locked();
35
36 AdaptiveDemuxer* demuxer_;
37
38 // Guards the members below. Only held for simple variable reads/writes, not
39 // during async operation.
40 base::Lock lock_;
41 bool playing_;
42 bool switch_pending_;
43 bool switch_timer_running_;
44 AdaptiveDemuxer::StreamIdVector video_ids_;
45 int current_id_index_;
46
47 DISALLOW_COPY_AND_ASSIGN(StreamSwitchManager);
48 };
49
50 StreamSwitchManager::StreamSwitchManager()
51 : demuxer_(NULL),
52 playing_(false),
53 switch_pending_(false),
54 switch_timer_running_(false),
55 current_id_index_(-1) {
56 }
57
58 StreamSwitchManager::~StreamSwitchManager() {}
59
60 void StreamSwitchManager::Init(AdaptiveDemuxer* demuxer) {
61 DCHECK(demuxer);
62 demuxer_ = demuxer;
63 video_ids_ = demuxer->GetVideoIds();
64 current_id_index_ = -1;
65
66 if (video_ids_.size() > 0) {
67 int current_id = demuxer->GetCurrentVideoId();
68 current_id_index_ = 0;
69 for (int i = 0; i < video_ids_.size(); i++) {
70 if (current_id == video_ids_[i]) {
71 current_id_index_ = i;
72 break;
73 }
74 }
75 }
76 }
77
78 void StreamSwitchManager::Play() {
79 base::AutoLock auto_lock(lock_);
80
81 DCHECK(!playing_);
82
83 playing_ = true;
84
85 if (!switch_timer_running_) {
86 StartSwitchTimer_Locked();
87 }
88 }
89
90 void StreamSwitchManager::Pause() {
91 base::AutoLock auto_lock(lock_);
92 DCHECK(playing_);
93 playing_ = false;
94 }
95
96 void StreamSwitchManager::Stop() {
97 base::AutoLock auto_lock(lock_);
98
99 DCHECK(!playing_);
100 demuxer_ = NULL;
101 }
102
103
104
105 void StreamSwitchManager::OnSwitchTimer() {
106 int new_stream_id = -1;
107 AdaptiveDemuxer* demuxer = NULL;
108 SeekHelper seek_helper;
109 {
110 base::AutoLock auto_lock(lock_);
111 switch_timer_running_ = false;
112
113 if (!switch_pending_) {
114 int new_id_index = (current_id_index_ + 1) % video_ids_.size();
115
116 if (new_id_index != current_id_index_) {
117 current_id_index_ = new_id_index;
118 switch_pending_ = true;
119 demuxer = demuxer_;
120 new_stream_id = video_ids_[new_id_index];
121 }
122 }
123
124 if (playing_)
125 StartSwitchTimer_Locked();
126 }
127
128 if (demuxer && new_stream_id != -1) {
129 demuxer->ChangeVideoStream(new_stream_id,
130 base::Bind(&StreamSwitchManager::OnSwitchDone,
131 this));
132 }
133 }
134
135 void StreamSwitchManager::OnSwitchDone(PipelineStatus status) {
136 base::AutoLock auto_lock(lock_);
137 switch_pending_ = false;
138 }
139
140 void StreamSwitchManager::StartSwitchTimer_Locked() {
141 lock_.AssertAcquired();
142
143 switch_timer_running_ = true;
144 MessageLoop::current()->PostDelayedTask(
145 FROM_HERE, NewRunnableMethod(this, &StreamSwitchManager::OnSwitchTimer),
146 kSwitchTimerPeriod);
147 }
148
14 // 149 //
15 // AdaptiveDemuxerStream 150 // AdaptiveDemuxerStream
16 // 151 //
17 AdaptiveDemuxerStream::AdaptiveDemuxerStream( 152 AdaptiveDemuxerStream::AdaptiveDemuxerStream(
18 StreamVector const& streams, int initial_stream) 153 StreamVector const& streams, int initial_stream)
19 : streams_(streams), current_stream_index_(initial_stream), 154 : streams_(streams), current_stream_index_(initial_stream),
20 bitstream_converter_enabled_(false) { 155 bitstream_converter_enabled_(false),
156 pending_reads_(0),
157 switch_index_(-1),
158 last_buffer_timestamp_(kNoTimestamp) {
21 DCheckSanity(); 159 DCheckSanity();
22 } 160 }
23 161
24 void AdaptiveDemuxerStream::DCheckSanity() { 162 void AdaptiveDemuxerStream::DCheckSanity() {
25 // We only carry out sanity checks in debug mode. 163 // We only carry out sanity checks in debug mode.
26 if (!logging::DEBUG_MODE) 164 if (!logging::DEBUG_MODE)
27 return; 165 return;
28 DCHECK(streams_[current_stream_index_].get()); 166 DCHECK(streams_[current_stream_index_].get())
167 << "current_stream_index_ : " << current_stream_index_;
29 168
30 bool non_null_stream_seen = false; 169 bool non_null_stream_seen = false;
31 Type type = DemuxerStream::UNKNOWN; 170 Type type = DemuxerStream::UNKNOWN;
32 const MediaFormat* media_format = NULL; 171 const MediaFormat* media_format = NULL;
33 for (size_t i = 0; i < streams_.size(); ++i) { 172 for (size_t i = 0; i < streams_.size(); ++i) {
34 if (!streams_[i]) 173 if (!streams_[i])
35 continue; 174 continue;
36 175
37 if (!non_null_stream_seen) { 176 if (!non_null_stream_seen) {
38 non_null_stream_seen = true; 177 non_null_stream_seen = true;
(...skipping 11 matching lines...) Expand all
50 current_stream_index_ = -1; 189 current_stream_index_ = -1;
51 streams_.clear(); 190 streams_.clear();
52 } 191 }
53 192
54 DemuxerStream* AdaptiveDemuxerStream::current_stream() { 193 DemuxerStream* AdaptiveDemuxerStream::current_stream() {
55 base::AutoLock auto_lock(lock_); 194 base::AutoLock auto_lock(lock_);
56 return streams_[current_stream_index_]; 195 return streams_[current_stream_index_];
57 } 196 }
58 197
59 void AdaptiveDemuxerStream::Read(const ReadCallback& read_callback) { 198 void AdaptiveDemuxerStream::Read(const ReadCallback& read_callback) {
60 current_stream()->Read(read_callback); 199 DemuxerStream* stream = NULL;
200
201 {
202 base::AutoLock auto_lock(lock_);
203
204 read_cb_queue_.push_back(read_callback);
205
206 // Check to make sure we aren't doing a stream switch. We only want to
207 // make calls on | streams_[current_stream_index_] | when we aren't
208 // in the middle of a stream switch. Since the callback is stored in
209 // | read_cb_queue_ | we will issue the Read() on the new stream once
210 // the switch has completed.
211 if (!IsSwitchPending_Locked()) {
212 stream = streams_[current_stream_index_];
213
214 pending_reads_++;
215 }
216 }
217
218 if (stream)
219 stream->Read(base::Bind(&AdaptiveDemuxerStream::OnReadDone, this));
61 } 220 }
62 221
63 AVStream* AdaptiveDemuxerStream::GetAVStream() { 222 AVStream* AdaptiveDemuxerStream::GetAVStream() {
64 return current_stream()->GetAVStream(); 223 return current_stream()->GetAVStream();
65 } 224 }
66 225
67 DemuxerStream::Type AdaptiveDemuxerStream::type() { 226 DemuxerStream::Type AdaptiveDemuxerStream::type() {
68 return current_stream()->type(); 227 return current_stream()->type();
69 } 228 }
70 229
71 const MediaFormat& AdaptiveDemuxerStream::media_format() { 230 const MediaFormat& AdaptiveDemuxerStream::media_format() {
72 return current_stream()->media_format(); 231 return current_stream()->media_format();
73 } 232 }
74 233
75 void AdaptiveDemuxerStream::EnableBitstreamConverter() { 234 void AdaptiveDemuxerStream::EnableBitstreamConverter() {
76 { 235 {
77 base::AutoLock auto_lock(lock_); 236 base::AutoLock auto_lock(lock_);
78 bitstream_converter_enabled_ = true; 237 bitstream_converter_enabled_ = true;
79 } 238 }
80 current_stream()->EnableBitstreamConverter(); 239 current_stream()->EnableBitstreamConverter();
81 } 240 }
82 241
83 void AdaptiveDemuxerStream::ChangeCurrentStream(int index) { 242 void AdaptiveDemuxerStream::OnAdaptiveDemuxerSeek() {
84 bool needs_bitstream_converter_enabled; 243 base::AutoLock auto_lock(lock_);
244
245 last_buffer_timestamp_ = kNoTimestamp;
246
247 // XXAJC Figure out what to do if this happens during a stream switch.
Ami GONE FROM CHROMIUM 2011/05/19 20:27:37 Boom.
248 }
249
250 void AdaptiveDemuxerStream::ChangeCurrentStream(int index,
251 const SeekHelper& seek_helper,
252 const PipelineStatusCB& cb) {
253 DCHECK_GE(index, 0);
254
255 PipelineStatusCB error_cb;
256 PipelineStatus error_status = PIPELINE_OK;
257
258 bool start_switch = false;
259
85 { 260 {
86 base::AutoLock auto_lock(lock_); 261 base::AutoLock auto_lock(lock_);
87 current_stream_index_ = index; 262
88 DCHECK(streams_[current_stream_index_]); 263 DCHECK_LE(index, streams_.size());
89 needs_bitstream_converter_enabled = bitstream_converter_enabled_; 264 DCHECK(streams_[index].get());
265 DCHECK(!IsSwitchPending_Locked());
266
267 // XXAJC - Still need to handle the case where the stream has ended.
268 if (index == current_stream_index_) {
269 error_cb = cb;
270 } else {
271 switch_cb_ = cb;
272 switch_index_ = index;
273 switch_seek_helper_ = seek_helper;
274 start_switch = (pending_reads_ == 0);
275 }
90 } 276 }
277
278 if (!error_cb.is_null()) {
279 error_cb.Run(error_status);
280 return;
281 }
282
283 if (start_switch)
284 StartSwitch();
285 }
286
287 void AdaptiveDemuxerStream::OnReadDone(Buffer* buffer) {
288 ReadCallback read_cb;
289 bool start_switch = false;
290
291 {
292 base::AutoLock auto_lock(lock_);
293
294 pending_reads_--;
295
296 DCHECK_GE(pending_reads_, 0);
297 DCHECK_GE(read_cb_queue_.size(), 0);
298
299 read_cb = read_cb_queue_.front();
300 read_cb_queue_.pop_front();
301
302 if (buffer && !buffer->IsEndOfStream())
303 last_buffer_timestamp_ = buffer->GetTimestamp();
304
305 start_switch = (pending_reads_ == 0 && IsSwitchPending_Locked());
306 }
307
308 if (!read_cb.is_null())
309 read_cb.Run(buffer);
310
311 if (start_switch)
312 StartSwitch();
313 }
314
315 bool AdaptiveDemuxerStream::IsSwitchPending_Locked() const {
316 lock_.AssertAcquired();
317 return !switch_cb_.is_null();
318 }
319
320 void AdaptiveDemuxerStream::StartSwitch() {
321 SeekHelper seek_helper;
322 base::TimeDelta seek_point;
323
324 {
325 base::AutoLock auto_lock(lock_);
326 DCHECK(IsSwitchPending_Locked());
327 DCHECK_EQ(pending_reads_, 0);
328 DCHECK_GE(switch_index_, 0);
329
330 seek_point = last_buffer_timestamp_;
331 seek_helper = switch_seek_helper_;
332
333 // XXAJX add code to call switch_cb_ if we are at the end of the stream now.
334 }
335
336 if (seek_point == kNoTimestamp) {
337 // We haven't seen a buffer so there is no need to seek. Just move on to
338 // the next stage in the switch process.
339 OnSwitchSeekDone(PIPELINE_OK, kNoTimestamp);
340 return;
341 }
342
343 DCHECK(!seek_helper.is_null());
344 seek_helper.Run(seek_point,
345 base::Bind(&AdaptiveDemuxerStream::OnSwitchSeekDone, this));
346 }
347
348 void AdaptiveDemuxerStream::OnSwitchSeekDone(PipelineStatus status,
349 const base::TimeDelta& seek_time) {
350 DemuxerStream* stream = NULL;
351 PipelineStatusCB switch_cb;
352 int reads_to_request = 0;
353 bool needs_bitstream_converter_enabled = false;
354
355 {
356 base::AutoLock auto_lock(lock_);
357
358 if (status == PIPELINE_OK) {
359 DCHECK(streams_[switch_index_]);
360
361 current_stream_index_ = switch_index_;
362 needs_bitstream_converter_enabled = bitstream_converter_enabled_;
363 }
364
365 // Clear stream switch state.
366 switch_cb = switch_cb_;
367 switch_cb_.Reset();
368 switch_index_ = -1;
369 switch_seek_helper_.Reset();
370
371 // Get the number of outstanding Read()s on this object.
372 reads_to_request = read_cb_queue_.size();
373
374 DCHECK_EQ(pending_reads_, 0);
375 pending_reads_ = reads_to_request;
376
377 stream = streams_[current_stream_index_];
378 }
379
91 if (needs_bitstream_converter_enabled) 380 if (needs_bitstream_converter_enabled)
92 EnableBitstreamConverter(); 381 EnableBitstreamConverter();
382
383 if (stream) {
384 // Make the Read() calls that were deferred during the stream switch.
385 for(;reads_to_request > 0; --reads_to_request)
386 stream->Read(base::Bind(&AdaptiveDemuxerStream::OnReadDone, this));
387 }
388
389 // Signal that the stream switch has completed.
390 if (!switch_cb.is_null())
391 switch_cb.Run(status);
93 } 392 }
94 393
95 // 394 //
96 // AdaptiveDemuxer 395 // AdaptiveDemuxer
97 // 396 //
98 397
99 AdaptiveDemuxer::AdaptiveDemuxer(DemuxerVector const& demuxers, 398 AdaptiveDemuxer::AdaptiveDemuxer(DemuxerVector const& demuxers,
100 int initial_audio_demuxer_index, 399 int initial_audio_demuxer_index,
101 int initial_video_demuxer_index) 400 int initial_video_demuxer_index)
102 : demuxers_(demuxers), 401 : demuxers_(demuxers),
103 current_audio_demuxer_index_(initial_audio_demuxer_index), 402 current_audio_demuxer_index_(initial_audio_demuxer_index),
104 current_video_demuxer_index_(initial_video_demuxer_index) { 403 current_video_demuxer_index_(initial_video_demuxer_index),
404 playback_rate_(0),
405 switch_pending_(false),
406 stream_switch_manager_(new StreamSwitchManager()){
105 DCHECK(!demuxers_.empty()); 407 DCHECK(!demuxers_.empty());
106 DCHECK_GE(current_audio_demuxer_index_, -1); 408 DCHECK_GE(current_audio_demuxer_index_, -1);
107 DCHECK_GE(current_video_demuxer_index_, -1); 409 DCHECK_GE(current_video_demuxer_index_, -1);
108 DCHECK_LT(current_audio_demuxer_index_, static_cast<int>(demuxers_.size())); 410 DCHECK_LT(current_audio_demuxer_index_, static_cast<int>(demuxers_.size()));
109 DCHECK_LT(current_video_demuxer_index_, static_cast<int>(demuxers_.size())); 411 DCHECK_LT(current_video_demuxer_index_, static_cast<int>(demuxers_.size()));
110 DCHECK(current_audio_demuxer_index_ != -1 || 412 DCHECK(current_audio_demuxer_index_ != -1 ||
111 current_video_demuxer_index_ != -1); 413 current_video_demuxer_index_ != -1);
112 AdaptiveDemuxerStream::StreamVector audio_streams, video_streams; 414 AdaptiveDemuxerStream::StreamVector audio_streams, video_streams;
113 for (size_t i = 0; i < demuxers_.size(); ++i) { 415 for (size_t i = 0; i < demuxers_.size(); ++i) {
114 audio_streams.push_back(demuxers_[i]->GetStream(DemuxerStream::AUDIO)); 416 audio_streams.push_back(demuxers_[i]->GetStream(DemuxerStream::AUDIO));
115 video_streams.push_back(demuxers_[i]->GetStream(DemuxerStream::VIDEO)); 417 video_streams.push_back(demuxers_[i]->GetStream(DemuxerStream::VIDEO));
116 } 418 }
117 if (current_audio_demuxer_index_ >= 0) { 419 if (current_audio_demuxer_index_ >= 0) {
118 audio_stream_ = new AdaptiveDemuxerStream( 420 audio_stream_ = new AdaptiveDemuxerStream(
119 audio_streams, current_audio_demuxer_index_); 421 audio_streams, current_audio_demuxer_index_);
120 } 422 }
121 if (current_video_demuxer_index_ >= 0) { 423 if (current_video_demuxer_index_ >= 0) {
122 video_stream_ = new AdaptiveDemuxerStream( 424 video_stream_ = new AdaptiveDemuxerStream(
123 video_streams, current_video_demuxer_index_); 425 video_streams, current_video_demuxer_index_);
124 } 426 }
125 427
428 stream_switch_manager_->Init(this);
429
126 // TODO(fischman): any streams in the underlying demuxers that aren't being 430 // TODO(fischman): any streams in the underlying demuxers that aren't being
127 // consumed currently need to be sent to /dev/null or else FFmpegDemuxer will 431 // consumed currently need to be sent to /dev/null or else FFmpegDemuxer will
128 // hold data for them in memory, waiting for them to get drained by a 432 // hold data for them in memory, waiting for them to get drained by a
129 // non-existent decoder. 433 // non-existent decoder.
130 } 434 }
131 435
132 AdaptiveDemuxer::~AdaptiveDemuxer() {} 436 AdaptiveDemuxer::~AdaptiveDemuxer() {}
133 437
134 void AdaptiveDemuxer::ChangeCurrentDemuxer(int audio_index, int video_index) { 438 void AdaptiveDemuxer::ChangeVideoStream(int video_index,
439 const PipelineStatusCB& done_cb) {
135 // TODO(fischman): this is currently broken because when a new Demuxer is to 440 // TODO(fischman): this is currently broken because when a new Demuxer is to
136 // be used we need to set_host(host()) it, and we need to set_host(NULL) the 441 // be used we need to set_host(host()) it, and we need to set_host(NULL) the
137 // current Demuxer if it's no longer being used. 442 // current Demuxer if it's no longer being used.
443
444 AdaptiveDemuxerStream* stream = NULL;
445 PipelineStatus error_status = PIPELINE_OK;
446 bool run_callback_with_ok = false;
447 SeekHelper seek_helper;
448
449 {
450 base::AutoLock auto_lock(lock_);
451
452 if (!video_stream_) {
453 error_status = PIPELINE_ERROR_INVALID_STATE;
454 } else if (switch_pending_) {
455 error_status = PIPELINE_ERROR_OPERATION_PENDING;
456 } else if (current_video_demuxer_index_ == video_index) {
457 run_callback_with_ok = true;
458 } else {
459 stream = video_stream_;
460 switch_pending_ = true;
461 seek_helper = base::Bind(&AdaptiveDemuxer::StartStreamSwitchSeek,
462 this,
463 DemuxerStream::VIDEO,
464 video_index);
465 }
466 }
467
468 if (run_callback_with_ok || error_status != PIPELINE_OK) {
469 done_cb.Run(error_status);
470 return;
471 }
472
473 DCHECK(stream);
474 stream->ChangeCurrentStream(
475 video_index, seek_helper,
476 base::Bind(&AdaptiveDemuxer::ChangeVideoStreamDone, this, video_index,
477 done_cb));
478 }
479
480 int AdaptiveDemuxer::GetCurrentVideoId() const {
138 base::AutoLock auto_lock(lock_); 481 base::AutoLock auto_lock(lock_);
139 current_audio_demuxer_index_ = audio_index; 482 return current_video_demuxer_index_;
140 current_video_demuxer_index_ = video_index; 483 }
141 if (audio_stream_) 484
142 audio_stream_->ChangeCurrentStream(audio_index); 485 AdaptiveDemuxer::StreamIdVector AdaptiveDemuxer::GetVideoIds() const {
143 if (video_stream_) 486 StreamIdVector ids;
144 video_stream_->ChangeCurrentStream(video_index); 487 base::AutoLock auto_lock(lock_);
488
489 for (int i = 0; i < demuxers_.size(); i++) {
490 if (demuxers_[i]->GetStream(DemuxerStream::VIDEO))
491 ids.push_back(i);
492 }
493
494 return ids;
495 }
496
497 void AdaptiveDemuxer::ChangeVideoStreamDone(int new_stream_index,
498 const PipelineStatusCB& done_cb,
499 PipelineStatus status) {
500 {
501 base::AutoLock auto_lock(lock_);
502
503 switch_pending_ = false;
504
505 if (status == PIPELINE_OK) {
506 demuxers_[current_video_demuxer_index_]->SetPlaybackRate(0);
507 current_video_demuxer_index_ = new_stream_index;
508 demuxers_[current_video_demuxer_index_]->SetPlaybackRate(playback_rate_);
509 }
510 }
511
512 done_cb.Run(status);
145 } 513 }
146 514
147 Demuxer* AdaptiveDemuxer::current_demuxer(DemuxerStream::Type type) { 515 Demuxer* AdaptiveDemuxer::current_demuxer(DemuxerStream::Type type) {
148 base::AutoLock auto_lock(lock_); 516 base::AutoLock auto_lock(lock_);
149 switch (type) { 517 switch (type) {
150 case DemuxerStream::AUDIO: 518 case DemuxerStream::AUDIO:
151 return (current_audio_demuxer_index_ < 0) ? NULL : 519 return (current_audio_demuxer_index_ < 0) ? NULL :
152 demuxers_[current_audio_demuxer_index_]; 520 demuxers_[current_audio_demuxer_index_];
153 case DemuxerStream::VIDEO: 521 case DemuxerStream::VIDEO:
154 return (current_video_demuxer_index_ < 0) ? NULL : 522 return (current_video_demuxer_index_ < 0) ? NULL :
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
234 602
235 base::Lock lock_; 603 base::Lock lock_;
236 int remaining_count_; 604 int remaining_count_;
237 FilterStatusCB orig_cb_; 605 FilterStatusCB orig_cb_;
238 PipelineStatus overall_status_; 606 PipelineStatus overall_status_;
239 607
240 DISALLOW_COPY_AND_ASSIGN(CountingStatusCB); 608 DISALLOW_COPY_AND_ASSIGN(CountingStatusCB);
241 }; 609 };
242 610
243 void AdaptiveDemuxer::Stop(FilterCallback* callback) { 611 void AdaptiveDemuxer::Stop(FilterCallback* callback) {
612 stream_switch_manager_->Stop();
613
244 // Stop() must be called on all of the demuxers even though only one demuxer 614 // Stop() must be called on all of the demuxers even though only one demuxer
245 // is actively delivering audio and another one is delivering video. This 615 // is actively delivering audio and another one is delivering video. This
246 // just satisfies the contract that all demuxers must have Stop() called on 616 // just satisfies the contract that all demuxers must have Stop() called on
247 // them before they are destroyed. 617 // them before they are destroyed.
248 // 618 //
249 // TODO: Remove CountingCallback once Stop() is converted to FilterStatusCB. 619 // TODO: Remove CountingCallback once Stop() is converted to FilterStatusCB.
250 CountingCallback* wrapper = new CountingCallback(demuxers_.size(), callback); 620 CountingCallback* wrapper = new CountingCallback(demuxers_.size(), callback);
251 for (size_t i = 0; i < demuxers_.size(); ++i) 621 for (size_t i = 0; i < demuxers_.size(); ++i)
252 demuxers_[i]->Stop(wrapper->GetACallback()); 622 demuxers_[i]->Stop(wrapper->GetACallback());
253 } 623 }
254 624
255 void AdaptiveDemuxer::Seek(base::TimeDelta time, const FilterStatusCB& cb) { 625 void AdaptiveDemuxer::Seek(base::TimeDelta time, const FilterStatusCB& cb) {
626
627 if (audio_stream_)
628 audio_stream_->OnAdaptiveDemuxerSeek();
629
630 if (video_stream_)
631 video_stream_->OnAdaptiveDemuxerSeek();
632
256 Demuxer* audio = current_demuxer(DemuxerStream::AUDIO); 633 Demuxer* audio = current_demuxer(DemuxerStream::AUDIO);
257 Demuxer* video = current_demuxer(DemuxerStream::VIDEO); 634 Demuxer* video = current_demuxer(DemuxerStream::VIDEO);
258 int count = (audio ? 1 : 0) + (video && audio != video ? 1 : 0); 635 int count = (audio ? 1 : 0) + (video && audio != video ? 1 : 0);
259 CountingStatusCB* wrapper = new CountingStatusCB(count, cb); 636 CountingStatusCB* wrapper = new CountingStatusCB(count, cb);
260 if (audio) 637 if (audio)
261 audio->Seek(time, wrapper->GetACallback()); 638 audio->Seek(time, wrapper->GetACallback());
262 if (video && audio != video) 639 if (video && audio != video)
263 video->Seek(time, wrapper->GetACallback()); 640 video->Seek(time, wrapper->GetACallback());
264 } 641 }
265 642
266 void AdaptiveDemuxer::OnAudioRendererDisabled() { 643 void AdaptiveDemuxer::OnAudioRendererDisabled() {
267 for (size_t i = 0; i < demuxers_.size(); ++i) 644 for (size_t i = 0; i < demuxers_.size(); ++i)
268 demuxers_[i]->OnAudioRendererDisabled(); 645 demuxers_[i]->OnAudioRendererDisabled();
269 } 646 }
270 647
271 void AdaptiveDemuxer::set_host(FilterHost* filter_host) { 648 void AdaptiveDemuxer::set_host(FilterHost* filter_host) {
272 Demuxer* audio = current_demuxer(DemuxerStream::AUDIO); 649 Demuxer* audio = current_demuxer(DemuxerStream::AUDIO);
273 Demuxer* video = current_demuxer(DemuxerStream::VIDEO); 650 Demuxer* video = current_demuxer(DemuxerStream::VIDEO);
274 if (audio) audio->set_host(filter_host); 651 if (audio) audio->set_host(filter_host);
275 if (video && audio != video) video->set_host(filter_host); 652 if (video && audio != video) video->set_host(filter_host);
276 } 653 }
277 654
278 void AdaptiveDemuxer::SetPlaybackRate(float playback_rate) { 655 void AdaptiveDemuxer::SetPlaybackRate(float playback_rate) {
656 {
657 base::AutoLock auto_lock(lock_);
658 if (playback_rate_ == 0 && playback_rate > 0) {
659 stream_switch_manager_->Play();
660 } else if (playback_rate_ > 0 && playback_rate == 0) {
661 stream_switch_manager_->Pause();
662 }
663
664 playback_rate_ = playback_rate;
665 }
666
279 Demuxer* audio = current_demuxer(DemuxerStream::AUDIO); 667 Demuxer* audio = current_demuxer(DemuxerStream::AUDIO);
280 Demuxer* video = current_demuxer(DemuxerStream::VIDEO); 668 Demuxer* video = current_demuxer(DemuxerStream::VIDEO);
281 if (audio) audio->SetPlaybackRate(playback_rate); 669 if (audio) audio->SetPlaybackRate(playback_rate);
282 if (video && audio != video) video->SetPlaybackRate(playback_rate); 670 if (video && audio != video) video->SetPlaybackRate(playback_rate);
283 } 671 }
284 672
285 void AdaptiveDemuxer::SetPreload(Preload preload) { 673 void AdaptiveDemuxer::SetPreload(Preload preload) {
286 for (size_t i = 0; i < demuxers_.size(); ++i) 674 for (size_t i = 0; i < demuxers_.size(); ++i)
287 demuxers_[i]->SetPreload(preload); 675 demuxers_[i]->SetPreload(preload);
288 } 676 }
289 677
290 scoped_refptr<DemuxerStream> AdaptiveDemuxer::GetStream( 678 scoped_refptr<DemuxerStream> AdaptiveDemuxer::GetStream(
291 DemuxerStream::Type type) { 679 DemuxerStream::Type type) {
292 switch (type) { 680 switch (type) {
293 case DemuxerStream::AUDIO: 681 case DemuxerStream::AUDIO:
294 return audio_stream_; 682 return audio_stream_;
295 case DemuxerStream::VIDEO: 683 case DemuxerStream::VIDEO:
296 return video_stream_; 684 return video_stream_;
297 default: 685 default:
298 LOG(DFATAL) << "Unexpected type " << type; 686 LOG(DFATAL) << "Unexpected type " << type;
299 return NULL; 687 return NULL;
300 } 688 }
301 } 689 }
302 690
691 void AdaptiveDemuxer::StartStreamSwitchSeek(DemuxerStream::Type type,
692 int stream_index,
693 const base::TimeDelta& seek_time,
694 const SeekHelperCB& seek_cb) {
695 DCHECK(!seek_cb.is_null());
696
697 Demuxer* demuxer = NULL;
698 base::TimeDelta seek_point;
699 FilterStatusCB filter_cb;
700
701 {
702 base::AutoLock auto_lock(lock_);
703
704 demuxer = demuxers_[stream_index];
705
706 if (GetSeekTimeAfter(demuxer->GetStream(type)->GetAVStream(), seek_time,
707 &seek_point)) {
708 // We found a seek point.
709 filter_cb = base::Bind(&AdaptiveDemuxer::OnStreamSeekDone, this,
710 seek_point, seek_cb);
711 } else {
712 // We didn't find a seek point. Assume we don't have index data for it
713 // yet. Seek to the specified time to force index data to be loaded.
714 seek_point = seek_time;
715 filter_cb = base::Bind(&AdaptiveDemuxer::OnIndexSeekDone, this,
716 type, stream_index, seek_time, seek_cb);
717 }
718 }
719
720 if (!demuxer) {
721 seek_cb.Run(PIPELINE_ERROR_INVALID_STATE, base::TimeDelta());
722 return;
723 }
724
725 demuxer->Seek(seek_point, filter_cb);
726 }
727
728 void AdaptiveDemuxer::OnIndexSeekDone(DemuxerStream::Type type,
729 int stream_index,
730 const base::TimeDelta& seek_time,
731 const SeekHelperCB& seek_cb,
732 PipelineStatus status) {
733 base::TimeDelta seek_point;
734 FilterStatusCB filter_cb;
735
736 Demuxer* demuxer = NULL;
737
738 if (status != PIPELINE_OK) {
739 seek_cb.Run(status, base::TimeDelta());
740 return;
741 }
742
743 {
744 base::AutoLock auto_lock(lock_);
745
746 demuxer = demuxers_[stream_index];
747
748 // Look for a seek point now that we have index data.
749 if (GetSeekTimeAfter(demuxer->GetStream(type)->GetAVStream(), seek_time,
750 &seek_point)) {
751 filter_cb = base::Bind(&AdaptiveDemuxer::OnStreamSeekDone, this,
752 seek_point, seek_cb);
753 } else {
754 demuxer = NULL;
755 }
756 }
757
758 if (demuxer) {
759 demuxer->Seek(seek_point, filter_cb);
760 return;
761 }
762
763 // No seek point for specified seek_time.
764 seek_cb.Run(PIPELINE_ERROR_INITIALIZATION_FAILED, base::TimeDelta());
765 }
766
767 void AdaptiveDemuxer::OnStreamSeekDone(const base::TimeDelta& seek_point,
768 const SeekHelperCB& seek_cb,
769 PipelineStatus status) {
770 if (status != PIPELINE_OK) {
771 seek_cb.Run(status, base::TimeDelta());
772 return;
773 }
774
775 seek_cb.Run(PIPELINE_OK, seek_point);
776 }
777
778
303 // 779 //
304 // AdaptiveDemuxerFactory 780 // AdaptiveDemuxerFactory
305 // 781 //
306 782
307 AdaptiveDemuxerFactory::AdaptiveDemuxerFactory( 783 AdaptiveDemuxerFactory::AdaptiveDemuxerFactory(
308 DemuxerFactory* delegate_factory) 784 DemuxerFactory* delegate_factory)
309 : delegate_factory_(delegate_factory) { 785 : delegate_factory_(delegate_factory) {
310 DCHECK(delegate_factory); 786 DCHECK(delegate_factory);
311 } 787 }
312 788
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
485 delete cb; 961 delete cb;
486 return; 962 return;
487 } 963 }
488 DemuxerAccumulator* accumulator = new DemuxerAccumulator( 964 DemuxerAccumulator* accumulator = new DemuxerAccumulator(
489 audio_index, video_index, urls.size(), cb); 965 audio_index, video_index, urls.size(), cb);
490 for (size_t i = 0; i < urls.size(); ++i) 966 for (size_t i = 0; i < urls.size(); ++i)
491 delegate_factory_->Build(urls[i], accumulator->GetNthCallback(i)); 967 delegate_factory_->Build(urls[i], accumulator->GetNthCallback(i));
492 } 968 }
493 969
494 } // namespace media 970 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698