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 3 // found in the LICENSE file. 4 5 #ifndef MEDIA_FILTERS_CHUNK_DEMUXER_H_ 6 #define MEDIA_FILTERS_CHUNK_DEMUXER_H_ 7 8 #include <map> 9 #include <string> 10 #include <utility> 11 #include <vector> 12 13 #include "base/synchronization/lock.h" 14 #include "media/base/byte_queue.h" 15 #include "media/base/demuxer.h" 16 #include "media/base/ranges.h" 17 #include "media/base/stream_parser.h" 18 #include "media/base/text_track.h" 19 #include "media/filters/source_buffer_stream.h" 20 21 namespace media { 22 23 class ChunkDemuxerStream; 24 class FFmpegURLProtocol; 25 class SourceState; 26 27 // Demuxer implementation that allows chunks of media data to be passed 28 // from JavaScript to the media stack. 29 class MEDIA_EXPORT ChunkDemuxer : public Demuxer { 30 public: 31 enum Status { 32 kOk, // ID added w/o error. 33 kNotSupported, // Type specified is not supported. 34 kReachedIdLimit, // Reached ID limit. We can't handle any more IDs. 35 }; 36 37 typedef base::Callback<void(const std::string& type, 38 scoped_ptr<uint8[]> init_data, 39 int init_data_size)> NeedKeyCB; 40 41 // |open_cb| Run when Initialize() is called to signal that the demuxer 42 // is ready to receive media data via AppenData(). 43 // |need_key_cb| Run when the demuxer determines that an encryption key is 44 // needed to decrypt the content. 45 // |add_text_track_cb| Run when demuxer detects the presence of an inband 46 // text track. 47 // |log_cb| Run when parsing error messages need to be logged to the error 48 // console. 49 ChunkDemuxer(const base::Closure& open_cb, 50 const NeedKeyCB& need_key_cb, 51 const AddTextTrackCB& add_text_track_cb, 52 const LogCB& log_cb); 53 virtual ~ChunkDemuxer(); 54 55 // Demuxer implementation. 56 virtual void Initialize(DemuxerHost* host, 57 const PipelineStatusCB& cb) OVERRIDE; 58 virtual void Stop(const base::Closure& callback) OVERRIDE; 59 virtual void Seek(base::TimeDelta time, const PipelineStatusCB& cb) OVERRIDE; 60 virtual void OnAudioRendererDisabled() OVERRIDE; 61 virtual DemuxerStream* GetStream(DemuxerStream::Type type) OVERRIDE; 62 virtual base::TimeDelta GetStartTime() const OVERRIDE; 63 64 // Methods used by an external object to control this demuxer. 65 // 66 // Indicates that a new Seek() call is on its way. Any pending Reads on the 67 // DemuxerStream objects should be aborted immediately inside this call and 68 // future Read calls should return kAborted until the Seek() call occurs. 69 // This method MUST ALWAYS be called before Seek() is called to signal that 70 // the next Seek() call represents the seek point we actually want to return 71 // data for. 72 // |seek_time| - The presentation timestamp for the seek that triggered this 73 // call. It represents the most recent position the caller is trying to seek 74 // to. 75 void StartWaitingForSeek(base::TimeDelta seek_time); 76 77 // Indicates that a Seek() call is on its way, but another seek has been 78 // requested that will override the impending Seek() call. Any pending Reads 79 // on the DemuxerStream objects should be aborted immediately inside this call 80 // and future Read calls should return kAborted until the next 81 // StartWaitingForSeek() call. This method also arranges for the next Seek() 82 // call received before a StartWaitingForSeek() call to immediately call its 83 // callback without waiting for any data. 84 // |seek_time| - The presentation timestamp for the seek request that 85 // triggered this call. It represents the most recent position the caller is 86 // trying to seek to. 87 void CancelPendingSeek(base::TimeDelta seek_time); 88 89 // Registers a new |id| to use for AppendData() calls. |type| indicates 90 // the MIME type for the data that we intend to append for this ID. 91 // kOk is returned if the demuxer has enough resources to support another ID 92 // and supports the format indicated by |type|. 93 // kNotSupported is returned if |type| is not a supported format. 94 // kReachedIdLimit is returned if the demuxer cannot handle another ID right 95 // now. 96 Status AddId(const std::string& id, const std::string& type, 97 std::vector<std::string>& codecs); 98 99 // Removed an ID & associated resources that were previously added with 100 // AddId(). 101 void RemoveId(const std::string& id); 102 103 // Gets the currently buffered ranges for the specified ID. 104 Ranges<base::TimeDelta> GetBufferedRanges(const std::string& id) const; 105 106 // Appends media data to the source buffer associated with |id|. 107 void AppendData(const std::string& id, const uint8* data, size_t length); 108 109 // Aborts parsing the current segment and reset the parser to a state where 110 // it can accept a new segment. 111 void Abort(const std::string& id); 112 113 // Remove buffers between |start| and |end| for the source buffer 114 // associated with |id|. 115 void Remove(const std::string& id, base::TimeDelta start, 116 base::TimeDelta end); 117 118 // Returns the current presentation duration. 119 double GetDuration(); 120 double GetDuration_Locked(); 121 122 // Notifies the demuxer that the duration of the media has changed to 123 // |duration|. 124 void SetDuration(double duration); 125 126 // Sets a time |offset| to be applied to subsequent buffers appended to the 127 // source buffer associated with |id|. Returns true if the offset is set 128 // properly, false if the offset cannot be applied because we're in the 129 // middle of parsing a media segment. 130 bool SetTimestampOffset(const std::string& id, base::TimeDelta offset); 131 132 // Called to signal changes in the "end of stream" 133 // state. UnmarkEndOfStream() must not be called if a matching 134 // MarkEndOfStream() has not come before it. 135 void MarkEndOfStream(PipelineStatus status); 136 void UnmarkEndOfStream(); 137 138 // Set the append window start and end values for the source buffer 139 // associated with |id|. 140 void SetAppendWindowStart(const std::string& id, base::TimeDelta start); 141 void SetAppendWindowEnd(const std::string& id, base::TimeDelta end); 142 143 void Shutdown(); 144 145 void SetMemoryLimitsForTesting(int memory_limit); 146 147 private: 148 enum State { 149 WAITING_FOR_INIT, 150 INITIALIZING, 151 INITIALIZED, 152 ENDED, 153 PARSE_ERROR, 154 SHUTDOWN, 155 }; 156 157 void ChangeState_Locked(State new_state); 158 159 // Reports an error and puts the demuxer in a state where it won't accept more 160 // data. 161 void ReportError_Locked(PipelineStatus error); 162 163 // Returns true if any stream has seeked to a time without buffered data. 164 bool IsSeekWaitingForData_Locked() const; 165 166 // Returns true if all streams can successfully call EndOfStream, 167 // false if any can not. 168 bool CanEndOfStream_Locked() const; 169 170 // SourceState callbacks. 171 void OnSourceInitDone(bool success, base::TimeDelta duration); 172 173 // Creates a DemuxerStream for the specified |type|. 174 // Returns a new ChunkDemuxerStream instance if a stream of this type 175 // has not been created before. Returns NULL otherwise. 176 ChunkDemuxerStream* CreateDemuxerStream(DemuxerStream::Type type); 177 178 bool OnTextBuffers(TextTrack* text_track, 179 const StreamParser::BufferQueue& buffers); 180 void OnNewMediaSegment(const std::string& source_id, 181 base::TimeDelta start_timestamp); 182 183 // Computes the intersection between the video & audio 184 // buffered ranges. 185 Ranges<base::TimeDelta> ComputeIntersection() const; 186 187 // Applies |time_offset| to the timestamps of |buffers|. 188 void AdjustBufferTimestamps(const StreamParser::BufferQueue& buffers, 189 base::TimeDelta timestamp_offset); 190 191 // Returns true if |source_id| is valid, false otherwise. 192 bool IsValidId(const std::string& source_id) const; 193 194 // Increases |duration_| if |last_appended_buffer_timestamp| exceeds the 195 // current |duration_|. The |duration_| is set to the end buffered timestamp 196 // of |stream|. 197 void IncreaseDurationIfNecessary( 198 base::TimeDelta last_appended_buffer_timestamp, 199 ChunkDemuxerStream* stream); 200 201 // Decreases |duration_| if the buffered region is less than |duration_| when 202 // EndOfStream() is called. 203 void DecreaseDurationIfNecessary(); 204 205 // Sets |duration_| to |new_duration|, sets |user_specified_duration_| to -1 206 // and notifies |host_|. 207 void UpdateDuration(base::TimeDelta new_duration); 208 209 // Returns the ranges representing the buffered data in the demuxer. 210 Ranges<base::TimeDelta> GetBufferedRanges() const; 211 212 // Start returning data on all DemuxerStreams. 213 void StartReturningData(); 214 215 // Aborts pending reads on all DemuxerStreams. 216 void AbortPendingReads(); 217 218 // Completes any pending reads if it is possible to do so. 219 void CompletePendingReadsIfPossible(); 220 221 // Seeks all SourceBufferStreams to |seek_time|. 222 void SeekAllSources(base::TimeDelta seek_time); 223 224 mutable base::Lock lock_; 225 State state_; 226 bool cancel_next_seek_; 227 228 DemuxerHost* host_; 229 base::Closure open_cb_; 230 NeedKeyCB need_key_cb_; 231 AddTextTrackCB add_text_track_cb_; 232 // Callback used to report error strings that can help the web developer 233 // figure out what is wrong with the content. 234 LogCB log_cb_; 235 236 PipelineStatusCB init_cb_; 237 PipelineStatusCB seek_cb_; 238 239 scoped_ptr<ChunkDemuxerStream> audio_; 240 scoped_ptr<ChunkDemuxerStream> video_; 241 242 // Keeps |audio_| alive when audio has been disabled. 243 scoped_ptr<ChunkDemuxerStream> disabled_audio_; 244 245 base::TimeDelta duration_; 246 247 // The duration passed to the last SetDuration(). If 248 // SetDuration() is never called or an AppendData() call or 249 // a EndOfStream() call changes |duration_|, then this 250 // variable is set to < 0 to indicate that the |duration_| represents 251 // the actual duration instead of a user specified value. 252 double user_specified_duration_; 253 254 typedef std::map<std::string, SourceState*> SourceStateMap; 255 SourceStateMap source_state_map_; 256 257 // Used to ensure that (1) config data matches the type and codec provided in 258 // AddId(), (2) only 1 audio and 1 video sources are added, and (3) ids may be 259 // removed with RemoveID() but can not be re-added (yet). 260 std::string source_id_audio_; 261 std::string source_id_video_; 262 263 DISALLOW_COPY_AND_ASSIGN(ChunkDemuxer); 264 }; 265 266 } // namespace media 267 268 #endif // MEDIA_FILTERS_CHUNK_DEMUXER_H_ 269