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

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

Issue 10558011: Fix ChunkDemuxer so it properly outputs buffered ranges. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address CR comments. Created 8 years, 6 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/filters/chunk_demuxer.h ('k') | media/filters/chunk_demuxer_unittest.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 (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/filters/chunk_demuxer.h" 5 #include "media/filters/chunk_demuxer.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/message_loop.h" 9 #include "base/message_loop.h"
10 #include "base/string_util.h" 10 #include "base/string_util.h"
11 #include "media/base/audio_decoder_config.h" 11 #include "media/base/audio_decoder_config.h"
12 #include "media/base/stream_parser_buffer.h" 12 #include "media/base/stream_parser_buffer.h"
13 #include "media/base/video_decoder_config.h" 13 #include "media/base/video_decoder_config.h"
14 #include "media/filters/chunk_demuxer_client.h" 14 #include "media/filters/chunk_demuxer_client.h"
15 #include "media/mp4/mp4_stream_parser.h" 15 #include "media/mp4/mp4_stream_parser.h"
16 #include "media/webm/webm_stream_parser.h" 16 #include "media/webm/webm_stream_parser.h"
17 17
18 using base::TimeDelta;
19
18 namespace media { 20 namespace media {
19 21
20 struct CodecInfo { 22 struct CodecInfo {
21 const char* pattern; 23 const char* pattern;
22 DemuxerStream::Type type; 24 DemuxerStream::Type type;
23 }; 25 };
24 26
25 typedef StreamParser* (*ParserFactoryFunction)(); 27 typedef StreamParser* (*ParserFactoryFunction)();
26 28
27 struct SupportedTypeInfo { 29 struct SupportedTypeInfo {
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 return new mp4::MP4StreamParser(); 68 return new mp4::MP4StreamParser();
67 } 69 }
68 70
69 static const SupportedTypeInfo kSupportedTypeInfo[] = { 71 static const SupportedTypeInfo kSupportedTypeInfo[] = {
70 { "video/webm", &BuildWebMParser, kVideoWebMCodecs }, 72 { "video/webm", &BuildWebMParser, kVideoWebMCodecs },
71 { "audio/webm", &BuildWebMParser, kAudioWebMCodecs }, 73 { "audio/webm", &BuildWebMParser, kAudioWebMCodecs },
72 { "video/mp4", &BuildMP4Parser, kVideoMP4Codecs }, 74 { "video/mp4", &BuildMP4Parser, kVideoMP4Codecs },
73 { "audio/mp4", &BuildMP4Parser, kAudioMP4Codecs }, 75 { "audio/mp4", &BuildMP4Parser, kAudioMP4Codecs },
74 }; 76 };
75 77
78
79 // The fake total size we use for converting times to bytes
80 // for AddBufferedByteRange() calls.
81 // TODO(acolwell): Remove this once Pipeline accepts buffered times
82 // instead of only buffered bytes.
83 enum { kFakeTotalBytes = 1000000 };
84
76 // Checks to see if the specified |type| and |codecs| list are supported. 85 // Checks to see if the specified |type| and |codecs| list are supported.
77 // Returns true if |type| and all codecs listed in |codecs| are supported. 86 // Returns true if |type| and all codecs listed in |codecs| are supported.
78 // |factory_function| contains a function that can build a StreamParser 87 // |factory_function| contains a function that can build a StreamParser
79 // for this type. 88 // for this type.
80 // |has_audio| is true if an audio codec was specified. 89 // |has_audio| is true if an audio codec was specified.
81 // |has_video| is true if a video codec was specified. 90 // |has_video| is true if a video codec was specified.
82 // Returns false otherwise. The values of |factory_function|, |has_audio|, 91 // Returns false otherwise. The values of |factory_function|, |has_audio|,
83 // and |has_video| are undefined. 92 // and |has_video| are undefined.
84 static bool IsSupported(const std::string& type, 93 static bool IsSupported(const std::string& type,
85 std::vector<std::string>& codecs, 94 std::vector<std::string>& codecs,
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
140 class ChunkDemuxerStream : public DemuxerStream { 149 class ChunkDemuxerStream : public DemuxerStream {
141 public: 150 public:
142 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; 151 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue;
143 typedef std::deque<ReadCB> ReadCBQueue; 152 typedef std::deque<ReadCB> ReadCBQueue;
144 typedef std::deque<base::Closure> ClosureQueue; 153 typedef std::deque<base::Closure> ClosureQueue;
145 154
146 explicit ChunkDemuxerStream(const AudioDecoderConfig& audio_config); 155 explicit ChunkDemuxerStream(const AudioDecoderConfig& audio_config);
147 explicit ChunkDemuxerStream(const VideoDecoderConfig& video_config); 156 explicit ChunkDemuxerStream(const VideoDecoderConfig& video_config);
148 157
149 void StartWaitingForSeek(); 158 void StartWaitingForSeek();
150 void Seek(base::TimeDelta time); 159 void Seek(TimeDelta time);
151 bool IsSeekPending() const; 160 bool IsSeekPending() const;
152 void Flush(); 161 void Flush();
153 162
154 // Add buffers to this stream. Buffers are stored in SourceBufferStreams, 163 // Add buffers to this stream. Buffers are stored in SourceBufferStreams,
155 // which handle ordering and overlap resolution. 164 // which handle ordering and overlap resolution.
156 // Returns true if buffers were successfully added. 165 // Returns true if buffers were successfully added.
157 bool Append(const StreamParser::BufferQueue& buffers); 166 bool Append(const StreamParser::BufferQueue& buffers);
158 167
159 // Returns a list of the buffered time ranges. 168 // Returns a list of the buffered time ranges.
160 SourceBufferStream::TimespanList GetBufferedTime() const; 169 Ranges<TimeDelta> GetBufferedTime() const;
161 170
162 // Signal to the stream that buffers handed in through subsequent calls to 171 // Signal to the stream that buffers handed in through subsequent calls to
163 // Append() belong to a media segment that starts at |start_timestamp|. 172 // Append() belong to a media segment that starts at |start_timestamp|.
164 void OnNewMediaSegment(base::TimeDelta start_timestamp); 173 void OnNewMediaSegment(TimeDelta start_timestamp);
165 174
166 // Called when mid-stream config updates occur. 175 // Called when mid-stream config updates occur.
167 // Returns true if the new config is accepted. 176 // Returns true if the new config is accepted.
168 // Returns false if the new config should trigger an error. 177 // Returns false if the new config should trigger an error.
169 bool UpdateAudioConfig(const AudioDecoderConfig& config); 178 bool UpdateAudioConfig(const AudioDecoderConfig& config);
170 bool UpdateVideoConfig(const VideoDecoderConfig& config); 179 bool UpdateVideoConfig(const VideoDecoderConfig& config);
171 180
172 void EndOfStream(); 181 void EndOfStream();
173 bool CanEndOfStream() const; 182 bool CanEndOfStream() const;
174 void Shutdown(); 183 void Shutdown();
(...skipping 30 matching lines...) Expand all
205 Type type_; 214 Type type_;
206 215
207 scoped_ptr<SourceBufferStream> stream_; 216 scoped_ptr<SourceBufferStream> stream_;
208 217
209 mutable base::Lock lock_; 218 mutable base::Lock lock_;
210 State state_; 219 State state_;
211 ReadCBQueue read_cbs_; 220 ReadCBQueue read_cbs_;
212 221
213 // The timestamp of the current media segment being parsed by 222 // The timestamp of the current media segment being parsed by
214 // |stream_parser_|. 223 // |stream_parser_|.
215 base::TimeDelta media_segment_start_time_; 224 TimeDelta media_segment_start_time_;
216 225
217 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); 226 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream);
218 }; 227 };
219 228
220 ChunkDemuxerStream::ChunkDemuxerStream(const AudioDecoderConfig& audio_config) 229 ChunkDemuxerStream::ChunkDemuxerStream(const AudioDecoderConfig& audio_config)
221 : type_(AUDIO), 230 : type_(AUDIO),
222 state_(RETURNING_DATA_FOR_READS), 231 state_(RETURNING_DATA_FOR_READS),
223 media_segment_start_time_(kNoTimestamp()) { 232 media_segment_start_time_(kNoTimestamp()) {
224 stream_.reset(new SourceBufferStream(audio_config)); 233 stream_.reset(new SourceBufferStream(audio_config));
225 } 234 }
(...skipping 11 matching lines...) Expand all
237 base::AutoLock auto_lock(lock_); 246 base::AutoLock auto_lock(lock_);
238 ChangeState_Locked(WAITING_FOR_SEEK); 247 ChangeState_Locked(WAITING_FOR_SEEK);
239 248
240 std::swap(read_cbs_, read_cbs); 249 std::swap(read_cbs_, read_cbs);
241 } 250 }
242 251
243 for (ReadCBQueue::iterator it = read_cbs.begin(); it != read_cbs.end(); ++it) 252 for (ReadCBQueue::iterator it = read_cbs.begin(); it != read_cbs.end(); ++it)
244 it->Run(NULL); 253 it->Run(NULL);
245 } 254 }
246 255
247 void ChunkDemuxerStream::Seek(base::TimeDelta time) { 256 void ChunkDemuxerStream::Seek(TimeDelta time) {
248 base::AutoLock auto_lock(lock_); 257 base::AutoLock auto_lock(lock_);
249 258
250 DCHECK(read_cbs_.empty()); 259 DCHECK(read_cbs_.empty());
251 260
252 stream_->Seek(time); 261 stream_->Seek(time);
253 262
254 if (state_ == WAITING_FOR_SEEK) 263 if (state_ == WAITING_FOR_SEEK)
255 ChangeState_Locked(RETURNING_DATA_FOR_READS); 264 ChangeState_Locked(RETURNING_DATA_FOR_READS);
256 } 265 }
257 266
258 bool ChunkDemuxerStream::IsSeekPending() const { 267 bool ChunkDemuxerStream::IsSeekPending() const {
259 base::AutoLock auto_lock(lock_); 268 base::AutoLock auto_lock(lock_);
260 return stream_->IsSeekPending(); 269 return stream_->IsSeekPending();
261 } 270 }
262 271
263 void ChunkDemuxerStream::Flush() { 272 void ChunkDemuxerStream::Flush() {
264 media_segment_start_time_ = kNoTimestamp(); 273 media_segment_start_time_ = kNoTimestamp();
265 } 274 }
266 275
267 void ChunkDemuxerStream::OnNewMediaSegment(base::TimeDelta start_timestamp) { 276 void ChunkDemuxerStream::OnNewMediaSegment(TimeDelta start_timestamp) {
268 media_segment_start_time_ = start_timestamp; 277 media_segment_start_time_ = start_timestamp;
269 } 278 }
270 279
271 bool ChunkDemuxerStream::Append(const StreamParser::BufferQueue& buffers) { 280 bool ChunkDemuxerStream::Append(const StreamParser::BufferQueue& buffers) {
272 if (buffers.empty()) 281 if (buffers.empty())
273 return false; 282 return false;
274 283
275 ClosureQueue closures; 284 ClosureQueue closures;
276 { 285 {
277 base::AutoLock auto_lock(lock_); 286 base::AutoLock auto_lock(lock_);
278 DCHECK_NE(state_, SHUTDOWN); 287 DCHECK_NE(state_, SHUTDOWN);
279 DCHECK(media_segment_start_time_ != kNoTimestamp()); 288 DCHECK(media_segment_start_time_ != kNoTimestamp());
280 if (!stream_->Append(buffers, media_segment_start_time_)) { 289 if (!stream_->Append(buffers, media_segment_start_time_)) {
281 DVLOG(1) << "ChunkDemuxerStream::Append() : stream append failed"; 290 DVLOG(1) << "ChunkDemuxerStream::Append() : stream append failed";
282 return false; 291 return false;
283 } 292 }
284 CreateReadDoneClosures_Locked(&closures); 293 CreateReadDoneClosures_Locked(&closures);
285 } 294 }
286 295
287 for (ClosureQueue::iterator it = closures.begin(); it != closures.end(); ++it) 296 for (ClosureQueue::iterator it = closures.begin(); it != closures.end(); ++it)
288 it->Run(); 297 it->Run();
289 298
290 return true; 299 return true;
291 } 300 }
292 301
293 SourceBufferStream::TimespanList ChunkDemuxerStream::GetBufferedTime() const { 302 Ranges<TimeDelta> ChunkDemuxerStream::GetBufferedTime() const {
294 base::AutoLock auto_lock(lock_); 303 base::AutoLock auto_lock(lock_);
295 return stream_->GetBufferedTime(); 304 return stream_->GetBufferedTime();
296 } 305 }
297 306
298 bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config) { 307 bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config) {
299 DCHECK(config.IsValidConfig()); 308 DCHECK(config.IsValidConfig());
300 DCHECK_EQ(type_, AUDIO); 309 DCHECK_EQ(type_, AUDIO);
301 310
302 const AudioDecoderConfig& current_config = 311 const AudioDecoderConfig& current_config =
303 stream_->GetCurrentAudioDecoderConfig(); 312 stream_->GetCurrentAudioDecoderConfig();
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
456 if (!stream_->GetNextBuffer(&buffer)) 465 if (!stream_->GetNextBuffer(&buffer))
457 return; 466 return;
458 closures->push_back(base::Bind(read_cbs_.front(), buffer)); 467 closures->push_back(base::Bind(read_cbs_.front(), buffer));
459 read_cbs_.pop_front(); 468 read_cbs_.pop_front();
460 } 469 }
461 } 470 }
462 471
463 ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client) 472 ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client)
464 : state_(WAITING_FOR_INIT), 473 : state_(WAITING_FOR_INIT),
465 host_(NULL), 474 host_(NULL),
466 client_(client), 475 client_(client) {
467 buffered_bytes_(0) {
468 DCHECK(client); 476 DCHECK(client);
469 } 477 }
470 478
471 void ChunkDemuxer::Initialize(DemuxerHost* host, 479 void ChunkDemuxer::Initialize(DemuxerHost* host,
472 const PipelineStatusCB& cb) { 480 const PipelineStatusCB& cb) {
473 DVLOG(1) << "Init()"; 481 DVLOG(1) << "Init()";
474 { 482 {
475 base::AutoLock auto_lock(lock_); 483 base::AutoLock auto_lock(lock_);
476 DCHECK_EQ(state_, WAITING_FOR_INIT); 484 DCHECK_EQ(state_, WAITING_FOR_INIT);
477 host_ = host; 485 host_ = host;
478 486
479 ChangeState_Locked(INITIALIZING); 487 ChangeState_Locked(INITIALIZING);
480 init_cb_ = cb; 488 init_cb_ = cb;
481 } 489 }
482 490
483 client_->DemuxerOpened(this); 491 client_->DemuxerOpened(this);
484 } 492 }
485 493
486 void ChunkDemuxer::Stop(const base::Closure& callback) { 494 void ChunkDemuxer::Stop(const base::Closure& callback) {
487 DVLOG(1) << "Stop()"; 495 DVLOG(1) << "Stop()";
488 Shutdown(); 496 Shutdown();
489 callback.Run(); 497 callback.Run();
490 } 498 }
491 499
492 void ChunkDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) { 500 void ChunkDemuxer::Seek(TimeDelta time, const PipelineStatusCB& cb) {
493 DVLOG(1) << "Seek(" << time.InSecondsF() << ")"; 501 DVLOG(1) << "Seek(" << time.InSecondsF() << ")";
494 502
495 PipelineStatus status = PIPELINE_ERROR_INVALID_STATE; 503 PipelineStatus status = PIPELINE_ERROR_INVALID_STATE;
496 { 504 {
497 base::AutoLock auto_lock(lock_); 505 base::AutoLock auto_lock(lock_);
498 506
499 if (state_ == INITIALIZED || state_ == ENDED) { 507 if (state_ == INITIALIZED || state_ == ENDED) {
500 if (audio_) 508 if (audio_)
501 audio_->Seek(time); 509 audio_->Seek(time);
502 510
(...skipping 28 matching lines...) Expand all
531 DemuxerStream::Type type) { 539 DemuxerStream::Type type) {
532 if (type == DemuxerStream::VIDEO) 540 if (type == DemuxerStream::VIDEO)
533 return video_; 541 return video_;
534 542
535 if (type == DemuxerStream::AUDIO) 543 if (type == DemuxerStream::AUDIO)
536 return audio_; 544 return audio_;
537 545
538 return NULL; 546 return NULL;
539 } 547 }
540 548
541 base::TimeDelta ChunkDemuxer::GetStartTime() const { 549 TimeDelta ChunkDemuxer::GetStartTime() const {
542 DVLOG(1) << "GetStartTime()"; 550 DVLOG(1) << "GetStartTime()";
543 // TODO(acolwell) : Fix this so it uses the time on the first packet. 551 // TODO(acolwell) : Fix this so it uses the time on the first packet.
544 // (crbug.com/132815) 552 // (crbug.com/132815)
545 return base::TimeDelta(); 553 return TimeDelta();
546 } 554 }
547 555
548 void ChunkDemuxer::StartWaitingForSeek() { 556 void ChunkDemuxer::StartWaitingForSeek() {
549 DVLOG(1) << "StartWaitingForSeek()"; 557 DVLOG(1) << "StartWaitingForSeek()";
550 base::AutoLock auto_lock(lock_); 558 base::AutoLock auto_lock(lock_);
551 DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN); 559 DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN);
552 560
553 if (state_ == SHUTDOWN) 561 if (state_ == SHUTDOWN)
554 return; 562 return;
555 563
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
620 delete stream_parser_map_[id]; 628 delete stream_parser_map_[id];
621 stream_parser_map_.erase(id); 629 stream_parser_map_.erase(id);
622 630
623 if (source_id_audio_ == id && audio_) 631 if (source_id_audio_ == id && audio_)
624 audio_->Shutdown(); 632 audio_->Shutdown();
625 633
626 if (source_id_video_ == id && video_) 634 if (source_id_video_ == id && video_)
627 video_->Shutdown(); 635 video_->Shutdown();
628 } 636 }
629 637
630 bool ChunkDemuxer::GetBufferedRanges(const std::string& id, 638 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const {
631 Ranges* ranges_out) const {
632 DCHECK(!id.empty()); 639 DCHECK(!id.empty());
633 DCHECK_GT(stream_parser_map_.count(id), 0u); 640 DCHECK_GT(stream_parser_map_.count(id), 0u);
634 DCHECK(id == source_id_audio_ || id == source_id_video_); 641 DCHECK(id == source_id_audio_ || id == source_id_video_);
635 DCHECK(ranges_out);
636 642
637 base::AutoLock auto_lock(lock_); 643 base::AutoLock auto_lock(lock_);
638 644
639 if (id == source_id_audio_ && id != source_id_video_) { 645 if (id == source_id_audio_ && id != source_id_video_) {
640 // Only include ranges that have been buffered in |audio_| 646 // Only include ranges that have been buffered in |audio_|
641 return CopyIntoRanges(audio_->GetBufferedTime(), ranges_out); 647 return audio_->GetBufferedTime();
642 } 648 }
643 649
644 if (id != source_id_audio_ && id == source_id_video_) { 650 if (id != source_id_audio_ && id == source_id_video_) {
645 // Only include ranges that have been buffered in |video_| 651 // Only include ranges that have been buffered in |video_|
646 return CopyIntoRanges(video_->GetBufferedTime(), ranges_out); 652 return video_->GetBufferedTime();
647 } 653 }
648 654
655 return ComputeIntersection();
656 }
657
658 Ranges<TimeDelta> ChunkDemuxer::ComputeIntersection() const {
659 lock_.AssertAcquired();
660
661 if (!audio_ || !video_)
662 return Ranges<TimeDelta>();
663
649 // Include ranges that have been buffered in both |audio_| and |video_|. 664 // Include ranges that have been buffered in both |audio_| and |video_|.
650 SourceBufferStream::TimespanList audio_ranges = audio_->GetBufferedTime(); 665 Ranges<TimeDelta> audio_ranges = audio_->GetBufferedTime();
651 SourceBufferStream::TimespanList video_ranges = video_->GetBufferedTime(); 666 Ranges<TimeDelta> video_ranges = video_->GetBufferedTime();
652 SourceBufferStream::TimespanList::const_iterator video_ranges_itr = 667 Ranges<TimeDelta> result = audio_ranges.IntersectionWith(video_ranges);
653 video_ranges.begin();
654 SourceBufferStream::TimespanList::const_iterator audio_ranges_itr =
655 audio_ranges.begin();
656 bool success = false;
657 668
658 while (audio_ranges_itr != audio_ranges.end() && 669 if (state_ == ENDED) {
659 video_ranges_itr != video_ranges.end()) { 670 // If appending has ended, extend the intersection to include all of the
660 // If this is the last range and EndOfStream() was called (i.e. all data 671 // data from the last ranges for each stream. This allows the buffered
Ami GONE FROM CHROMIUM 2012/06/19 20:23:38 So then this is not completely correct, as you say
acolwell GONE FROM CHROMIUM 2012/06/19 22:39:36 Done.
661 // has been appended), choose the max end point of the ranges. 672 // information to match the actual time range that will get played out if
662 bool last_range_after_ended = 673 // the streams have slightly different lengths. We only do this if the
663 state_ == ENDED && 674 // final ranges overlap because this indicates there is actually a location
Ami GONE FROM CHROMIUM 2012/06/19 20:23:38 The final ranges must overlap b/c you don't allow
acolwell GONE FROM CHROMIUM 2012/06/19 22:39:36 Done.
664 (audio_ranges_itr + 1) == audio_ranges.end() && 675 // you can seek to, near the end, where we have data for both streams.
665 (video_ranges_itr + 1) == video_ranges.end(); 676 TimeDelta audio_start = audio_ranges.start(audio_ranges.size() - 1);
677 TimeDelta audio_end = audio_ranges.end(audio_ranges.size() - 1);
678 TimeDelta video_start = video_ranges.start(video_ranges.size() - 1);
679 TimeDelta video_end = video_ranges.end(video_ranges.size() - 1);
666 680
667 // Audio range start time is within the video range. 681 if ((audio_start <= video_start && video_start <= audio_end) ||
Ami GONE FROM CHROMIUM 2012/06/19 20:23:38 ...and this if needs to turn into a DCHECK.
acolwell GONE FROM CHROMIUM 2012/06/19 22:39:36 Done.
668 if ((*audio_ranges_itr).first >= (*video_ranges_itr).first && 682 (video_start <= audio_start && audio_start <= video_end)) {
669 (*audio_ranges_itr).first <= (*video_ranges_itr).second) { 683 result.Add(std::max(audio_start, video_start),
Ami GONE FROM CHROMIUM 2012/06/19 20:23:38 Once you DCHECK, this Add can be result.Add(result
acolwell GONE FROM CHROMIUM 2012/06/19 22:39:36 Done.
670 AddIntersectionRange(*audio_ranges_itr, *video_ranges_itr, 684 std::max(audio_end, video_end));
671 last_range_after_ended, ranges_out);
672 audio_ranges_itr++;
673 success = true;
674 continue;
675 } 685 }
676
677 // Video range start time is within the audio range.
678 if ((*video_ranges_itr).first >= (*audio_ranges_itr).first &&
679 (*video_ranges_itr).first <= (*audio_ranges_itr).second) {
680 AddIntersectionRange(*video_ranges_itr, *audio_ranges_itr,
681 last_range_after_ended, ranges_out);
682 video_ranges_itr++;
683 success = true;
684 continue;
685 }
686
687 // No overlap was found. Increment the earliest one and keep looking.
688 if ((*audio_ranges_itr).first < (*video_ranges_itr).first)
689 audio_ranges_itr++;
690 else
691 video_ranges_itr++;
692 } 686 }
693 687
694 return success; 688 return result;
695 }
696
697 bool ChunkDemuxer::CopyIntoRanges(
698 const SourceBufferStream::TimespanList& timespans,
699 Ranges* ranges_out) const {
700 for (SourceBufferStream::TimespanList::const_iterator itr = timespans.begin();
701 itr != timespans.end(); ++itr) {
702 ranges_out->push_back(*itr);
703 }
704 return !timespans.empty();
705 }
706
707 void ChunkDemuxer::AddIntersectionRange(
708 SourceBufferStream::Timespan timespan_a,
709 SourceBufferStream::Timespan timespan_b,
710 bool last_range_after_ended,
711 Ranges* ranges_out) const {
712 base::TimeDelta start = timespan_a.first;
713
714 // If this is the last range after EndOfStream() was called, choose the later
715 // end point of the ranges, otherwise choose the earlier.
716 base::TimeDelta end;
717 if (last_range_after_ended)
718 end = std::max(timespan_a.second, timespan_b.second);
719 else
720 end = std::min(timespan_a.second, timespan_b.second);
721
722 ranges_out->push_back(std::make_pair(start, end));
723 } 689 }
724 690
725 bool ChunkDemuxer::AppendData(const std::string& id, 691 bool ChunkDemuxer::AppendData(const std::string& id,
726 const uint8* data, 692 const uint8* data,
727 size_t length) { 693 size_t length) {
728 DVLOG(1) << "AppendData(" << id << ", " << length << ")"; 694 DVLOG(1) << "AppendData(" << id << ", " << length << ")";
729 695
730 DCHECK(!id.empty()); 696 DCHECK(!id.empty());
731 DCHECK(data); 697 DCHECK(data);
732 DCHECK_GT(length, 0u); 698 DCHECK_GT(length, 0u);
733 699
734 int64 buffered_bytes = 0; 700 Ranges<TimeDelta> ranges;
735 701
736 PipelineStatusCB cb; 702 PipelineStatusCB cb;
737 { 703 {
738 base::AutoLock auto_lock(lock_); 704 base::AutoLock auto_lock(lock_);
739 705
740 // Capture if the SourceBuffer has a pending seek before we start parsing. 706 // Capture if the SourceBuffer has a pending seek before we start parsing.
741 bool old_seek_pending = IsSeekPending_Locked(); 707 bool old_seek_pending = IsSeekPending_Locked();
742 708
743 switch (state_) { 709 switch (state_) {
744 case INITIALIZING: 710 case INITIALIZING:
(...skipping 20 matching lines...) Expand all
765 DVLOG(1) << "AppendData(): called in unexpected state " << state_; 731 DVLOG(1) << "AppendData(): called in unexpected state " << state_;
766 return false; 732 return false;
767 } 733 }
768 734
769 // Check to see if data was appended at the pending seek point. This 735 // Check to see if data was appended at the pending seek point. This
770 // indicates we have parsed enough data to complete the seek. 736 // indicates we have parsed enough data to complete the seek.
771 if (old_seek_pending && !IsSeekPending_Locked() && !seek_cb_.is_null()) { 737 if (old_seek_pending && !IsSeekPending_Locked() && !seek_cb_.is_null()) {
772 std::swap(cb, seek_cb_); 738 std::swap(cb, seek_cb_);
773 } 739 }
774 740
775 buffered_bytes_ += length; 741 if (duration_ > TimeDelta() && duration_ != kInfiniteDuration()) {
776 buffered_bytes = buffered_bytes_; 742 if (audio_ && !video_) {
743 ranges = audio_->GetBufferedTime();
744 } else if (!audio_ && video_) {
745 ranges = video_->GetBufferedTime();
746 } else {
747 ranges = ComputeIntersection();
748 }
749 }
777 } 750 }
778 751
779 // Notify the host of 'network activity' because we got data, using a bogus 752 DCHECK(!ranges.size() || duration_ > TimeDelta());
780 // range. 753 for (size_t i = 0; i < ranges.size(); ++i) {
781 host_->AddBufferedByteRange(0, buffered_bytes); 754 // Notify the host of 'network activity' because we got data.
755 int64 start =
756 kFakeTotalBytes * ranges.start(i).InSecondsF() / duration_.InSecondsF();
757 int64 end =
758 kFakeTotalBytes * ranges.end(i).InSecondsF() / duration_.InSecondsF();
759 host_->AddBufferedByteRange(start, end);
760 }
782 761
783 if (!cb.is_null()) 762 if (!cb.is_null())
784 cb.Run(PIPELINE_OK); 763 cb.Run(PIPELINE_OK);
785 764
786 return true; 765 return true;
787 } 766 }
788 767
789 void ChunkDemuxer::Abort(const std::string& id) { 768 void ChunkDemuxer::Abort(const std::string& id) {
790 DVLOG(1) << "Abort(" << id << ")"; 769 DVLOG(1) << "Abort(" << id << ")";
791 DCHECK(!id.empty()); 770 DCHECK(!id.empty());
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
921 900
922 return seek_pending; 901 return seek_pending;
923 } 902 }
924 903
925 bool ChunkDemuxer::CanEndOfStream_Locked() const { 904 bool ChunkDemuxer::CanEndOfStream_Locked() const {
926 lock_.AssertAcquired(); 905 lock_.AssertAcquired();
927 return (!audio_ || audio_->CanEndOfStream()) && 906 return (!audio_ || audio_->CanEndOfStream()) &&
928 (!video_ || video_->CanEndOfStream()); 907 (!video_ || video_->CanEndOfStream());
929 } 908 }
930 909
931 void ChunkDemuxer::OnStreamParserInitDone(bool success, 910 void ChunkDemuxer::OnStreamParserInitDone(bool success, TimeDelta duration) {
932 base::TimeDelta duration) {
933 DVLOG(1) << "OnSourceBufferInitDone(" << success << ", " 911 DVLOG(1) << "OnSourceBufferInitDone(" << success << ", "
934 << duration.InSecondsF() << ")"; 912 << duration.InSecondsF() << ")";
935 lock_.AssertAcquired(); 913 lock_.AssertAcquired();
936 DCHECK_EQ(state_, INITIALIZING); 914 DCHECK_EQ(state_, INITIALIZING);
937 if (!success || (!audio_ && !video_)) { 915 if (!success || (!audio_ && !video_)) {
938 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); 916 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
939 return; 917 return;
940 } 918 }
941 919
942 if (duration > duration_) 920 if (duration > duration_)
943 duration_ = duration; 921 duration_ = duration;
944 922
945 // Wait until all streams have initialized. 923 // Wait until all streams have initialized.
946 if ((!source_id_audio_.empty() && !audio_) || 924 if ((!source_id_audio_.empty() && !audio_) ||
947 (!source_id_video_.empty() && !video_)) 925 (!source_id_video_.empty() && !video_))
948 return; 926 return;
949 927
928 if (duration_ > TimeDelta() && duration_ != kInfiniteDuration())
929 host_->SetTotalBytes(kFakeTotalBytes);
950 host_->SetDuration(duration_); 930 host_->SetDuration(duration_);
951 931
952 ChangeState_Locked(INITIALIZED); 932 ChangeState_Locked(INITIALIZED);
953 PipelineStatusCB cb; 933 PipelineStatusCB cb;
954 std::swap(cb, init_cb_); 934 std::swap(cb, init_cb_);
955 cb.Run(PIPELINE_OK); 935 cb.Run(PIPELINE_OK);
956 } 936 }
957 937
958 bool ChunkDemuxer::OnNewConfigs(bool has_audio, bool has_video, 938 bool ChunkDemuxer::OnNewConfigs(bool has_audio, bool has_video,
959 const AudioDecoderConfig& audio_config, 939 const AudioDecoderConfig& audio_config,
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
1017 return video_->Append(buffers); 997 return video_->Append(buffers);
1018 } 998 }
1019 999
1020 bool ChunkDemuxer::OnNeedKey(scoped_array<uint8> init_data, 1000 bool ChunkDemuxer::OnNeedKey(scoped_array<uint8> init_data,
1021 int init_data_size) { 1001 int init_data_size) {
1022 client_->DemuxerNeedKey(init_data.Pass(), init_data_size); 1002 client_->DemuxerNeedKey(init_data.Pass(), init_data_size);
1023 return true; 1003 return true;
1024 } 1004 }
1025 1005
1026 void ChunkDemuxer::OnNewMediaSegment(const std::string& source_id, 1006 void ChunkDemuxer::OnNewMediaSegment(const std::string& source_id,
1027 base::TimeDelta start_timestamp) { 1007 TimeDelta start_timestamp) {
1028 // TODO(vrk): There should be a special case for the first appends where all 1008 // TODO(vrk): There should be a special case for the first appends where all
1029 // streams (for both demuxed and muxed case) begin at the earliest stream 1009 // streams (for both demuxed and muxed case) begin at the earliest stream
1030 // timestamp. (crbug.com/132815) 1010 // timestamp. (crbug.com/132815)
1031 if (audio_ && source_id == source_id_audio_) 1011 if (audio_ && source_id == source_id_audio_)
1032 audio_->OnNewMediaSegment(start_timestamp); 1012 audio_->OnNewMediaSegment(start_timestamp);
1033 if (video_ && source_id == source_id_video_) 1013 if (video_ && source_id == source_id_video_)
1034 video_->OnNewMediaSegment(start_timestamp); 1014 video_->OnNewMediaSegment(start_timestamp);
1035 } 1015 }
1036 1016
1037 } // namespace media 1017 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/chunk_demuxer.h ('k') | media/filters/chunk_demuxer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698