summaryrefslogtreecommitdiffstats
path: root/media/filters/frame_processor.h
blob: 0a1ecc641858840226f4ac11b1160de591a5bd4e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_FILTERS_FRAME_PROCESSOR_H_
#define MEDIA_FILTERS_FRAME_PROCESSOR_H_

#include <map>

#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/time/time.h"
#include "media/base/media_export.h"
#include "media/base/media_log.h"
#include "media/base/stream_parser.h"
#include "media/filters/chunk_demuxer.h"

namespace media {

class MseTrackBuffer;

// Helper class that implements Media Source Extension's coded frame processing
// algorithm.
class MEDIA_EXPORT FrameProcessor {
 public:
  typedef base::Callback<void(base::TimeDelta)> UpdateDurationCB;

  // TODO(wolenetz/acolwell): Ensure that all TrackIds are coherent and unique
  // for each track buffer. For now, special track identifiers are used for each
  // of audio and video here, and text TrackIds are assumed to be non-negative.
  // See http://crbug.com/341581.
  enum {
    kAudioTrackId = -2,
    kVideoTrackId = -3
  };

  FrameProcessor(const UpdateDurationCB& update_duration_cb,
                 const scoped_refptr<MediaLog>& media_log);
  ~FrameProcessor();

  // Get/set the current append mode, which if true means "sequence" and if
  // false means "segments".
  // See http://www.w3.org/TR/media-source/#widl-SourceBuffer-mode.
  bool sequence_mode() { return sequence_mode_; }
  void SetSequenceMode(bool sequence_mode);

  // Processes buffers in |audio_buffers|, |video_buffers|, and |text_map|.
  // Returns true on success or false on failure which indicates decode error.
  // |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.
  // Uses |*timestamp_offset| according to the coded frame processing algorithm,
  // including updating it as required in 'sequence' mode frame processing.
  bool ProcessFrames(const StreamParser::BufferQueue& audio_buffers,
                     const StreamParser::BufferQueue& video_buffers,
                     const StreamParser::TextBufferQueueMap& text_map,
                     base::TimeDelta append_window_start,
                     base::TimeDelta append_window_end,
                     base::TimeDelta* timestamp_offset);

  // Signals the frame processor to update its group start timestamp to be
  // |timestamp_offset| if it is in sequence append mode.
  void SetGroupStartTimestampIfInSequenceMode(base::TimeDelta timestamp_offset);

  // Adds a new track with unique track ID |id|.
  // If |id| has previously been added, returns false to indicate error.
  // Otherwise, returns true, indicating future ProcessFrames() will emit
  // frames for the track |id| to |stream|.
  bool AddTrack(StreamParser::TrackId id, ChunkDemuxerStream* stream);

  // Updates the internal mapping of TrackId to track buffer for the track
  // buffer formerly associated with |old_id| to be associated with |new_id|.
  // Returns false to indicate failure due to either no existing track buffer
  // for |old_id| or collision with previous track buffer already mapped to
  // |new_id|. Otherwise returns true.
  bool UpdateTrack(StreamParser::TrackId old_id, StreamParser::TrackId new_id);

  // Sets the need random access point flag on all track buffers to true.
  void SetAllTrackBuffersNeedRandomAccessPoint();

  // Resets state for the coded frame processing algorithm as described in steps
  // 2-5 of the MSE Reset Parser State algorithm described at
  // http://www.w3.org/TR/media-source/#sourcebuffer-reset-parser-state
  void Reset();

  // Must be called when the audio config is updated.  Used to manage when
  // the preroll buffer is cleared and the allowed "fudge" factor between
  // preroll buffers.
  void OnPossibleAudioConfigUpdate(const AudioDecoderConfig& config);

 private:
  friend class FrameProcessorTest;

  typedef std::map<StreamParser::TrackId, MseTrackBuffer*> TrackBufferMap;

