Chromium Code Reviews| Index: media/filters/chunk_demuxer.cc |
| diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc |
| index 2e22cd834f5b69ad66f0a2a95b00207e94d5fcbd..e0fbfb2e1812083971caea9f905a0bd2c8dcc120 100644 |
| --- a/media/filters/chunk_demuxer.cc |
| +++ b/media/filters/chunk_demuxer.cc |
| @@ -5,7 +5,6 @@ |
| #include "media/filters/chunk_demuxer.h" |
| #include <algorithm> |
| -#include <deque> |
| #include <limits> |
| #include <list> |
| @@ -18,6 +17,7 @@ |
| #include "media/base/bind_to_current_loop.h" |
| #include "media/base/stream_parser_buffer.h" |
| #include "media/base/video_decoder_config.h" |
| +#include "media/filters/legacy_frame_processor.h" |
| #include "media/filters/stream_parser_factory.h" |
| using base::TimeDelta; |
| @@ -86,17 +86,13 @@ class SourceState { |
| typedef base::Callback<ChunkDemuxerStream*( |
| DemuxerStream::Type)> CreateDemuxerStreamCB; |
| - // Callback signature used to notify ChunkDemuxer of timestamps |
| - // that may cause the duration to be updated. |
| - typedef base::Callback<void( |
| - TimeDelta, ChunkDemuxerStream*)> IncreaseDurationCB; |
| - |
| typedef base::Callback<void( |
| ChunkDemuxerStream*, const TextTrackConfig&)> NewTextTrackCB; |
| - SourceState(scoped_ptr<StreamParser> stream_parser, const LogCB& log_cb, |
| - const CreateDemuxerStreamCB& create_demuxer_stream_cb, |
| - const IncreaseDurationCB& increase_duration_cb); |
| + SourceState( |
| + scoped_ptr<StreamParser> stream_parser, |
| + scoped_ptr<FrameProcessorBase> frame_processor, const LogCB& log_cb, |
| + const CreateDemuxerStreamCB& create_demuxer_stream_cb); |
| ~SourceState(); |
| @@ -108,11 +104,14 @@ class SourceState { |
| // Appends new data to the StreamParser. |
| // Returns true if the data was successfully appended. Returns false if an |
| - // error occurred. Appending uses cached |timestamp_offset_| and may update |
| - // |*timestamp_offset| if |timestamp_offset| is not NULL. |
| - // TODO(wolenetz): Rework so |timestamp_offset_| is only valid during |
| - // Append(). See http://crbug.com/347623. |
| - bool Append(const uint8* data, size_t length, double* timestamp_offset); |
| + // error occurred. |*timestamp_offset| is used and possibly updated by the |
| + // append. |append_window_start| and |append_window_end| correspond to the MSE |
| + // spec's similarly named source buffer attributes that are used in coded |
| + // frame processing. |
| + bool Append(const uint8* data, size_t length, |
| + const base::TimeDelta& append_window_start, |
|
acolwell GONE FROM CHROMIUM
2014/03/11 20:00:37
ditto
wolenetz
2014/03/12 00:46:14
Done in the prereq CL I split out of this.
|
| + const base::TimeDelta& append_window_end, |
| + base::TimeDelta* timestamp_offset); |
| // Aborts the current append sequence and resets the parser. |
| void Abort(); |
| @@ -121,20 +120,11 @@ class SourceState { |
| // ChunkDemuxerStreams managed by this object. |
| void Remove(TimeDelta start, TimeDelta end, TimeDelta duration); |
| - // Sets user-specified |timestamp_offset_| if possible. |
| - // Returns true if the offset was set. Returns false if the offset could not |
| - // be set at this time. |
| - bool SetTimestampOffset(TimeDelta timestamp_offset); |
| + // Returns true if currently parsing a media segment, or false otherwise. |
| + bool IsParsingMediaSegment() const { return parsing_media_segment_; } |
|
acolwell GONE FROM CHROMIUM
2014/03/11 20:00:37
nit: unix_hacker_style since this is a simple acce
wolenetz
2014/03/12 00:46:14
Done in the prereq CL I split out of this.
|
| - // Sets |sequence_mode_| to |sequence_mode| if possible. |
| - // Returns true if the mode update was allowed. Returns false if the mode |
| - // could not be updated at this time. |
| - bool SetSequenceMode(bool sequence_mode); |
| - |
| - void set_append_window_start(TimeDelta start) { |
| - append_window_start_ = start; |
| - } |
| - void set_append_window_end(TimeDelta end) { append_window_end_ = end; } |
| + // Sets |frame_processor_|'s sequence mode to |sequence_mode|. |
| + void SetSequenceMode(bool sequence_mode); |
| // Returns the range of buffered data in this source, capped at |duration|. |
| // |ended| - Set to true if end of stream has been signalled and the special |
| @@ -177,67 +167,30 @@ class SourceState { |
| // Called by the |stream_parser_| at the end of a media segment. |
| void OnEndOfMediaSegment(); |
| - // Called by the |stream_parser_| when new buffers have been parsed. It |
| - // applies |timestamp_offset_| to all buffers in |audio_buffers|, |
| - // |video_buffers| and |text_map| and then calls Append() with the modified |
| - // buffers on |audio_|, |video_| and/or the text demuxer streams associated |
| - // with the track numbers in |text_map|. |
| + // Called by the |stream_parser_| when new buffers have been parsed. |
| + // It processes the new buffers using |frame_processor_|, which includes |
| + // appending the processed frames to associated demuxer streams for each |
| + // frame's track. |
| // Returns true on a successful call. Returns false if an error occurred while |
| // processing the buffers. |
| bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers, |
| const StreamParser::BufferQueue& video_buffers, |
| const StreamParser::TextBufferQueueMap& text_map); |
| - // Helper function for OnNewBuffers() when new text buffers have been parsed. |
| - // It applies |timestamp_offset_| to all buffers in |buffers| and then appends |
| - // the (modified) buffers to the demuxer stream associated with |
| - // the track having |text_track_id|. |
| - // Returns true on a successful call. Returns false if an error occurred while |
| - // processing the buffers. |
| - bool OnTextBuffers(StreamParser::TrackId text_track_id, |
| - const StreamParser::BufferQueue& buffers); |
| - |
| - // Helper function that appends |buffers| to |stream| and calls |
| - // |increase_duration_cb_| to potentially update the duration. |
| - // Returns true if the append was successful. Returns false if |
| - // |stream| is NULL or something in |buffers| caused the append to fail. |
| - bool AppendAndUpdateDuration(ChunkDemuxerStream* stream, |
| - const StreamParser::BufferQueue& buffers); |
| - |
| - // Helper function that adds |timestamp_offset_| to each buffer in |buffers|. |
| - void AdjustBufferTimestamps(const StreamParser::BufferQueue& buffers); |
| - |
| - // Filters out buffers that are outside of the append window |
| - // [|append_window_start_|, |append_window_end_|). |
| - // |needs_keyframe| is a pointer to the |xxx_need_keyframe_| flag |
| - // associated with the |buffers|. Its state is read an updated as |
| - // this method filters |buffers|. |
| - // Buffers that are inside the append window are appended to the end |
| - // of |filtered_buffers|. |
| - void FilterWithAppendWindow(const StreamParser::BufferQueue& buffers, |
| - bool* needs_keyframe, |
| - StreamParser::BufferQueue* filtered_buffers); |
| - |
| CreateDemuxerStreamCB create_demuxer_stream_cb_; |
| - IncreaseDurationCB increase_duration_cb_; |
| NewTextTrackCB new_text_track_cb_; |
| - // The offset to apply to media segment timestamps. |
| - TimeDelta timestamp_offset_; |
| - |
| - // Flag that tracks whether or not the current Append() operation changed |
| - // |timestamp_offset_|. |
| - bool timestamp_offset_updated_by_append_; |
| - |
| - // Tracks the mode by which appended media is processed. If true, then |
| - // appended media is processed using "sequence" mode. Otherwise, appended |
| - // media is processed using "segments" mode. |
| - // TODO(wolenetz): Enable "sequence" mode logic. See http://crbug.com/249422 |
| - // and http://crbug.com/333437. |
| - bool sequence_mode_; |
| + // During Append(), if OnNewBuffers() coded frame processing updates the |
| + // timestamp offset then |*timestamp_offset_during_append_| is also updated |
| + // so Append()'s caller can know the new offset. This pointer is only non-NULL |
| + // during the lifetime of an Append() call. |
| + base::TimeDelta* timestamp_offset_during_append_; |
| - TimeDelta append_window_start_; |
| - TimeDelta append_window_end_; |
| + // During Append(), coded frame processing triggered by OnNewBuffers() |
| + // requires these two attributes. These are only valid during the lifetime of |
| + // an Append() call. |
| + base::TimeDelta append_window_start_during_append_; |
| + base::TimeDelta append_window_end_during_append_; |
| // Set to true if the next buffers appended within the append window |
| // represent the start of a new media segment. This flag being set |
| @@ -247,142 +200,40 @@ class SourceState { |
| // appended data. |
| bool new_media_segment_; |
| - // Keeps track of whether |timestamp_offset_| or |sequence_mode_| can be |
| - // updated. These cannot be updated if a media segment is being parsed. |
| + // Keeps track of whether a media segment is being parsed. |
| bool parsing_media_segment_; |
| // The object used to parse appended data. |
| scoped_ptr<StreamParser> stream_parser_; |
| - ChunkDemuxerStream* audio_; |
| - bool audio_needs_keyframe_; |
| - |
| - ChunkDemuxerStream* video_; |
| - bool video_needs_keyframe_; |
| + ChunkDemuxerStream* audio_; // Not owned by |this|. |
| + ChunkDemuxerStream* video_; // Not owned by |this|. |
| typedef std::map<StreamParser::TrackId, ChunkDemuxerStream*> TextStreamMap; |
| - TextStreamMap text_stream_map_; |
| + TextStreamMap text_stream_map_; // |this| owns the map's stream pointers. |
| + scoped_ptr<FrameProcessorBase> frame_processor_; |
| LogCB log_cb_; |
| DISALLOW_COPY_AND_ASSIGN(SourceState); |
| }; |
| -class ChunkDemuxerStream : public DemuxerStream { |
| - public: |
| - typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; |
| - |
| - explicit ChunkDemuxerStream(Type type); |
| - virtual ~ChunkDemuxerStream(); |
| - |
| - // ChunkDemuxerStream control methods. |
| - void StartReturningData(); |
| - void AbortReads(); |
| - void CompletePendingReadIfPossible(); |
| - void Shutdown(); |
| - |
| - // SourceBufferStream manipulation methods. |
| - void Seek(TimeDelta time); |
| - bool IsSeekWaitingForData() const; |
| - |
| - // Add buffers to this stream. Buffers are stored in SourceBufferStreams, |
| - // which handle ordering and overlap resolution. |
| - // Returns true if buffers were successfully added. |
| - bool Append(const StreamParser::BufferQueue& buffers); |
| - |
| - // Removes buffers between |start| and |end| according to the steps |
| - // in the "Coded Frame Removal Algorithm" in the Media Source |
| - // Extensions Spec. |
| - // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#sourcebuffer-coded-frame-removal |
| - // |
| - // |duration| is the current duration of the presentation. It is |
| - // required by the computation outlined in the spec. |
| - void Remove(TimeDelta start, TimeDelta end, TimeDelta duration); |
| - |
| - // Signal to the stream that duration has changed to |duration|. |
| - void OnSetDuration(TimeDelta duration); |
| - |
| - // Returns the range of buffered data in this stream, capped at |duration|. |
| - Ranges<TimeDelta> GetBufferedRanges(TimeDelta duration) const; |
| - |
| - // Returns the duration of the buffered data. |
| - // Returns TimeDelta() if the stream has no buffered data. |
| - TimeDelta GetBufferedDuration() const; |
| - |
| - // Signal to the stream that buffers handed in through subsequent calls to |
| - // Append() belong to a media segment that starts at |start_timestamp|. |
| - void OnNewMediaSegment(TimeDelta start_timestamp); |
| - |
| - // Called when midstream config updates occur. |
| - // Returns true if the new config is accepted. |
| - // Returns false if the new config should trigger an error. |
| - bool UpdateAudioConfig(const AudioDecoderConfig& config, const LogCB& log_cb); |
| - bool UpdateVideoConfig(const VideoDecoderConfig& config, const LogCB& log_cb); |
| - void UpdateTextConfig(const TextTrackConfig& config, const LogCB& log_cb); |
| - |
| - void MarkEndOfStream(); |
| - void UnmarkEndOfStream(); |
| - |
| - // DemuxerStream methods. |
| - virtual void Read(const ReadCB& read_cb) OVERRIDE; |
| - virtual Type type() OVERRIDE; |
| - virtual void EnableBitstreamConverter() OVERRIDE; |
| - virtual AudioDecoderConfig audio_decoder_config() OVERRIDE; |
| - virtual VideoDecoderConfig video_decoder_config() OVERRIDE; |
| - |
| - // Returns the text track configuration. It is an error to call this method |
| - // if type() != TEXT. |
| - TextTrackConfig text_track_config(); |
| - |
| - // Sets the memory limit, in bytes, on the SourceBufferStream. |
| - void set_memory_limit_for_testing(int memory_limit) { |
| - stream_->set_memory_limit_for_testing(memory_limit); |
| - } |
| - |
| - private: |
| - enum State { |
| - UNINITIALIZED, |
| - RETURNING_DATA_FOR_READS, |
| - RETURNING_ABORT_FOR_READS, |
| - SHUTDOWN, |
| - }; |
| - |
| - // Assigns |state_| to |state| |
| - void ChangeState_Locked(State state); |
| - |
| - void CompletePendingReadIfPossible_Locked(); |
| - |
| - // Specifies the type of the stream. |
| - Type type_; |
| - |
| - scoped_ptr<SourceBufferStream> stream_; |
| - |
| - mutable base::Lock lock_; |
| - State state_; |
| - ReadCB read_cb_; |
| - |
| - DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); |
| -}; |
| - |
| -SourceState::SourceState(scoped_ptr<StreamParser> stream_parser, |
| - const LogCB& log_cb, |
| - const CreateDemuxerStreamCB& create_demuxer_stream_cb, |
| - const IncreaseDurationCB& increase_duration_cb) |
| +SourceState::SourceState( |
| + scoped_ptr<StreamParser> stream_parser, |
| + scoped_ptr<FrameProcessorBase> frame_processor, |
| + const LogCB& log_cb, |
| + const CreateDemuxerStreamCB& create_demuxer_stream_cb) |
| : create_demuxer_stream_cb_(create_demuxer_stream_cb), |
| - increase_duration_cb_(increase_duration_cb), |
| - timestamp_offset_updated_by_append_(false), |
| - sequence_mode_(false), |
| - append_window_end_(kInfiniteDuration()), |
| + timestamp_offset_during_append_(NULL), |
| new_media_segment_(false), |
| parsing_media_segment_(false), |
| stream_parser_(stream_parser.release()), |
| audio_(NULL), |
| - audio_needs_keyframe_(true), |
| video_(NULL), |
| - video_needs_keyframe_(true), |
| + frame_processor_(frame_processor.release()), |
| log_cb_(log_cb) { |
| DCHECK(!create_demuxer_stream_cb_.is_null()); |
| - DCHECK(!increase_duration_cb_.is_null()); |
| + DCHECK(frame_processor_); |
| } |
| SourceState::~SourceState() { |
| @@ -414,37 +265,29 @@ void SourceState::Init(const StreamParser::InitCB& init_cb, |
| log_cb_); |
| } |
| -bool SourceState::SetTimestampOffset(TimeDelta timestamp_offset) { |
| - if (parsing_media_segment_) |
| - return false; |
| - |
| - timestamp_offset_ = timestamp_offset; |
| - return true; |
| -} |
| - |
| -bool SourceState::SetSequenceMode(bool sequence_mode) { |
| - if (parsing_media_segment_) |
| - return false; |
| +void SourceState::SetSequenceMode(bool sequence_mode) { |
| + DCHECK(!parsing_media_segment_); |
| - sequence_mode_ = sequence_mode; |
| - return true; |
| + frame_processor_->SetSequenceMode(sequence_mode); |
| } |
| bool SourceState::Append(const uint8* data, size_t length, |
| - double* timestamp_offset) { |
| - timestamp_offset_updated_by_append_ = false; |
| + const base::TimeDelta& append_window_start, |
| + const base::TimeDelta& append_window_end, |
| + base::TimeDelta* timestamp_offset) { |
| + DCHECK(timestamp_offset); |
| + DCHECK(!timestamp_offset_during_append_); |
| + timestamp_offset_during_append_ = timestamp_offset; |
| + append_window_start_during_append_ = append_window_start; |
| + append_window_end_during_append_ = append_window_end; |
| bool err = stream_parser_->Parse(data, length); |
|
acolwell GONE FROM CHROMIUM
2014/03/11 20:00:37
nit: Add a TODO here to change the StreamParser::P
wolenetz
2014/03/12 00:46:14
Done in prereq CL I split out of this. I assigned
|
| - |
| - if (timestamp_offset_updated_by_append_ && timestamp_offset) |
| - *timestamp_offset = timestamp_offset_.InSecondsF(); |
| - |
| + timestamp_offset_during_append_ = NULL; |
| return err; |
| } |
| void SourceState::Abort() { |
| stream_parser_->Flush(); |
| - audio_needs_keyframe_ = true; |
| - video_needs_keyframe_ = true; |
| + frame_processor_->Reset(); |
| parsing_media_segment_ = false; |
| } |
| @@ -631,19 +474,6 @@ bool SourceState::IsSeekWaitingForData() const { |
| return false; |
| } |
| -void SourceState::AdjustBufferTimestamps( |
| - const StreamParser::BufferQueue& buffers) { |
| - if (timestamp_offset_ == TimeDelta()) |
| - return; |
| - |
| - for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); |
| - itr != buffers.end(); ++itr) { |
| - (*itr)->SetDecodeTimestamp( |
| - (*itr)->GetDecodeTimestamp() + timestamp_offset_); |
| - (*itr)->set_timestamp((*itr)->timestamp() + timestamp_offset_); |
| - } |
| -} |
| - |
| bool SourceState::OnNewConfigs( |
| bool allow_audio, bool allow_video, |
| const AudioDecoderConfig& audio_config, |
| @@ -689,6 +519,12 @@ bool SourceState::OnNewConfigs( |
| DVLOG(1) << "Failed to create an audio stream."; |
| return false; |
| } |
| + |
| + if (!frame_processor_->AddTrack(FrameProcessorBase::kAudioTrackId, |
| + audio_)) { |
| + DVLOG(1) << "Failed to add audio track to frame processor."; |
| + return false; |
| + } |
| } |
| success &= audio_->UpdateAudioConfig(audio_config, log_cb_); |
| @@ -702,6 +538,12 @@ bool SourceState::OnNewConfigs( |
| DVLOG(1) << "Failed to create a video stream."; |
| return false; |
| } |
| + |
| + if (!frame_processor_->AddTrack(FrameProcessorBase::kVideoTrackId, |
| + video_)) { |
| + DVLOG(1) << "Failed to add video track to frame processor."; |
| + return false; |
| + } |
| } |
| success &= video_->UpdateVideoConfig(video_config, log_cb_); |
| @@ -713,6 +555,12 @@ bool SourceState::OnNewConfigs( |
| itr != text_configs.end(); ++itr) { |
| ChunkDemuxerStream* const text_stream = |
| create_demuxer_stream_cb_.Run(DemuxerStream::TEXT); |
| + if (!frame_processor_->AddTrack(itr->first, text_stream)) { |
| + success &= false; |
| + MEDIA_LOG(log_cb_) << "Failed to add text track ID " << itr->first |
| + << " to frame processor."; |
| + break; |
| + } |
| text_stream->UpdateTextConfig(itr->second, log_cb_); |
| text_stream_map_[itr->first] = text_stream; |
| new_text_track_cb_.Run(text_stream, itr->second); |
| @@ -782,167 +630,13 @@ bool SourceState::OnNewBuffers( |
| const StreamParser::BufferQueue& audio_buffers, |
| const StreamParser::BufferQueue& video_buffers, |
| const StreamParser::TextBufferQueueMap& text_map) { |
| - DCHECK(!audio_buffers.empty() || !video_buffers.empty() || |
| - !text_map.empty()); |
| - |
| - // TODO(wolenetz): DCHECK + return false if any of these buffers have UNKNOWN |
| - // type() in upcoming coded frame processing compliant implementation. See |
| - // http://crbug.com/249422. |
| - |
| - AdjustBufferTimestamps(audio_buffers); |
| - AdjustBufferTimestamps(video_buffers); |
| - |
| - StreamParser::BufferQueue filtered_audio; |
| - StreamParser::BufferQueue filtered_video; |
| - |
| - FilterWithAppendWindow(audio_buffers, &audio_needs_keyframe_, |
| - &filtered_audio); |
| - |
| - FilterWithAppendWindow(video_buffers, &video_needs_keyframe_, |
| - &filtered_video); |
| - |
| - if ((!filtered_audio.empty() || !filtered_video.empty()) && |
| - new_media_segment_) { |
| - // Find the earliest timestamp in the filtered buffers and use that for the |
| - // segment start timestamp. |
| - TimeDelta segment_timestamp = kNoTimestamp(); |
| - |
| - if (!filtered_audio.empty()) |
| - segment_timestamp = filtered_audio.front()->GetDecodeTimestamp(); |
| - |
| - if (!filtered_video.empty() && |
| - (segment_timestamp == kNoTimestamp() || |
| - filtered_video.front()->GetDecodeTimestamp() < segment_timestamp)) { |
| - segment_timestamp = filtered_video.front()->GetDecodeTimestamp(); |
| - } |
| - |
| - new_media_segment_ = false; |
| - |
| - if (audio_) |
| - audio_->OnNewMediaSegment(segment_timestamp); |
| - |
| - if (video_) |
| - video_->OnNewMediaSegment(segment_timestamp); |
| - |
| - for (TextStreamMap::iterator itr = text_stream_map_.begin(); |
| - itr != text_stream_map_.end(); ++itr) { |
| - itr->second->OnNewMediaSegment(segment_timestamp); |
| - } |
| - } |
| - |
| - if (!filtered_audio.empty() && |
| - !AppendAndUpdateDuration(audio_, filtered_audio)) { |
| - return false; |
| - } |
| - |
| - if (!filtered_video.empty() && |
| - !AppendAndUpdateDuration(video_, filtered_video)) { |
| - return false; |
| - } |
| - |
| - if (text_map.empty()) |
| - return true; |
| - |
| - // Process any buffers for each of the text tracks in the map. |
| - bool all_text_buffers_empty = true; |
| - for (StreamParser::TextBufferQueueMap::const_iterator itr = text_map.begin(); |
| - itr != text_map.end(); |
| - ++itr) { |
| - const StreamParser::BufferQueue text_buffers = itr->second; |
| - if (!text_buffers.empty()) { |
| - all_text_buffers_empty = false; |
| - if (!OnTextBuffers(itr->first, text_buffers)) |
| - return false; |
| - } |
| - } |
| - |
| - DCHECK(!all_text_buffers_empty); |
| - return true; |
| -} |
| + DVLOG(2) << "OnNewBuffers()"; |
| + DCHECK(timestamp_offset_during_append_); |
| -bool SourceState::OnTextBuffers( |
| - StreamParser::TrackId text_track_id, |
| - const StreamParser::BufferQueue& buffers) { |
| - DCHECK(!buffers.empty()); |
| - |
| - TextStreamMap::iterator itr = text_stream_map_.find(text_track_id); |
| - if (itr == text_stream_map_.end()) |
| - return false; |
| - |
| - AdjustBufferTimestamps(buffers); |
| - |
| - StreamParser::BufferQueue filtered_buffers; |
| - bool needs_keyframe = false; |
| - FilterWithAppendWindow(buffers, &needs_keyframe, &filtered_buffers); |
| - |
| - if (filtered_buffers.empty()) |
| - return true; |
| - |
| - return AppendAndUpdateDuration(itr->second, filtered_buffers); |
| -} |
| - |
| -bool SourceState::AppendAndUpdateDuration( |
| - ChunkDemuxerStream* stream, |
| - const StreamParser::BufferQueue& buffers) { |
| - DCHECK(!buffers.empty()); |
| - |
| - if (!stream || !stream->Append(buffers)) |
| - return false; |
| - |
| - increase_duration_cb_.Run(buffers.back()->timestamp(), stream); |
| - return true; |
| -} |
| - |
| -void SourceState::FilterWithAppendWindow( |
| - const StreamParser::BufferQueue& buffers, bool* needs_keyframe, |
| - StreamParser::BufferQueue* filtered_buffers) { |
| - DCHECK(needs_keyframe); |
| - DCHECK(filtered_buffers); |
| - |
| - // This loop implements steps 1.9, 1.10, & 1.11 of the "Coded frame |
| - // processing loop" in the Media Source Extensions spec. |
| - // These steps filter out buffers that are not within the "append |
| - // window" and handles resyncing on the next random access point |
| - // (i.e., next keyframe) if a buffer gets dropped. |
| - for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); |
| - itr != buffers.end(); ++itr) { |
| - // Filter out buffers that are outside the append window. Anytime |
| - // a buffer gets dropped we need to set |*needs_keyframe| to true |
| - // because we can only resume decoding at keyframes. |
| - TimeDelta presentation_timestamp = (*itr)->timestamp(); |
| - |
| - // TODO(acolwell): Change |frame_end_timestamp| value to |
| - // |presentation_timestamp + (*itr)->duration()|, like the spec |
| - // requires, once frame durations are actually present in all buffers. |
| - TimeDelta frame_end_timestamp = presentation_timestamp; |
| - if (presentation_timestamp < append_window_start_ || |
| - frame_end_timestamp > append_window_end_) { |
| - DVLOG(1) << "Dropping buffer outside append window." |
| - << " presentation_timestamp " |
| - << presentation_timestamp.InSecondsF(); |
| - *needs_keyframe = true; |
| - |
| - // This triggers a discontinuity so we need to treat the next frames |
| - // appended within the append window as if they were the beginning of a |
| - // new segment. |
| - new_media_segment_ = true; |
| - continue; |
| - } |
| - |
| - // If |*needs_keyframe| is true then filter out buffers until we |
| - // encounter the next keyframe. |
| - if (*needs_keyframe) { |
| - if (!(*itr)->IsKeyframe()) { |
| - DVLOG(1) << "Dropping non-keyframe. presentation_timestamp " |
| - << presentation_timestamp.InSecondsF(); |
| - continue; |
| - } |
| - |
| - *needs_keyframe = false; |
| - } |
| - |
| - filtered_buffers->push_back(*itr); |
| - } |
| + return frame_processor_->ProcessFrames( |
| + audio_buffers, video_buffers, text_map, |
| + append_window_start_during_append_, append_window_end_during_append_, |
| + &new_media_segment_, timestamp_offset_during_append_); |
| } |
| ChunkDemuxerStream::ChunkDemuxerStream(Type type) |
| @@ -1370,11 +1064,14 @@ ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id, |
| if (has_video) |
| source_id_video_ = id; |
| + scoped_ptr<FrameProcessorBase> frame_processor(new LegacyFrameProcessor( |
| + base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary, |
| + base::Unretained(this)))); |
| + |
| scoped_ptr<SourceState> source_state( |
| - new SourceState(stream_parser.Pass(), log_cb_, |
| + new SourceState(stream_parser.Pass(), |
| + frame_processor.Pass(), log_cb_, |
| base::Bind(&ChunkDemuxer::CreateDemuxerStream, |
| - base::Unretained(this)), |
| - base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary, |
| base::Unretained(this)))); |
| SourceState::NewTextTrackCB new_text_track_cb; |
| @@ -1421,10 +1118,13 @@ Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { |
| void ChunkDemuxer::AppendData(const std::string& id, |
| const uint8* data, size_t length, |
| - double* timestamp_offset) { |
| + const base::TimeDelta& append_window_start, |
| + const base::TimeDelta& append_window_end, |
| + base::TimeDelta* timestamp_offset) { |
| DVLOG(1) << "AppendData(" << id << ", " << length << ")"; |
| DCHECK(!id.empty()); |
| + DCHECK(timestamp_offset); |
| Ranges<TimeDelta> ranges; |
| @@ -1445,6 +1145,8 @@ void ChunkDemuxer::AppendData(const std::string& id, |
| case INITIALIZING: |
| DCHECK(IsValidId(id)); |
| if (!source_state_map_[id]->Append(data, length, |
| + append_window_start, |
| + append_window_end, |
| timestamp_offset)) { |
| ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); |
| return; |
| @@ -1454,6 +1156,8 @@ void ChunkDemuxer::AppendData(const std::string& id, |
| case INITIALIZED: { |
| DCHECK(IsValidId(id)); |
| if (!source_state_map_[id]->Append(data, length, |
| + append_window_start, |
| + append_window_end, |
| timestamp_offset)) { |
| ReportError_Locked(PIPELINE_ERROR_DECODE); |
| return; |
| @@ -1566,22 +1270,22 @@ void ChunkDemuxer::SetDuration(double duration) { |
| } |
| } |
| -bool ChunkDemuxer::SetTimestampOffset(const std::string& id, TimeDelta offset) { |
| +bool ChunkDemuxer::IsParsingMediaSegment(const std::string& id) { |
| base::AutoLock auto_lock(lock_); |
| - DVLOG(1) << "SetTimestampOffset(" << id << ", " << offset.InSecondsF() << ")"; |
| + DVLOG(1) << "IsParsingMediaSegment(" << id << ")"; |
| CHECK(IsValidId(id)); |
| - return source_state_map_[id]->SetTimestampOffset(offset); |
| + return source_state_map_[id]->IsParsingMediaSegment(); |
| } |
| -bool ChunkDemuxer::SetSequenceMode(const std::string& id, |
| +void ChunkDemuxer::SetSequenceMode(const std::string& id, |
| bool sequence_mode) { |
| base::AutoLock auto_lock(lock_); |
| DVLOG(1) << "SetSequenceMode(" << id << ", " << sequence_mode << ")"; |
| CHECK(IsValidId(id)); |
| DCHECK_NE(state_, ENDED); |
| - return source_state_map_[id]->SetSequenceMode(sequence_mode); |
| + source_state_map_[id]->SetSequenceMode(sequence_mode); |
| } |
| void ChunkDemuxer::MarkEndOfStream(PipelineStatus status) { |
| @@ -1634,22 +1338,6 @@ void ChunkDemuxer::UnmarkEndOfStream() { |
| } |
| } |
| -void ChunkDemuxer::SetAppendWindowStart(const std::string& id, |
| - TimeDelta start) { |
| - base::AutoLock auto_lock(lock_); |
| - DVLOG(1) << "SetAppendWindowStart(" << id << ", " |
| - << start.InSecondsF() << ")"; |
| - CHECK(IsValidId(id)); |
| - source_state_map_[id]->set_append_window_start(start); |
| -} |
| - |
| -void ChunkDemuxer::SetAppendWindowEnd(const std::string& id, TimeDelta end) { |
| - base::AutoLock auto_lock(lock_); |
| - DVLOG(1) << "SetAppendWindowEnd(" << id << ", " << end.InSecondsF() << ")"; |
| - CHECK(IsValidId(id)); |
| - source_state_map_[id]->set_append_window_end(end); |
| -} |
| - |
| void ChunkDemuxer::Shutdown() { |
| DVLOG(1) << "Shutdown()"; |
| base::AutoLock auto_lock(lock_); |