content/media/VideoUtils.cpp

Fri, 16 Jan 2015 04:50:19 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 04:50:19 +0100
branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
permissions
-rw-r--r--

Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include "VideoUtils.h"
     6 #include "MediaResource.h"
     7 #include "mozilla/dom/TimeRanges.h"
     8 #include "nsMathUtils.h"
     9 #include "nsSize.h"
    10 #include "VorbisUtils.h"
    11 #include "ImageContainer.h"
    13 #include <stdint.h>
    15 namespace mozilla {
    17 using layers::PlanarYCbCrImage;
    19 // Converts from number of audio frames to microseconds, given the specified
    20 // audio rate.
    21 CheckedInt64 FramesToUsecs(int64_t aFrames, uint32_t aRate) {
    22   return (CheckedInt64(aFrames) * USECS_PER_S) / aRate;
    23 }
    25 // Converts from microseconds to number of audio frames, given the specified
    26 // audio rate.
    27 CheckedInt64 UsecsToFrames(int64_t aUsecs, uint32_t aRate) {
    28   return (CheckedInt64(aUsecs) * aRate) / USECS_PER_S;
    29 }
    31 nsresult SecondsToUsecs(double aSeconds, int64_t& aOutUsecs) {
    32   if (aSeconds * double(USECS_PER_S) > INT64_MAX) {
    33     return NS_ERROR_FAILURE;
    34   }
    35   aOutUsecs = int64_t(aSeconds * double(USECS_PER_S));
    36   return NS_OK;
    37 }
    39 static int32_t ConditionDimension(float aValue)
    40 {
    41   // This will exclude NaNs and too-big values.
    42   if (aValue > 1.0 && aValue <= INT32_MAX)
    43     return int32_t(NS_round(aValue));
    44   return 0;
    45 }
    47 void ScaleDisplayByAspectRatio(nsIntSize& aDisplay, float aAspectRatio)
    48 {
    49   if (aAspectRatio > 1.0) {
    50     // Increase the intrinsic width
    51     aDisplay.width = ConditionDimension(aAspectRatio * aDisplay.width);
    52   } else {
    53     // Increase the intrinsic height
    54     aDisplay.height = ConditionDimension(aDisplay.height / aAspectRatio);
    55   }
    56 }
    58 static int64_t BytesToTime(int64_t offset, int64_t length, int64_t durationUs) {
    59   NS_ASSERTION(length > 0, "Must have positive length");
    60   double r = double(offset) / double(length);
    61   if (r > 1.0)
    62     r = 1.0;
    63   return int64_t(double(durationUs) * r);
    64 }
    66 void GetEstimatedBufferedTimeRanges(mozilla::MediaResource* aStream,
    67                                     int64_t aDurationUsecs,
    68                                     mozilla::dom::TimeRanges* aOutBuffered)
    69 {
    70   // Nothing to cache if the media takes 0us to play.
    71   if (aDurationUsecs <= 0 || !aStream || !aOutBuffered)
    72     return;
    74   // Special case completely cached files.  This also handles local files.
    75   if (aStream->IsDataCachedToEndOfResource(0)) {
    76     aOutBuffered->Add(0, double(aDurationUsecs) / USECS_PER_S);
    77     return;
    78   }
    80   int64_t totalBytes = aStream->GetLength();
    82   // If we can't determine the total size, pretend that we have nothing
    83   // buffered. This will put us in a state of eternally-low-on-undecoded-data
    84   // which is not great, but about the best we can do.
    85   if (totalBytes <= 0)
    86     return;
    88   int64_t startOffset = aStream->GetNextCachedData(0);
    89   while (startOffset >= 0) {
    90     int64_t endOffset = aStream->GetCachedDataEnd(startOffset);
    91     // Bytes [startOffset..endOffset] are cached.
    92     NS_ASSERTION(startOffset >= 0, "Integer underflow in GetBuffered");
    93     NS_ASSERTION(endOffset >= 0, "Integer underflow in GetBuffered");
    95     int64_t startUs = BytesToTime(startOffset, totalBytes, aDurationUsecs);
    96     int64_t endUs = BytesToTime(endOffset, totalBytes, aDurationUsecs);
    97     if (startUs != endUs) {
    98       aOutBuffered->Add(double(startUs) / USECS_PER_S,
    99                         double(endUs) / USECS_PER_S);
   100     }
   101     startOffset = aStream->GetNextCachedData(endOffset);
   102   }
   103   return;
   104 }
   106 int DownmixAudioToStereo(mozilla::AudioDataValue* buffer,
   107                          int channels, uint32_t frames)
   108 {
   109   int outChannels;
   110   outChannels = 2;
   111 #ifdef MOZ_SAMPLE_TYPE_FLOAT32
   112   // Downmix matrix. Per-row normalization 1 for rows 3,4 and 2 for rows 5-8.
   113   static const float dmatrix[6][8][2]= {
   114       /*3*/{{0.5858f,0},{0.4142f,0.4142f},{0,     0.5858f}},
   115       /*4*/{{0.4226f,0},{0,      0.4226f},{0.366f,0.2114f},{0.2114f,0.366f}},
   116       /*5*/{{0.6510f,0},{0.4600f,0.4600f},{0,     0.6510f},{0.5636f,0.3254f},{0.3254f,0.5636f}},
   117       /*6*/{{0.5290f,0},{0.3741f,0.3741f},{0,     0.5290f},{0.4582f,0.2645f},{0.2645f,0.4582f},{0.3741f,0.3741f}},
   118       /*7*/{{0.4553f,0},{0.3220f,0.3220f},{0,     0.4553f},{0.3943f,0.2277f},{0.2277f,0.3943f},{0.2788f,0.2788f},{0.3220f,0.3220f}},
   119       /*8*/{{0.3886f,0},{0.2748f,0.2748f},{0,     0.3886f},{0.3366f,0.1943f},{0.1943f,0.3366f},{0.3366f,0.1943f},{0.1943f,0.3366f},{0.2748f,0.2748f}},
   120   };
   121   // Re-write the buffer with downmixed data
   122   for (uint32_t i = 0; i < frames; i++) {
   123     float sampL = 0.0;
   124     float sampR = 0.0;
   125     for (int j = 0; j < channels; j++) {
   126       sampL+=buffer[i*channels+j]*dmatrix[channels-3][j][0];
   127       sampR+=buffer[i*channels+j]*dmatrix[channels-3][j][1];
   128     }
   129     buffer[i*outChannels]=sampL;
   130     buffer[i*outChannels+1]=sampR;
   131   }
   132 #else
   133   // Downmix matrix. Per-row normalization 1 for rows 3,4 and 2 for rows 5-8.
   134   // Coefficients in Q14.
   135   static const int16_t dmatrix[6][8][2]= {
   136       /*3*/{{9598, 0},{6786,6786},{0,   9598}},
   137       /*4*/{{6925, 0},{0,   6925},{5997,3462},{3462,5997}},
   138       /*5*/{{10663,0},{7540,7540},{0,  10663},{9234,5331},{5331,9234}},
   139       /*6*/{{8668, 0},{6129,6129},{0,   8668},{7507,4335},{4335,7507},{6129,6129}},
   140       /*7*/{{7459, 0},{5275,5275},{0,   7459},{6460,3731},{3731,6460},{4568,4568},{5275,5275}},
   141       /*8*/{{6368, 0},{4502,4502},{0,   6368},{5514,3184},{3184,5514},{5514,3184},{3184,5514},{4502,4502}}
   142   };
   143   // Re-write the buffer with downmixed data
   144   for (uint32_t i = 0; i < frames; i++) {
   145     int32_t sampL = 0;
   146     int32_t sampR = 0;
   147     for (int j = 0; j < channels; j++) {
   148       sampL+=buffer[i*channels+j]*dmatrix[channels-3][j][0];
   149       sampR+=buffer[i*channels+j]*dmatrix[channels-3][j][1];
   150     }
   151     sampL = (sampL + 8192)>>14;
   152     buffer[i*outChannels] = static_cast<mozilla::AudioDataValue>(MOZ_CLIP_TO_15(sampL));
   153     sampR = (sampR + 8192)>>14;
   154     buffer[i*outChannels+1] = static_cast<mozilla::AudioDataValue>(MOZ_CLIP_TO_15(sampR));
   155   }
   156 #endif
   157   return outChannels;
   158 }
   160 bool
   161 IsVideoContentType(const nsCString& aContentType)
   162 {
   163   NS_NAMED_LITERAL_CSTRING(video, "video");
   164   if (FindInReadable(video, aContentType)) {
   165     return true;
   166   }
   167   return false;
   168 }
   170 bool
   171 IsValidVideoRegion(const nsIntSize& aFrame, const nsIntRect& aPicture,
   172                    const nsIntSize& aDisplay)
   173 {
   174   return
   175     aFrame.width <= PlanarYCbCrImage::MAX_DIMENSION &&
   176     aFrame.height <= PlanarYCbCrImage::MAX_DIMENSION &&
   177     aFrame.width * aFrame.height <= MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
   178     aFrame.width * aFrame.height != 0 &&
   179     aPicture.width <= PlanarYCbCrImage::MAX_DIMENSION &&
   180     aPicture.x < PlanarYCbCrImage::MAX_DIMENSION &&
   181     aPicture.x + aPicture.width < PlanarYCbCrImage::MAX_DIMENSION &&
   182     aPicture.height <= PlanarYCbCrImage::MAX_DIMENSION &&
   183     aPicture.y < PlanarYCbCrImage::MAX_DIMENSION &&
   184     aPicture.y + aPicture.height < PlanarYCbCrImage::MAX_DIMENSION &&
   185     aPicture.width * aPicture.height <= MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
   186     aPicture.width * aPicture.height != 0 &&
   187     aDisplay.width <= PlanarYCbCrImage::MAX_DIMENSION &&
   188     aDisplay.height <= PlanarYCbCrImage::MAX_DIMENSION &&
   189     aDisplay.width * aDisplay.height <= MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
   190     aDisplay.width * aDisplay.height != 0;
   191 }
   193 } // end namespace mozilla

mercurial