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.
5 #ifndef MEDIA_FILTERS_CHUNK_DEMUXER_H_
6 #define MEDIA_FILTERS_CHUNK_DEMUXER_H_
14 #include "base/synchronization/lock.h"
15 #include "media/base/byte_queue.h"
16 #include "media/base/demuxer.h"
17 #include "media/base/ranges.h"
18 #include "media/base/stream_parser.h"
19 #include "media/filters/source_buffer_stream.h"
23 class FFmpegURLProtocol
;
26 class MEDIA_EXPORT ChunkDemuxerStream
: public DemuxerStream
{
28 typedef std::deque
<scoped_refptr
<StreamParserBuffer
> > BufferQueue
;
30 explicit ChunkDemuxerStream(Type type
, bool splice_frames_enabled
);
31 virtual ~ChunkDemuxerStream();
33 // ChunkDemuxerStream control methods.
34 void StartReturningData();
36 void CompletePendingReadIfPossible();
39 // SourceBufferStream manipulation methods.
40 void Seek(base::TimeDelta time
);
41 bool IsSeekWaitingForData() const;
43 // Add buffers to this stream. Buffers are stored in SourceBufferStreams,
44 // which handle ordering and overlap resolution.
45 // Returns true if buffers were successfully added.
46 bool Append(const StreamParser::BufferQueue
& buffers
);
48 // Removes buffers between |start| and |end| according to the steps
49 // in the "Coded Frame Removal Algorithm" in the Media Source
51 // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#sourcebuffer-coded-frame-removal
53 // |duration| is the current duration of the presentation. It is
54 // required by the computation outlined in the spec.
55 void Remove(base::TimeDelta start
, base::TimeDelta end
,
56 base::TimeDelta duration
);
58 // Signal to the stream that duration has changed to |duration|.
59 void OnSetDuration(base::TimeDelta duration
);
61 // Returns the range of buffered data in this stream, capped at |duration|.
62 Ranges
<base::TimeDelta
> GetBufferedRanges(base::TimeDelta duration
) const;
64 // Returns the duration of the buffered data.
65 // Returns base::TimeDelta() if the stream has no buffered data.
66 base::TimeDelta
GetBufferedDuration() const;
68 // Signal to the stream that buffers handed in through subsequent calls to
69 // Append() belong to a media segment that starts at |start_timestamp|.
70 void OnNewMediaSegment(DecodeTimestamp start_timestamp
);
72 // Called when midstream config updates occur.
73 // Returns true if the new config is accepted.
74 // Returns false if the new config should trigger an error.
75 bool UpdateAudioConfig(const AudioDecoderConfig
& config
, const LogCB
& log_cb
);
76 bool UpdateVideoConfig(const VideoDecoderConfig
& config
, const LogCB
& log_cb
);
77 void UpdateTextConfig(const TextTrackConfig
& config
, const LogCB
& log_cb
);
79 void MarkEndOfStream();
80 void UnmarkEndOfStream();
82 // DemuxerStream methods.
83 virtual void Read(const ReadCB
& read_cb
) OVERRIDE
;
84 virtual Type
type() OVERRIDE
;
85 virtual AudioDecoderConfig
audio_decoder_config() OVERRIDE
;
86 virtual VideoDecoderConfig
video_decoder_config() OVERRIDE
;
87 virtual bool SupportsConfigChanges() OVERRIDE
;
88 virtual VideoRotation
video_rotation() OVERRIDE
;
90 // Returns the text track configuration. It is an error to call this method
92 TextTrackConfig
text_track_config();
94 // Sets the memory limit, in bytes, on the SourceBufferStream.
95 void set_memory_limit(int memory_limit
) {
96 stream_
->set_memory_limit(memory_limit
);
99 bool supports_partial_append_window_trimming() const {
100 return partial_append_window_trimming_enabled_
;
106 RETURNING_DATA_FOR_READS
,
107 RETURNING_ABORT_FOR_READS
,
111 // Assigns |state_| to |state|
112 void ChangeState_Locked(State state
);
114 void CompletePendingReadIfPossible_Locked();
116 // Specifies the type of the stream.
119 scoped_ptr
<SourceBufferStream
> stream_
;
121 mutable base::Lock lock_
;
124 bool splice_frames_enabled_
;
125 bool partial_append_window_trimming_enabled_
;
127 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream
);
130 // Demuxer implementation that allows chunks of media data to be passed
131 // from JavaScript to the media stack.
132 class MEDIA_EXPORT ChunkDemuxer
: public Demuxer
{
135 kOk
, // ID added w/o error.
136 kNotSupported
, // Type specified is not supported.
137 kReachedIdLimit
, // Reached ID limit. We can't handle any more IDs.
140 typedef base::Closure InitSegmentReceivedCB
;
142 // |open_cb| Run when Initialize() is called to signal that the demuxer
143 // is ready to receive media data via AppenData().
144 // |need_key_cb| Run when the demuxer determines that an encryption key is
145 // needed to decrypt the content.
146 // |enable_text| Process inband text tracks in the normal way when true,
147 // otherwise ignore them.
148 // |log_cb| Run when parsing error messages need to be logged to the error
150 // |splice_frames_enabled| Indicates that it's okay to generate splice frames
151 // per the MSE specification. Renderers must understand DecoderBuffer's
152 // splice_timestamp() field.
153 ChunkDemuxer(const base::Closure
& open_cb
,
154 const NeedKeyCB
& need_key_cb
,
156 bool splice_frames_enabled
);
157 virtual ~ChunkDemuxer();
159 // Demuxer implementation.
160 virtual void Initialize(DemuxerHost
* host
,
161 const PipelineStatusCB
& cb
,
162 bool enable_text_tracks
) OVERRIDE
;
163 virtual void Stop() OVERRIDE
;
164 virtual void Seek(base::TimeDelta time
, const PipelineStatusCB
& cb
) OVERRIDE
;
165 virtual base::Time
GetTimelineOffset() const OVERRIDE
;
166 virtual DemuxerStream
* GetStream(DemuxerStream::Type type
) OVERRIDE
;
167 virtual base::TimeDelta
GetStartTime() const OVERRIDE
;
168 virtual Liveness
GetLiveness() const OVERRIDE
;
170 // Methods used by an external object to control this demuxer.
172 // Indicates that a new Seek() call is on its way. Any pending Reads on the
173 // DemuxerStream objects should be aborted immediately inside this call and
174 // future Read calls should return kAborted until the Seek() call occurs.
175 // This method MUST ALWAYS be called before Seek() is called to signal that
176 // the next Seek() call represents the seek point we actually want to return
178 // |seek_time| - The presentation timestamp for the seek that triggered this
179 // call. It represents the most recent position the caller is trying to seek
181 void StartWaitingForSeek(base::TimeDelta seek_time
);
183 // Indicates that a Seek() call is on its way, but another seek has been
184 // requested that will override the impending Seek() call. Any pending Reads
185 // on the DemuxerStream objects should be aborted immediately inside this call
186 // and future Read calls should return kAborted until the next
187 // StartWaitingForSeek() call. This method also arranges for the next Seek()
188 // call received before a StartWaitingForSeek() call to immediately call its
189 // callback without waiting for any data.
190 // |seek_time| - The presentation timestamp for the seek request that
191 // triggered this call. It represents the most recent position the caller is
192 // trying to seek to.
193 void CancelPendingSeek(base::TimeDelta seek_time
);
195 // Registers a new |id| to use for AppendData() calls. |type| indicates
196 // the MIME type for the data that we intend to append for this ID.
197 // kOk is returned if the demuxer has enough resources to support another ID
198 // and supports the format indicated by |type|.
199 // kNotSupported is returned if |type| is not a supported format.
200 // kReachedIdLimit is returned if the demuxer cannot handle another ID right
202 Status
AddId(const std::string
& id
, const std::string
& type
,
203 std::vector
<std::string
>& codecs
);
205 // Removed an ID & associated resources that were previously added with
207 void RemoveId(const std::string
& id
);
209 // Gets the currently buffered ranges for the specified ID.
210 Ranges
<base::TimeDelta
> GetBufferedRanges(const std::string
& id
) const;
212 // Appends media data to the source buffer associated with |id|, applying
213 // and possibly updating |*timestamp_offset| during coded frame processing.
214 // |append_window_start| and |append_window_end| correspond to the MSE spec's
215 // similarly named source buffer attributes that are used in coded frame
217 // |init_segment_received_cb| is run for each newly successfully parsed
218 // initialization segment.
219 void AppendData(const std::string
& id
, const uint8
* data
, size_t length
,
220 base::TimeDelta append_window_start
,
221 base::TimeDelta append_window_end
,
222 base::TimeDelta
* timestamp_offset
,
223 const InitSegmentReceivedCB
& init_segment_received_cb
);
225 // Aborts parsing the current segment and reset the parser to a state where
226 // it can accept a new segment.
227 // Some pending frames can be emitted during that process. These frames are
228 // applied |timestamp_offset|.
229 void Abort(const std::string
& id
,
230 base::TimeDelta append_window_start
,
231 base::TimeDelta append_window_end
,
232 base::TimeDelta
* timestamp_offset
);
234 // Remove buffers between |start| and |end| for the source buffer
235 // associated with |id|.
236 void Remove(const std::string
& id
, base::TimeDelta start
,
237 base::TimeDelta end
);
239 // Returns the current presentation duration.
240 double GetDuration();
241 double GetDuration_Locked();
243 // Notifies the demuxer that the duration of the media has changed to
245 void SetDuration(double duration
);
247 // Returns true if the source buffer associated with |id| is currently parsing
248 // a media segment, or false otherwise.
249 bool IsParsingMediaSegment(const std::string
& id
);
251 // Set the append mode to be applied to subsequent buffers appended to the
252 // source buffer associated with |id|. If |sequence_mode| is true, caller
253 // is requesting "sequence" mode. Otherwise, caller is requesting "segments"
255 void SetSequenceMode(const std::string
& id
, bool sequence_mode
);
257 // Signals the coded frame processor for the source buffer associated with
258 // |id| to update its group start timestamp to be |timestamp_offset| if it is
259 // in sequence append mode.
260 void SetGroupStartTimestampIfInSequenceMode(const std::string
& id
,
261 base::TimeDelta timestamp_offset
);
263 // Called to signal changes in the "end of stream"
264 // state. UnmarkEndOfStream() must not be called if a matching
265 // MarkEndOfStream() has not come before it.
266 void MarkEndOfStream(PipelineStatus status
);
267 void UnmarkEndOfStream();
271 // Sets the memory limit on each stream of a specific type.
272 // |memory_limit| is the maximum number of bytes each stream of type |type|
273 // is allowed to hold in its buffer.
274 void SetMemoryLimits(DemuxerStream::Type type
, int memory_limit
);
276 // Returns the ranges representing the buffered data in the demuxer.
277 // TODO(wolenetz): Remove this method once MediaSourceDelegate no longer
278 // requires it for doing hack browser seeks to I-frame on Android. See
279 // http://crbug.com/304234.
280 Ranges
<base::TimeDelta
> GetBufferedRanges() const;
292 void ChangeState_Locked(State new_state
);
294 // Reports an error and puts the demuxer in a state where it won't accept more
296 void ReportError_Locked(PipelineStatus error
);
298 // Returns true if any stream has seeked to a time without buffered data.
299 bool IsSeekWaitingForData_Locked() const;
301 // Returns true if all streams can successfully call EndOfStream,
302 // false if any can not.
303 bool CanEndOfStream_Locked() const;
305 // SourceState callbacks.
306 void OnSourceInitDone(bool success
,
307 const StreamParser::InitParameters
& params
);
309 // Creates a DemuxerStream for the specified |type|.
310 // Returns a new ChunkDemuxerStream instance if a stream of this type
311 // has not been created before. Returns NULL otherwise.
312 ChunkDemuxerStream
* CreateDemuxerStream(DemuxerStream::Type type
);
314 void OnNewTextTrack(ChunkDemuxerStream
* text_stream
,
315 const TextTrackConfig
& config
);
317 // Returns true if |source_id| is valid, false otherwise.
318 bool IsValidId(const std::string
& source_id
) const;
320 // Increases |duration_| to |new_duration|, if |new_duration| is higher.
321 void IncreaseDurationIfNecessary(base::TimeDelta new_duration
);
323 // Decreases |duration_| if the buffered region is less than |duration_| when
324 // EndOfStream() is called.
325 void DecreaseDurationIfNecessary();
327 // Sets |duration_| to |new_duration|, sets |user_specified_duration_| to -1
328 // and notifies |host_|.
329 void UpdateDuration(base::TimeDelta new_duration
);
331 // Returns the ranges representing the buffered data in the demuxer.
332 Ranges
<base::TimeDelta
> GetBufferedRanges_Locked() const;
334 // Start returning data on all DemuxerStreams.
335 void StartReturningData();
337 // Aborts pending reads on all DemuxerStreams.
338 void AbortPendingReads();
340 // Completes any pending reads if it is possible to do so.
341 void CompletePendingReadsIfPossible();
343 // Seeks all SourceBufferStreams to |seek_time|.
344 void SeekAllSources(base::TimeDelta seek_time
);
346 // Shuts down all DemuxerStreams by calling Shutdown() on
347 // all objects in |source_state_map_|.
348 void ShutdownAllStreams();
350 mutable base::Lock lock_
;
352 bool cancel_next_seek_
;
355 base::Closure open_cb_
;
356 NeedKeyCB need_key_cb_
;
358 // Callback used to report error strings that can help the web developer
359 // figure out what is wrong with the content.
362 PipelineStatusCB init_cb_
;
363 // Callback to execute upon seek completion.
364 // TODO(wolenetz/acolwell): Protect against possible double-locking by first
365 // releasing |lock_| before executing this callback. See
366 // http://crbug.com/308226
367 PipelineStatusCB seek_cb_
;
369 scoped_ptr
<ChunkDemuxerStream
> audio_
;
370 scoped_ptr
<ChunkDemuxerStream
> video_
;
372 base::TimeDelta duration_
;
374 // The duration passed to the last SetDuration(). If
375 // SetDuration() is never called or an AppendData() call or
376 // a EndOfStream() call changes |duration_|, then this
377 // variable is set to < 0 to indicate that the |duration_| represents
378 // the actual duration instead of a user specified value.
379 double user_specified_duration_
;
381 base::Time timeline_offset_
;
384 typedef std::map
<std::string
, SourceState
*> SourceStateMap
;
385 SourceStateMap source_state_map_
;
387 // Used to ensure that (1) config data matches the type and codec provided in
388 // AddId(), (2) only 1 audio and 1 video sources are added, and (3) ids may be
389 // removed with RemoveID() but can not be re-added (yet).
390 std::string source_id_audio_
;
391 std::string source_id_video_
;
393 // Indicates that splice frame generation is enabled.
394 const bool splice_frames_enabled_
;
396 DISALLOW_COPY_AND_ASSIGN(ChunkDemuxer
);
401 #endif // MEDIA_FILTERS_CHUNK_DEMUXER_H_