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_); |