  // If |track_buffers_| contains |id|, returns a pointer to the associated
  // MseTrackBuffer. Otherwise, returns NULL.
  MseTrackBuffer* FindTrack(StreamParser::TrackId id);

  // Signals all track buffers' streams that a coded frame group is starting
  // with decode timestamp |start_timestamp|.
  void NotifyStartOfCodedFrameGroup(DecodeTimestamp start_timestamp);

  // Helper that signals each track buffer to append any processed, but not yet
  // appended, frames to its stream. Returns true on success, or false if one or
  // more of the appends failed.
  bool FlushProcessedFrames();

  // Handles partial append window trimming of |buffer|.  Returns true if the
  // given |buffer| can be partially trimmed or have preroll added; otherwise,
  // returns false.
  //
  // If |buffer| overlaps |append_window_start|, the portion of |buffer| before
  // |append_window_start| will be marked for post-decode discard.  Further, if
  // |audio_preroll_buffer_| exists and abuts |buffer|, it will be set as
  // preroll on |buffer| and |audio_preroll_buffer_| will be cleared.  If the
  // preroll buffer does not abut |buffer|, it will be discarded unused.
  //
  // Likewise, if |buffer| overlaps |append_window_end|, the portion of |buffer|
  // after |append_window_end| will be marked for post-decode discard.
  //
  // If |buffer| lies entirely before |append_window_start|, and thus would
  // normally be discarded, |audio_preroll_buffer_| will be set to |buffer| and
  // the method will return false.
  bool HandlePartialAppendWindowTrimming(
      base::TimeDelta append_window_start,
      base::TimeDelta append_window_end,
      const scoped_refptr<StreamParserBuffer>& buffer);

  // Helper that processes one frame with the coded frame processing algorithm.
  // Returns false on error or true on success.
  bool ProcessFrame(const scoped_refptr<StreamParserBuffer>& frame,
                    base::TimeDelta append_window_start,
                    base::TimeDelta append_window_end,
                    base::TimeDelta* timestamp_offset);

  // TrackId-indexed map of each track's stream.
  TrackBufferMap track_buffers_;

  // The last audio buffer seen by the frame processor that was removed because
  // it was entirely before the start of the append window.
  scoped_refptr<StreamParserBuffer> audio_preroll_buffer_;

  // The AudioDecoderConfig associated with buffers handed to ProcessFrames().
  AudioDecoderConfig current_audio_config_;
  base::TimeDelta sample_duration_;

  // The AppendMode of the associated SourceBuffer.
  // See SetSequenceMode() for interpretation of |sequence_mode_|.
  // Per http://www.w3.org/TR/media-source/#widl-SourceBuffer-mode:
  // Controls how a sequence of media segments are handled. This is initially
  // set to false ("segments").
  bool sequence_mode_ = false;

  // Flag to track whether or not the next processed frame is a continuation of
  // a coded frame group. This flag resets to false upon detection of
  // discontinuity, and becomes true once a processed coded frame for the
  // current coded frame group is sent to its track buffer.
  bool in_coded_frame_group_ = false;

  // Tracks the MSE coded frame processing variable of same name.
  // Initially kNoTimestamp(), meaning "unset".
  base::TimeDelta group_start_timestamp_;

  // Tracks the MSE coded frame processing variable of same name. It stores the
  // highest coded frame end timestamp across all coded frames in the current
  // coded frame group. It is set to 0 when the SourceBuffer object is created
  // and gets updated by ProcessFrames().
  base::TimeDelta group_end_timestamp_;

  UpdateDurationCB update_duration_cb_;

  // MediaLog for reporting messages and properties to debug content and engine.
  scoped_refptr<MediaLog> media_log_;

  // Counters that limit spam to |media_log_| for frame processor warnings.
  int num_dropped_preroll_warnings_ = 0;
  int num_dts_beyond_pts_warnings_ = 0;

  DISALLOW_COPY_AND_ASSIGN(FrameProcessor);
};

}  // namespace media

#endif  // MEDIA_FILTERS_FRAME_PROCESSOR_H_