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_