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