blob: fe8e671fddb47a4796c3bad3750427e2ba7a6eba [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <map>
#include <string>
#include <utility>
#include <vector>
#include "base/synchronization/lock.h"
#include "media/base/byte_queue.h"
#include "media/base/demuxer.h"
#include "media/base/ranges.h"
#include "media/base/stream_parser.h"
#include "media/filters/source_buffer_stream.h"
namespace media {
class ChunkDemuxerClient;
class ChunkDemuxerStream;
class FFmpegURLProtocol;
// Demuxer implementation that allows chunks of media data to be passed
// from JavaScript to the media stack.
class MEDIA_EXPORT ChunkDemuxer : public Demuxer {
enum Status {
kOk, // ID added w/o error.
kNotSupported, // Type specified is not supported.
kReachedIdLimit, // Reached ID limit. We can't handle any more IDs.
explicit ChunkDemuxer(ChunkDemuxerClient* client);
// Demuxer implementation.
virtual void Initialize(DemuxerHost* host,
const PipelineStatusCB& cb) OVERRIDE;
virtual void Stop(const base::Closure& callback) OVERRIDE;
virtual void Seek(base::TimeDelta time, const PipelineStatusCB& cb) OVERRIDE;
virtual void OnAudioRendererDisabled() OVERRIDE;
virtual scoped_refptr<DemuxerStream> GetStream(
DemuxerStream::Type type) OVERRIDE;
virtual base::TimeDelta GetStartTime() const OVERRIDE;
virtual int GetBitrate() OVERRIDE;
// Methods used by an external object to control this demuxer.
void StartWaitingForSeek();
// Registers a new |id| to use for AppendData() calls. |type| indicates
// the MIME type for the data that we intend to append for this ID.
// kOk is returned if the demuxer has enough resources to support another ID
// and supports the format indicated by |type|.
// kNotSupported is returned if |type| is not a supported format.
// kReachedIdLimit is returned if the demuxer cannot handle another ID right
// now.
Status AddId(const std::string& id, const std::string& type,
std::vector<std::string>& codecs);
// Removed an ID & associated resources that were previously added with
// AddId().
void RemoveId(const std::string& id);
// Gets the currently buffered ranges for the specified ID.
Ranges<base::TimeDelta> GetBufferedRanges(const std::string& id) const;
// Appends media data to the source buffer associated with |id|. Returns
// false if this method is called in an invalid state.
bool AppendData(const std::string& id, const uint8* data, size_t length);
// Aborts parsing the current segment and reset the parser to a state where
// it can accept a new segment.
void Abort(const std::string& id);
// Sets a time |offset| in seconds to be applied to subsequent buffers
// appended to the source buffer assicated with |id|. Returns true if the
// offset is set properly, false if the offset cannot be applied because we're
// in the middle of parsing a media segment.
bool SetTimestampOffset(const std::string& id, double offset);
// Signals an EndOfStream request.
// Returns false if called in an unexpected state or if there is a gap between
// the current position and the end of the buffered data.
bool EndOfStream(PipelineStatus status);
void Shutdown();
virtual ~ChunkDemuxer();
enum State {
void ChangeState_Locked(State new_state);
// Reports an error and puts the demuxer in a state where it won't accept more
// data.
void ReportError_Locked(PipelineStatus error);
// Returns true if any stream has seeked to a time without buffered data.
bool IsSeekPending_Locked() const;
// Returns true if all streams can successfully call EndOfStream,
// false if any can not.
bool CanEndOfStream_Locked() const;
// StreamParser callbacks.
void OnStreamParserInitDone(bool success, base::TimeDelta duration);
bool OnNewConfigs(bool has_audio, bool has_video,
const AudioDecoderConfig& audio_config,
const VideoDecoderConfig& video_config);
bool OnAudioBuffers(const StreamParser::BufferQueue& buffers);
bool OnVideoBuffers(const StreamParser::BufferQueue& buffers);
bool OnNeedKey(scoped_array<uint8> init_data, int init_data_size);
void OnNewMediaSegment(const std::string& source_id,
base::TimeDelta start_timestamp);
void OnEndOfMediaSegment(const std::string& source_id);
// Computes the intersection between the video & audio
// buffered ranges.
Ranges<base::TimeDelta> ComputeIntersection() const;
// Applies |time_offset| to the timestamps of |buffers|.
void AdjustBufferTimestamps(const StreamParser::BufferQueue& buffers,
base::TimeDelta timestamp_offset);
// Returns true if |source_id| is valid, false otherwise.
bool IsValidId(const std::string& source_id) const;
// Increases |duration_| if the newly appended |buffers| exceed the current
// |duration_|. The |duration_| is set to the end buffered timestamp of
// |stream|.
void IncreaseDurationIfNecessary(
const StreamParser::BufferQueue& buffers,
const scoped_refptr<ChunkDemuxerStream>& stream);
// Decreases |duration_| if the buffered region is less than |duration_| when
// EndOfStream() is called.
void DecreaseDurationIfNecessary();
// Sets |duration_| to |new_duration| and notifies |host_|.
void UpdateDuration(base::TimeDelta new_duration);
// Returns the ranges representing the buffered data in the demuxer.
Ranges<base::TimeDelta> GetBufferedRanges() const;
mutable base::Lock lock_;
State state_;
DemuxerHost* host_;
ChunkDemuxerClient* client_;
PipelineStatusCB init_cb_;
PipelineStatusCB seek_cb_;
scoped_refptr<ChunkDemuxerStream> audio_;
scoped_refptr<ChunkDemuxerStream> video_;
base::TimeDelta duration_;
typedef std::map<std::string, StreamParser*> StreamParserMap;
StreamParserMap stream_parser_map_;
// Contains state belonging to a source id.
struct SourceInfo {
base::TimeDelta timestamp_offset;
bool can_update_offset;
typedef std::map<std::string, SourceInfo> SourceInfoMap;
SourceInfoMap source_info_map_;
// Used to ensure that (1) config data matches the type and codec provided in
// AddId(), (2) only 1 audio and 1 video sources are added, and (3) ids may be
// removed with RemoveID() but can not be re-added (yet).
std::string source_id_audio_;
std::string source_id_video_;
base::TimeDelta start_time_;
} // namespace media