content/media/MediaData.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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 #include "MediaData.h"
     7 #include "MediaInfo.h"
     8 #ifdef MOZ_OMX_DECODER
     9 #include "GrallocImages.h"
    10 #include "mozilla/layers/TextureClient.h"
    11 #endif
    12 #include "VideoUtils.h"
    13 #include "ImageContainer.h"
    15 #ifdef MOZ_WIDGET_GONK
    16 #include <cutils/properties.h>
    17 #endif
    19 namespace mozilla {
    21 using namespace mozilla::gfx;
    22 using layers::ImageContainer;
    23 using layers::PlanarYCbCrImage;
    24 using layers::PlanarYCbCrData;
    26 void
    27 AudioData::EnsureAudioBuffer()
    28 {
    29   if (mAudioBuffer)
    30     return;
    31   mAudioBuffer = SharedBuffer::Create(mFrames*mChannels*sizeof(AudioDataValue));
    33   AudioDataValue* data = static_cast<AudioDataValue*>(mAudioBuffer->Data());
    34   for (uint32_t i = 0; i < mFrames; ++i) {
    35     for (uint32_t j = 0; j < mChannels; ++j) {
    36       data[j*mFrames + i] = mAudioData[i*mChannels + j];
    37     }
    38   }
    39 }
    41 static bool
    42 ValidatePlane(const VideoData::YCbCrBuffer::Plane& aPlane)
    43 {
    44   return aPlane.mWidth <= PlanarYCbCrImage::MAX_DIMENSION &&
    45          aPlane.mHeight <= PlanarYCbCrImage::MAX_DIMENSION &&
    46          aPlane.mWidth * aPlane.mHeight < MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
    47          aPlane.mStride > 0;
    48 }
    50 #ifdef MOZ_WIDGET_GONK
    51 static bool
    52 IsYV12Format(const VideoData::YCbCrBuffer::Plane& aYPlane,
    53              const VideoData::YCbCrBuffer::Plane& aCbPlane,
    54              const VideoData::YCbCrBuffer::Plane& aCrPlane)
    55 {
    56   return
    57     aYPlane.mWidth % 2 == 0 &&
    58     aYPlane.mHeight % 2 == 0 &&
    59     aYPlane.mWidth / 2 == aCbPlane.mWidth &&
    60     aYPlane.mHeight / 2 == aCbPlane.mHeight &&
    61     aCbPlane.mWidth == aCrPlane.mWidth &&
    62     aCbPlane.mHeight == aCrPlane.mHeight;
    63 }
    65 static bool
    66 IsInEmulator()
    67 {
    68   char propQemu[PROPERTY_VALUE_MAX];
    69   property_get("ro.kernel.qemu", propQemu, "");
    70   return !strncmp(propQemu, "1", 1);
    71 }
    73 #endif
    75 VideoData::VideoData(int64_t aOffset, int64_t aTime, int64_t aDuration, int64_t aTimecode)
    76   : MediaData(VIDEO_FRAME, aOffset, aTime, aDuration),
    77     mTimecode(aTimecode),
    78     mDuplicate(true),
    79     mKeyframe(false)
    80 {
    81   MOZ_COUNT_CTOR(VideoData);
    82   NS_ASSERTION(mDuration >= 0, "Frame must have non-negative duration.");
    83 }
    85 VideoData::VideoData(int64_t aOffset,
    86                      int64_t aTime,
    87                      int64_t aDuration,
    88                      bool aKeyframe,
    89                      int64_t aTimecode,
    90                      IntSize aDisplay)
    91   : MediaData(VIDEO_FRAME, aOffset, aTime, aDuration),
    92     mDisplay(aDisplay),
    93     mTimecode(aTimecode),
    94     mDuplicate(false),
    95     mKeyframe(aKeyframe)
    96 {
    97   MOZ_COUNT_CTOR(VideoData);
    98   NS_ASSERTION(mDuration >= 0, "Frame must have non-negative duration.");
    99 }
   101 VideoData::~VideoData()
   102 {
   103   MOZ_COUNT_DTOR(VideoData);
   104 }
   106 size_t
   107 VideoData::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
   108 {
   109   size_t size = aMallocSizeOf(this);
   111   // Currently only PLANAR_YCBCR has a well defined function for determining
   112   // it's size, so reporting is limited to that type.
   113   if (mImage && mImage->GetFormat() == ImageFormat::PLANAR_YCBCR) {
   114     const mozilla::layers::PlanarYCbCrImage* img =
   115         static_cast<const mozilla::layers::PlanarYCbCrImage*>(mImage.get());
   116     size += img->SizeOfIncludingThis(aMallocSizeOf);
   117   }
   119   return size;
   120 }
   122 /* static */
   123 VideoData* VideoData::ShallowCopyUpdateDuration(VideoData* aOther,
   124                                                 int64_t aDuration)
   125 {
   126   VideoData* v = new VideoData(aOther->mOffset,
   127                                aOther->mTime,
   128                                aDuration,
   129                                aOther->mKeyframe,
   130                                aOther->mTimecode,
   131                                aOther->mDisplay);
   132   v->mImage = aOther->mImage;
   133   return v;
   134 }
   136 /* static */
   137 VideoData* VideoData::ShallowCopyUpdateTimestamp(VideoData* aOther,
   138                                                  int64_t aTimestamp)
   139 {
   140   NS_ENSURE_TRUE(aOther, nullptr);
   141   VideoData* v = new VideoData(aOther->mOffset,
   142                                aTimestamp,
   143                                aOther->GetEndTime() - aTimestamp,
   144                                aOther->mKeyframe,
   145                                aOther->mTimecode,
   146                                aOther->mDisplay);
   147   v->mImage = aOther->mImage;
   148   return v;
   149 }
   151 /* static */
   152 void VideoData::SetVideoDataToImage(PlanarYCbCrImage* aVideoImage,
   153                                     VideoInfo& aInfo,
   154                                     const YCbCrBuffer &aBuffer,
   155                                     const IntRect& aPicture,
   156                                     bool aCopyData)
   157 {
   158   if (!aVideoImage) {
   159     return;
   160   }
   161   const YCbCrBuffer::Plane &Y = aBuffer.mPlanes[0];
   162   const YCbCrBuffer::Plane &Cb = aBuffer.mPlanes[1];
   163   const YCbCrBuffer::Plane &Cr = aBuffer.mPlanes[2];
   165   PlanarYCbCrData data;
   166   data.mYChannel = Y.mData + Y.mOffset;
   167   data.mYSize = IntSize(Y.mWidth, Y.mHeight);
   168   data.mYStride = Y.mStride;
   169   data.mYSkip = Y.mSkip;
   170   data.mCbChannel = Cb.mData + Cb.mOffset;
   171   data.mCrChannel = Cr.mData + Cr.mOffset;
   172   data.mCbCrSize = IntSize(Cb.mWidth, Cb.mHeight);
   173   data.mCbCrStride = Cb.mStride;
   174   data.mCbSkip = Cb.mSkip;
   175   data.mCrSkip = Cr.mSkip;
   176   data.mPicX = aPicture.x;
   177   data.mPicY = aPicture.y;
   178   data.mPicSize = aPicture.Size();
   179   data.mStereoMode = aInfo.mStereoMode;
   181   aVideoImage->SetDelayedConversion(true);
   182   if (aCopyData) {
   183     aVideoImage->SetData(data);
   184   } else {
   185     aVideoImage->SetDataNoCopy(data);
   186   }
   187 }
   189 /* static */
   190 VideoData* VideoData::Create(VideoInfo& aInfo,
   191                              ImageContainer* aContainer,
   192                              Image* aImage,
   193                              int64_t aOffset,
   194                              int64_t aTime,
   195                              int64_t aDuration,
   196                              const YCbCrBuffer& aBuffer,
   197                              bool aKeyframe,
   198                              int64_t aTimecode,
   199                              const IntRect& aPicture)
   200 {
   201   if (!aImage && !aContainer) {
   202     // Create a dummy VideoData with no image. This gives us something to
   203     // send to media streams if necessary.
   204     nsAutoPtr<VideoData> v(new VideoData(aOffset,
   205                                          aTime,
   206                                          aDuration,
   207                                          aKeyframe,
   208                                          aTimecode,
   209                                          aInfo.mDisplay.ToIntSize()));
   210     return v.forget();
   211   }
   213   // The following situation should never happen unless there is a bug
   214   // in the decoder
   215   if (aBuffer.mPlanes[1].mWidth != aBuffer.mPlanes[2].mWidth ||
   216       aBuffer.mPlanes[1].mHeight != aBuffer.mPlanes[2].mHeight) {
   217     NS_ERROR("C planes with different sizes");
   218     return nullptr;
   219   }
   221   // The following situations could be triggered by invalid input
   222   if (aPicture.width <= 0 || aPicture.height <= 0) {
   223     NS_WARNING("Empty picture rect");
   224     return nullptr;
   225   }
   226   if (!ValidatePlane(aBuffer.mPlanes[0]) || !ValidatePlane(aBuffer.mPlanes[1]) ||
   227       !ValidatePlane(aBuffer.mPlanes[2])) {
   228     NS_WARNING("Invalid plane size");
   229     return nullptr;
   230   }
   232   // Ensure the picture size specified in the headers can be extracted out of
   233   // the frame we've been supplied without indexing out of bounds.
   234   CheckedUint32 xLimit = aPicture.x + CheckedUint32(aPicture.width);
   235   CheckedUint32 yLimit = aPicture.y + CheckedUint32(aPicture.height);
   236   if (!xLimit.isValid() || xLimit.value() > aBuffer.mPlanes[0].mStride ||
   237       !yLimit.isValid() || yLimit.value() > aBuffer.mPlanes[0].mHeight)
   238   {
   239     // The specified picture dimensions can't be contained inside the video
   240     // frame, we'll stomp memory if we try to copy it. Fail.
   241     NS_WARNING("Overflowing picture rect");
   242     return nullptr;
   243   }
   245   nsAutoPtr<VideoData> v(new VideoData(aOffset,
   246                                        aTime,
   247                                        aDuration,
   248                                        aKeyframe,
   249                                        aTimecode,
   250                                        aInfo.mDisplay.ToIntSize()));
   251 #ifdef MOZ_WIDGET_GONK
   252   const YCbCrBuffer::Plane &Y = aBuffer.mPlanes[0];
   253   const YCbCrBuffer::Plane &Cb = aBuffer.mPlanes[1];
   254   const YCbCrBuffer::Plane &Cr = aBuffer.mPlanes[2];
   255 #endif
   257   if (!aImage) {
   258     // Currently our decoder only knows how to output to ImageFormat::PLANAR_YCBCR
   259     // format.
   260 #ifdef MOZ_WIDGET_GONK
   261     if (IsYV12Format(Y, Cb, Cr) && !IsInEmulator()) {
   262       v->mImage = aContainer->CreateImage(ImageFormat::GRALLOC_PLANAR_YCBCR);
   263     }
   264 #endif
   265     if (!v->mImage) {
   266       v->mImage = aContainer->CreateImage(ImageFormat::PLANAR_YCBCR);
   267     }
   268   } else {
   269     v->mImage = aImage;
   270   }
   272   if (!v->mImage) {
   273     return nullptr;
   274   }
   275   NS_ASSERTION(v->mImage->GetFormat() == ImageFormat::PLANAR_YCBCR ||
   276                v->mImage->GetFormat() == ImageFormat::GRALLOC_PLANAR_YCBCR,
   277                "Wrong format?");
   278   PlanarYCbCrImage* videoImage = static_cast<PlanarYCbCrImage*>(v->mImage.get());
   280   if (!aImage) {
   281     VideoData::SetVideoDataToImage(videoImage, aInfo, aBuffer, aPicture,
   282                                    true /* aCopyData */);
   283   } else {
   284     VideoData::SetVideoDataToImage(videoImage, aInfo, aBuffer, aPicture,
   285                                    false /* aCopyData */);
   286   }
   288 #ifdef MOZ_WIDGET_GONK
   289   if (!videoImage->IsValid() && !aImage && IsYV12Format(Y, Cb, Cr)) {
   290     // Failed to allocate gralloc. Try fallback.
   291     v->mImage = aContainer->CreateImage(ImageFormat::PLANAR_YCBCR);
   292     if (!v->mImage) {
   293       return nullptr;
   294     }
   295     videoImage = static_cast<PlanarYCbCrImage*>(v->mImage.get());
   296     VideoData::SetVideoDataToImage(videoImage, aInfo, aBuffer, aPicture,
   297                                    true /* aCopyData */);
   298   }
   299 #endif
   300   return v.forget();
   301 }
   303 /* static */
   304 VideoData* VideoData::Create(VideoInfo& aInfo,
   305                              ImageContainer* aContainer,
   306                              int64_t aOffset,
   307                              int64_t aTime,
   308                              int64_t aDuration,
   309                              const YCbCrBuffer& aBuffer,
   310                              bool aKeyframe,
   311                              int64_t aTimecode,
   312                              const IntRect& aPicture)
   313 {
   314   return Create(aInfo, aContainer, nullptr, aOffset, aTime, aDuration, aBuffer,
   315                 aKeyframe, aTimecode, aPicture);
   316 }
   318 /* static */
   319 VideoData* VideoData::Create(VideoInfo& aInfo,
   320                              Image* aImage,
   321                              int64_t aOffset,
   322                              int64_t aTime,
   323                              int64_t aDuration,
   324                              const YCbCrBuffer& aBuffer,
   325                              bool aKeyframe,
   326                              int64_t aTimecode,
   327                              const IntRect& aPicture)
   328 {
   329   return Create(aInfo, nullptr, aImage, aOffset, aTime, aDuration, aBuffer,
   330                 aKeyframe, aTimecode, aPicture);
   331 }
   333 /* static */
   334 VideoData* VideoData::CreateFromImage(VideoInfo& aInfo,
   335                                       ImageContainer* aContainer,
   336                                       int64_t aOffset,
   337                                       int64_t aTime,
   338                                       int64_t aDuration,
   339                                       const nsRefPtr<Image>& aImage,
   340                                       bool aKeyframe,
   341                                       int64_t aTimecode,
   342                                       const IntRect& aPicture)
   343 {
   344   nsAutoPtr<VideoData> v(new VideoData(aOffset,
   345                                        aTime,
   346                                        aDuration,
   347                                        aKeyframe,
   348                                        aTimecode,
   349                                        aInfo.mDisplay.ToIntSize()));
   350   v->mImage = aImage;
   351   return v.forget();
   352 }
   354 #ifdef MOZ_OMX_DECODER
   355 /* static */
   356 VideoData* VideoData::Create(VideoInfo& aInfo,
   357                              ImageContainer* aContainer,
   358                              int64_t aOffset,
   359                              int64_t aTime,
   360                              int64_t aDuration,
   361                              mozilla::layers::TextureClient* aBuffer,
   362                              bool aKeyframe,
   363                              int64_t aTimecode,
   364                              const IntRect& aPicture)
   365 {
   366   if (!aContainer) {
   367     // Create a dummy VideoData with no image. This gives us something to
   368     // send to media streams if necessary.
   369     nsAutoPtr<VideoData> v(new VideoData(aOffset,
   370                                          aTime,
   371                                          aDuration,
   372                                          aKeyframe,
   373                                          aTimecode,
   374                                          aInfo.mDisplay.ToIntSize()));
   375     return v.forget();
   376   }
   378   // The following situations could be triggered by invalid input
   379   if (aPicture.width <= 0 || aPicture.height <= 0) {
   380     NS_WARNING("Empty picture rect");
   381     return nullptr;
   382   }
   384   // Ensure the picture size specified in the headers can be extracted out of
   385   // the frame we've been supplied without indexing out of bounds.
   386   CheckedUint32 xLimit = aPicture.x + CheckedUint32(aPicture.width);
   387   CheckedUint32 yLimit = aPicture.y + CheckedUint32(aPicture.height);
   388   if (!xLimit.isValid() || !yLimit.isValid())
   389   {
   390     // The specified picture dimensions can't be contained inside the video
   391     // frame, we'll stomp memory if we try to copy it. Fail.
   392     NS_WARNING("Overflowing picture rect");
   393     return nullptr;
   394   }
   396   nsAutoPtr<VideoData> v(new VideoData(aOffset,
   397                                        aTime,
   398                                        aDuration,
   399                                        aKeyframe,
   400                                        aTimecode,
   401                                        aInfo.mDisplay.ToIntSize()));
   403   v->mImage = aContainer->CreateImage(ImageFormat::GRALLOC_PLANAR_YCBCR);
   404   if (!v->mImage) {
   405     return nullptr;
   406   }
   407   NS_ASSERTION(v->mImage->GetFormat() == ImageFormat::GRALLOC_PLANAR_YCBCR,
   408                "Wrong format?");
   409   typedef mozilla::layers::GrallocImage GrallocImage;
   410   GrallocImage* videoImage = static_cast<GrallocImage*>(v->mImage.get());
   411   GrallocImage::GrallocData data;
   413   data.mPicSize = aPicture.Size();
   414   data.mGraphicBuffer = aBuffer;
   416   videoImage->SetData(data);
   418   return v.forget();
   419 }
   420 #endif  // MOZ_OMX_DECODER
   422 } // namespace mozilla

mercurial