Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(261)

Unified Diff: media/filters/chunk_demuxer.cc

Issue 191513002: Extract coded frame processing from SourceState into LegacyFrameProcessor (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address PS4 nits Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/filters/chunk_demuxer.h ('k') | media/filters/frame_processor_base.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/filters/chunk_demuxer.cc
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc
index 6505b2c131141c6aa32d2c229bb9061121a2d0e3..17f1d96c9046de426f653cddef6ff0565b403901 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();
@@ -127,7 +123,7 @@ class SourceState {
// Returns true if currently parsing a media segment, or false otherwise.
bool parsing_media_segment() const { return parsing_media_segment_; }
- // Sets |sequence_mode_| to |sequence_mode|.
+ // 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|.
@@ -171,52 +167,17 @@ 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_during_append_| to all buffers in
- // |audio_buffers|, |video_buffers| and |text_map|, filters buffers against
- // |append_window_[start,end]_during_append_| and then calls Append()
- // with the surviving 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_during_append_| to all buffers in |buffers|,
- // filters the buffers against |append_window_[start,end]_during_append_| 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_during_append_| to each buffer
- // in |buffers|.
- void AdjustBufferTimestamps(const StreamParser::BufferQueue& buffers);
-
- // Filters out buffers that are outside of the append window
- // [|append_window_start_during_append_|, |append_window_end_during_append_|).
- // |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_;
// During Append(), if OnNewBuffers() coded frame processing updates the
@@ -231,13 +192,6 @@ class SourceState {
TimeDelta append_window_start_during_append_;
TimeDelta append_window_end_during_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_;
-
// Set to true if the next buffers appended within the append window
// represent the start of a new media segment. This flag being set
// triggers a call to |new_segment_cb_| when the new buffers are
@@ -255,133 +209,33 @@ class SourceState {
scoped_ptr<StreamParser> stream_parser_;
ChunkDemuxerStream* audio_; // Not owned by |this|.
- bool audio_needs_keyframe_;
-
ChunkDemuxerStream* video_; // Not owned by |this|.
- bool video_needs_keyframe_;
typedef std::map<StreamParser::TrackId, ChunkDemuxerStream*> TextStreamMap;
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_during_append_(NULL),
- sequence_mode_(false),
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() {
@@ -416,7 +270,7 @@ void SourceState::Init(const StreamParser::InitCB& init_cb,
void SourceState::SetSequenceMode(bool sequence_mode) {
DCHECK(!parsing_media_segment_);
- sequence_mode_ = sequence_mode;
+ frame_processor_->SetSequenceMode(sequence_mode);
}
bool SourceState::Append(const uint8* data, size_t length,
@@ -438,8 +292,7 @@ bool SourceState::Append(const uint8* data, size_t length,
void SourceState::Abort() {
stream_parser_->Flush();
- audio_needs_keyframe_ = true;
- video_needs_keyframe_ = true;
+ frame_processor_->Reset();
parsing_media_segment_ = false;
}
@@ -626,20 +479,6 @@ bool SourceState::IsSeekWaitingForData() const {
return false;
}
-void SourceState::AdjustBufferTimestamps(
- const StreamParser::BufferQueue& buffers) {
- TimeDelta timestamp_offset = *timestamp_offset_during_append_;
- 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,
@@ -685,6 +524,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_);
@@ -698,6 +543,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_);
@@ -709,6 +560,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);
@@ -780,167 +637,11 @@ bool SourceState::OnNewBuffers(
const StreamParser::TextBufferQueueMap& text_map) {
DVLOG(2) << "OnNewBuffers()";
DCHECK(timestamp_offset_during_append_);
- 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;
-}
-
-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_during_append_ ||
- frame_end_timestamp > append_window_end_during_append_) {
- 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)
@@ -1368,11 +1069,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;
« no previous file with comments | « media/filters/chunk_demuxer.h ('k') | media/filters/frame_processor_base.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698