1 // Copyright 2014 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_FRAME_PROCESSOR_H_ 6 #define MEDIA_FILTERS_FRAME_PROCESSOR_H_ 7 8 #include <map> 9 10 #include "base/basictypes.h" 11 #include "base/callback_forward.h" 12 #include "base/time/time.h" 13 #include "media/base/media_export.h" 14 #include "media/base/stream_parser.h" 15 #include "media/filters/chunk_demuxer.h" 16 17 namespace media { 18 19 class MseTrackBuffer; 20 21 // Helper class that implements Media Source Extension's coded frame processing 22 // algorithm. 23 class MEDIA_EXPORT FrameProcessor { 24 public: 25 typedef base::Callback<void(base::TimeDelta)> UpdateDurationCB; 26 27 // TODO(wolenetz/acolwell): Ensure that all TrackIds are coherent and unique 28 // for each track buffer. For now, special track identifiers are used for each 29 // of audio and video here, and text TrackIds are assumed to be non-negative. 30 // See http://crbug.com/341581. 31 enum { 32 kAudioTrackId = -2, 33 kVideoTrackId = -3 34 }; 35 36 explicit FrameProcessor(const UpdateDurationCB& update_duration_cb); 37 ~FrameProcessor(); 38 39 // Get/set the current append mode, which if true means "sequence" and if 40 // false means "segments". 41 // See http://www.w3.org/TR/media-source/#widl-SourceBuffer-mode. 42 bool sequence_mode() { return sequence_mode_; } 43 void SetSequenceMode(bool sequence_mode); 44 45 // Processes buffers in |audio_buffers|, |video_buffers|, and |text_map|. 46 // Returns true on success or false on failure which indicates decode error. 47 // |append_window_start| and |append_window_end| correspond to the MSE spec's 48 // similarly named source buffer attributes that are used in coded frame 49 // processing. 50 // |*new_media_segment| tracks whether the next buffers processed within the 51 // append window represent the start of a new media segment. This method may 52 // both use and update this flag. 53 // Uses |*timestamp_offset| according to the coded frame processing algorithm, 54 // including updating it as required in 'sequence' mode frame processing. 55 bool ProcessFrames(const StreamParser::BufferQueue& audio_buffers, 56 const StreamParser::BufferQueue& video_buffers, 57 const StreamParser::TextBufferQueueMap& text_map, 58 base::TimeDelta append_window_start, 59 base::TimeDelta append_window_end, 60 bool* new_media_segment, 61 base::TimeDelta* timestamp_offset); 62 63 // Signals the frame processor to update its group start timestamp to be 64 // |timestamp_offset| if it is in sequence append mode. 65 void SetGroupStartTimestampIfInSequenceMode(base::TimeDelta timestamp_offset); 66 67 // Adds a new track with unique track ID |id|. 68 // If |id| has previously been added, returns false to indicate error. 69 // Otherwise, returns true, indicating future ProcessFrames() will emit 70 // frames for the track |id| to |stream|. 71 bool AddTrack(StreamParser::TrackId id, ChunkDemuxerStream* stream); 72 73 // Updates the internal mapping of TrackId to track buffer for the track 74 // buffer formerly associated with |old_id| to be associated with |new_id|. 75 // Returns false to indicate failure due to either no existing track buffer 76 // for |old_id| or collision with previous track buffer already mapped to 77 // |new_id|. Otherwise returns true. 78 bool UpdateTrack(StreamParser::TrackId old_id, StreamParser::TrackId new_id); 79 80 // Sets the need random access point flag on all track buffers to true. 81 void SetAllTrackBuffersNeedRandomAccessPoint(); 82 83 // Resets state for the coded frame processing algorithm as described in steps 84 // 2-5 of the MSE Reset Parser State algorithm described at 85 // http://www.w3.org/TR/media-source/#sourcebuffer-reset-parser-state 86 void Reset(); 87 88 // Must be called when the audio config is updated. Used to manage when 89 // the preroll buffer is cleared and the allowed "fudge" factor between 90 // preroll buffers. 91 void OnPossibleAudioConfigUpdate(const AudioDecoderConfig& config); 92 93 private: 94 typedef std::map<StreamParser::TrackId, MseTrackBuffer*> TrackBufferMap; 95 96 // If |track_buffers_| contains |id|, returns a pointer to the associated 97 // MseTrackBuffer. Otherwise, returns NULL. 98 MseTrackBuffer* FindTrack(StreamParser::TrackId id); 99 100 // Signals all track buffers' streams that a new media segment is starting 101 // with decode timestamp |segment_timestamp|. 102 void NotifyNewMediaSegmentStarting(DecodeTimestamp segment_timestamp); 103 104 // Helper that signals each track buffer to append any processed, but not yet 105 // appended, frames to its stream. Returns true on success, or false if one or 106 // more of the appends failed. 107 bool FlushProcessedFrames(); 108 109 // Handles partial append window trimming of |buffer|. Returns true if the 110 // given |buffer| can be partially trimmed or have preroll added; otherwise, 111 // returns false. 112 // 113 // If |buffer| overlaps |append_window_start|, the portion of |buffer| before 114 // |append_window_start| will be marked for post-decode discard. Further, if 115 // |audio_preroll_buffer_| exists and abuts |buffer|, it will be set as 116 // preroll on |buffer| and |audio_preroll_buffer_| will be cleared. If the 117 // preroll buffer does not abut |buffer|, it will be discarded unused. 118 // 119 // Likewise, if |buffer| overlaps |append_window_end|, the portion of |buffer| 120 // after |append_window_end| will be marked for post-decode discard. 121 // 122 // If |buffer| lies entirely before |append_window_start|, and thus would 123 // normally be discarded, |audio_preroll_buffer_| will be set to |buffer| and 124 // the method will return false. 125 bool HandlePartialAppendWindowTrimming( 126 base::TimeDelta append_window_start, 127 base::TimeDelta append_window_end, 128 const scoped_refptr<StreamParserBuffer>& buffer); 129 130 // Helper that processes one frame with the coded frame processing algorithm. 131 // Returns false on error or true on success. 132 bool ProcessFrame(const scoped_refptr<StreamParserBuffer>& frame, 133 base::TimeDelta append_window_start, 134 base::TimeDelta append_window_end, 135 base::TimeDelta* timestamp_offset, 136 bool* new_media_segment); 137 138 // TrackId-indexed map of each track's stream. 139 TrackBufferMap track_buffers_; 140 141 // The last audio buffer seen by the frame processor that was removed because 142 // it was entirely before the start of the append window. 143 scoped_refptr<StreamParserBuffer> audio_preroll_buffer_; 144 145 // The AudioDecoderConfig associated with buffers handed to ProcessFrames(). 146 AudioDecoderConfig current_audio_config_; 147 base::TimeDelta sample_duration_; 148 149 // The AppendMode of the associated SourceBuffer. 150 // See SetSequenceMode() for interpretation of |sequence_mode_|. 151 // Per http://www.w3.org/TR/media-source/#widl-SourceBuffer-mode: 152 // Controls how a sequence of media segments are handled. This is initially 153 // set to false ("segments"). 154 bool sequence_mode_; 155 156 // Tracks the MSE coded frame processing variable of same name. 157 // Initially kNoTimestamp(), meaning "unset". 158 base::TimeDelta group_start_timestamp_; 159 160 // Tracks the MSE coded frame processing variable of same name. It stores the 161 // highest coded frame end timestamp across all coded frames in the current 162 // coded frame group. It is set to 0 when the SourceBuffer object is created 163 // and gets updated by ProcessFrames(). 164 base::TimeDelta group_end_timestamp_; 165 166 UpdateDurationCB update_duration_cb_; 167 168 DISALLOW_COPY_AND_ASSIGN(FrameProcessor); 169 }; 170 171 } // namespace media 172 173 #endif // MEDIA_FILTERS_FRAME_PROCESSOR_H_ 174