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
17namespace media {
18
19class MseTrackBuffer;
20
21// Helper class that implements Media Source Extension's coded frame processing
22// algorithm.
23class 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