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