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
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260
  261
  262
  263
  264
  265
  266
  267
  268
  269
  270
  271
  272
  273
  274
  275
  276
  277
  278
  279
  280
  281
  282
  283
  284
  285
  286
  287
  288
  289
  290
  291
  292
  293
  294
  295
  296
  297
  298
  299
  300
  301
  302
  303
  304
  305
  306
  307
  308
  309
  310
  311
  312
  313
  314
  315
  316
  317
  318
  319
  320
  321
  322
  323
  324
  325
  326
  327
  328
  329
  330
  331
  332

media / base / decoder_buffer.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_DECODER_BUFFER_H_
#define MEDIA_BASE_DECODER_BUFFER_H_

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

#include <memory>
#include <optional>
#include <ostream>
#include <string>
#include <utility>

#include "base/check.h"
#include "base/containers/heap_array.h"
#include "base/containers/span.h"
#include "base/memory/raw_span.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/ref_counted.h"
#include "base/memory/shared_memory_mapping.h"
#include "base/memory/unsafe_shared_memory_region.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "media/base/decoder_buffer_side_data.h"
#include "media/base/decrypt_config.h"
#include "media/base/media_export.h"
#include "media/base/timestamp_constants.h"

namespace media {

// A specialized buffer for interfacing with audio / video decoders.
//
// Also includes decoder specific functionality for decryption.
//
// NOTE: It is illegal to call any method when end_of_stream() is true.
class MEDIA_EXPORT DecoderBuffer
    : public base::RefCountedThreadSafe<DecoderBuffer> {
 public:
  // ExternalMemory wraps a class owning a buffer and expose the data interface
  // through Span(). This class is derived by a class that owns the class owning
  // the buffer owner class.
  struct MEDIA_EXPORT ExternalMemory {
   public:
    virtual ~ExternalMemory() = default;
    virtual const base::span<const uint8_t> Span() const = 0;
  };

  using DiscardPadding = DecoderBufferSideData::DiscardPadding;

  // TODO(crbug.com/365814210): Remove this structure. It's barely used outside
  // of unit tests.
  struct MEDIA_EXPORT TimeInfo {
    // Presentation time of the frame.
    base::TimeDelta timestamp;

    // Presentation duration of the frame.
    base::TimeDelta duration;

    // Duration of (audio) samples from the beginning and end of this frame
    // which should be discarded after decoding. A value of kInfiniteDuration
    // for the first value indicates the entire frame should be discarded; the
    // second value must be base::TimeDelta() in this case.
    DiscardPadding discard_padding;
  };

  // Allocates buffer with |size| > 0. |is_key_frame_| will default to false.
  // If size is 0, no buffer will be allocated.
  // TODO(crbug.com/365814210): Remove this constructor. Clients should use the
  // FromArray constructor instead asking for a writable DecoderBuffer.
  explicit DecoderBuffer(size_t size);

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

  // Create a DecoderBuffer whose |data_| is copied from |data|. The buffer's
  // |is_key_frame_| will default to false.
  static scoped_refptr<DecoderBuffer> CopyFrom(base::span<const uint8_t> data);

  // Create a DecoderBuffer where data() of |size| bytes resides within the heap
  // as byte array. The buffer's |is_key_frame_| will default to false.
  //
  // Ownership of |data| is transferred to the buffer.
  static scoped_refptr<DecoderBuffer> FromArray(base::HeapArray<uint8_t> data);

  // Create a DecoderBuffer where data() of |size| bytes resides within the
  // memory referred to by |region| at non-negative offset |offset|. The
  // buffer's |is_key_frame_| will default to false.
  //
  // The shared memory will be mapped read-only.
  //
  // If mapping fails, nullptr will be returned.
  static scoped_refptr<DecoderBuffer> FromSharedMemoryRegion(
      base::UnsafeSharedMemoryRegion region,
      uint64_t offset,
      size_t size);

  // Create a DecoderBuffer where data() of |size| bytes resides within the
  // ReadOnlySharedMemoryRegion referred to by |mapping| at non-negative offset
  // |offset|. The buffer's |is_key_frame_| will default to false.
  //
  // Ownership of |region| is transferred to the buffer.
  static scoped_refptr<DecoderBuffer> FromSharedMemoryRegion(
      base::ReadOnlySharedMemoryRegion region,
      uint64_t offset,
      size_t size);

  // Creates a DecoderBuffer with ExternalMemory. The buffer accessed through
  // the created DecoderBuffer is |span| of |external_memory||.
  // |external_memory| is owned by DecoderBuffer until it is destroyed.
  static scoped_refptr<DecoderBuffer> FromExternalMemory(
      std::unique_ptr<ExternalMemory> external_memory);

  // Create a DecoderBuffer indicating we've reached end of stream. If this is
  // an EOS buffer for a config change, the upcoming config may optionally be
  // provided to allow the decoder to make more optimal configuration decisions.
  //
  // Calling any method other than end_of_stream() or next_config() on the
  // resulting buffer is disallowed.
  using ConfigVariant = DecoderBufferSideData::ConfigVariant;
  static scoped_refptr<DecoderBuffer> CreateEOSBuffer(
      std::optional<ConfigVariant> next_config = std::nullopt);

  // Method to verify if subsamples of a DecoderBuffer match.
  static bool DoSubsamplesMatch(const DecoderBuffer& buffer);

  // TODO(crbug.com/365814210): Remove this method.
  TimeInfo time_info() const {
    DCHECK(!end_of_stream());
    return {timestamp_, duration_, discard_padding()};
  }

  base::TimeDelta timestamp() const {
    DCHECK(!end_of_stream());
    return timestamp_;
  }

  // TODO(crbug.com/365814210): This should be renamed at some point, but to
  // avoid a yak shave keep as a virtual with hacker_style() for now.
  virtual void set_timestamp(base::TimeDelta timestamp);

  base::TimeDelta duration() const {
    DCHECK(!end_of_stream());
    return duration_;
  }

  void set_duration(base::TimeDelta duration) {
    DCHECK(!end_of_stream());
    DCHECK(duration == kNoTimestamp ||
           (duration >= base::TimeDelta() && duration != kInfiniteDuration))
        << duration.InSecondsF();
    duration_ = duration;
  }

  // The pointer to the start of the buffer. Prefer to construct a span around
  // the buffer, such as `base::span(decoder_buffer)`.
  // TODO(crbug.com/365814210): Remove in favor of AsSpan().
  const uint8_t* data() const {
    DCHECK(!end_of_stream());
    if (external_memory_)
      return external_memory_->Span().data();
    return data_.data();
  }

  // TODO(crbug.com/373790934): This is unnecessary; this type can be implicitly
  // converted to a span<const uint8_t>.
  base::span<const uint8_t> AsSpan() const;

  // The number of bytes in the buffer.
  size_t size() const {
    DCHECK(!end_of_stream());
    return external_memory_ ? external_memory_->Span().size() : data_.size();
  }

  // Prefer writable_span(), though it should also be removed.
  //
  // TODO(crbug.com/41383992): Remove writable_data().
  uint8_t* writable_data() const {
    DCHECK(!end_of_stream());
    DCHECK(!external_memory_);
    return const_cast<uint8_t*>(data_.data());
  }

  // TODO(crbug.com/41383992): Remove writable_span().
  base::span<uint8_t> writable_span() const {
    // TODO(crbug.com/40284755): `data_` should be converted to HeapArray, then
    // it can give out a span safely.
    return UNSAFE_TODO(base::span(writable_data(), size()));
  }

  bool empty() const {
    return external_memory_ ? external_memory_->Span().empty() : data_.empty();
  }

  // Read-only iteration as bytes. This allows this type to meet the
  // requirements of `std::ranges::contiguous_range`, and thus be implicitly
  // convertible to a span.
  auto begin() const {
    return external_memory_ ? external_memory_->Span().begin() : data_.begin();
  }
  auto end() const {
    return external_memory_ ? external_memory_->Span().end() : data_.end();
  }

  // TODO(crbug.com/365814210): Change the return type to std::optional.
  DiscardPadding discard_padding() const {
    DCHECK(!end_of_stream());
    return side_data_ ? side_data_->discard_padding : DiscardPadding();
  }

  // TODO(crbug.com/365814210): Remove this method and force callers to get it
  // through side_data().
  void set_discard_padding(const DiscardPadding& discard_padding);

  // Returns DecryptConfig associated with |this|. Returns null if |this| is
  // not encrypted.
  const DecryptConfig* decrypt_config() const {
    DCHECK(!end_of_stream());
    return decrypt_config_.get();
  }

  // TODO(b/331652782): integrate the setter function into the constructor to
  // make |decrypt_config_| immutable.
  void set_decrypt_config(std::unique_ptr<DecryptConfig> decrypt_config) {
    DCHECK(!end_of_stream());
    decrypt_config_ = std::move(decrypt_config);
  }

  bool end_of_stream() const { return is_end_of_stream_; }

  bool is_key_frame() const {
    DCHECK(!end_of_stream());
    return is_key_frame_;
  }

  bool is_encrypted() const {
    DCHECK(!end_of_stream());
    return decrypt_config() && decrypt_config()->encryption_scheme() !=
                                   EncryptionScheme::kUnencrypted;
  }

  void set_is_key_frame(bool is_key_frame) {
    DCHECK(!end_of_stream());
    is_key_frame_ = is_key_frame;
  }

  // Returns DecoderBufferSideData associated with `this`. Check if `side_data_`
  // exists using `has_side_data()` before calling this function.
  const DecoderBufferSideData* side_data() const {
    DCHECK(!end_of_stream());
    return side_data_.get();
  }

  // TODO(b/331652782): integrate the setter function into the constructor to
  // make |side_data_| immutable.
  DecoderBufferSideData& WritableSideData();
  void set_side_data(std::unique_ptr<DecoderBufferSideData> side_data);

  // Returns true if all fields in |buffer| matches this buffer including
  // |data_|.
  bool MatchesForTesting(const DecoderBuffer& buffer) const;

  // As above, except that |data_| is not compared.
  bool MatchesMetadataForTesting(const DecoderBuffer& buffer) const;

  // Returns a human-readable string describing |*this|.
  std::string AsHumanReadableString(bool verbose = false) const;

  // Returns total memory usage for both bookkeeping and buffered data. The
  // function is added for more accurately memory management.
  virtual size_t GetMemoryUsage() const;

  // Accessor for DecoderBufferSideData::next_config.
  std::optional<ConfigVariant> next_config() const {
    DCHECK(end_of_stream());
    return side_data_ ? side_data_->next_config : std::nullopt;
  }

 protected:
  friend class base::RefCountedThreadSafe<DecoderBuffer>;
  enum class DecoderBufferType { kNormal, kEndOfStream };

  // Allocates a buffer with a copy of |data| in it. |is_key_frame_| will
  // default to false.
  explicit DecoderBuffer(base::span<const uint8_t> data);

  explicit DecoderBuffer(base::HeapArray<uint8_t> data);

  explicit DecoderBuffer(std::unique_ptr<ExternalMemory> external_memory);

  DecoderBuffer(DecoderBufferType decoder_buffer_type,
                std::optional<ConfigVariant> next_config);

  virtual ~DecoderBuffer();

  // Encoded data, if it is stored on the heap.
  const base::HeapArray<uint8_t> data_;

 private:
  // ***************************************************************************
  // WARNING: This is a highly allocated object. Care should be taken when
  // adding any fields to make sure they are absolutely necessary. If a field
  // must be added and can be optional, ensure it is heap allocated through the
  // usage of something like std::unique_ptr.
  // ***************************************************************************

  // Presentation time of the frame.
  base::TimeDelta timestamp_;

  // Presentation duration of the frame.
  base::TimeDelta duration_;

  // Structured side data.
  std::unique_ptr<DecoderBufferSideData> side_data_;

  const std::unique_ptr<ExternalMemory> external_memory_;

  // Encryption parameters for the encoded data.
  std::unique_ptr<DecryptConfig> decrypt_config_;

  // Whether the frame was marked as a keyframe in the container.
  bool is_key_frame_ : 1 = false;

  // Whether the buffer represent the end of stream.
  const bool is_end_of_stream_ : 1 = false;
};

}  // namespace media

#endif  // MEDIA_BASE_DECODER_BUFFER_H_