chunk_demuxer.h revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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
20namespace media {
21
22class ChunkDemuxerStream;
23class FFmpegURLProtocol;
24class SourceState;
25
26// Demuxer implementation that allows chunks of media data to be passed
27// from JavaScript to the media stack.
28class 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  typedef base::Callback<void(const std::string& type,
37                              scoped_ptr<uint8[]> init_data,
38                              int init_data_size)> NeedKeyCB;
39
40  // |open_cb| Run when Initialize() is called to signal that the demuxer
41  //   is ready to receive media data via AppenData().
42  // |need_key_cb| Run when the demuxer determines that an encryption key is
43  //   needed to decrypt the content.
44  // |log_cb| Run when parsing error messages need to be logged to the error
45  //   console.
46  ChunkDemuxer(const base::Closure& open_cb, const NeedKeyCB& need_key_cb,
47               const LogCB& log_cb);
48  virtual ~ChunkDemuxer();
49
50  // Demuxer implementation.
51  virtual void Initialize(DemuxerHost* host,
52                          const PipelineStatusCB& cb) 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  void StartWaitingForSeek();
61  void CancelPendingSeek();
62
63  // Registers a new |id| to use for AppendData() calls. |type| indicates
64  // the MIME type for the data that we intend to append for this ID.
65  // kOk is returned if the demuxer has enough resources to support another ID
66  //    and supports the format indicated by |type|.
67  // kNotSupported is returned if |type| is not a supported format.
68  // kReachedIdLimit is returned if the demuxer cannot handle another ID right
69  //    now.
70  Status AddId(const std::string& id, const std::string& type,
71               std::vector<std::string>& codecs);
72
73  // Removed an ID & associated resources that were previously added with
74  // AddId().
75  void RemoveId(const std::string& id);
76
77  // Gets the currently buffered ranges for the specified ID.
78  Ranges<base::TimeDelta> GetBufferedRanges(const std::string& id) const;
79
80  // Appends media data to the source buffer associated with |id|.
81  void AppendData(const std::string& id, const uint8* data, size_t length);
82
83  // Aborts parsing the current segment and reset the parser to a state where
84  // it can accept a new segment.
85  void Abort(const std::string& id);
86
87  // Returns the current presentation duration.
88  double GetDuration();
89  double GetDuration_Locked();
90
91  // Notifies the demuxer that the duration of the media has changed to
92  // |duration|.
93  void SetDuration(double duration);
94
95  // Sets a time |offset| to be applied to subsequent buffers appended to the
96  // source buffer assicated with |id|. Returns true if the offset is set
97  // properly, false if the offset cannot be applied because we're in the
98  // middle of parsing a media segment.
99  bool SetTimestampOffset(const std::string& id, base::TimeDelta offset);
100
101  // Signals an EndOfStream request.
102  // Returns false if called in an unexpected state or if there is a gap between
103  // the current position and the end of the buffered data.
104  bool EndOfStream(PipelineStatus status);
105  void Shutdown();
106
107 private:
108  enum State {
109    WAITING_FOR_INIT,
110    INITIALIZING,
111    INITIALIZED,
112    ENDED,
113    PARSE_ERROR,
114    SHUTDOWN,
115  };
116
117  void ChangeState_Locked(State new_state);
118
119  // Reports an error and puts the demuxer in a state where it won't accept more
120  // data.
121  void ReportError_Locked(PipelineStatus error);
122
123  // Returns true if any stream has seeked to a time without buffered data.
124  bool IsSeekPending_Locked() const;
125
126  // Returns true if all streams can successfully call EndOfStream,
127  // false if any can not.
128  bool CanEndOfStream_Locked() const;
129
130  // SourceState callbacks.
131  void OnSourceInitDone(bool success, base::TimeDelta duration);
132  bool OnNewConfigs(bool has_audio, bool has_video,
133                    const AudioDecoderConfig& audio_config,
134                    const VideoDecoderConfig& video_config);
135  bool OnAudioBuffers(const StreamParser::BufferQueue& buffers);
136  bool OnVideoBuffers(const StreamParser::BufferQueue& buffers);
137  bool OnNeedKey(const std::string& type,
138                 scoped_ptr<uint8[]> init_data,
139                 int init_data_size);
140  void OnNewMediaSegment(const std::string& source_id,
141                         base::TimeDelta start_timestamp);
142
143  // Computes the intersection between the video & audio
144  // buffered ranges.
145  Ranges<base::TimeDelta> ComputeIntersection() const;
146
147  // Applies |time_offset| to the timestamps of |buffers|.
148  void AdjustBufferTimestamps(const StreamParser::BufferQueue& buffers,
149                              base::TimeDelta timestamp_offset);
150
151  // Returns true if |source_id| is valid, false otherwise.
152  bool IsValidId(const std::string& source_id) const;
153
154  // Increases |duration_| if the newly appended |buffers| exceed the current
155  // |duration_|. The |duration_| is set to the end buffered timestamp of
156  // |stream|.
157  void IncreaseDurationIfNecessary(
158      const StreamParser::BufferQueue& buffers,
159      ChunkDemuxerStream* stream);
160
161  // Decreases |duration_| if the buffered region is less than |duration_| when
162  // EndOfStream() is called.
163  void DecreaseDurationIfNecessary();
164
165  // Sets |duration_| to |new_duration|, sets |user_specified_duration_| to -1
166  // and notifies |host_|.
167  void UpdateDuration(base::TimeDelta new_duration);
168
169  // Returns the ranges representing the buffered data in the demuxer.
170  Ranges<base::TimeDelta> GetBufferedRanges() const;
171
172  mutable base::Lock lock_;
173  State state_;
174
175  DemuxerHost* host_;
176  base::Closure open_cb_;
177  NeedKeyCB need_key_cb_;
178  // Callback used to report error strings that can help the web developer
179  // figure out what is wrong with the content.
180  LogCB log_cb_;
181
182  PipelineStatusCB init_cb_;
183  PipelineStatusCB seek_cb_;
184
185  scoped_ptr<ChunkDemuxerStream> audio_;
186  scoped_ptr<ChunkDemuxerStream> video_;
187
188  // Keeps |audio_| alive when audio has been disabled.
189  scoped_ptr<ChunkDemuxerStream> disabled_audio_;
190
191  base::TimeDelta duration_;
192
193  // The duration passed to the last SetDuration(). If
194  // SetDuration() is never called or an AppendData() call or
195  // a EndOfStream() call changes |duration_|, then this
196  // variable is set to < 0 to indicate that the |duration_| represents
197  // the actual duration instead of a user specified value.
198  double user_specified_duration_;
199
200  typedef std::map<std::string, SourceState*> SourceStateMap;
201  SourceStateMap source_state_map_;
202
203  // Used to ensure that (1) config data matches the type and codec provided in
204  // AddId(), (2) only 1 audio and 1 video sources are added, and (3) ids may be
205  // removed with RemoveID() but can not be re-added (yet).
206  std::string source_id_audio_;
207  std::string source_id_video_;
208
209  DISALLOW_COPY_AND_ASSIGN(ChunkDemuxer);
210};
211
212}  // namespace media
213
214#endif  // MEDIA_FILTERS_CHUNK_DEMUXER_H_
215