/src/mozilla-central/dom/media/MediaData.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | #if !defined(MediaData_h) |
7 | | #define MediaData_h |
8 | | |
9 | | #include "AudioConfig.h" |
10 | | #include "AudioSampleFormat.h" |
11 | | #include "ImageTypes.h" |
12 | | #include "SharedBuffer.h" |
13 | | #include "TimeUnits.h" |
14 | | #include "mozilla/CheckedInt.h" |
15 | | #include "mozilla/PodOperations.h" |
16 | | #include "mozilla/RefPtr.h" |
17 | | #include "mozilla/Span.h" |
18 | | #include "mozilla/UniquePtr.h" |
19 | | #include "mozilla/UniquePtrExtensions.h" |
20 | | #include "mozilla/gfx/Rect.h" |
21 | | #include "nsString.h" |
22 | | #include "nsTArray.h" |
23 | | |
24 | | namespace mozilla { |
25 | | |
26 | | namespace layers { |
27 | | class Image; |
28 | | class ImageContainer; |
29 | | class KnowsCompositor; |
30 | | } // namespace layers |
31 | | |
32 | | class MediaByteBuffer; |
33 | | class TrackInfoSharedPtr; |
34 | | |
35 | | // AlignedBuffer: |
36 | | // Memory allocations are fallibles. Methods return a boolean indicating if |
37 | | // memory allocations were successful. Return values should always be checked. |
38 | | // AlignedBuffer::mData will be nullptr if no memory has been allocated or if |
39 | | // an error occurred during construction. |
40 | | // Existing data is only ever modified if new memory allocation has succeeded |
41 | | // and preserved if not. |
42 | | // |
43 | | // The memory referenced by mData will always be Alignment bytes aligned and the |
44 | | // underlying buffer will always have a size such that Alignment bytes blocks |
45 | | // can be used to read the content, regardless of the mSize value. Buffer is |
46 | | // zeroed on creation, elements are not individually constructed. |
47 | | // An Alignment value of 0 means that the data isn't aligned. |
48 | | // |
49 | | // Type must be trivially copyable. |
50 | | // |
51 | | // AlignedBuffer can typically be used in place of UniquePtr<Type[]> however |
52 | | // care must be taken as all memory allocations are fallible. |
53 | | // Example: |
54 | | // auto buffer = MakeUniqueFallible<float[]>(samples) |
55 | | // becomes: AlignedFloatBuffer buffer(samples) |
56 | | // |
57 | | // auto buffer = MakeUnique<float[]>(samples) |
58 | | // becomes: |
59 | | // AlignedFloatBuffer buffer(samples); |
60 | | // if (!buffer) { return NS_ERROR_OUT_OF_MEMORY; } |
61 | | |
62 | | template <typename Type, int Alignment = 32> |
63 | | class AlignedBuffer |
64 | | { |
65 | | public: |
66 | | AlignedBuffer() |
67 | | : mData(nullptr) |
68 | | , mLength(0) |
69 | | , mBuffer(nullptr) |
70 | | , mCapacity(0) |
71 | 0 | { |
72 | 0 | } Unexecuted instantiation: mozilla::AlignedBuffer<short, 32>::AlignedBuffer() Unexecuted instantiation: mozilla::AlignedBuffer<unsigned char, 32>::AlignedBuffer() |
73 | | |
74 | | explicit AlignedBuffer(size_t aLength) |
75 | | : mData(nullptr) |
76 | | , mLength(0) |
77 | | , mBuffer(nullptr) |
78 | | , mCapacity(0) |
79 | 0 | { |
80 | 0 | if (EnsureCapacity(aLength)) { |
81 | 0 | mLength = aLength; |
82 | 0 | } |
83 | 0 | } Unexecuted instantiation: mozilla::AlignedBuffer<unsigned char, 32>::AlignedBuffer(unsigned long) Unexecuted instantiation: mozilla::AlignedBuffer<float, 32>::AlignedBuffer(unsigned long) |
84 | | |
85 | | AlignedBuffer(const Type* aData, size_t aLength) |
86 | | : AlignedBuffer(aLength) |
87 | 0 | { |
88 | 0 | if (!mData) { |
89 | 0 | return; |
90 | 0 | } |
91 | 0 | PodCopy(mData, aData, aLength); |
92 | 0 | } |
93 | | |
94 | | AlignedBuffer(const AlignedBuffer& aOther) |
95 | | : AlignedBuffer(aOther.Data(), aOther.Length()) |
96 | | { |
97 | | } |
98 | | |
99 | | AlignedBuffer(AlignedBuffer&& aOther) |
100 | | : mData(aOther.mData) |
101 | | , mLength(aOther.mLength) |
102 | | , mBuffer(std::move(aOther.mBuffer)) |
103 | | , mCapacity(aOther.mCapacity) |
104 | 0 | { |
105 | 0 | aOther.mData = nullptr; |
106 | 0 | aOther.mLength = 0; |
107 | 0 | aOther.mCapacity = 0; |
108 | 0 | } |
109 | | |
110 | | AlignedBuffer& operator=(AlignedBuffer&& aOther) |
111 | | { |
112 | | this->~AlignedBuffer(); |
113 | | new (this) AlignedBuffer(std::move(aOther)); |
114 | | return *this; |
115 | | } |
116 | | |
117 | 0 | Type* Data() const { return mData; } |
118 | 0 | size_t Length() const { return mLength; } |
119 | 0 | size_t Size() const { return mLength * sizeof(Type); } |
120 | | Type& operator[](size_t aIndex) |
121 | 0 | { |
122 | 0 | MOZ_ASSERT(aIndex < mLength); |
123 | 0 | return mData[aIndex]; |
124 | 0 | } |
125 | | const Type& operator[](size_t aIndex) const |
126 | 0 | { |
127 | 0 | MOZ_ASSERT(aIndex < mLength); |
128 | 0 | return mData[aIndex]; |
129 | 0 | } |
130 | | // Set length of buffer, allocating memory as required. |
131 | | // If length is increased, new buffer area is filled with 0. |
132 | | bool SetLength(size_t aLength) |
133 | 0 | { |
134 | 0 | if (aLength > mLength && !EnsureCapacity(aLength)) { |
135 | 0 | return false; |
136 | 0 | } |
137 | 0 | mLength = aLength; |
138 | 0 | return true; |
139 | 0 | } Unexecuted instantiation: mozilla::AlignedBuffer<short, 32>::SetLength(unsigned long) Unexecuted instantiation: mozilla::AlignedBuffer<unsigned char, 32>::SetLength(unsigned long) |
140 | | // Add aData at the beginning of buffer. |
141 | | bool Prepend(const Type* aData, size_t aLength) |
142 | 0 | { |
143 | 0 | if (!EnsureCapacity(aLength + mLength)) { |
144 | 0 | return false; |
145 | 0 | } |
146 | 0 | |
147 | 0 | // Shift the data to the right by aLength to leave room for the new data. |
148 | 0 | PodMove(mData + aLength, mData, mLength); |
149 | 0 | PodCopy(mData, aData, aLength); |
150 | 0 |
|
151 | 0 | mLength += aLength; |
152 | 0 | return true; |
153 | 0 | } |
154 | | // Add aData at the end of buffer. |
155 | | bool Append(const Type* aData, size_t aLength) |
156 | 0 | { |
157 | 0 | if (!EnsureCapacity(aLength + mLength)) { |
158 | 0 | return false; |
159 | 0 | } |
160 | 0 | |
161 | 0 | PodCopy(mData + mLength, aData, aLength); |
162 | 0 |
|
163 | 0 | mLength += aLength; |
164 | 0 | return true; |
165 | 0 | } |
166 | | // Replace current content with aData. |
167 | | bool Replace(const Type* aData, size_t aLength) |
168 | 0 | { |
169 | 0 | // If aLength is smaller than our current length, we leave the buffer as is, |
170 | 0 | // only adjusting the reported length. |
171 | 0 | if (!EnsureCapacity(aLength)) { |
172 | 0 | return false; |
173 | 0 | } |
174 | 0 | |
175 | 0 | PodCopy(mData, aData, aLength); |
176 | 0 | mLength = aLength; |
177 | 0 | return true; |
178 | 0 | } |
179 | | // Clear the memory buffer. Will set target mData and mLength to 0. |
180 | | void Clear() |
181 | 0 | { |
182 | 0 | mLength = 0; |
183 | 0 | mData = nullptr; |
184 | 0 | } |
185 | | |
186 | | // Methods for reporting memory. |
187 | | size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const |
188 | | { |
189 | | size_t size = aMallocSizeOf(this); |
190 | | size += aMallocSizeOf(mBuffer.get()); |
191 | | return size; |
192 | | } |
193 | | // AlignedBuffer is typically allocated on the stack. As such, you likely |
194 | | // want to use SizeOfExcludingThis |
195 | | size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const |
196 | 0 | { |
197 | 0 | return aMallocSizeOf(mBuffer.get()); |
198 | 0 | } Unexecuted instantiation: mozilla::AlignedBuffer<float, 32>::SizeOfExcludingThis(unsigned long (*)(void const*)) const Unexecuted instantiation: mozilla::AlignedBuffer<unsigned char, 32>::SizeOfExcludingThis(unsigned long (*)(void const*)) const |
199 | | size_t ComputedSizeOfExcludingThis() const |
200 | | { |
201 | | return mCapacity; |
202 | | } |
203 | | |
204 | | // For backward compatibility with UniquePtr<Type[]> |
205 | 0 | Type* get() const { return mData; } |
206 | 0 | explicit operator bool() const { return mData != nullptr; } Unexecuted instantiation: mozilla::AlignedBuffer<unsigned char, 32>::operator bool() const Unexecuted instantiation: mozilla::AlignedBuffer<float, 32>::operator bool() const |
207 | | |
208 | | // Size in bytes of extra space allocated for padding. |
209 | | static size_t AlignmentPaddingSize() |
210 | 0 | { |
211 | 0 | return AlignmentOffset() * 2; |
212 | 0 | } Unexecuted instantiation: mozilla::AlignedBuffer<short, 32>::AlignmentPaddingSize() Unexecuted instantiation: mozilla::AlignedBuffer<float, 32>::AlignmentPaddingSize() Unexecuted instantiation: mozilla::AlignedBuffer<unsigned char, 32>::AlignmentPaddingSize() |
213 | | |
214 | | void PopFront(size_t aSize) |
215 | 0 | { |
216 | 0 | MOZ_ASSERT(mLength >= aSize); |
217 | 0 | PodMove(mData, mData + aSize, mLength - aSize); |
218 | 0 | mLength -= aSize; |
219 | 0 | } |
220 | | |
221 | | private: |
222 | | static size_t AlignmentOffset() |
223 | 0 | { |
224 | 0 | return Alignment ? Alignment - 1 : 0; |
225 | 0 | } Unexecuted instantiation: mozilla::AlignedBuffer<short, 32>::AlignmentOffset() Unexecuted instantiation: mozilla::AlignedBuffer<float, 32>::AlignmentOffset() Unexecuted instantiation: mozilla::AlignedBuffer<unsigned char, 32>::AlignmentOffset() |
226 | | |
227 | | // Ensure that the backend buffer can hold aLength data. Will update mData. |
228 | | // Will enforce that the start of allocated data is always Alignment bytes |
229 | | // aligned and that it has sufficient end padding to allow for Alignment bytes |
230 | | // block read as required by some data decoders. |
231 | | // Returns false if memory couldn't be allocated. |
232 | | bool EnsureCapacity(size_t aLength) |
233 | 0 | { |
234 | 0 | if (!aLength) { |
235 | 0 | // No need to allocate a buffer yet. |
236 | 0 | return true; |
237 | 0 | } |
238 | 0 | const CheckedInt<size_t> sizeNeeded = |
239 | 0 | CheckedInt<size_t>(aLength) * sizeof(Type) + AlignmentPaddingSize(); |
240 | 0 |
|
241 | 0 | if (!sizeNeeded.isValid() || sizeNeeded.value() >= INT32_MAX) { |
242 | 0 | // overflow or over an acceptable size. |
243 | 0 | return false; |
244 | 0 | } |
245 | 0 | if (mData && mCapacity >= sizeNeeded.value()) { |
246 | 0 | return true; |
247 | 0 | } |
248 | 0 | auto newBuffer = MakeUniqueFallible<uint8_t[]>(sizeNeeded.value()); |
249 | 0 | if (!newBuffer) { |
250 | 0 | return false; |
251 | 0 | } |
252 | 0 | |
253 | 0 | // Find alignment address. |
254 | 0 | const uintptr_t alignmask = AlignmentOffset(); |
255 | 0 | Type* newData = reinterpret_cast<Type*>( |
256 | 0 | (reinterpret_cast<uintptr_t>(newBuffer.get()) + alignmask) & ~alignmask); |
257 | 0 | MOZ_ASSERT(uintptr_t(newData) % (AlignmentOffset()+1) == 0); |
258 | 0 |
|
259 | 0 | MOZ_ASSERT(!mLength || mData); |
260 | 0 |
|
261 | 0 | PodZero(newData + mLength, aLength - mLength); |
262 | 0 | if (mLength) { |
263 | 0 | PodCopy(newData, mData, mLength); |
264 | 0 | } |
265 | 0 |
|
266 | 0 | mBuffer = std::move(newBuffer); |
267 | 0 | mCapacity = sizeNeeded.value(); |
268 | 0 | mData = newData; |
269 | 0 |
|
270 | 0 | return true; |
271 | 0 | } Unexecuted instantiation: mozilla::AlignedBuffer<short, 32>::EnsureCapacity(unsigned long) Unexecuted instantiation: mozilla::AlignedBuffer<unsigned char, 32>::EnsureCapacity(unsigned long) Unexecuted instantiation: mozilla::AlignedBuffer<float, 32>::EnsureCapacity(unsigned long) |
272 | | Type* mData; |
273 | | size_t mLength; |
274 | | UniquePtr<uint8_t[]> mBuffer; |
275 | | size_t mCapacity; |
276 | | }; |
277 | | |
278 | | typedef AlignedBuffer<uint8_t> AlignedByteBuffer; |
279 | | typedef AlignedBuffer<float> AlignedFloatBuffer; |
280 | | typedef AlignedBuffer<int16_t> AlignedShortBuffer; |
281 | | typedef AlignedBuffer<AudioDataValue> AlignedAudioBuffer; |
282 | | |
283 | | // Container that holds media samples. |
284 | | class MediaData |
285 | | { |
286 | | public: |
287 | | |
288 | | NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaData) |
289 | | |
290 | | enum Type |
291 | | { |
292 | | AUDIO_DATA = 0, |
293 | | VIDEO_DATA, |
294 | | RAW_DATA, |
295 | | NULL_DATA |
296 | | }; |
297 | | |
298 | | MediaData(Type aType, |
299 | | int64_t aOffset, |
300 | | const media::TimeUnit& aTimestamp, |
301 | | const media::TimeUnit& aDuration, |
302 | | uint32_t aFrames) |
303 | | : mType(aType) |
304 | | , mOffset(aOffset) |
305 | | , mTime(aTimestamp) |
306 | | , mTimecode(aTimestamp) |
307 | | , mDuration(aDuration) |
308 | | , mFrames(aFrames) |
309 | | , mKeyframe(false) |
310 | 0 | { |
311 | 0 | } |
312 | | |
313 | | // Type of contained data. |
314 | | const Type mType; |
315 | | |
316 | | // Approximate byte offset where this data was demuxed from its media. |
317 | | int64_t mOffset; |
318 | | |
319 | | // Start time of sample. |
320 | | media::TimeUnit mTime; |
321 | | |
322 | | // Codec specific internal time code. For Ogg based codecs this is the |
323 | | // granulepos. |
324 | | media::TimeUnit mTimecode; |
325 | | |
326 | | // Duration of sample, in microseconds. |
327 | | media::TimeUnit mDuration; |
328 | | |
329 | | // Amount of frames for contained data. |
330 | | const uint32_t mFrames; |
331 | | |
332 | | bool mKeyframe; |
333 | | |
334 | | media::TimeUnit GetEndTime() const |
335 | 0 | { |
336 | 0 | return mTime + mDuration; |
337 | 0 | } |
338 | | |
339 | | bool AdjustForStartTime(int64_t aStartTime) |
340 | 0 | { |
341 | 0 | mTime = mTime - media::TimeUnit::FromMicroseconds(aStartTime); |
342 | 0 | return !mTime.IsNegative(); |
343 | 0 | } |
344 | | |
345 | | template <typename ReturnType> |
346 | | const ReturnType* As() const |
347 | | { |
348 | | MOZ_ASSERT(this->mType == ReturnType::sType); |
349 | | return static_cast<const ReturnType*>(this); |
350 | | } |
351 | | |
352 | | template <typename ReturnType> |
353 | | ReturnType* As() |
354 | 0 | { |
355 | 0 | MOZ_ASSERT(this->mType == ReturnType::sType); |
356 | 0 | return static_cast<ReturnType*>(this); |
357 | 0 | } |
358 | | |
359 | | protected: |
360 | | MediaData(Type aType, uint32_t aFrames) |
361 | | : mType(aType) |
362 | | , mOffset(0) |
363 | | , mFrames(aFrames) |
364 | | , mKeyframe(false) |
365 | 0 | { |
366 | 0 | } |
367 | | |
368 | 0 | virtual ~MediaData() { } |
369 | | |
370 | | }; |
371 | | |
372 | | // NullData is for decoder generating a sample which doesn't need to be |
373 | | // rendered. |
374 | | class NullData : public MediaData |
375 | | { |
376 | | public: |
377 | | NullData(int64_t aOffset, |
378 | | const media::TimeUnit& aTime, |
379 | | const media::TimeUnit& aDuration) |
380 | | : MediaData(NULL_DATA, aOffset, aTime, aDuration, 0) |
381 | | { |
382 | | } |
383 | | |
384 | | static const Type sType = NULL_DATA; |
385 | | }; |
386 | | |
387 | | // Holds chunk a decoded audio frames. |
388 | | class AudioData : public MediaData |
389 | | { |
390 | | public: |
391 | | |
392 | | AudioData(int64_t aOffset, |
393 | | const media::TimeUnit& aTime, |
394 | | const media::TimeUnit& aDuration, |
395 | | uint32_t aFrames, |
396 | | AlignedAudioBuffer&& aData, |
397 | | uint32_t aChannels, |
398 | | uint32_t aRate, |
399 | | uint32_t aChannelMap = AudioConfig::ChannelLayout::UNKNOWN_MAP) |
400 | | : MediaData(sType, aOffset, aTime, aDuration, aFrames) |
401 | | , mChannels(aChannels) |
402 | | , mChannelMap(aChannelMap) |
403 | | , mRate(aRate) |
404 | | , mAudioData(std::move(aData)) |
405 | 0 | { |
406 | 0 | } |
407 | | |
408 | | static const Type sType = AUDIO_DATA; |
409 | | static const char* sTypeName; |
410 | | |
411 | | // Creates a new AudioData identical to aOther, but with a different |
412 | | // specified timestamp and duration. All data from aOther is copied |
413 | | // into the new AudioData but the audio data which is transferred. |
414 | | // After such call, the original aOther is unusable. |
415 | | static already_AddRefed<AudioData> |
416 | | TransferAndUpdateTimestampAndDuration(AudioData* aOther, |
417 | | const media::TimeUnit& aTimestamp, |
418 | | const media::TimeUnit& aDuration); |
419 | | |
420 | | size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const; |
421 | | |
422 | | // If mAudioBuffer is null, creates it from mAudioData. |
423 | | void EnsureAudioBuffer(); |
424 | | |
425 | | // To check whether mAudioData has audible signal, it's used to distinguish |
426 | | // the audiable data and silent data. |
427 | | bool IsAudible() const; |
428 | | |
429 | | const uint32_t mChannels; |
430 | | // The AudioConfig::ChannelLayout map. Channels are ordered as per SMPTE |
431 | | // definition. A value of UNKNOWN_MAP indicates unknown layout. |
432 | | // ChannelMap is an unsigned bitmap compatible with Windows' WAVE and FFmpeg |
433 | | // channel map. |
434 | | const AudioConfig::ChannelLayout::ChannelMap mChannelMap; |
435 | | const uint32_t mRate; |
436 | | // At least one of mAudioBuffer/mAudioData must be non-null. |
437 | | // mChannels channels, each with mFrames frames |
438 | | RefPtr<SharedBuffer> mAudioBuffer; |
439 | | // mFrames frames, each with mChannels values |
440 | | AlignedAudioBuffer mAudioData; |
441 | | |
442 | | protected: |
443 | 0 | ~AudioData() { } |
444 | | }; |
445 | | |
446 | | namespace layers { |
447 | | class TextureClient; |
448 | | class PlanarYCbCrImage; |
449 | | } // namespace layers |
450 | | |
451 | | class VideoInfo; |
452 | | |
453 | | // Holds a decoded video frame, in YCbCr format. These are queued in the reader. |
454 | | class VideoData : public MediaData |
455 | | { |
456 | | public: |
457 | | typedef gfx::IntRect IntRect; |
458 | | typedef gfx::IntSize IntSize; |
459 | | typedef layers::ImageContainer ImageContainer; |
460 | | typedef layers::Image Image; |
461 | | typedef layers::PlanarYCbCrImage PlanarYCbCrImage; |
462 | | |
463 | | static const Type sType = VIDEO_DATA; |
464 | | static const char* sTypeName; |
465 | | |
466 | | // YCbCr data obtained from decoding the video. The index's are: |
467 | | // 0 = Y |
468 | | // 1 = Cb |
469 | | // 2 = Cr |
470 | | struct YCbCrBuffer |
471 | | { |
472 | | struct Plane |
473 | | { |
474 | | uint8_t* mData; |
475 | | uint32_t mWidth; |
476 | | uint32_t mHeight; |
477 | | uint32_t mStride; |
478 | | uint32_t mOffset; |
479 | | uint32_t mSkip; |
480 | | }; |
481 | | |
482 | | Plane mPlanes[3]; |
483 | | YUVColorSpace mYUVColorSpace = YUVColorSpace::BT601; |
484 | | uint32_t mBitDepth = 8; |
485 | | }; |
486 | | |
487 | | class Listener |
488 | | { |
489 | | public: |
490 | | virtual void OnSentToCompositor() = 0; |
491 | | virtual ~Listener() { } |
492 | | }; |
493 | | |
494 | | // Constructs a VideoData object. If aImage is nullptr, creates a new Image |
495 | | // holding a copy of the YCbCr data passed in aBuffer. If aImage is not |
496 | | // nullptr, it's stored as the underlying video image and aBuffer is assumed |
497 | | // to point to memory within aImage so no copy is made. aTimecode is a codec |
498 | | // specific number representing the timestamp of the frame of video data. |
499 | | // Returns nsnull if an error occurs. This may indicate that memory couldn't |
500 | | // be allocated to create the VideoData object, or it may indicate some |
501 | | // problem with the input data (e.g. negative stride). |
502 | | |
503 | | |
504 | | // Creates a new VideoData containing a deep copy of aBuffer. May use |
505 | | // aContainer to allocate an Image to hold the copied data. |
506 | | static already_AddRefed<VideoData> CreateAndCopyData( |
507 | | const VideoInfo& aInfo, |
508 | | ImageContainer* aContainer, |
509 | | int64_t aOffset, |
510 | | const media::TimeUnit& aTime, |
511 | | const media::TimeUnit& aDuration, |
512 | | const YCbCrBuffer& aBuffer, |
513 | | bool aKeyframe, |
514 | | const media::TimeUnit& aTimecode, |
515 | | const IntRect& aPicture, |
516 | | layers::KnowsCompositor* aAllocator = nullptr); |
517 | | |
518 | | static already_AddRefed<VideoData> CreateAndCopyData( |
519 | | const VideoInfo& aInfo, |
520 | | ImageContainer* aContainer, |
521 | | int64_t aOffset, |
522 | | const media::TimeUnit& aTime, |
523 | | const media::TimeUnit& aDuration, |
524 | | const YCbCrBuffer& aBuffer, |
525 | | const YCbCrBuffer::Plane& aAlphaPlane, |
526 | | bool aKeyframe, |
527 | | const media::TimeUnit& aTimecode, |
528 | | const IntRect& aPicture); |
529 | | |
530 | | static already_AddRefed<VideoData> CreateFromImage( |
531 | | const IntSize& aDisplay, |
532 | | int64_t aOffset, |
533 | | const media::TimeUnit& aTime, |
534 | | const media::TimeUnit& aDuration, |
535 | | const RefPtr<Image>& aImage, |
536 | | bool aKeyframe, |
537 | | const media::TimeUnit& aTimecode); |
538 | | |
539 | | // Initialize PlanarYCbCrImage. Only When aCopyData is true, |
540 | | // video data is copied to PlanarYCbCrImage. |
541 | | static bool SetVideoDataToImage(PlanarYCbCrImage* aVideoImage, |
542 | | const VideoInfo& aInfo, |
543 | | const YCbCrBuffer& aBuffer, |
544 | | const IntRect& aPicture, |
545 | | bool aCopyData); |
546 | | |
547 | | size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const; |
548 | | |
549 | | // Dimensions at which to display the video frame. The picture region |
550 | | // will be scaled to this size. This is should be the picture region's |
551 | | // dimensions scaled with respect to its aspect ratio. |
552 | | const IntSize mDisplay; |
553 | | |
554 | | // This frame's image. |
555 | | RefPtr<Image> mImage; |
556 | | |
557 | | int32_t mFrameID; |
558 | | |
559 | | VideoData(int64_t aOffset, |
560 | | const media::TimeUnit& aTime, |
561 | | const media::TimeUnit& aDuration, |
562 | | bool aKeyframe, |
563 | | const media::TimeUnit& aTimecode, |
564 | | IntSize aDisplay, |
565 | | uint32_t aFrameID); |
566 | | |
567 | | void SetListener(UniquePtr<Listener> aListener); |
568 | | void MarkSentToCompositor(); |
569 | | bool IsSentToCompositor() { return mSentToCompositor; } |
570 | | |
571 | | void UpdateDuration(const media::TimeUnit& aDuration); |
572 | | void UpdateTimestamp(const media::TimeUnit& aTimestamp); |
573 | | |
574 | | void SetNextKeyFrameTime(const media::TimeUnit& aTime) |
575 | 0 | { |
576 | 0 | mNextKeyFrameTime = aTime; |
577 | 0 | } |
578 | | |
579 | | const media::TimeUnit& NextKeyFrameTime() const |
580 | 0 | { |
581 | 0 | return mNextKeyFrameTime; |
582 | 0 | } |
583 | | |
584 | | protected: |
585 | | ~VideoData(); |
586 | | |
587 | | bool mSentToCompositor; |
588 | | UniquePtr<Listener> mListener; |
589 | | media::TimeUnit mNextKeyFrameTime; |
590 | | }; |
591 | | |
592 | | class CryptoTrack |
593 | | { |
594 | | public: |
595 | | CryptoTrack() : mValid(false), mMode(0), mIVSize(0) { } |
596 | | bool mValid; |
597 | | int32_t mMode; |
598 | | int32_t mIVSize; |
599 | | nsTArray<uint8_t> mKeyId; |
600 | | }; |
601 | | |
602 | | class CryptoSample : public CryptoTrack |
603 | | { |
604 | | public: |
605 | | nsTArray<uint16_t> mPlainSizes; |
606 | | nsTArray<uint32_t> mEncryptedSizes; |
607 | | nsTArray<uint8_t> mIV; |
608 | | nsTArray<nsTArray<uint8_t>> mInitDatas; |
609 | | nsString mInitDataType; |
610 | | }; |
611 | | |
612 | | // MediaRawData is a MediaData container used to store demuxed, still compressed |
613 | | // samples. |
614 | | // Use MediaRawData::CreateWriter() to obtain a MediaRawDataWriter object that |
615 | | // provides methods to modify and manipulate the data. |
616 | | // Memory allocations are fallible. Methods return a boolean indicating if |
617 | | // memory allocations were successful. Return values should always be checked. |
618 | | // MediaRawData::mData will be nullptr if no memory has been allocated or if |
619 | | // an error occurred during construction. |
620 | | // Existing data is only ever modified if new memory allocation has succeeded |
621 | | // and preserved if not. |
622 | | // |
623 | | // The memory referenced by mData will always be 32 bytes aligned and the |
624 | | // underlying buffer will always have a size such that 32 bytes blocks can be |
625 | | // used to read the content, regardless of the mSize value. Buffer is zeroed |
626 | | // on creation. |
627 | | // |
628 | | // Typical usage: create new MediaRawData; create the associated |
629 | | // MediaRawDataWriter, call SetSize() to allocate memory, write to mData, |
630 | | // up to mSize bytes. |
631 | | |
632 | | class MediaRawData; |
633 | | |
634 | | class MediaRawDataWriter |
635 | | { |
636 | | public: |
637 | | // Pointer to data or null if not-yet allocated |
638 | | uint8_t* Data(); |
639 | | // Writeable size of buffer. |
640 | | size_t Size(); |
641 | | // Writeable reference to MediaRawData::mCryptoInternal |
642 | | CryptoSample& mCrypto; |
643 | | |
644 | | // Data manipulation methods. mData and mSize may be updated accordingly. |
645 | | |
646 | | // Set size of buffer, allocating memory as required. |
647 | | // If size is increased, new buffer area is filled with 0. |
648 | | MOZ_MUST_USE bool SetSize(size_t aSize); |
649 | | // Add aData at the beginning of buffer. |
650 | | MOZ_MUST_USE bool Prepend(const uint8_t* aData, size_t aSize); |
651 | | // Replace current content with aData. |
652 | | MOZ_MUST_USE bool Replace(const uint8_t* aData, size_t aSize); |
653 | | // Clear the memory buffer. Will set target mData and mSize to 0. |
654 | | void Clear(); |
655 | | // Remove aSize bytes from the front of the sample. |
656 | | void PopFront(size_t aSize); |
657 | | |
658 | | private: |
659 | | friend class MediaRawData; |
660 | | explicit MediaRawDataWriter(MediaRawData* aMediaRawData); |
661 | | MOZ_MUST_USE bool EnsureSize(size_t aSize); |
662 | | MediaRawData* mTarget; |
663 | | }; |
664 | | |
665 | | class MediaRawData final : public MediaData |
666 | | { |
667 | | public: |
668 | | MediaRawData(); |
669 | | MediaRawData(const uint8_t* aData, size_t aSize); |
670 | | MediaRawData(const uint8_t* aData, size_t aSize, |
671 | | const uint8_t* aAlphaData, size_t aAlphaSize); |
672 | | |
673 | | // Pointer to data or null if not-yet allocated |
674 | | const uint8_t* Data() const { return mBuffer.Data(); } |
675 | | // Pointer to alpha data or null if not-yet allocated |
676 | | const uint8_t* AlphaData() const { return mAlphaBuffer.Data(); } |
677 | | // Size of buffer. |
678 | 0 | size_t Size() const { return mBuffer.Length(); } |
679 | | size_t AlphaSize() const { return mAlphaBuffer.Length(); } |
680 | | size_t ComputedSizeOfIncludingThis() const |
681 | | { |
682 | | return sizeof(*this) |
683 | | + mBuffer.ComputedSizeOfExcludingThis() |
684 | | + mAlphaBuffer.ComputedSizeOfExcludingThis(); |
685 | | } |
686 | | // Access the buffer as a Span. |
687 | | operator Span<const uint8_t>() { return MakeSpan(Data(), Size()); } |
688 | | |
689 | | const CryptoSample& mCrypto; |
690 | | RefPtr<MediaByteBuffer> mExtraData; |
691 | | |
692 | | // Used by the Vorbis decoder and Ogg demuxer. |
693 | | // Indicates that this is the last packet of the stream. |
694 | | bool mEOS = false; |
695 | | |
696 | | // Indicate to the audio decoder that mDiscardPadding frames should be |
697 | | // trimmed. |
698 | | uint32_t mDiscardPadding = 0; |
699 | | |
700 | | RefPtr<TrackInfoSharedPtr> mTrackInfo; |
701 | | |
702 | | // Return a deep copy or nullptr if out of memory. |
703 | | already_AddRefed<MediaRawData> Clone() const; |
704 | | // Create a MediaRawDataWriter for this MediaRawData. The writer is not |
705 | | // thread-safe. |
706 | | UniquePtr<MediaRawDataWriter> CreateWriter(); |
707 | | size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const; |
708 | | |
709 | | protected: |
710 | | ~MediaRawData(); |
711 | | |
712 | | private: |
713 | | friend class MediaRawDataWriter; |
714 | | AlignedByteBuffer mBuffer; |
715 | | AlignedByteBuffer mAlphaBuffer; |
716 | | CryptoSample mCryptoInternal; |
717 | | MediaRawData(const MediaRawData&); // Not implemented |
718 | | }; |
719 | | |
720 | | // MediaByteBuffer is a ref counted infallible TArray. |
721 | | class MediaByteBuffer : public nsTArray<uint8_t> |
722 | | { |
723 | | NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaByteBuffer); |
724 | | MediaByteBuffer() = default; |
725 | | explicit MediaByteBuffer(size_t aCapacity) : nsTArray<uint8_t>(aCapacity) { } |
726 | | |
727 | | private: |
728 | | ~MediaByteBuffer() { } |
729 | | }; |
730 | | |
731 | | } // namespace mozilla |
732 | | |
733 | | #endif // MediaData_h |