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
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202

media / base / stream_parser.h [blame]

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_BASE_STREAM_PARSER_H_
#define MEDIA_BASE_STREAM_PARSER_H_

#include <stddef.h>
#include <stdint.h>

#include <memory>
#include <vector>

#include "base/containers/circular_deque.h"
#include "base/containers/flat_map.h"
#include "base/containers/span.h"
#include "base/functional/callback_forward.h"
#include "base/memory/scoped_refptr.h"
#include "base/time/time.h"
#include "media/base/demuxer_stream.h"
#include "media/base/eme_constants.h"
#include "media/base/media_export.h"

namespace media {

class MediaLog;
class MediaTracks;
class StreamParserBuffer;

// Abstract interface for parsing media byte streams.
class MEDIA_EXPORT StreamParser {
 public:
  using BufferQueue = base::circular_deque<scoped_refptr<StreamParserBuffer>>;

  // Range of |TrackId| is dependent upon stream parsers.
  // It is the key for BufferQueueMap structure returned by stream parsers.
  using TrackId = int;

  // Map of track ID to decode-timestamp-ordered buffers for the track.
  using BufferQueueMap = base::flat_map<TrackId, BufferQueue>;

  // With incremental parsing, parse can succeed yet also still indicate there
  // is more uninspected data to parse. This enum identifies the possible
  // results of incremental parsing by a StreamParser.
  // TODO:(crbug.com/1378678): Investigate usage of TypeStatus<T>::Or<U> where
  // this is used.
  enum class ParseStatus {
    kFailed,
    kSuccess,
    kSuccessHasMoreData,
  };

  // Incremental parse of a potentially large pending data considers up to this
  // many further bytes from the pending bytes during the Parse() call. Moved
  // from older incremental append+parse logic in SourceBuffer, this size value
  // was originally chosen as 128KiB to not block the renderer event loop very
  // long. This value had been selected by looking at YouTube SourceBuffer usage
  // across a variety of bitrates, to allow relatively large appendBuffer()
  // calls while keeping each parse iteration's duration within ~5-15ms range.
  // This value may change in future updates as platform capabilities have
  // generally improved.
  // TODO(crbug.com/40244251): Tune this experimentally.
  static constexpr int kMaxPendingBytesPerParse = 128 * 1024;  // 128KiB

  // Stream parameters passed in InitCB.
  struct MEDIA_EXPORT InitParameters {
    InitParameters(base::TimeDelta duration);

    // Stream duration.
    base::TimeDelta duration;

    // Indicates the source time associated with presentation timestamp 0. A
    // null Time is returned if no mapping to Time exists.
    base::Time timeline_offset;

    // Indicates live stream.
    StreamLiveness liveness = StreamLiveness::kUnknown;

    // Counts of tracks detected by type within this stream. Not all of these
    // tracks may be selected for use by the parser.
    int detected_audio_track_count = 0;
    int detected_video_track_count = 0;
  };

  // Indicates completion of parser initialization.
  //   params - Stream parameters.
  typedef base::OnceCallback<void(const InitParameters& params)> InitCB;

  // Indicates when new stream configurations have been parsed.
  // First parameter - An object containing information about media tracks as
  //                   well as audio/video decoder configs associated with each
  //                   track the parser will use from the stream.
  // Return value - True if the new configurations are accepted.
  //                False if the new configurations are not supported
  //                and indicates that a parsing error should be signalled.
  typedef base::RepeatingCallback<bool(std::unique_ptr<MediaTracks>)>
      NewConfigCB;

  // New stream buffers have been parsed.
  // First parameter - A map of track ids to queues of newly parsed buffers.
  // Return value - True indicates that the buffers are accepted.
  //                False if something was wrong with the buffers and a parsing
  //                error should be signalled.
  typedef base::RepeatingCallback<bool(const BufferQueueMap&)> NewBuffersCB;

  // Signals the beginning of a new media segment.
  typedef base::RepeatingCallback<void()> NewMediaSegmentCB;

  // Signals the end of a media segment.
  typedef base::RepeatingCallback<void()> EndMediaSegmentCB;

  // A new potentially encrypted stream has been parsed.
  // First parameter - The type of the initialization data associated with the
  //                   stream.
  // Second parameter - The initialization data associated with the stream.
  typedef base::RepeatingCallback<void(EmeInitDataType,
                                       const std::vector<uint8_t>&)>
      EncryptedMediaInitDataCB;

