content/media/VideoUtils.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/media/VideoUtils.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,193 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +#include "VideoUtils.h"
     1.9 +#include "MediaResource.h"
    1.10 +#include "mozilla/dom/TimeRanges.h"
    1.11 +#include "nsMathUtils.h"
    1.12 +#include "nsSize.h"
    1.13 +#include "VorbisUtils.h"
    1.14 +#include "ImageContainer.h"
    1.15 +
    1.16 +#include <stdint.h>
    1.17 +
    1.18 +namespace mozilla {
    1.19 +
    1.20 +using layers::PlanarYCbCrImage;
    1.21 +
    1.22 +// Converts from number of audio frames to microseconds, given the specified
    1.23 +// audio rate.
    1.24 +CheckedInt64 FramesToUsecs(int64_t aFrames, uint32_t aRate) {
    1.25 +  return (CheckedInt64(aFrames) * USECS_PER_S) / aRate;
    1.26 +}
    1.27 +
    1.28 +// Converts from microseconds to number of audio frames, given the specified
    1.29 +// audio rate.
    1.30 +CheckedInt64 UsecsToFrames(int64_t aUsecs, uint32_t aRate) {
    1.31 +  return (CheckedInt64(aUsecs) * aRate) / USECS_PER_S;
    1.32 +}
    1.33 +
    1.34 +nsresult SecondsToUsecs(double aSeconds, int64_t& aOutUsecs) {
    1.35 +  if (aSeconds * double(USECS_PER_S) > INT64_MAX) {
    1.36 +    return NS_ERROR_FAILURE;
    1.37 +  }
    1.38 +  aOutUsecs = int64_t(aSeconds * double(USECS_PER_S));
    1.39 +  return NS_OK;
    1.40 +}
    1.41 +
    1.42 +static int32_t ConditionDimension(float aValue)
    1.43 +{
    1.44 +  // This will exclude NaNs and too-big values.
    1.45 +  if (aValue > 1.0 && aValue <= INT32_MAX)
    1.46 +    return int32_t(NS_round(aValue));
    1.47 +  return 0;
    1.48 +}
    1.49 +
    1.50 +void ScaleDisplayByAspectRatio(nsIntSize& aDisplay, float aAspectRatio)
    1.51 +{
    1.52 +  if (aAspectRatio > 1.0) {
    1.53 +    // Increase the intrinsic width
    1.54 +    aDisplay.width = ConditionDimension(aAspectRatio * aDisplay.width);
    1.55 +  } else {
    1.56 +    // Increase the intrinsic height
    1.57 +    aDisplay.height = ConditionDimension(aDisplay.height / aAspectRatio);
    1.58 +  }
    1.59 +}
    1.60 +
    1.61 +static int64_t BytesToTime(int64_t offset, int64_t length, int64_t durationUs) {
    1.62 +  NS_ASSERTION(length > 0, "Must have positive length");
    1.63 +  double r = double(offset) / double(length);
    1.64 +  if (r > 1.0)
    1.65 +    r = 1.0;
    1.66 +  return int64_t(double(durationUs) * r);
    1.67 +}
    1.68 +
    1.69 +void GetEstimatedBufferedTimeRanges(mozilla::MediaResource* aStream,
    1.70 +                                    int64_t aDurationUsecs,
    1.71 +                                    mozilla::dom::TimeRanges* aOutBuffered)
    1.72 +{
    1.73 +  // Nothing to cache if the media takes 0us to play.
    1.74 +  if (aDurationUsecs <= 0 || !aStream || !aOutBuffered)
    1.75 +    return;
    1.76 +
    1.77 +  // Special case completely cached files.  This also handles local files.
    1.78 +  if (aStream->IsDataCachedToEndOfResource(0)) {
    1.79 +    aOutBuffered->Add(0, double(aDurationUsecs) / USECS_PER_S);
    1.80 +    return;
    1.81 +  }
    1.82 +
    1.83 +  int64_t totalBytes = aStream->GetLength();
    1.84 +
    1.85 +  // If we can't determine the total size, pretend that we have nothing
    1.86 +  // buffered. This will put us in a state of eternally-low-on-undecoded-data
    1.87 +  // which is not great, but about the best we can do.
    1.88 +  if (totalBytes <= 0)
    1.89 +    return;
    1.90 +
    1.91 +  int64_t startOffset = aStream->GetNextCachedData(0);
    1.92 +  while (startOffset >= 0) {
    1.93 +    int64_t endOffset = aStream->GetCachedDataEnd(startOffset);
    1.94 +    // Bytes [startOffset..endOffset] are cached.
    1.95 +    NS_ASSERTION(startOffset >= 0, "Integer underflow in GetBuffered");
    1.96 +    NS_ASSERTION(endOffset >= 0, "Integer underflow in GetBuffered");
    1.97 +
    1.98 +    int64_t startUs = BytesToTime(startOffset, totalBytes, aDurationUsecs);
    1.99 +    int64_t endUs = BytesToTime(endOffset, totalBytes, aDurationUsecs);
   1.100 +    if (startUs != endUs) {
   1.101 +      aOutBuffered->Add(double(startUs) / USECS_PER_S,
   1.102 +                        double(endUs) / USECS_PER_S);
   1.103 +    }
   1.104 +    startOffset = aStream->GetNextCachedData(endOffset);
   1.105 +  }
   1.106 +  return;
   1.107 +}
   1.108 +
   1.109 +int DownmixAudioToStereo(mozilla::AudioDataValue* buffer,
   1.110 +                         int channels, uint32_t frames)
   1.111 +{
   1.112 +  int outChannels;
   1.113 +  outChannels = 2;
   1.114 +#ifdef MOZ_SAMPLE_TYPE_FLOAT32
   1.115 +  // Downmix matrix. Per-row normalization 1 for rows 3,4 and 2 for rows 5-8.
   1.116 +  static const float dmatrix[6][8][2]= {
   1.117 +      /*3*/{{0.5858f,0},{0.4142f,0.4142f},{0,     0.5858f}},
   1.118 +      /*4*/{{0.4226f,0},{0,      0.4226f},{0.366f,0.2114f},{0.2114f,0.366f}},
   1.119 +      /*5*/{{0.6510f,0},{0.4600f,0.4600f},{0,     0.6510f},{0.5636f,0.3254f},{0.3254f,0.5636f}},
   1.120 +      /*6*/{{0.5290f,0},{0.3741f,0.3741f},{0,     0.5290f},{0.4582f,0.2645f},{0.2645f,0.4582f},{0.3741f,0.3741f}},
   1.121 +      /*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}},
   1.122 +      /*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}},
   1.123 +  };
   1.124 +  // Re-write the buffer with downmixed data
   1.125 +  for (uint32_t i = 0; i < frames; i++) {
   1.126 +    float sampL = 0.0;
   1.127 +    float sampR = 0.0;
   1.128 +    for (int j = 0; j < channels; j++) {
   1.129 +      sampL+=buffer[i*channels+j]*dmatrix[channels-3][j][0];
   1.130 +      sampR+=buffer[i*channels+j]*dmatrix[channels-3][j][1];
   1.131 +    }
   1.132 +    buffer[i*outChannels]=sampL;
   1.133 +    buffer[i*outChannels+1]=sampR;
   1.134 +  }
   1.135 +#else
   1.136 +  // Downmix matrix. Per-row normalization 1 for rows 3,4 and 2 for rows 5-8.
   1.137 +  // Coefficients in Q14.
   1.138 +  static const int16_t dmatrix[6][8][2]= {
   1.139 +      /*3*/{{9598, 0},{6786,6786},{0,   9598}},
   1.140 +      /*4*/{{6925, 0},{0,   6925},{5997,3462},{3462,5997}},
   1.141 +      /*5*/{{10663,0},{7540,7540},{0,  10663},{9234,5331},{5331,9234}},
   1.142 +      /*6*/{{8668, 0},{6129,6129},{0,   8668},{7507,4335},{4335,7507},{6129,6129}},
   1.143 +      /*7*/{{7459, 0},{5275,5275},{0,   7459},{6460,3731},{3731,6460},{4568,4568},{5275,5275}},
   1.144 +      /*8*/{{6368, 0},{4502,4502},{0,   6368},{5514,3184},{3184,5514},{5514,3184},{3184,5514},{4502,4502}}
   1.145 +  };
   1.146 +  // Re-write the buffer with downmixed data
   1.147 +  for (uint32_t i = 0; i < frames; i++) {
   1.148 +    int32_t sampL = 0;
   1.149 +    int32_t sampR = 0;
   1.150 +    for (int j = 0; j < channels; j++) {
   1.151 +      sampL+=buffer[i*channels+j]*dmatrix[channels-3][j][0];
   1.152 +      sampR+=buffer[i*channels+j]*dmatrix[channels-3][j][1];
   1.153 +    }
   1.154 +    sampL = (sampL + 8192)>>14;
   1.155 +    buffer[i*outChannels] = static_cast<mozilla::AudioDataValue>(MOZ_CLIP_TO_15(sampL));
   1.156 +    sampR = (sampR + 8192)>>14;
   1.157 +    buffer[i*outChannels+1] = static_cast<mozilla::AudioDataValue>(MOZ_CLIP_TO_15(sampR));
   1.158 +  }
   1.159 +#endif
   1.160 +  return outChannels;
   1.161 +}
   1.162 +
   1.163 +bool
   1.164 +IsVideoContentType(const nsCString& aContentType)
   1.165 +{
   1.166 +  NS_NAMED_LITERAL_CSTRING(video, "video");
   1.167 +  if (FindInReadable(video, aContentType)) {
   1.168 +    return true;
   1.169 +  }
   1.170 +  return false;
   1.171 +}
   1.172 +
   1.173 +bool
   1.174 +IsValidVideoRegion(const nsIntSize& aFrame, const nsIntRect& aPicture,
   1.175 +                   const nsIntSize& aDisplay)
   1.176 +{
   1.177 +  return
   1.178 +    aFrame.width <= PlanarYCbCrImage::MAX_DIMENSION &&
   1.179 +    aFrame.height <= PlanarYCbCrImage::MAX_DIMENSION &&
   1.180 +    aFrame.width * aFrame.height <= MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
   1.181 +    aFrame.width * aFrame.height != 0 &&
   1.182 +    aPicture.width <= PlanarYCbCrImage::MAX_DIMENSION &&
   1.183 +    aPicture.x < PlanarYCbCrImage::MAX_DIMENSION &&
   1.184 +    aPicture.x + aPicture.width < PlanarYCbCrImage::MAX_DIMENSION &&
   1.185 +    aPicture.height <= PlanarYCbCrImage::MAX_DIMENSION &&
   1.186 +    aPicture.y < PlanarYCbCrImage::MAX_DIMENSION &&
   1.187 +    aPicture.y + aPicture.height < PlanarYCbCrImage::MAX_DIMENSION &&
   1.188 +    aPicture.width * aPicture.height <= MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
   1.189 +    aPicture.width * aPicture.height != 0 &&
   1.190 +    aDisplay.width <= PlanarYCbCrImage::MAX_DIMENSION &&
   1.191 +    aDisplay.height <= PlanarYCbCrImage::MAX_DIMENSION &&
   1.192 +    aDisplay.width * aDisplay.height <= MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
   1.193 +    aDisplay.width * aDisplay.height != 0;
   1.194 +}
   1.195 +
   1.196 +} // end namespace mozilla

mercurial