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

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

Issue 23702007: Render inband text tracks in the media pipeline (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: incorporate aaron's comments (10/12) Created 7 years, 2 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
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 <algorithm> 7 #include <algorithm>
8 #include <deque> 8 #include <deque>
9 #include <limits> 9 #include <limits>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/callback_helpers.h" 12 #include "base/callback_helpers.h"
13 #include "base/location.h" 13 #include "base/location.h"
14 #include "base/message_loop/message_loop_proxy.h" 14 #include "base/message_loop/message_loop_proxy.h"
15 #include "media/base/audio_decoder_config.h" 15 #include "media/base/audio_decoder_config.h"
16 #include "media/base/bind_to_loop.h" 16 #include "media/base/bind_to_loop.h"
17 #include "media/base/stream_parser_buffer.h" 17 #include "media/base/stream_parser_buffer.h"
18 #include "media/base/video_decoder_config.h" 18 #include "media/base/video_decoder_config.h"
19 #include "media/filters/stream_parser_factory.h" 19 #include "media/filters/stream_parser_factory.h"
20 #include "media/webm/webm_webvtt_parser.h"
21 20
22 using base::TimeDelta; 21 using base::TimeDelta;
23 22
24 namespace media { 23 namespace media {
25 24
26 // Contains state belonging to a source id. 25 // Contains state belonging to a source id.
27 class SourceState { 26 class SourceState {
28 public: 27 public:
29 // Callback signature used to create ChunkDemuxerStreams. 28 // Callback signature used to create ChunkDemuxerStreams.
30 typedef base::Callback<ChunkDemuxerStream*( 29 typedef base::Callback<ChunkDemuxerStream*(
31 DemuxerStream::Type)> CreateDemuxerStreamCB; 30 DemuxerStream::Type)> CreateDemuxerStreamCB;
32 31
33 // Callback signature used to notify ChunkDemuxer of timestamps 32 // Callback signature used to notify ChunkDemuxer of timestamps
34 // that may cause the duration to be updated. 33 // that may cause the duration to be updated.
35 typedef base::Callback<void( 34 typedef base::Callback<void(
36 TimeDelta, ChunkDemuxerStream*)> IncreaseDurationCB; 35 TimeDelta, ChunkDemuxerStream*)> IncreaseDurationCB;
37 36
38 SourceState(scoped_ptr<StreamParser> stream_parser, const LogCB& log_cb, 37 SourceState(scoped_ptr<StreamParser> stream_parser, const LogCB& log_cb,
39 const CreateDemuxerStreamCB& create_demuxer_stream_cb, 38 const CreateDemuxerStreamCB& create_demuxer_stream_cb,
40 const IncreaseDurationCB& increase_duration_cb); 39 const IncreaseDurationCB& increase_duration_cb);
41 40
41 // Called when a new text track has been parsed, so the demuxer can alert
42 // the demuxer host.
43 typedef base::Callback<void(ChunkDemuxerStream* stream,
44 TextKind kind,
45 const std::string& name,
46 const std::string& language)> NewTextTrackCB;
47
42 void Init(const StreamParser::InitCB& init_cb, 48 void Init(const StreamParser::InitCB& init_cb,
43 bool allow_audio, 49 bool allow_audio,
44 bool allow_video, 50 bool allow_video,
45 const StreamParser::NewTextBuffersCB& text_cb,
46 const StreamParser::NeedKeyCB& need_key_cb, 51 const StreamParser::NeedKeyCB& need_key_cb,
47 const AddTextTrackCB& add_text_track_cb); 52 const NewTextTrackCB& new_text_track_cb);
48 53
49 // Appends new data to the StreamParser. 54 // Appends new data to the StreamParser.
50 // Returns true if the data was successfully appended. Returns false if an 55 // Returns true if the data was successfully appended. Returns false if an
51 // error occurred. 56 // error occurred.
52 bool Append(const uint8* data, size_t length); 57 bool Append(const uint8* data, size_t length);
53 58
54 // Aborts the current append sequence and resets the parser. 59 // Aborts the current append sequence and resets the parser.
55 void Abort(); 60 void Abort();
56 61
57 // Sets |timestamp_offset_| if possible. 62 // Sets |timestamp_offset_| if possible.
(...skipping 25 matching lines...) Expand all
83 88
84 // Called by the |stream_parser_| when new buffers have been parsed. It 89 // Called by the |stream_parser_| when new buffers have been parsed. It
85 // applies |timestamp_offset_| to all buffers in |audio_buffers| and 90 // applies |timestamp_offset_| to all buffers in |audio_buffers| and
86 // |video_buffers| and then calls Append() on |audio_| and/or 91 // |video_buffers| and then calls Append() on |audio_| and/or
87 // |video_| with the modified buffers. 92 // |video_| with the modified buffers.
88 // Returns true on a successful call. Returns false if an error occured while 93 // Returns true on a successful call. Returns false if an error occured while
89 // processing the buffers. 94 // processing the buffers.
90 bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers, 95 bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers,
91 const StreamParser::BufferQueue& video_buffers); 96 const StreamParser::BufferQueue& video_buffers);
92 97
98 void OnNewTextTrack(int text_track_num,
99 TextKind kind,
100 const std::string& name,
101 const std::string& language);
102
93 // Called by the |stream_parser_| when new text buffers have been parsed. It 103 // Called by the |stream_parser_| when new text buffers have been parsed. It
94 // applies |timestamp_offset_| to all buffers in |buffers| and then calls 104 // applies |timestamp_offset_| to all buffers in |buffers| and then appends
95 // |new_buffers_cb| with the modified buffers. 105 // the (modified) buffers to the demuxer stream associated with
106 // the track having |text_track_number|.
96 // Returns true on a successful call. Returns false if an error occured while 107 // Returns true on a successful call. Returns false if an error occured while
97 // processing the buffers. 108 // processing the buffers.
98 bool OnTextBuffers(const StreamParser::NewTextBuffersCB& new_buffers_cb, 109 bool OnTextBuffers(int text_track_number,
99 TextTrack* text_track,
100 const StreamParser::BufferQueue& buffers); 110 const StreamParser::BufferQueue& buffers);
101 111
102 // Helper function that adds |timestamp_offset_| to each buffer in |buffers|. 112 // Helper function that adds |timestamp_offset_| to each buffer in |buffers|.
103 void AdjustBufferTimestamps(const StreamParser::BufferQueue& buffers); 113 void AdjustBufferTimestamps(const StreamParser::BufferQueue& buffers);
104 114
105 // Filters out buffers that are outside of the append window 115 // Filters out buffers that are outside of the append window
106 // [|append_window_start_|, |append_window_end_|). 116 // [|append_window_start_|, |append_window_end_|).
107 // |needs_keyframe| is a pointer to the |xxx_need_keyframe_| flag 117 // |needs_keyframe| is a pointer to the |xxx_need_keyframe_| flag
108 // associated with the |buffers|. Its state is read an updated as 118 // associated with the |buffers|. Its state is read an updated as
109 // this method filters |buffers|. 119 // this method filters |buffers|.
(...skipping 25 matching lines...) Expand all
135 145
136 // The object used to parse appended data. 146 // The object used to parse appended data.
137 scoped_ptr<StreamParser> stream_parser_; 147 scoped_ptr<StreamParser> stream_parser_;
138 148
139 ChunkDemuxerStream* audio_; 149 ChunkDemuxerStream* audio_;
140 bool audio_needs_keyframe_; 150 bool audio_needs_keyframe_;
141 151
142 ChunkDemuxerStream* video_; 152 ChunkDemuxerStream* video_;
143 bool video_needs_keyframe_; 153 bool video_needs_keyframe_;
144 154
155 NewTextTrackCB new_text_track_cb_;
156
157 typedef std::map<int, ChunkDemuxerStream*> TextStreamMap;
158 TextStreamMap text_stream_map_;
159
145 LogCB log_cb_; 160 LogCB log_cb_;
146 161
147 DISALLOW_COPY_AND_ASSIGN(SourceState); 162 DISALLOW_COPY_AND_ASSIGN(SourceState);
148 }; 163 };
149 164
150 class ChunkDemuxerStream : public DemuxerStream { 165 class ChunkDemuxerStream : public DemuxerStream {
151 public: 166 public:
152 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; 167 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue;
153 168
154 explicit ChunkDemuxerStream(Type type); 169 explicit ChunkDemuxerStream(Type type);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 201
187 // Signal to the stream that buffers handed in through subsequent calls to 202 // Signal to the stream that buffers handed in through subsequent calls to
188 // Append() belong to a media segment that starts at |start_timestamp|. 203 // Append() belong to a media segment that starts at |start_timestamp|.
189 void OnNewMediaSegment(TimeDelta start_timestamp); 204 void OnNewMediaSegment(TimeDelta start_timestamp);
190 205
191 // Called when midstream config updates occur. 206 // Called when midstream config updates occur.
192 // Returns true if the new config is accepted. 207 // Returns true if the new config is accepted.
193 // Returns false if the new config should trigger an error. 208 // Returns false if the new config should trigger an error.
194 bool UpdateAudioConfig(const AudioDecoderConfig& config, const LogCB& log_cb); 209 bool UpdateAudioConfig(const AudioDecoderConfig& config, const LogCB& log_cb);
195 bool UpdateVideoConfig(const VideoDecoderConfig& config, const LogCB& log_cb); 210 bool UpdateVideoConfig(const VideoDecoderConfig& config, const LogCB& log_cb);
211 void UpdateTextConfig(const LogCB& log_cb);
196 212
197 void MarkEndOfStream(); 213 void MarkEndOfStream();
198 void UnmarkEndOfStream(); 214 void UnmarkEndOfStream();
199 215
200 // DemuxerStream methods. 216 // DemuxerStream methods.
201 virtual void Read(const ReadCB& read_cb) OVERRIDE; 217 virtual void Read(const ReadCB& read_cb) OVERRIDE;
202 virtual Type type() OVERRIDE; 218 virtual Type type() OVERRIDE;
203 virtual void EnableBitstreamConverter() OVERRIDE; 219 virtual void EnableBitstreamConverter() OVERRIDE;
204 virtual AudioDecoderConfig audio_decoder_config() OVERRIDE; 220 virtual AudioDecoderConfig audio_decoder_config() OVERRIDE;
205 virtual VideoDecoderConfig video_decoder_config() OVERRIDE; 221 virtual VideoDecoderConfig video_decoder_config() OVERRIDE;
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 video_(NULL), 270 video_(NULL),
255 video_needs_keyframe_(true), 271 video_needs_keyframe_(true),
256 log_cb_(log_cb) { 272 log_cb_(log_cb) {
257 DCHECK(!create_demuxer_stream_cb_.is_null()); 273 DCHECK(!create_demuxer_stream_cb_.is_null());
258 DCHECK(!increase_duration_cb_.is_null()); 274 DCHECK(!increase_duration_cb_.is_null());
259 } 275 }
260 276
261 void SourceState::Init(const StreamParser::InitCB& init_cb, 277 void SourceState::Init(const StreamParser::InitCB& init_cb,
262 bool allow_audio, 278 bool allow_audio,
263 bool allow_video, 279 bool allow_video,
264 const StreamParser::NewTextBuffersCB& text_cb,
265 const StreamParser::NeedKeyCB& need_key_cb, 280 const StreamParser::NeedKeyCB& need_key_cb,
266 const AddTextTrackCB& add_text_track_cb) { 281 const NewTextTrackCB& new_text_track_cb) {
267 StreamParser::NewBuffersCB audio_cb; 282 StreamParser::NewBuffersCB audio_cb;
283 new_text_track_cb_ = new_text_track_cb;
268 284
269 stream_parser_->Init(init_cb, 285 stream_parser_->Init(init_cb,
270 base::Bind(&SourceState::OnNewConfigs, 286 base::Bind(&SourceState::OnNewConfigs,
271 base::Unretained(this), 287 base::Unretained(this),
272 allow_audio, 288 allow_audio,
273 allow_video), 289 allow_video),
274 base::Bind(&SourceState::OnNewBuffers, 290 base::Bind(&SourceState::OnNewBuffers,
275 base::Unretained(this)), 291 base::Unretained(this)),
276 base::Bind(&SourceState::OnTextBuffers, 292 base::Bind(&SourceState::OnTextBuffers,
277 base::Unretained(this), text_cb), 293 base::Unretained(this)),
278 need_key_cb, 294 need_key_cb,
279 add_text_track_cb, 295 base::Bind(&SourceState::OnNewTextTrack,
296 base::Unretained(this)),
280 base::Bind(&SourceState::OnNewMediaSegment, 297 base::Bind(&SourceState::OnNewMediaSegment,
281 base::Unretained(this)), 298 base::Unretained(this)),
282 base::Bind(&SourceState::OnEndOfMediaSegment, 299 base::Bind(&SourceState::OnEndOfMediaSegment,
283 base::Unretained(this)), 300 base::Unretained(this)),
284 log_cb_); 301 log_cb_);
285 } 302 }
286 303
287 bool SourceState::SetTimestampOffset(TimeDelta timestamp_offset) { 304 bool SourceState::SetTimestampOffset(TimeDelta timestamp_offset) {
288 if (!can_update_offset_) 305 if (!can_update_offset_)
289 return false; 306 return false;
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
425 segment_timestamp = filtered_video.front()->GetDecodeTimestamp(); 442 segment_timestamp = filtered_video.front()->GetDecodeTimestamp();
426 } 443 }
427 444
428 new_media_segment_ = false; 445 new_media_segment_ = false;
429 446
430 if (audio_) 447 if (audio_)
431 audio_->OnNewMediaSegment(segment_timestamp); 448 audio_->OnNewMediaSegment(segment_timestamp);
432 449
433 if (video_) 450 if (video_)
434 video_->OnNewMediaSegment(segment_timestamp); 451 video_->OnNewMediaSegment(segment_timestamp);
452
453 for (TextStreamMap::iterator itr = text_stream_map_.begin();
454 itr != text_stream_map_.end(); ++itr) {
455 itr->second->OnNewMediaSegment(segment_timestamp);
456 }
435 } 457 }
436 458
437 if (!filtered_audio.empty()) { 459 if (!filtered_audio.empty()) {
438 if (!audio_ || !audio_->Append(filtered_audio)) 460 if (!audio_ || !audio_->Append(filtered_audio))
439 return false; 461 return false;
440 increase_duration_cb_.Run(filtered_audio.back()->timestamp(), audio_); 462 increase_duration_cb_.Run(filtered_audio.back()->timestamp(), audio_);
441 } 463 }
442 464
443 if (!filtered_video.empty()) { 465 if (!filtered_video.empty()) {
444 if (!video_ || !video_->Append(filtered_video)) 466 if (!video_ || !video_->Append(filtered_video))
445 return false; 467 return false;
446 increase_duration_cb_.Run(filtered_video.back()->timestamp(), video_); 468 increase_duration_cb_.Run(filtered_video.back()->timestamp(), video_);
447 } 469 }
448 470
449 return true; 471 return true;
450 } 472 }
451 473
452 bool SourceState::OnTextBuffers( 474 bool SourceState::OnTextBuffers(
453 const StreamParser::NewTextBuffersCB& new_buffers_cb, 475 int text_track_number,
454 TextTrack* text_track,
455 const StreamParser::BufferQueue& buffers) { 476 const StreamParser::BufferQueue& buffers) {
456 if (new_buffers_cb.is_null()) 477 if (buffers.empty())
acolwell GONE FROM CHROMIUM 2013/10/14 20:42:24 nit: DCHECK(!buffers.empty()) instead.
Matthew Heaney (Chromium) 2013/10/17 05:46:44 Done.
Matthew Heaney (Chromium) 2013/10/17 05:46:44 Done.
457 return false; 478 return true;
479
480 TextStreamMap::iterator itr = text_stream_map_.find(text_track_number);
481 if (itr == text_stream_map_.end())
482 return true;
acolwell GONE FROM CHROMIUM 2013/10/14 20:42:24 nit: I think this should return false. Doesn't thi
Matthew Heaney (Chromium) 2013/10/17 05:46:44 Done.
458 483
459 AdjustBufferTimestamps(buffers); 484 AdjustBufferTimestamps(buffers);
460 485
461 return new_buffers_cb.Run(text_track, buffers); 486 return itr->second->Append(buffers);
487 }
488
489 void SourceState::OnNewTextTrack(int text_track_number,
acolwell GONE FROM CHROMIUM 2013/10/14 20:42:24 I think this may need to be folded into OnNewConfi
Matthew Heaney (Chromium) 2013/10/17 05:46:44 I did an incomplete implementation. You can check
490 TextKind kind,
491 const std::string& name,
492 const std::string& language) {
493 ChunkDemuxerStream* const text_stream =
494 create_demuxer_stream_cb_.Run(DemuxerStream::TEXT);
495
496 // Interpret NULL as meaning that inband text tracks are disabled.
497 if (text_stream) {
498 text_stream->UpdateTextConfig(log_cb_);
499 text_stream_map_[text_track_number] = text_stream;
500 new_text_track_cb_.Run(text_stream, kind, name, language);
501 }
462 } 502 }
463 503
464 void SourceState::FilterWithAppendWindow( 504 void SourceState::FilterWithAppendWindow(
465 const StreamParser::BufferQueue& buffers, bool* needs_keyframe, 505 const StreamParser::BufferQueue& buffers, bool* needs_keyframe,
466 StreamParser::BufferQueue* filtered_buffers) { 506 StreamParser::BufferQueue* filtered_buffers) {
467 DCHECK(needs_keyframe); 507 DCHECK(needs_keyframe);
468 DCHECK(filtered_buffers); 508 DCHECK(filtered_buffers);
469 509
470 // This loop implements steps 1.9, 1.10, & 1.11 of the "Coded frame 510 // This loop implements steps 1.9, 1.10, & 1.11 of the "Coded frame
471 // processing loop" in the Media Source Extensions spec. 511 // processing loop" in the Media Source Extensions spec.
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
642 682
643 if (!stream_) { 683 if (!stream_) {
644 DCHECK_EQ(state_, UNINITIALIZED); 684 DCHECK_EQ(state_, UNINITIALIZED);
645 stream_.reset(new SourceBufferStream(config, log_cb)); 685 stream_.reset(new SourceBufferStream(config, log_cb));
646 return true; 686 return true;
647 } 687 }
648 688
649 return stream_->UpdateVideoConfig(config); 689 return stream_->UpdateVideoConfig(config);
650 } 690 }
651 691
692 void ChunkDemuxerStream::UpdateTextConfig(const LogCB& log_cb) {
693 DCHECK_EQ(type_, TEXT);
694 base::AutoLock auto_lock(lock_);
695
696 if (!stream_) {
697 DCHECK_EQ(state_, UNINITIALIZED);
698 stream_.reset(new SourceBufferStream(log_cb));
699 }
acolwell GONE FROM CHROMIUM 2013/10/14 20:42:24 This needs to verify that kind and language haven'
Matthew Heaney (Chromium) 2013/10/17 05:46:44 See if I got OnNewConfigs right, then I can adjust
700 }
701
652 void ChunkDemuxerStream::MarkEndOfStream() { 702 void ChunkDemuxerStream::MarkEndOfStream() {
653 base::AutoLock auto_lock(lock_); 703 base::AutoLock auto_lock(lock_);
654 stream_->MarkEndOfStream(); 704 stream_->MarkEndOfStream();
655 } 705 }
656 706
657 void ChunkDemuxerStream::UnmarkEndOfStream() { 707 void ChunkDemuxerStream::UnmarkEndOfStream() {
658 base::AutoLock auto_lock(lock_); 708 base::AutoLock auto_lock(lock_);
659 stream_->UnmarkEndOfStream(); 709 stream_->UnmarkEndOfStream();
660 } 710 }
661 711
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
737 status = DemuxerStream::kOk; 787 status = DemuxerStream::kOk;
738 buffer = StreamParserBuffer::CreateEOSBuffer(); 788 buffer = StreamParserBuffer::CreateEOSBuffer();
739 break; 789 break;
740 } 790 }
741 791
742 base::ResetAndReturn(&read_cb_).Run(status, buffer); 792 base::ResetAndReturn(&read_cb_).Run(status, buffer);
743 } 793 }
744 794
745 ChunkDemuxer::ChunkDemuxer(const base::Closure& open_cb, 795 ChunkDemuxer::ChunkDemuxer(const base::Closure& open_cb,
746 const NeedKeyCB& need_key_cb, 796 const NeedKeyCB& need_key_cb,
747 const AddTextTrackCB& add_text_track_cb, 797 bool enable_text,
748 const LogCB& log_cb) 798 const LogCB& log_cb)
749 : state_(WAITING_FOR_INIT), 799 : state_(WAITING_FOR_INIT),
750 cancel_next_seek_(false), 800 cancel_next_seek_(false),
751 host_(NULL), 801 host_(NULL),
752 open_cb_(open_cb), 802 open_cb_(open_cb),
753 need_key_cb_(need_key_cb), 803 need_key_cb_(need_key_cb),
754 add_text_track_cb_(add_text_track_cb), 804 enable_text_(enable_text),
755 log_cb_(log_cb), 805 log_cb_(log_cb),
756 duration_(kNoTimestamp()), 806 duration_(kNoTimestamp()),
757 user_specified_duration_(-1) { 807 user_specified_duration_(-1) {
758 DCHECK(!open_cb_.is_null()); 808 DCHECK(!open_cb_.is_null());
759 DCHECK(!need_key_cb_.is_null()); 809 DCHECK(!need_key_cb_.is_null());
760 } 810 }
761 811
762 void ChunkDemuxer::Initialize(DemuxerHost* host, const PipelineStatusCB& cb) { 812 void ChunkDemuxer::Initialize(DemuxerHost* host, const PipelineStatusCB& cb) {
763 DVLOG(1) << "Init()"; 813 DVLOG(1) << "Init()";
764 814
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
821 871
822 // Demuxer implementation. 872 // Demuxer implementation.
823 DemuxerStream* ChunkDemuxer::GetStream(DemuxerStream::Type type) { 873 DemuxerStream* ChunkDemuxer::GetStream(DemuxerStream::Type type) {
824 base::AutoLock auto_lock(lock_); 874 base::AutoLock auto_lock(lock_);
825 if (type == DemuxerStream::VIDEO) 875 if (type == DemuxerStream::VIDEO)
826 return video_.get(); 876 return video_.get();
827 877
828 if (type == DemuxerStream::AUDIO) 878 if (type == DemuxerStream::AUDIO)
829 return audio_.get(); 879 return audio_.get();
830 880
831 return NULL; 881 if (!enable_text_ || text_stream_set_.empty())
acolwell GONE FROM CHROMIUM 2013/10/14 20:42:24 nit: I'd prefer to not return text tracks through
Matthew Heaney (Chromium) 2013/10/17 05:46:44 Done.
882 return NULL;
883
884 TextStreamSet::iterator itr = text_stream_set_.begin();
885 return *itr;
832 } 886 }
833 887
834 TimeDelta ChunkDemuxer::GetStartTime() const { 888 TimeDelta ChunkDemuxer::GetStartTime() const {
835 return TimeDelta(); 889 return TimeDelta();
836 } 890 }
837 891
838 void ChunkDemuxer::StartWaitingForSeek(TimeDelta seek_time) { 892 void ChunkDemuxer::StartWaitingForSeek(TimeDelta seek_time) {
839 DVLOG(1) << "StartWaitingForSeek()"; 893 DVLOG(1) << "StartWaitingForSeek()";
840 base::AutoLock auto_lock(lock_); 894 base::AutoLock auto_lock(lock_);
841 DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN || 895 DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN ||
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
903 new SourceState(stream_parser.Pass(), log_cb_, 957 new SourceState(stream_parser.Pass(), log_cb_,
904 base::Bind(&ChunkDemuxer::CreateDemuxerStream, 958 base::Bind(&ChunkDemuxer::CreateDemuxerStream,
905 base::Unretained(this)), 959 base::Unretained(this)),
906 base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary, 960 base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary,
907 base::Unretained(this)))); 961 base::Unretained(this))));
908 962
909 source_state->Init( 963 source_state->Init(
910 base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this)), 964 base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this)),
911 has_audio, 965 has_audio,
912 has_video, 966 has_video,
913 base::Bind(&ChunkDemuxer::OnTextBuffers, base::Unretained(this)),
914 need_key_cb_, 967 need_key_cb_,
915 add_text_track_cb_); 968 base::Bind(&ChunkDemuxer::OnNewTextTrack, base::Unretained(this)));
916 969
917 source_state_map_[id] = source_state.release(); 970 source_state_map_[id] = source_state.release();
918 return kOk; 971 return kOk;
919 } 972 }
920 973
921 void ChunkDemuxer::RemoveId(const std::string& id) { 974 void ChunkDemuxer::RemoveId(const std::string& id) {
922 base::AutoLock auto_lock(lock_); 975 base::AutoLock auto_lock(lock_);
923 CHECK(IsValidId(id)); 976 CHECK(IsValidId(id));
924 977
925 delete source_state_map_[id]; 978 delete source_state_map_[id];
926 source_state_map_.erase(id); 979 source_state_map_.erase(id);
927 980
928 if (source_id_audio_ == id) { 981 if (source_id_audio_ == id) {
929 if (audio_) 982 if (audio_)
930 audio_->Shutdown(); 983 audio_->Shutdown();
931 source_id_audio_.clear(); 984 source_id_audio_.clear();
932 } 985 }
933 986
934 if (source_id_video_ == id) { 987 if (source_id_video_ == id) {
935 if (video_) 988 if (video_)
936 video_->Shutdown(); 989 video_->Shutdown();
937 source_id_video_.clear(); 990 source_id_video_.clear();
938 } 991 }
992
993 // TODO(matthewjheaney): delete the text streams associated with this id
acolwell GONE FROM CHROMIUM 2013/10/14 20:42:24 This needs to be addressed in this CL. If you let
Matthew Heaney (Chromium) 2013/10/17 05:46:44 I did a partial implementation. You can see if I'
939 } 994 }
940 995
941 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { 996 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const {
942 base::AutoLock auto_lock(lock_); 997 base::AutoLock auto_lock(lock_);
943 DCHECK(!id.empty()); 998 DCHECK(!id.empty());
944 DCHECK(IsValidId(id)); 999 DCHECK(IsValidId(id));
945 DCHECK(id == source_id_audio_ || id == source_id_video_); 1000 DCHECK(id == source_id_audio_ || id == source_id_video_);
946 1001
947 if (id == source_id_audio_ && id != source_id_video_) { 1002 if (id == source_id_audio_ && id != source_id_video_) {
948 // Only include ranges that have been buffered in |audio_| 1003 // Only include ranges that have been buffered in |audio_|
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after
1245 state_ = new_state; 1300 state_ = new_state;
1246 } 1301 }
1247 1302
1248 ChunkDemuxer::~ChunkDemuxer() { 1303 ChunkDemuxer::~ChunkDemuxer() {
1249 DCHECK_NE(state_, INITIALIZED); 1304 DCHECK_NE(state_, INITIALIZED);
1250 for (SourceStateMap::iterator it = source_state_map_.begin(); 1305 for (SourceStateMap::iterator it = source_state_map_.begin();
1251 it != source_state_map_.end(); ++it) { 1306 it != source_state_map_.end(); ++it) {
1252 delete it->second; 1307 delete it->second;
1253 } 1308 }
1254 source_state_map_.clear(); 1309 source_state_map_.clear();
1310
1311 TextStreamSet::iterator it = text_stream_set_.begin();
acolwell GONE FROM CHROMIUM 2013/10/14 20:42:24 This would go away if you let SourceState own the
Matthew Heaney (Chromium) 2013/10/17 05:46:44 Done.
1312 while (it != text_stream_set_.end()) {
1313 ChunkDemuxerStream* text_stream = *it;
1314 text_stream_set_.erase(it++);
1315 delete text_stream;
1316 }
1255 } 1317 }
1256 1318
1257 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) { 1319 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) {
1258 DVLOG(1) << "ReportError_Locked(" << error << ")"; 1320 DVLOG(1) << "ReportError_Locked(" << error << ")";
1259 lock_.AssertAcquired(); 1321 lock_.AssertAcquired();
1260 DCHECK_NE(error, PIPELINE_OK); 1322 DCHECK_NE(error, PIPELINE_OK);
1261 1323
1262 ChangeState_Locked(PARSE_ERROR); 1324 ChangeState_Locked(PARSE_ERROR);
1263 1325
1264 PipelineStatusCB cb; 1326 PipelineStatusCB cb;
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
1335 return NULL; 1397 return NULL;
1336 audio_.reset(new ChunkDemuxerStream(DemuxerStream::AUDIO)); 1398 audio_.reset(new ChunkDemuxerStream(DemuxerStream::AUDIO));
1337 return audio_.get(); 1399 return audio_.get();
1338 break; 1400 break;
1339 case DemuxerStream::VIDEO: 1401 case DemuxerStream::VIDEO:
1340 if (video_) 1402 if (video_)
1341 return NULL; 1403 return NULL;
1342 video_.reset(new ChunkDemuxerStream(DemuxerStream::VIDEO)); 1404 video_.reset(new ChunkDemuxerStream(DemuxerStream::VIDEO));
1343 return video_.get(); 1405 return video_.get();
1344 break; 1406 break;
1407 case DemuxerStream::TEXT: {
1408 // TODO(matthewjheaney): we need to destroy this text stream
1409 ChunkDemuxerStream* text_stream =
1410 new ChunkDemuxerStream(DemuxerStream::TEXT);
1411 text_stream_set_.insert(text_stream);
1412 return text_stream;
1413 break;
1414 }
1345 case DemuxerStream::UNKNOWN: 1415 case DemuxerStream::UNKNOWN:
1346 case DemuxerStream::NUM_TYPES: 1416 case DemuxerStream::NUM_TYPES:
1347 NOTREACHED(); 1417 NOTREACHED();
1348 return NULL; 1418 return NULL;
1349 } 1419 }
1350 NOTREACHED(); 1420 NOTREACHED();
1351 return NULL; 1421 return NULL;
1352 } 1422 }
1353 1423
1354 bool ChunkDemuxer::OnTextBuffers( 1424 void ChunkDemuxer::OnNewTextTrack(ChunkDemuxerStream* text_stream,
1355 TextTrack* text_track, 1425 TextKind kind,
1356 const StreamParser::BufferQueue& buffers) { 1426 const std::string& name,
1427 const std::string& language) {
1357 lock_.AssertAcquired(); 1428 lock_.AssertAcquired();
1358 DCHECK_NE(state_, SHUTDOWN); 1429 DCHECK_NE(state_, SHUTDOWN);
1359 1430 DCHECK(text_stream_set_.find(text_stream) != text_stream_set_.end());
1360 // TODO(matthewjheaney): IncreaseDurationIfNecessary 1431 host_->AddTextStream(text_stream, kind, name, language);
1361
1362 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin();
1363 itr != buffers.end(); ++itr) {
1364 const StreamParserBuffer* const buffer = itr->get();
1365 const TimeDelta start = buffer->timestamp();
1366 const TimeDelta end = start + buffer->duration();
1367
1368 std::string id, settings, content;
1369
1370 WebMWebVTTParser::Parse(buffer->data(),
1371 buffer->data_size(),
1372 &id, &settings, &content);
1373
1374 text_track->addWebVTTCue(start, end, id, content, settings);
1375 }
1376
1377 return true;
1378 } 1432 }
1379 1433
1380 bool ChunkDemuxer::IsValidId(const std::string& source_id) const { 1434 bool ChunkDemuxer::IsValidId(const std::string& source_id) const {
1381 lock_.AssertAcquired(); 1435 lock_.AssertAcquired();
1382 return source_state_map_.count(source_id) > 0u; 1436 return source_state_map_.count(source_id) > 0u;
1383 } 1437 }
1384 1438
1385 void ChunkDemuxer::UpdateDuration(TimeDelta new_duration) { 1439 void ChunkDemuxer::UpdateDuration(TimeDelta new_duration) {
1386 DCHECK(duration_ != new_duration); 1440 DCHECK(duration_ != new_duration);
1387 user_specified_duration_ = -1; 1441 user_specified_duration_ = -1;
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
1421 return video_->GetBufferedRanges(duration_); 1475 return video_->GetBufferedRanges(duration_);
1422 return ComputeIntersection(); 1476 return ComputeIntersection();
1423 } 1477 }
1424 1478
1425 void ChunkDemuxer::StartReturningData() { 1479 void ChunkDemuxer::StartReturningData() {
1426 if (audio_) 1480 if (audio_)
1427 audio_->StartReturningData(); 1481 audio_->StartReturningData();
1428 1482
1429 if (video_) 1483 if (video_)
1430 video_->StartReturningData(); 1484 video_->StartReturningData();
1485
1486 for (TextStreamSet::iterator itr = text_stream_set_.begin();
acolwell GONE FROM CHROMIUM 2013/10/14 20:42:24 nit: Consider iterating over the SourceState objec
Matthew Heaney (Chromium) 2013/10/17 05:46:44 Done.
1487 itr != text_stream_set_.end(); ++itr) {
1488 (*itr)->StartReturningData();
1489 }
1431 } 1490 }
1432 1491
1433 void ChunkDemuxer::AbortPendingReads() { 1492 void ChunkDemuxer::AbortPendingReads() {
1434 if (audio_) 1493 if (audio_)
1435 audio_->AbortReads(); 1494 audio_->AbortReads();
1436 1495
1437 if (video_) 1496 if (video_)
1438 video_->AbortReads(); 1497 video_->AbortReads();
1498
1499 for (TextStreamSet::iterator itr = text_stream_set_.begin();
acolwell GONE FROM CHROMIUM 2013/10/14 20:42:24 ditto for this & the other 2 methods below.
Matthew Heaney (Chromium) 2013/10/17 05:46:44 Done.
1500 itr != text_stream_set_.end(); ++itr) {
1501 (*itr)->AbortReads();
1502 }
1439 } 1503 }
1440 1504
1441 void ChunkDemuxer::SeekAllSources(TimeDelta seek_time) { 1505 void ChunkDemuxer::SeekAllSources(TimeDelta seek_time) {
1442 if (audio_) 1506 if (audio_)
1443 audio_->Seek(seek_time); 1507 audio_->Seek(seek_time);
1444 1508
1445 if (video_) 1509 if (video_)
1446 video_->Seek(seek_time); 1510 video_->Seek(seek_time);
1511
1512 for (TextStreamSet::iterator itr = text_stream_set_.begin();
1513 itr != text_stream_set_.end(); ++itr) {
1514 (*itr)->Seek(seek_time);
1515 }
1447 } 1516 }
1448 1517
1449 void ChunkDemuxer::CompletePendingReadsIfPossible() { 1518 void ChunkDemuxer::CompletePendingReadsIfPossible() {
1450 if (audio_) 1519 if (audio_)
1451 audio_->CompletePendingReadIfPossible(); 1520 audio_->CompletePendingReadIfPossible();
1452 1521
1453 if (video_) 1522 if (video_)
1454 video_->CompletePendingReadIfPossible(); 1523 video_->CompletePendingReadIfPossible();
1524
1525 for (TextStreamSet::iterator itr = text_stream_set_.begin();
1526 itr != text_stream_set_.end(); ++itr) {
1527 (*itr)->CompletePendingReadIfPossible();
1528 }
1455 } 1529 }
1456 1530
1457 } // namespace media 1531 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698