  StreamParser();

  StreamParser(const StreamParser&) = delete;
  StreamParser& operator=(const StreamParser&) = delete;

  virtual ~StreamParser();

  // Initializes the parser with necessary callbacks. Must be called before any
  // data is passed to AppendToParseBuffer() or any call to Parse() or
  // ProcessChunks(). `init_cb` will be called once enough data has been parsed
  // to determine the initial stream configurations, presentation start time,
  // and duration.
  virtual void Init(InitCB init_cb,
                    NewConfigCB config_cb,
                    NewBuffersCB new_buffers_cb,
                    EncryptedMediaInitDataCB encrypted_media_init_data_cb,
                    NewMediaSegmentCB new_segment_cb,
                    EndMediaSegmentCB end_of_segment_cb,
                    MediaLog* media_log) = 0;

  // Called during the reset parser state algorithm. This flushes the current
  // parser and puts the parser in a state where it can receive data. This
  // method does not need to invoke the EndMediaSegmentCB since the parser reset
  // algorithm already resets the segment parsing state.
  virtual void Flush() = 0;

  // Returns the MSE byte stream format registry's "Generate Timestamps Flag"
  // for the byte stream corresponding to this parser.
  virtual bool GetGenerateTimestampsFlag() const = 0;

  // Called when there is new data to parse. Any previously provided data must
  // have been fully attempted to be parsed (by one or more calls to Parse()
  // until kSuccess results) or has been Flush()'ed. Returns true if the parser
  // successfully copied the data from `buf` for use in future Parse() calls.
  // Returns false if the parser was unable to allocate resources; content in
  // `buf` is not copied as a result, and this failure is reported (through
  // various layers) up to the SourceBuffer's implementation of appendBuffer(),
  // which should then notify the app of append failure using a
  // `QuotaExceededErr` exception per the MSE specification. App could use a
  // back-off and retry strategy or otherwise alter their behavior to attempt to
  // buffer media for further playback.
  [[nodiscard]] virtual bool AppendToParseBuffer(
      base::span<const uint8_t> buf) = 0;

  // Attempts to parse more data previously provided via AppendToParseBuffer().
  // May not attempt to parse all of it in one pass;
  // `max_pending_bytes_to_inspect` should normally be set to
  // kMaxPendingBytesPerParse, except if the caller needs to use a different
  // amount (for example, a file verification parse or a test case that needs to
  // involve a larger or smaller amount of the pending data in one call to
  // Parse()).
  // Returns kSuccess if the parse succeeded and all previously provided data
  // from AppendToParseBuffer() has been inspected.
  // Returns kSuccessHasMoreData if the parse succeeded, yet there remains
  // uninspected data remaining from AppendToParseBuffer(); more call(s) to this
  // method are necessary for the parser to attempt inspection of that data.
  // Returns kFailed if there was a parse error.
  //
  // Regular "bytestream-formatted" StreamParsers should fully implement
  // Parse(), but WebCodecsEncodedChunkStreamParsers should instead fully
  // implement ProcessChunks().
  [[nodiscard]] virtual ParseStatus Parse(int max_pending_bytes_to_inspect) = 0;
  [[nodiscard]] virtual bool ProcessChunks(
      std::unique_ptr<BufferQueue> buffer_queue);
};

// Appends to |merged_buffers| the provided buffers in decode-timestamp order.
// Any previous contents of |merged_buffers| is assumed to have lower
// decode timestamps versus the provided buffers. All provided buffer queues
// are assumed to already be in decode-timestamp order.
// Returns false if any of the provided audio/video buffers are found
// to not be in decode timestamp order, or have a decode timestamp less than
// the last buffer, if any, in |merged_buffers|. Partial results may exist
// in |merged_buffers| in this case. Returns true on success.
// No validation of media type within the various buffer queues is done here.
// TODO(wolenetz/acolwell): Merge incrementally in parsers to eliminate
// subtle issues with tie-breaking. See http://crbug.com/338484.
MEDIA_EXPORT bool MergeBufferQueues(const StreamParser::BufferQueueMap& buffers,
                                    StreamParser::BufferQueue* merged_buffers);

}  // namespace media

#endif  // MEDIA_BASE_STREAM_PARSER_H_