| OLD | NEW | 
|---|
| 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 "base/stl_util.h" | 
| 15 #include "media/base/audio_decoder_config.h" | 16 #include "media/base/audio_decoder_config.h" | 
| 16 #include "media/base/bind_to_loop.h" | 17 #include "media/base/bind_to_loop.h" | 
| 17 #include "media/base/stream_parser_buffer.h" | 18 #include "media/base/stream_parser_buffer.h" | 
| 18 #include "media/base/video_decoder_config.h" | 19 #include "media/base/video_decoder_config.h" | 
| 19 #include "media/filters/stream_parser_factory.h" | 20 #include "media/filters/stream_parser_factory.h" | 
| 20 #include "media/webm/webm_webvtt_parser.h" |  | 
| 21 | 21 | 
| 22 using base::TimeDelta; | 22 using base::TimeDelta; | 
| 23 | 23 | 
| 24 namespace media { | 24 namespace media { | 
| 25 | 25 | 
| 26 // Contains state belonging to a source id. | 26 // Contains state belonging to a source id. | 
| 27 class SourceState { | 27 class SourceState { | 
| 28  public: | 28  public: | 
| 29   // Callback signature used to create ChunkDemuxerStreams. | 29   // Callback signature used to create ChunkDemuxerStreams. | 
| 30   typedef base::Callback<ChunkDemuxerStream*( | 30   typedef base::Callback<ChunkDemuxerStream*( | 
| 31       DemuxerStream::Type)> CreateDemuxerStreamCB; | 31       DemuxerStream::Type)> CreateDemuxerStreamCB; | 
| 32 | 32 | 
| 33   // Callback signature used to notify ChunkDemuxer of timestamps | 33   // Callback signature used to notify ChunkDemuxer of timestamps | 
| 34   // that may cause the duration to be updated. | 34   // that may cause the duration to be updated. | 
| 35   typedef base::Callback<void( | 35   typedef base::Callback<void( | 
| 36       TimeDelta, ChunkDemuxerStream*)> IncreaseDurationCB; | 36       TimeDelta, ChunkDemuxerStream*)> IncreaseDurationCB; | 
| 37 | 37 | 
|  | 38   typedef base::Callback<void( | 
|  | 39       ChunkDemuxerStream*, const TextTrackConfig&)> NewTextTrackCB; | 
|  | 40 | 
| 38   SourceState(scoped_ptr<StreamParser> stream_parser, const LogCB& log_cb, | 41   SourceState(scoped_ptr<StreamParser> stream_parser, const LogCB& log_cb, | 
| 39               const CreateDemuxerStreamCB& create_demuxer_stream_cb, | 42               const CreateDemuxerStreamCB& create_demuxer_stream_cb, | 
| 40               const IncreaseDurationCB& increase_duration_cb); | 43               const IncreaseDurationCB& increase_duration_cb); | 
| 41 | 44 | 
|  | 45   ~SourceState(); | 
|  | 46 | 
| 42   void Init(const StreamParser::InitCB& init_cb, | 47   void Init(const StreamParser::InitCB& init_cb, | 
| 43             bool allow_audio, | 48             bool allow_audio, | 
| 44             bool allow_video, | 49             bool allow_video, | 
| 45             const StreamParser::NewTextBuffersCB& text_cb, |  | 
| 46             const StreamParser::NeedKeyCB& need_key_cb, | 50             const StreamParser::NeedKeyCB& need_key_cb, | 
| 47             const AddTextTrackCB& add_text_track_cb); | 51             const NewTextTrackCB& new_text_track_cb); | 
| 48 | 52 | 
| 49   // Appends new data to the StreamParser. | 53   // Appends new data to the StreamParser. | 
| 50   // Returns true if the data was successfully appended. Returns false if an | 54   // Returns true if the data was successfully appended. Returns false if an | 
| 51   // error occurred. | 55   // error occurred. | 
| 52   bool Append(const uint8* data, size_t length); | 56   bool Append(const uint8* data, size_t length); | 
| 53 | 57 | 
| 54   // Aborts the current append sequence and resets the parser. | 58   // Aborts the current append sequence and resets the parser. | 
| 55   void Abort(); | 59   void Abort(); | 
| 56 | 60 | 
| 57   // Sets |timestamp_offset_| if possible. | 61   // Sets |timestamp_offset_| if possible. | 
| 58   // Returns if the offset was set. Returns false if the offset could not be | 62   // Returns if the offset was set. Returns false if the offset could not be | 
| 59   // updated at this time. | 63   // updated at this time. | 
| 60   bool SetTimestampOffset(TimeDelta timestamp_offset); | 64   bool SetTimestampOffset(TimeDelta timestamp_offset); | 
| 61 | 65 | 
| 62   TimeDelta timestamp_offset() const { return timestamp_offset_; } | 66   TimeDelta timestamp_offset() const { return timestamp_offset_; } | 
| 63 | 67 | 
| 64   void set_append_window_start(TimeDelta start) { | 68   void set_append_window_start(TimeDelta start) { | 
| 65     append_window_start_ = start; | 69     append_window_start_ = start; | 
| 66   } | 70   } | 
| 67   void set_append_window_end(TimeDelta end) { append_window_end_ = end; } | 71   void set_append_window_end(TimeDelta end) { append_window_end_ = end; } | 
| 68 | 72 | 
|  | 73   void TextStartReturningData(); | 
|  | 74   void TextAbortReads(); | 
|  | 75   void TextSeek(TimeDelta seek_time); | 
|  | 76   void TextCompletePendingReadIfPossible(); | 
|  | 77 | 
| 69  private: | 78  private: | 
| 70   // Called by the |stream_parser_| when a new initialization segment is | 79   // Called by the |stream_parser_| when a new initialization segment is | 
| 71   // encountered. | 80   // encountered. | 
| 72   // Returns true on a successful call. Returns false if an error occured while | 81   // Returns true on a successful call. Returns false if an error occured while | 
| 73   // processing decoder configurations. | 82   // processing decoder configurations. | 
| 74   bool OnNewConfigs(bool allow_audio, bool allow_video, | 83   bool OnNewConfigs(bool allow_audio, bool allow_video, | 
| 75                     const AudioDecoderConfig& audio_config, | 84                     const AudioDecoderConfig& audio_config, | 
| 76                     const VideoDecoderConfig& video_config); | 85                     const VideoDecoderConfig& video_config, | 
|  | 86                     const TextTrackConfigMap& text_configs); | 
| 77 | 87 | 
| 78   // Called by the |stream_parser_| at the beginning of a new media segment. | 88   // Called by the |stream_parser_| at the beginning of a new media segment. | 
| 79   void OnNewMediaSegment(); | 89   void OnNewMediaSegment(); | 
| 80 | 90 | 
| 81   // Called by the |stream_parser_| at the end of a media segment. | 91   // Called by the |stream_parser_| at the end of a media segment. | 
| 82   void OnEndOfMediaSegment(); | 92   void OnEndOfMediaSegment(); | 
| 83 | 93 | 
| 84   // Called by the |stream_parser_| when new buffers have been parsed. It | 94   // Called by the |stream_parser_| when new buffers have been parsed. It | 
| 85   // applies |timestamp_offset_| to all buffers in |audio_buffers| and | 95   // applies |timestamp_offset_| to all buffers in |audio_buffers| and | 
| 86   // |video_buffers| and then calls Append() on |audio_| and/or | 96   // |video_buffers| and then calls Append() on |audio_| and/or | 
| 87   // |video_| with the modified buffers. | 97   // |video_| with the modified buffers. | 
| 88   // Returns true on a successful call. Returns false if an error occured while | 98   // Returns true on a successful call. Returns false if an error occured while | 
| 89   // processing the buffers. | 99   // processing the buffers. | 
| 90   bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers, | 100   bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers, | 
| 91                     const StreamParser::BufferQueue& video_buffers); | 101                     const StreamParser::BufferQueue& video_buffers); | 
| 92 | 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|. | 
| 110   // Buffers that are inside the append window are appended to the end | 120   // Buffers that are inside the append window are appended to the end | 
| 111   // of |filtered_buffers|. | 121   // of |filtered_buffers|. | 
| 112   void FilterWithAppendWindow(const StreamParser::BufferQueue& buffers, | 122   void FilterWithAppendWindow(const StreamParser::BufferQueue& buffers, | 
| 113                               bool* needs_keyframe, | 123                               bool* needs_keyframe, | 
| 114                               StreamParser::BufferQueue* filtered_buffers); | 124                               StreamParser::BufferQueue* filtered_buffers); | 
| 115 | 125 | 
| 116   CreateDemuxerStreamCB create_demuxer_stream_cb_; | 126   CreateDemuxerStreamCB create_demuxer_stream_cb_; | 
| 117   IncreaseDurationCB increase_duration_cb_; | 127   IncreaseDurationCB increase_duration_cb_; | 
|  | 128   NewTextTrackCB new_text_track_cb_; | 
| 118 | 129 | 
| 119   // The offset to apply to media segment timestamps. | 130   // The offset to apply to media segment timestamps. | 
| 120   TimeDelta timestamp_offset_; | 131   TimeDelta timestamp_offset_; | 
| 121 | 132 | 
| 122   TimeDelta append_window_start_; | 133   TimeDelta append_window_start_; | 
| 123   TimeDelta append_window_end_; | 134   TimeDelta append_window_end_; | 
| 124 | 135 | 
| 125   // Set to true if the next buffers appended within the append window | 136   // Set to true if the next buffers appended within the append window | 
| 126   // represent the start of a new media segment. This flag being set | 137   // represent the start of a new media segment. This flag being set | 
| 127   // triggers a call to |new_segment_cb_| when the new buffers are | 138   // triggers a call to |new_segment_cb_| when the new buffers are | 
| 128   // appended. The flag is set on actual media segment boundaries and | 139   // appended. The flag is set on actual media segment boundaries and | 
| 129   // when the "append window" filtering causes discontinuities in the | 140   // when the "append window" filtering causes discontinuities in the | 
| 130   // appended data. | 141   // appended data. | 
| 131   bool new_media_segment_; | 142   bool new_media_segment_; | 
| 132 | 143 | 
| 133   // Keeps track of whether |timestamp_offset_| can be modified. | 144   // Keeps track of whether |timestamp_offset_| can be modified. | 
| 134   bool can_update_offset_; | 145   bool can_update_offset_; | 
| 135 | 146 | 
| 136   // The object used to parse appended data. | 147   // The object used to parse appended data. | 
| 137   scoped_ptr<StreamParser> stream_parser_; | 148   scoped_ptr<StreamParser> stream_parser_; | 
| 138 | 149 | 
| 139   ChunkDemuxerStream* audio_; | 150   ChunkDemuxerStream* audio_; | 
| 140   bool audio_needs_keyframe_; | 151   bool audio_needs_keyframe_; | 
| 141 | 152 | 
| 142   ChunkDemuxerStream* video_; | 153   ChunkDemuxerStream* video_; | 
| 143   bool video_needs_keyframe_; | 154   bool video_needs_keyframe_; | 
| 144 | 155 | 
|  | 156   typedef std::map<int, ChunkDemuxerStream*> TextStreamMap; | 
|  | 157   TextStreamMap text_stream_map_; | 
|  | 158 | 
| 145   LogCB log_cb_; | 159   LogCB log_cb_; | 
| 146 | 160 | 
| 147   DISALLOW_COPY_AND_ASSIGN(SourceState); | 161   DISALLOW_COPY_AND_ASSIGN(SourceState); | 
| 148 }; | 162 }; | 
| 149 | 163 | 
| 150 class ChunkDemuxerStream : public DemuxerStream { | 164 class ChunkDemuxerStream : public DemuxerStream { | 
| 151  public: | 165  public: | 
| 152   typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; | 166   typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; | 
| 153 | 167 | 
| 154   explicit ChunkDemuxerStream(Type type); | 168   explicit ChunkDemuxerStream(Type type); | 
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 186 | 200 | 
| 187   // Signal to the stream that buffers handed in through subsequent calls to | 201   // Signal to the stream that buffers handed in through subsequent calls to | 
| 188   // Append() belong to a media segment that starts at |start_timestamp|. | 202   // Append() belong to a media segment that starts at |start_timestamp|. | 
| 189   void OnNewMediaSegment(TimeDelta start_timestamp); | 203   void OnNewMediaSegment(TimeDelta start_timestamp); | 
| 190 | 204 | 
| 191   // Called when midstream config updates occur. | 205   // Called when midstream config updates occur. | 
| 192   // Returns true if the new config is accepted. | 206   // Returns true if the new config is accepted. | 
| 193   // Returns false if the new config should trigger an error. | 207   // Returns false if the new config should trigger an error. | 
| 194   bool UpdateAudioConfig(const AudioDecoderConfig& config, const LogCB& log_cb); | 208   bool UpdateAudioConfig(const AudioDecoderConfig& config, const LogCB& log_cb); | 
| 195   bool UpdateVideoConfig(const VideoDecoderConfig& config, const LogCB& log_cb); | 209   bool UpdateVideoConfig(const VideoDecoderConfig& config, const LogCB& log_cb); | 
|  | 210   void UpdateTextConfig(const TextTrackConfig& config, const LogCB& log_cb); | 
| 196 | 211 | 
| 197   void MarkEndOfStream(); | 212   void MarkEndOfStream(); | 
| 198   void UnmarkEndOfStream(); | 213   void UnmarkEndOfStream(); | 
| 199 | 214 | 
| 200   // DemuxerStream methods. | 215   // DemuxerStream methods. | 
| 201   virtual void Read(const ReadCB& read_cb) OVERRIDE; | 216   virtual void Read(const ReadCB& read_cb) OVERRIDE; | 
| 202   virtual Type type() OVERRIDE; | 217   virtual Type type() OVERRIDE; | 
| 203   virtual void EnableBitstreamConverter() OVERRIDE; | 218   virtual void EnableBitstreamConverter() OVERRIDE; | 
| 204   virtual AudioDecoderConfig audio_decoder_config() OVERRIDE; | 219   virtual AudioDecoderConfig audio_decoder_config() OVERRIDE; | 
| 205   virtual VideoDecoderConfig video_decoder_config() OVERRIDE; | 220   virtual VideoDecoderConfig video_decoder_config() OVERRIDE; | 
| 206 | 221 | 
|  | 222   // Returns the text track configuration.  It is an error to call this method | 
|  | 223   // if type() != TEXT. | 
|  | 224   TextTrackConfig text_track_config(); | 
|  | 225 | 
| 207   void set_memory_limit_for_testing(int memory_limit) { | 226   void set_memory_limit_for_testing(int memory_limit) { | 
| 208     stream_->set_memory_limit_for_testing(memory_limit); | 227     stream_->set_memory_limit_for_testing(memory_limit); | 
| 209   } | 228   } | 
| 210 | 229 | 
| 211  private: | 230  private: | 
| 212   enum State { | 231   enum State { | 
| 213     UNINITIALIZED, | 232     UNINITIALIZED, | 
| 214     RETURNING_DATA_FOR_READS, | 233     RETURNING_DATA_FOR_READS, | 
| 215     RETURNING_ABORT_FOR_READS, | 234     RETURNING_ABORT_FOR_READS, | 
| 216     SHUTDOWN, | 235     SHUTDOWN, | 
| 217   }; | 236   }; | 
| 218 | 237 | 
| 219   // Assigns |state_| to |state| | 238   // Assigns |state_| to |state| | 
| 220   void ChangeState_Locked(State state); | 239   void ChangeState_Locked(State state); | 
| 221 | 240 | 
| 222   void CompletePendingReadIfPossible_Locked(); | 241   void CompletePendingReadIfPossible_Locked(); | 
| 223 | 242 | 
| 224   // Gets the value to pass to the next Read() callback. Returns true if | 243   // Gets the value to pass to the next Read() callback. Returns true if | 
| 225   // |status| and |buffer| should be passed to the callback. False indicates | 244   // |status| and |buffer| should be passed to the callback. False indicates | 
| 226   // that |status| and |buffer| were not set and more data is needed. | 245   // that |status| and |buffer| were not set and more data is needed. | 
| 227   bool GetNextBuffer_Locked(DemuxerStream::Status* status, | 246   bool GetNextBuffer_Locked(DemuxerStream::Status* status, | 
| 228                             scoped_refptr<StreamParserBuffer>* buffer); | 247                             scoped_refptr<StreamParserBuffer>* buffer); | 
| 229 | 248 | 
| 230   // Specifies the type of the stream (must be AUDIO or VIDEO for now). | 249   // Specifies the type of the stream. | 
| 231   Type type_; | 250   Type type_; | 
| 232 | 251 | 
| 233   scoped_ptr<SourceBufferStream> stream_; | 252   scoped_ptr<SourceBufferStream> stream_; | 
| 234 | 253 | 
| 235   mutable base::Lock lock_; | 254   mutable base::Lock lock_; | 
| 236   State state_; | 255   State state_; | 
| 237   ReadCB read_cb_; | 256   ReadCB read_cb_; | 
| 238 | 257 | 
| 239   DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); | 258   DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); | 
| 240 }; | 259 }; | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
| 251       stream_parser_(stream_parser.release()), | 270       stream_parser_(stream_parser.release()), | 
| 252       audio_(NULL), | 271       audio_(NULL), | 
| 253       audio_needs_keyframe_(true), | 272       audio_needs_keyframe_(true), | 
| 254       video_(NULL), | 273       video_(NULL), | 
| 255       video_needs_keyframe_(true), | 274       video_needs_keyframe_(true), | 
| 256       log_cb_(log_cb) { | 275       log_cb_(log_cb) { | 
| 257   DCHECK(!create_demuxer_stream_cb_.is_null()); | 276   DCHECK(!create_demuxer_stream_cb_.is_null()); | 
| 258   DCHECK(!increase_duration_cb_.is_null()); | 277   DCHECK(!increase_duration_cb_.is_null()); | 
| 259 } | 278 } | 
| 260 | 279 | 
|  | 280 SourceState::~SourceState() { | 
|  | 281   for (TextStreamMap::iterator itr = text_stream_map_.begin(); | 
|  | 282        itr != text_stream_map_.end(); ++itr) { | 
|  | 283     itr->second->Shutdown(); | 
|  | 284     delete itr->second; | 
|  | 285   } | 
|  | 286 } | 
|  | 287 | 
| 261 void SourceState::Init(const StreamParser::InitCB& init_cb, | 288 void SourceState::Init(const StreamParser::InitCB& init_cb, | 
| 262                        bool allow_audio, | 289                        bool allow_audio, | 
| 263                        bool allow_video, | 290                        bool allow_video, | 
| 264                        const StreamParser::NewTextBuffersCB& text_cb, |  | 
| 265                        const StreamParser::NeedKeyCB& need_key_cb, | 291                        const StreamParser::NeedKeyCB& need_key_cb, | 
| 266                        const AddTextTrackCB& add_text_track_cb) { | 292                        const NewTextTrackCB& new_text_track_cb) { | 
| 267   StreamParser::NewBuffersCB audio_cb; | 293   new_text_track_cb_ = new_text_track_cb; | 
| 268 | 294 | 
| 269   stream_parser_->Init(init_cb, | 295   stream_parser_->Init(init_cb, | 
| 270                        base::Bind(&SourceState::OnNewConfigs, | 296                        base::Bind(&SourceState::OnNewConfigs, | 
| 271                                   base::Unretained(this), | 297                                   base::Unretained(this), | 
| 272                                   allow_audio, | 298                                   allow_audio, | 
| 273                                   allow_video), | 299                                   allow_video), | 
| 274                        base::Bind(&SourceState::OnNewBuffers, | 300                        base::Bind(&SourceState::OnNewBuffers, | 
| 275                                   base::Unretained(this)), | 301                                   base::Unretained(this)), | 
| 276                        base::Bind(&SourceState::OnTextBuffers, | 302                        base::Bind(&SourceState::OnTextBuffers, | 
| 277                                   base::Unretained(this), text_cb), | 303                                   base::Unretained(this)), | 
| 278                        need_key_cb, | 304                        need_key_cb, | 
| 279                        add_text_track_cb, | 305                        !new_text_track_cb.is_null(), | 
| 280                        base::Bind(&SourceState::OnNewMediaSegment, | 306                        base::Bind(&SourceState::OnNewMediaSegment, | 
| 281                                   base::Unretained(this)), | 307                                   base::Unretained(this)), | 
| 282                        base::Bind(&SourceState::OnEndOfMediaSegment, | 308                        base::Bind(&SourceState::OnEndOfMediaSegment, | 
| 283                                   base::Unretained(this)), | 309                                   base::Unretained(this)), | 
| 284                        log_cb_); | 310                        log_cb_); | 
| 285 } | 311 } | 
| 286 | 312 | 
| 287 bool SourceState::SetTimestampOffset(TimeDelta timestamp_offset) { | 313 bool SourceState::SetTimestampOffset(TimeDelta timestamp_offset) { | 
| 288   if (!can_update_offset_) | 314   if (!can_update_offset_) | 
| 289     return false; | 315     return false; | 
| 290 | 316 | 
| 291   timestamp_offset_ = timestamp_offset; | 317   timestamp_offset_ = timestamp_offset; | 
| 292   return true; | 318   return true; | 
| 293 } | 319 } | 
| 294 | 320 | 
| 295 bool SourceState::Append(const uint8* data, size_t length) { | 321 bool SourceState::Append(const uint8* data, size_t length) { | 
| 296   return stream_parser_->Parse(data, length); | 322   return stream_parser_->Parse(data, length); | 
| 297 } | 323 } | 
| 298 | 324 | 
| 299 void SourceState::Abort() { | 325 void SourceState::Abort() { | 
| 300   stream_parser_->Flush(); | 326   stream_parser_->Flush(); | 
| 301   audio_needs_keyframe_ = true; | 327   audio_needs_keyframe_ = true; | 
| 302   video_needs_keyframe_ = true; | 328   video_needs_keyframe_ = true; | 
| 303   can_update_offset_ = true; | 329   can_update_offset_ = true; | 
| 304 } | 330 } | 
| 305 | 331 | 
|  | 332 | 
|  | 333 void SourceState::TextStartReturningData() { | 
|  | 334   for (TextStreamMap::iterator itr = text_stream_map_.begin(); | 
|  | 335        itr != text_stream_map_.end(); ++itr) { | 
|  | 336     itr->second->StartReturningData(); | 
|  | 337   } | 
|  | 338 } | 
|  | 339 | 
|  | 340 void SourceState::TextAbortReads() { | 
|  | 341   for (TextStreamMap::iterator itr = text_stream_map_.begin(); | 
|  | 342        itr != text_stream_map_.end(); ++itr) { | 
|  | 343     itr->second->AbortReads(); | 
|  | 344   } | 
|  | 345 } | 
|  | 346 | 
|  | 347 void SourceState::TextSeek(TimeDelta seek_time) { | 
|  | 348   for (TextStreamMap::iterator itr = text_stream_map_.begin(); | 
|  | 349        itr != text_stream_map_.end(); ++itr) { | 
|  | 350     itr->second->Seek(seek_time); | 
|  | 351   } | 
|  | 352 } | 
|  | 353 | 
|  | 354 void SourceState::TextCompletePendingReadIfPossible() { | 
|  | 355   for (TextStreamMap::iterator itr = text_stream_map_.begin(); | 
|  | 356        itr != text_stream_map_.end(); ++itr) { | 
|  | 357     itr->second->CompletePendingReadIfPossible(); | 
|  | 358   } | 
|  | 359 } | 
|  | 360 | 
| 306 void SourceState::AdjustBufferTimestamps( | 361 void SourceState::AdjustBufferTimestamps( | 
| 307     const StreamParser::BufferQueue& buffers) { | 362     const StreamParser::BufferQueue& buffers) { | 
| 308   if (timestamp_offset_ == TimeDelta()) | 363   if (timestamp_offset_ == TimeDelta()) | 
| 309     return; | 364     return; | 
| 310 | 365 | 
| 311   for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); | 366   for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); | 
| 312        itr != buffers.end(); ++itr) { | 367        itr != buffers.end(); ++itr) { | 
| 313     (*itr)->SetDecodeTimestamp( | 368     (*itr)->SetDecodeTimestamp( | 
| 314         (*itr)->GetDecodeTimestamp() + timestamp_offset_); | 369         (*itr)->GetDecodeTimestamp() + timestamp_offset_); | 
| 315     (*itr)->set_timestamp((*itr)->timestamp() + timestamp_offset_); | 370     (*itr)->set_timestamp((*itr)->timestamp() + timestamp_offset_); | 
| 316   } | 371   } | 
| 317 } | 372 } | 
| 318 | 373 | 
| 319 bool SourceState::OnNewConfigs(bool allow_audio, bool allow_video, | 374 bool SourceState::OnNewConfigs(bool allow_audio, bool allow_video, | 
| 320                                const AudioDecoderConfig& audio_config, | 375                                const AudioDecoderConfig& audio_config, | 
| 321                                const VideoDecoderConfig& video_config) { | 376                                const VideoDecoderConfig& video_config, | 
|  | 377                                const TextTrackConfigMap& text_configs) { | 
| 322   DVLOG(1) << "OnNewConfigs(" << allow_audio << ", " << allow_video | 378   DVLOG(1) << "OnNewConfigs(" << allow_audio << ", " << allow_video | 
| 323            << ", " << audio_config.IsValidConfig() | 379            << ", " << audio_config.IsValidConfig() | 
| 324            << ", " << video_config.IsValidConfig() << ")"; | 380            << ", " << video_config.IsValidConfig() << ")"; | 
| 325 | 381 | 
| 326   if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) { | 382   if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) { | 
| 327     DVLOG(1) << "OnNewConfigs() : Audio & video config are not valid!"; | 383     DVLOG(1) << "OnNewConfigs() : Audio & video config are not valid!"; | 
| 328     return false; | 384     return false; | 
| 329   } | 385   } | 
| 330 | 386 | 
| 331   // Signal an error if we get configuration info for stream types that weren't | 387   // Signal an error if we get configuration info for stream types that weren't | 
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 370 | 426 | 
| 371       if (!video_) { | 427       if (!video_) { | 
| 372         DVLOG(1) << "Failed to create a video stream."; | 428         DVLOG(1) << "Failed to create a video stream."; | 
| 373         return false; | 429         return false; | 
| 374       } | 430       } | 
| 375     } | 431     } | 
| 376 | 432 | 
| 377     success &= video_->UpdateVideoConfig(video_config, log_cb_); | 433     success &= video_->UpdateVideoConfig(video_config, log_cb_); | 
| 378   } | 434   } | 
| 379 | 435 | 
|  | 436   if (text_stream_map_.empty()) { | 
|  | 437     for (TextTrackConfigMap::const_iterator itr = text_configs.begin(); | 
|  | 438          itr != text_configs.end(); ++itr) { | 
|  | 439       ChunkDemuxerStream* const text_stream = | 
|  | 440           create_demuxer_stream_cb_.Run(DemuxerStream::TEXT); | 
|  | 441       text_stream->UpdateTextConfig(itr->second, log_cb_); | 
|  | 442       text_stream_map_[itr->first] = text_stream; | 
|  | 443     } | 
|  | 444   } else { | 
|  | 445     const size_t text_count = text_stream_map_.size(); | 
|  | 446     if (text_configs.size() != text_count) { | 
|  | 447       success &= false; | 
|  | 448     } else if (text_count == 1) { | 
|  | 449       TextTrackConfigMap::const_iterator config_itr = text_configs.begin(); | 
|  | 450       const TextTrackConfig& new_config = config_itr->second; | 
|  | 451       TextStreamMap::iterator stream_itr = text_stream_map_.begin(); | 
|  | 452       ChunkDemuxerStream* text_stream = stream_itr->second; | 
|  | 453       TextTrackConfig old_config = text_stream->text_track_config(); | 
|  | 454       if (!new_config.Matches(old_config)) { | 
|  | 455         success &= false; | 
|  | 456       } else { | 
|  | 457         text_stream_map_.clear(); | 
|  | 458         text_stream_map_[config_itr->first] = text_stream; | 
|  | 459       } | 
|  | 460     } else { | 
|  | 461       for (TextTrackConfigMap::const_iterator config_itr = text_configs.begin(); | 
|  | 462            config_itr != text_configs.end(); ++config_itr) { | 
|  | 463         TextStreamMap::iterator stream_itr = | 
|  | 464             text_stream_map_.find(config_itr->first); | 
|  | 465         if (stream_itr == text_stream_map_.end()) { | 
|  | 466           success &= false; | 
|  | 467           break; | 
|  | 468         } | 
|  | 469 | 
|  | 470         const TextTrackConfig& new_config = config_itr->second; | 
|  | 471         ChunkDemuxerStream* stream = stream_itr->second; | 
|  | 472         TextTrackConfig old_config = stream->text_track_config(); | 
|  | 473         if (!new_config.Matches(old_config)) { | 
|  | 474           success &= false; | 
|  | 475           break; | 
|  | 476         } | 
|  | 477       } | 
|  | 478     } | 
|  | 479   } | 
|  | 480 | 
| 380   DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed"); | 481   DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed"); | 
| 381   return success; | 482   return success; | 
| 382 } | 483 } | 
| 383 | 484 | 
| 384 void SourceState::OnNewMediaSegment() { | 485 void SourceState::OnNewMediaSegment() { | 
| 385   DVLOG(2) << "OnNewMediaSegment()"; | 486   DVLOG(2) << "OnNewMediaSegment()"; | 
| 386   can_update_offset_ = false; | 487   can_update_offset_ = false; | 
| 387   new_media_segment_ = true; | 488   new_media_segment_ = true; | 
| 388 } | 489 } | 
| 389 | 490 | 
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 425       segment_timestamp = filtered_video.front()->GetDecodeTimestamp(); | 526       segment_timestamp = filtered_video.front()->GetDecodeTimestamp(); | 
| 426     } | 527     } | 
| 427 | 528 | 
| 428     new_media_segment_ = false; | 529     new_media_segment_ = false; | 
| 429 | 530 | 
| 430     if (audio_) | 531     if (audio_) | 
| 431       audio_->OnNewMediaSegment(segment_timestamp); | 532       audio_->OnNewMediaSegment(segment_timestamp); | 
| 432 | 533 | 
| 433     if (video_) | 534     if (video_) | 
| 434       video_->OnNewMediaSegment(segment_timestamp); | 535       video_->OnNewMediaSegment(segment_timestamp); | 
|  | 536 | 
|  | 537     for (TextStreamMap::iterator itr = text_stream_map_.begin(); | 
|  | 538          itr != text_stream_map_.end(); ++itr) { | 
|  | 539       itr->second->OnNewMediaSegment(segment_timestamp); | 
|  | 540     } | 
| 435   } | 541   } | 
| 436 | 542 | 
| 437   if (!filtered_audio.empty()) { | 543   if (!filtered_audio.empty()) { | 
| 438     if (!audio_ || !audio_->Append(filtered_audio)) | 544     if (!audio_ || !audio_->Append(filtered_audio)) | 
| 439       return false; | 545       return false; | 
| 440     increase_duration_cb_.Run(filtered_audio.back()->timestamp(), audio_); | 546     increase_duration_cb_.Run(filtered_audio.back()->timestamp(), audio_); | 
| 441   } | 547   } | 
| 442 | 548 | 
| 443   if (!filtered_video.empty()) { | 549   if (!filtered_video.empty()) { | 
| 444     if (!video_ || !video_->Append(filtered_video)) | 550     if (!video_ || !video_->Append(filtered_video)) | 
| 445       return false; | 551       return false; | 
| 446     increase_duration_cb_.Run(filtered_video.back()->timestamp(), video_); | 552     increase_duration_cb_.Run(filtered_video.back()->timestamp(), video_); | 
| 447   } | 553   } | 
| 448 | 554 | 
| 449   return true; | 555   return true; | 
| 450 } | 556 } | 
| 451 | 557 | 
| 452 bool SourceState::OnTextBuffers( | 558 bool SourceState::OnTextBuffers( | 
| 453     const StreamParser::NewTextBuffersCB& new_buffers_cb, | 559     int text_track_number, | 
| 454     TextTrack* text_track, |  | 
| 455     const StreamParser::BufferQueue& buffers) { | 560     const StreamParser::BufferQueue& buffers) { | 
| 456   if (new_buffers_cb.is_null()) | 561   DCHECK(!buffers.empty()); | 
|  | 562 | 
|  | 563   TextStreamMap::iterator itr = text_stream_map_.find(text_track_number); | 
|  | 564   if (itr == text_stream_map_.end()) | 
| 457     return false; | 565     return false; | 
| 458 | 566 | 
| 459   AdjustBufferTimestamps(buffers); | 567   AdjustBufferTimestamps(buffers); | 
| 460 | 568 | 
| 461   return new_buffers_cb.Run(text_track, buffers); | 569   return itr->second->Append(buffers); | 
| 462 } | 570 } | 
| 463 | 571 | 
| 464 void SourceState::FilterWithAppendWindow( | 572 void SourceState::FilterWithAppendWindow( | 
| 465     const StreamParser::BufferQueue& buffers, bool* needs_keyframe, | 573     const StreamParser::BufferQueue& buffers, bool* needs_keyframe, | 
| 466     StreamParser::BufferQueue* filtered_buffers) { | 574     StreamParser::BufferQueue* filtered_buffers) { | 
| 467   DCHECK(needs_keyframe); | 575   DCHECK(needs_keyframe); | 
| 468   DCHECK(filtered_buffers); | 576   DCHECK(filtered_buffers); | 
| 469 | 577 | 
| 470   // This loop implements steps 1.9, 1.10, & 1.11 of the "Coded frame | 578   // This loop implements steps 1.9, 1.10, & 1.11 of the "Coded frame | 
| 471   // processing loop" in the Media Source Extensions spec. | 579   // processing loop" in the Media Source Extensions spec. | 
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 642 | 750 | 
| 643   if (!stream_) { | 751   if (!stream_) { | 
| 644     DCHECK_EQ(state_, UNINITIALIZED); | 752     DCHECK_EQ(state_, UNINITIALIZED); | 
| 645     stream_.reset(new SourceBufferStream(config, log_cb)); | 753     stream_.reset(new SourceBufferStream(config, log_cb)); | 
| 646     return true; | 754     return true; | 
| 647   } | 755   } | 
| 648 | 756 | 
| 649   return stream_->UpdateVideoConfig(config); | 757   return stream_->UpdateVideoConfig(config); | 
| 650 } | 758 } | 
| 651 | 759 | 
|  | 760 void ChunkDemuxerStream::UpdateTextConfig(const TextTrackConfig& config, | 
|  | 761                                           const LogCB& log_cb) { | 
|  | 762   DCHECK_EQ(type_, TEXT); | 
|  | 763   base::AutoLock auto_lock(lock_); | 
|  | 764   DCHECK(!stream_); | 
|  | 765   DCHECK_EQ(state_, UNINITIALIZED); | 
|  | 766   stream_.reset(new SourceBufferStream(config, log_cb)); | 
|  | 767 } | 
|  | 768 | 
| 652 void ChunkDemuxerStream::MarkEndOfStream() { | 769 void ChunkDemuxerStream::MarkEndOfStream() { | 
| 653   base::AutoLock auto_lock(lock_); | 770   base::AutoLock auto_lock(lock_); | 
| 654   stream_->MarkEndOfStream(); | 771   stream_->MarkEndOfStream(); | 
| 655 } | 772 } | 
| 656 | 773 | 
| 657 void ChunkDemuxerStream::UnmarkEndOfStream() { | 774 void ChunkDemuxerStream::UnmarkEndOfStream() { | 
| 658   base::AutoLock auto_lock(lock_); | 775   base::AutoLock auto_lock(lock_); | 
| 659   stream_->UnmarkEndOfStream(); | 776   stream_->UnmarkEndOfStream(); | 
| 660 } | 777 } | 
| 661 | 778 | 
| (...skipping 16 matching lines...) Expand all  Loading... | 
| 678   base::AutoLock auto_lock(lock_); | 795   base::AutoLock auto_lock(lock_); | 
| 679   return stream_->GetCurrentAudioDecoderConfig(); | 796   return stream_->GetCurrentAudioDecoderConfig(); | 
| 680 } | 797 } | 
| 681 | 798 | 
| 682 VideoDecoderConfig ChunkDemuxerStream::video_decoder_config() { | 799 VideoDecoderConfig ChunkDemuxerStream::video_decoder_config() { | 
| 683   CHECK_EQ(type_, VIDEO); | 800   CHECK_EQ(type_, VIDEO); | 
| 684   base::AutoLock auto_lock(lock_); | 801   base::AutoLock auto_lock(lock_); | 
| 685   return stream_->GetCurrentVideoDecoderConfig(); | 802   return stream_->GetCurrentVideoDecoderConfig(); | 
| 686 } | 803 } | 
| 687 | 804 | 
|  | 805 TextTrackConfig ChunkDemuxerStream::text_track_config() { | 
|  | 806   CHECK_EQ(type_, TEXT); | 
|  | 807   base::AutoLock auto_lock(lock_); | 
|  | 808   return stream_->GetCurrentTextTrackConfig(); | 
|  | 809 } | 
|  | 810 | 
| 688 void ChunkDemuxerStream::ChangeState_Locked(State state) { | 811 void ChunkDemuxerStream::ChangeState_Locked(State state) { | 
| 689   lock_.AssertAcquired(); | 812   lock_.AssertAcquired(); | 
| 690   DVLOG(1) << "ChunkDemuxerStream::ChangeState_Locked() : " | 813   DVLOG(1) << "ChunkDemuxerStream::ChangeState_Locked() : " | 
| 691            << "type " << type_ | 814            << "type " << type_ | 
| 692            << " - " << state_ << " -> " << state; | 815            << " - " << state_ << " -> " << state; | 
| 693   state_ = state; | 816   state_ = state; | 
| 694 } | 817 } | 
| 695 | 818 | 
| 696 ChunkDemuxerStream::~ChunkDemuxerStream() {} | 819 ChunkDemuxerStream::~ChunkDemuxerStream() {} | 
| 697 | 820 | 
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 737       status = DemuxerStream::kOk; | 860       status = DemuxerStream::kOk; | 
| 738       buffer = StreamParserBuffer::CreateEOSBuffer(); | 861       buffer = StreamParserBuffer::CreateEOSBuffer(); | 
| 739       break; | 862       break; | 
| 740   } | 863   } | 
| 741 | 864 | 
| 742   base::ResetAndReturn(&read_cb_).Run(status, buffer); | 865   base::ResetAndReturn(&read_cb_).Run(status, buffer); | 
| 743 } | 866 } | 
| 744 | 867 | 
| 745 ChunkDemuxer::ChunkDemuxer(const base::Closure& open_cb, | 868 ChunkDemuxer::ChunkDemuxer(const base::Closure& open_cb, | 
| 746                            const NeedKeyCB& need_key_cb, | 869                            const NeedKeyCB& need_key_cb, | 
| 747                            const AddTextTrackCB& add_text_track_cb, | 870                            bool enable_text, | 
| 748                            const LogCB& log_cb) | 871                            const LogCB& log_cb) | 
| 749     : state_(WAITING_FOR_INIT), | 872     : state_(WAITING_FOR_INIT), | 
| 750       cancel_next_seek_(false), | 873       cancel_next_seek_(false), | 
| 751       host_(NULL), | 874       host_(NULL), | 
| 752       open_cb_(open_cb), | 875       open_cb_(open_cb), | 
| 753       need_key_cb_(need_key_cb), | 876       need_key_cb_(need_key_cb), | 
| 754       add_text_track_cb_(add_text_track_cb), | 877       enable_text_(enable_text), | 
| 755       log_cb_(log_cb), | 878       log_cb_(log_cb), | 
| 756       duration_(kNoTimestamp()), | 879       duration_(kNoTimestamp()), | 
| 757       user_specified_duration_(-1) { | 880       user_specified_duration_(-1) { | 
| 758   DCHECK(!open_cb_.is_null()); | 881   DCHECK(!open_cb_.is_null()); | 
| 759   DCHECK(!need_key_cb_.is_null()); | 882   DCHECK(!need_key_cb_.is_null()); | 
| 760 } | 883 } | 
| 761 | 884 | 
| 762 void ChunkDemuxer::Initialize(DemuxerHost* host, const PipelineStatusCB& cb) { | 885 void ChunkDemuxer::Initialize(DemuxerHost* host, const PipelineStatusCB& cb) { | 
| 763   DVLOG(1) << "Init()"; | 886   DVLOG(1) << "Init()"; | 
| 764 | 887 | 
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 814 } | 937 } | 
| 815 | 938 | 
| 816 void ChunkDemuxer::OnAudioRendererDisabled() { | 939 void ChunkDemuxer::OnAudioRendererDisabled() { | 
| 817   base::AutoLock auto_lock(lock_); | 940   base::AutoLock auto_lock(lock_); | 
| 818   audio_->Shutdown(); | 941   audio_->Shutdown(); | 
| 819   disabled_audio_ = audio_.Pass(); | 942   disabled_audio_ = audio_.Pass(); | 
| 820 } | 943 } | 
| 821 | 944 | 
| 822 // Demuxer implementation. | 945 // Demuxer implementation. | 
| 823 DemuxerStream* ChunkDemuxer::GetStream(DemuxerStream::Type type) { | 946 DemuxerStream* ChunkDemuxer::GetStream(DemuxerStream::Type type) { | 
|  | 947   DCHECK_NE(type, DemuxerStream::TEXT); | 
| 824   base::AutoLock auto_lock(lock_); | 948   base::AutoLock auto_lock(lock_); | 
| 825   if (type == DemuxerStream::VIDEO) | 949   if (type == DemuxerStream::VIDEO) | 
| 826     return video_.get(); | 950     return video_.get(); | 
| 827 | 951 | 
| 828   if (type == DemuxerStream::AUDIO) | 952   if (type == DemuxerStream::AUDIO) | 
| 829     return audio_.get(); | 953     return audio_.get(); | 
| 830 | 954 | 
| 831   return NULL; | 955   return NULL; | 
| 832 } | 956 } | 
| 833 | 957 | 
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 899   if (has_video) | 1023   if (has_video) | 
| 900     source_id_video_ = id; | 1024     source_id_video_ = id; | 
| 901 | 1025 | 
| 902   scoped_ptr<SourceState> source_state( | 1026   scoped_ptr<SourceState> source_state( | 
| 903       new SourceState(stream_parser.Pass(), log_cb_, | 1027       new SourceState(stream_parser.Pass(), log_cb_, | 
| 904                       base::Bind(&ChunkDemuxer::CreateDemuxerStream, | 1028                       base::Bind(&ChunkDemuxer::CreateDemuxerStream, | 
| 905                                  base::Unretained(this)), | 1029                                  base::Unretained(this)), | 
| 906                       base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary, | 1030                       base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary, | 
| 907                                  base::Unretained(this)))); | 1031                                  base::Unretained(this)))); | 
| 908 | 1032 | 
|  | 1033   SourceState::NewTextTrackCB new_text_track_cb; | 
|  | 1034 | 
|  | 1035   if (enable_text_) { | 
|  | 1036     new_text_track_cb = base::Bind(&ChunkDemuxer::OnNewTextTrack, | 
|  | 1037                                    base::Unretained(this)); | 
|  | 1038   } | 
|  | 1039 | 
| 909   source_state->Init( | 1040   source_state->Init( | 
| 910       base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this)), | 1041       base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this)), | 
| 911       has_audio, | 1042       has_audio, | 
| 912       has_video, | 1043       has_video, | 
| 913       base::Bind(&ChunkDemuxer::OnTextBuffers, base::Unretained(this)), |  | 
| 914       need_key_cb_, | 1044       need_key_cb_, | 
| 915       add_text_track_cb_); | 1045       new_text_track_cb); | 
| 916 | 1046 | 
| 917   source_state_map_[id] = source_state.release(); | 1047   source_state_map_[id] = source_state.release(); | 
| 918   return kOk; | 1048   return kOk; | 
| 919 } | 1049 } | 
| 920 | 1050 | 
| 921 void ChunkDemuxer::RemoveId(const std::string& id) { | 1051 void ChunkDemuxer::RemoveId(const std::string& id) { | 
| 922   base::AutoLock auto_lock(lock_); | 1052   base::AutoLock auto_lock(lock_); | 
| 923   CHECK(IsValidId(id)); | 1053   CHECK(IsValidId(id)); | 
| 924 | 1054 | 
| 925   delete source_state_map_[id]; | 1055   delete source_state_map_[id]; | 
| (...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1335         return NULL; | 1465         return NULL; | 
| 1336       audio_.reset(new ChunkDemuxerStream(DemuxerStream::AUDIO)); | 1466       audio_.reset(new ChunkDemuxerStream(DemuxerStream::AUDIO)); | 
| 1337       return audio_.get(); | 1467       return audio_.get(); | 
| 1338       break; | 1468       break; | 
| 1339     case DemuxerStream::VIDEO: | 1469     case DemuxerStream::VIDEO: | 
| 1340       if (video_) | 1470       if (video_) | 
| 1341         return NULL; | 1471         return NULL; | 
| 1342       video_.reset(new ChunkDemuxerStream(DemuxerStream::VIDEO)); | 1472       video_.reset(new ChunkDemuxerStream(DemuxerStream::VIDEO)); | 
| 1343       return video_.get(); | 1473       return video_.get(); | 
| 1344       break; | 1474       break; | 
|  | 1475     case DemuxerStream::TEXT: { | 
|  | 1476       return new ChunkDemuxerStream(DemuxerStream::TEXT); | 
|  | 1477       break; | 
|  | 1478     } | 
| 1345     case DemuxerStream::UNKNOWN: | 1479     case DemuxerStream::UNKNOWN: | 
| 1346     case DemuxerStream::NUM_TYPES: | 1480     case DemuxerStream::NUM_TYPES: | 
| 1347       NOTREACHED(); | 1481       NOTREACHED(); | 
| 1348       return NULL; | 1482       return NULL; | 
| 1349   } | 1483   } | 
| 1350   NOTREACHED(); | 1484   NOTREACHED(); | 
| 1351   return NULL; | 1485   return NULL; | 
| 1352 } | 1486 } | 
| 1353 | 1487 | 
| 1354 bool ChunkDemuxer::OnTextBuffers( | 1488 void ChunkDemuxer::OnNewTextTrack(ChunkDemuxerStream* text_stream, | 
| 1355   TextTrack* text_track, | 1489                                   const TextTrackConfig& config) { | 
| 1356   const StreamParser::BufferQueue& buffers) { |  | 
| 1357   lock_.AssertAcquired(); | 1490   lock_.AssertAcquired(); | 
| 1358   DCHECK_NE(state_, SHUTDOWN); | 1491   DCHECK_NE(state_, SHUTDOWN); | 
| 1359 | 1492   host_->AddTextStream(text_stream, config); | 
| 1360   // TODO(matthewjheaney): IncreaseDurationIfNecessary |  | 
| 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 } | 1493 } | 
| 1379 | 1494 | 
| 1380 bool ChunkDemuxer::IsValidId(const std::string& source_id) const { | 1495 bool ChunkDemuxer::IsValidId(const std::string& source_id) const { | 
| 1381   lock_.AssertAcquired(); | 1496   lock_.AssertAcquired(); | 
| 1382   return source_state_map_.count(source_id) > 0u; | 1497   return source_state_map_.count(source_id) > 0u; | 
| 1383 } | 1498 } | 
| 1384 | 1499 | 
| 1385 void ChunkDemuxer::UpdateDuration(TimeDelta new_duration) { | 1500 void ChunkDemuxer::UpdateDuration(TimeDelta new_duration) { | 
| 1386   DCHECK(duration_ != new_duration); | 1501   DCHECK(duration_ != new_duration); | 
| 1387   user_specified_duration_ = -1; | 1502   user_specified_duration_ = -1; | 
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1421     return video_->GetBufferedRanges(duration_); | 1536     return video_->GetBufferedRanges(duration_); | 
| 1422   return ComputeIntersection(); | 1537   return ComputeIntersection(); | 
| 1423 } | 1538 } | 
| 1424 | 1539 | 
| 1425 void ChunkDemuxer::StartReturningData() { | 1540 void ChunkDemuxer::StartReturningData() { | 
| 1426   if (audio_) | 1541   if (audio_) | 
| 1427     audio_->StartReturningData(); | 1542     audio_->StartReturningData(); | 
| 1428 | 1543 | 
| 1429   if (video_) | 1544   if (video_) | 
| 1430     video_->StartReturningData(); | 1545     video_->StartReturningData(); | 
|  | 1546 | 
|  | 1547   for (SourceStateMap::iterator itr = source_state_map_.begin(); | 
|  | 1548        itr != source_state_map_.end(); ++itr) { | 
|  | 1549     itr->second->TextStartReturningData(); | 
|  | 1550   } | 
| 1431 } | 1551 } | 
| 1432 | 1552 | 
| 1433 void ChunkDemuxer::AbortPendingReads() { | 1553 void ChunkDemuxer::AbortPendingReads() { | 
| 1434   if (audio_) | 1554   if (audio_) | 
| 1435     audio_->AbortReads(); | 1555     audio_->AbortReads(); | 
| 1436 | 1556 | 
| 1437   if (video_) | 1557   if (video_) | 
| 1438     video_->AbortReads(); | 1558     video_->AbortReads(); | 
|  | 1559 | 
|  | 1560   for (SourceStateMap::iterator itr = source_state_map_.begin(); | 
|  | 1561        itr != source_state_map_.end(); ++itr) { | 
|  | 1562     itr->second->TextAbortReads(); | 
|  | 1563   } | 
| 1439 } | 1564 } | 
| 1440 | 1565 | 
| 1441 void ChunkDemuxer::SeekAllSources(TimeDelta seek_time) { | 1566 void ChunkDemuxer::SeekAllSources(TimeDelta seek_time) { | 
| 1442   if (audio_) | 1567   if (audio_) | 
| 1443     audio_->Seek(seek_time); | 1568     audio_->Seek(seek_time); | 
| 1444 | 1569 | 
| 1445   if (video_) | 1570   if (video_) | 
| 1446     video_->Seek(seek_time); | 1571     video_->Seek(seek_time); | 
|  | 1572 | 
|  | 1573   for (SourceStateMap::iterator itr = source_state_map_.begin(); | 
|  | 1574        itr != source_state_map_.end(); ++itr) { | 
|  | 1575     itr->second->TextSeek(seek_time); | 
|  | 1576   } | 
| 1447 } | 1577 } | 
| 1448 | 1578 | 
| 1449 void ChunkDemuxer::CompletePendingReadsIfPossible() { | 1579 void ChunkDemuxer::CompletePendingReadsIfPossible() { | 
| 1450   if (audio_) | 1580   if (audio_) | 
| 1451     audio_->CompletePendingReadIfPossible(); | 1581     audio_->CompletePendingReadIfPossible(); | 
| 1452 | 1582 | 
| 1453   if (video_) | 1583   if (video_) | 
| 1454     video_->CompletePendingReadIfPossible(); | 1584     video_->CompletePendingReadIfPossible(); | 
|  | 1585 | 
|  | 1586   for (SourceStateMap::iterator itr = source_state_map_.begin(); | 
|  | 1587        itr != source_state_map_.end(); ++itr) { | 
|  | 1588     itr->second->TextCompletePendingReadIfPossible(); | 
|  | 1589   } | 
| 1455 } | 1590 } | 
| 1456 | 1591 | 
| 1457 }  // namespace media | 1592 }  // namespace media | 
| OLD | NEW | 
|---|