content/media/MediaSegment.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     4  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #ifndef MOZILLA_MEDIASEGMENT_H_
     7 #define MOZILLA_MEDIASEGMENT_H_
     9 #include "nsTArray.h"
    10 #ifdef MOZILLA_INTERNAL_API
    11 #include "mozilla/TimeStamp.h"
    12 #endif
    13 #include <algorithm>
    14 #include "Latency.h"
    16 namespace mozilla {
    18 /**
    19  * We represent media times in 64-bit fixed point. So 1 MediaTime is
    20  * 1/(2^MEDIA_TIME_FRAC_BITS) seconds.
    21  */
    22 typedef int64_t MediaTime;
    23 const int64_t MEDIA_TIME_FRAC_BITS = 20;
    24 const int64_t MEDIA_TIME_MAX = INT64_MAX;
    26 inline MediaTime MillisecondsToMediaTime(int32_t aMS)
    27 {
    28   return (MediaTime(aMS) << MEDIA_TIME_FRAC_BITS)/1000;
    29 }
    31 inline MediaTime SecondsToMediaTime(double aS)
    32 {
    33   NS_ASSERTION(aS <= (MEDIA_TIME_MAX >> MEDIA_TIME_FRAC_BITS),
    34                "Out of range");
    35   return MediaTime(aS * (1 << MEDIA_TIME_FRAC_BITS));
    36 }
    38 inline double MediaTimeToSeconds(MediaTime aTime)
    39 {
    40   return aTime*(1.0/(1 << MEDIA_TIME_FRAC_BITS));
    41 }
    43 inline int64_t MediaTimeToMicroseconds(MediaTime aTime)
    44 {
    45   return aTime*(1000000.0/(1 << MEDIA_TIME_FRAC_BITS));
    46 }
    48 /**
    49  * A number of ticks at a rate determined by some underlying track (e.g.
    50  * audio sample rate). We want to make sure that multiplying TrackTicks by
    51  * 2^MEDIA_TIME_FRAC_BITS doesn't overflow, so we set its max accordingly.
    52  */
    53 typedef int64_t TrackTicks;
    54 const int64_t TRACK_TICKS_MAX = INT64_MAX >> MEDIA_TIME_FRAC_BITS;
    56 /**
    57  * A MediaSegment is a chunk of media data sequential in time. Different
    58  * types of data have different subclasses of MediaSegment, all inheriting
    59  * from MediaSegmentBase.
    60  * All MediaSegment data is timed using TrackTicks. The actual tick rate
    61  * is defined on a per-track basis. For some track types, this can be
    62  * a fixed constant for all tracks of that type (e.g. 1MHz for video).
    63  *
    64  * Each media segment defines a concept of "null media data" (e.g. silence
    65  * for audio or "no video frame" for video), which can be efficiently
    66  * represented. This is used for padding.
    67  */
    68 class MediaSegment {
    69 public:
    70   virtual ~MediaSegment()
    71   {
    72     MOZ_COUNT_DTOR(MediaSegment);
    73   }
    75   enum Type {
    76     AUDIO,
    77     VIDEO,
    78     TYPE_COUNT
    79   };
    81   /**
    82    * Gets the total duration of the segment.
    83    */
    84   TrackTicks GetDuration() const { return mDuration; }
    85   Type GetType() const { return mType; }
    87   /**
    88    * Create a MediaSegment of the same type.
    89    */
    90   virtual MediaSegment* CreateEmptyClone() const = 0;
    91   /**
    92    * Moves contents of aSource to the end of this segment.
    93    */
    94   virtual void AppendFrom(MediaSegment* aSource) = 0;
    95   /**
    96    * Append a slice of aSource to this segment.
    97    */
    98   virtual void AppendSlice(const MediaSegment& aSource,
    99                            TrackTicks aStart, TrackTicks aEnd) = 0;
   100   /**
   101    * Replace all contents up to aDuration with null data.
   102    */
   103   virtual void ForgetUpTo(TrackTicks aDuration) = 0;
   104   /**
   105    * Insert aDuration of null data at the start of the segment.
   106    */
   107   virtual void InsertNullDataAtStart(TrackTicks aDuration) = 0;
   108   /**
   109    * Insert aDuration of null data at the end of the segment.
   110    */
   111   virtual void AppendNullData(TrackTicks aDuration) = 0;
   112   /**
   113    * Replace contents with disabled data of the same duration
   114    */
   115   virtual void ReplaceWithDisabled() = 0;
   116   /**
   117    * Remove all contents, setting duration to 0.
   118    */
   119   virtual void Clear() = 0;
   121   virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
   122   {
   123     return 0;
   124   }
   126   virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
   127   {
   128     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   129   }
   131 protected:
   132   MediaSegment(Type aType) : mDuration(0), mType(aType)
   133   {
   134     MOZ_COUNT_CTOR(MediaSegment);
   135   }
   137   TrackTicks mDuration; // total of mDurations of all chunks
   138   Type mType;
   139 };
   141 /**
   142  * C is the implementation class subclassed from MediaSegmentBase.
   143  * C must contain a Chunk class.
   144  */
   145 template <class C, class Chunk> class MediaSegmentBase : public MediaSegment {
   146 public:
   147   virtual MediaSegment* CreateEmptyClone() const
   148   {
   149     return new C();
   150   }
   151   virtual void AppendFrom(MediaSegment* aSource)
   152   {
   153     NS_ASSERTION(aSource->GetType() == C::StaticType(), "Wrong type");
   154     AppendFromInternal(static_cast<C*>(aSource));
   155   }
   156   void AppendFrom(C* aSource)
   157   {
   158     AppendFromInternal(aSource);
   159   }
   160   virtual void AppendSlice(const MediaSegment& aSource,
   161                            TrackTicks aStart, TrackTicks aEnd)
   162   {
   163     NS_ASSERTION(aSource.GetType() == C::StaticType(), "Wrong type");
   164     AppendSliceInternal(static_cast<const C&>(aSource), aStart, aEnd);
   165   }
   166   void AppendSlice(const C& aOther, TrackTicks aStart, TrackTicks aEnd)
   167   {
   168     AppendSliceInternal(aOther, aStart, aEnd);
   169   }
   170   /**
   171    * Replace the first aDuration ticks with null media data, because the data
   172    * will not be required again.
   173    */
   174   virtual void ForgetUpTo(TrackTicks aDuration)
   175   {
   176     if (mChunks.IsEmpty() || aDuration <= 0) {
   177       return;
   178     }
   179     if (mChunks[0].IsNull()) {
   180       TrackTicks extraToForget = std::min(aDuration, mDuration) - mChunks[0].GetDuration();
   181       if (extraToForget > 0) {
   182         RemoveLeading(extraToForget, 1);
   183         mChunks[0].mDuration += extraToForget;
   184         mDuration += extraToForget;
   185       }
   186       return;
   187     }
   188     RemoveLeading(aDuration, 0);
   189     mChunks.InsertElementAt(0)->SetNull(aDuration);
   190     mDuration += aDuration;
   191   }
   192   virtual void InsertNullDataAtStart(TrackTicks aDuration)
   193   {
   194     if (aDuration <= 0) {
   195       return;
   196     }
   197     if (!mChunks.IsEmpty() && mChunks[0].IsNull()) {
   198       mChunks[0].mDuration += aDuration;
   199     } else {
   200       mChunks.InsertElementAt(0)->SetNull(aDuration);
   201     }
   202 #ifdef MOZILLA_INTERNAL_API
   203     mChunks[0].mTimeStamp = mozilla::TimeStamp::Now();
   204 #endif
   205     mDuration += aDuration;
   206   }
   207   virtual void AppendNullData(TrackTicks aDuration)
   208   {
   209     if (aDuration <= 0) {
   210       return;
   211     }
   212     if (!mChunks.IsEmpty() && mChunks[mChunks.Length() - 1].IsNull()) {
   213       mChunks[mChunks.Length() - 1].mDuration += aDuration;
   214     } else {
   215       mChunks.AppendElement()->SetNull(aDuration);
   216     }
   217     mDuration += aDuration;
   218   }
   219   virtual void ReplaceWithDisabled()
   220   {
   221     if (GetType() != AUDIO) {
   222       MOZ_CRASH("Disabling unknown segment type");
   223     }
   224     TrackTicks duration = GetDuration();
   225     Clear();
   226     AppendNullData(duration);
   227   }
   228   virtual void Clear()
   229   {
   230     mDuration = 0;
   231     mChunks.Clear();
   232   }
   234   class ChunkIterator {
   235   public:
   236     ChunkIterator(MediaSegmentBase<C, Chunk>& aSegment)
   237       : mSegment(aSegment), mIndex(0) {}
   238     bool IsEnded() { return mIndex >= mSegment.mChunks.Length(); }
   239     void Next() { ++mIndex; }
   240     Chunk& operator*() { return mSegment.mChunks[mIndex]; }
   241     Chunk* operator->() { return &mSegment.mChunks[mIndex]; }
   242   private:
   243     MediaSegmentBase<C, Chunk>& mSegment;
   244     uint32_t mIndex;
   245   };
   247   void RemoveLeading(TrackTicks aDuration)
   248   {
   249     RemoveLeading(aDuration, 0);
   250   }
   252 #ifdef MOZILLA_INTERNAL_API
   253   void GetStartTime(TimeStamp &aTime) {
   254     aTime = mChunks[0].mTimeStamp;
   255   }
   256 #endif
   258   virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE
   259   {
   260     size_t amount = mChunks.SizeOfExcludingThis(aMallocSizeOf);
   261     for (size_t i = 0; i < mChunks.Length(); i++) {
   262       amount += mChunks[i].SizeOfExcludingThisIfUnshared(aMallocSizeOf);
   263     }
   264     return amount;
   265   }
   267   virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE
   268   {
   269     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   270   }
   272 protected:
   273   MediaSegmentBase(Type aType) : MediaSegment(aType) {}
   275   /**
   276    * Appends the contents of aSource to this segment, clearing aSource.
   277    */
   278   void AppendFromInternal(MediaSegmentBase<C, Chunk>* aSource)
   279   {
   280     MOZ_ASSERT(aSource->mDuration >= 0);
   281     mDuration += aSource->mDuration;
   282     aSource->mDuration = 0;
   283     if (!mChunks.IsEmpty() && !aSource->mChunks.IsEmpty() &&
   284         mChunks[mChunks.Length() - 1].CanCombineWithFollowing(aSource->mChunks[0])) {
   285       mChunks[mChunks.Length() - 1].mDuration += aSource->mChunks[0].mDuration;
   286       aSource->mChunks.RemoveElementAt(0);
   287     }
   288     mChunks.MoveElementsFrom(aSource->mChunks);
   289   }
   291   void AppendSliceInternal(const MediaSegmentBase<C, Chunk>& aSource,
   292                            TrackTicks aStart, TrackTicks aEnd)
   293   {
   294     MOZ_ASSERT(aStart <= aEnd, "Endpoints inverted");
   295     NS_WARN_IF_FALSE(aStart >= 0 && aEnd <= aSource.mDuration, "Slice out of range");
   296     mDuration += aEnd - aStart;
   297     TrackTicks offset = 0;
   298     for (uint32_t i = 0; i < aSource.mChunks.Length() && offset < aEnd; ++i) {
   299       const Chunk& c = aSource.mChunks[i];
   300       TrackTicks start = std::max(aStart, offset);
   301       TrackTicks nextOffset = offset + c.GetDuration();
   302       TrackTicks end = std::min(aEnd, nextOffset);
   303       if (start < end) {
   304         mChunks.AppendElement(c)->SliceTo(start - offset, end - offset);
   305       }
   306       offset = nextOffset;
   307     }
   308   }
   310   Chunk* AppendChunk(TrackTicks aDuration)
   311   {
   312     MOZ_ASSERT(aDuration >= 0);
   313     Chunk* c = mChunks.AppendElement();
   314     c->mDuration = aDuration;
   315     mDuration += aDuration;
   316     return c;
   317   }
   319   Chunk* FindChunkContaining(TrackTicks aOffset, TrackTicks* aStart = nullptr)
   320   {
   321     if (aOffset < 0) {
   322       return nullptr;
   323     }
   324     TrackTicks offset = 0;
   325     for (uint32_t i = 0; i < mChunks.Length(); ++i) {
   326       Chunk& c = mChunks[i];
   327       TrackTicks nextOffset = offset + c.GetDuration();
   328       if (aOffset < nextOffset) {
   329         if (aStart) {
   330           *aStart = offset;
   331         }
   332         return &c;
   333       }
   334       offset = nextOffset;
   335     }
   336     return nullptr;
   337   }
   339   Chunk* GetLastChunk()
   340   {
   341     if (mChunks.IsEmpty()) {
   342       return nullptr;
   343     }
   344     return &mChunks[mChunks.Length() - 1];
   345   }
   347   void RemoveLeading(TrackTicks aDuration, uint32_t aStartIndex)
   348   {
   349     NS_ASSERTION(aDuration >= 0, "Can't remove negative duration");
   350     TrackTicks t = aDuration;
   351     uint32_t chunksToRemove = 0;
   352     for (uint32_t i = aStartIndex; i < mChunks.Length() && t > 0; ++i) {
   353       Chunk* c = &mChunks[i];
   354       if (c->GetDuration() > t) {
   355         c->SliceTo(t, c->GetDuration());
   356         t = 0;
   357         break;
   358       }
   359       t -= c->GetDuration();
   360       chunksToRemove = i + 1 - aStartIndex;
   361     }
   362     mChunks.RemoveElementsAt(aStartIndex, chunksToRemove);
   363     mDuration -= aDuration - t;
   364   }
   366   nsTArray<Chunk> mChunks;
   367 #ifdef MOZILLA_INTERNAL_API
   368   mozilla::TimeStamp mTimeStamp;
   369 #endif
   370 };
   372 }
   374 #endif /* MOZILLA_MEDIASEGMENT_H_ */

mercurial