content/media/fmp4/BlankDecoderModule.cpp

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 /* vim:set ts=2 sw=2 sts=2 et cindent: */
     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/. */
     7 #include "MediaDecoderReader.h"
     8 #include "PlatformDecoderModule.h"
     9 #include "nsRect.h"
    10 #include "mozilla/RefPtr.h"
    11 #include "mozilla/CheckedInt.h"
    12 #include "VideoUtils.h"
    13 #include "ImageContainer.h"
    14 #include "mp4_demuxer/mp4_demuxer.h"
    15 #include "MediaTaskQueue.h"
    17 namespace mozilla {
    19 // Decoder that uses a passed in object's Create function to create blank
    20 // MediaData objects.
    21 template<class BlankMediaDataCreator>
    22 class BlankMediaDataDecoder : public MediaDataDecoder {
    23 public:
    25   BlankMediaDataDecoder(BlankMediaDataCreator* aCreator,
    26                         MediaTaskQueue* aTaskQueue,
    27                         MediaDataDecoderCallback* aCallback)
    28     : mCreator(aCreator)
    29     , mTaskQueue(aTaskQueue)
    30     , mCallback(aCallback)
    31   {
    32   }
    34   virtual nsresult Init() MOZ_OVERRIDE {
    35     return NS_OK;
    36   }
    38   virtual nsresult Shutdown() MOZ_OVERRIDE {
    39     return NS_OK;
    40   }
    42   class OutputEvent : public nsRunnable {
    43   public:
    44     OutputEvent(mp4_demuxer::MP4Sample* aSample,
    45                 MediaDataDecoderCallback* aCallback,
    46                 BlankMediaDataCreator* aCreator)
    47       : mSample(aSample)
    48       , mCreator(aCreator)
    49       , mCallback(aCallback)
    50     {
    51     }
    52     NS_IMETHOD Run() MOZ_OVERRIDE
    53     {
    54       mCallback->Output(mCreator->Create(mSample->composition_timestamp,
    55                                          mSample->duration,
    56                                          mSample->byte_offset));
    57       return NS_OK;
    58     }
    59   private:
    60     nsAutoPtr<mp4_demuxer::MP4Sample> mSample;
    61     BlankMediaDataCreator* mCreator;
    62     MediaDataDecoderCallback* mCallback;
    63   };
    65   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE
    66   {
    67     // The MediaDataDecoder must delete the sample when we're finished
    68     // with it, so the OutputEvent stores it in an nsAutoPtr and deletes
    69     // it once it's run.
    70     RefPtr<nsIRunnable> r(new OutputEvent(aSample, mCallback, mCreator));
    71     mTaskQueue->Dispatch(r);
    72     return NS_OK;
    73   }
    75   virtual nsresult Flush() MOZ_OVERRIDE {
    76     return NS_OK;
    77   }
    79   virtual nsresult Drain() MOZ_OVERRIDE {
    80     return NS_OK;
    81   }
    83 private:
    84   nsAutoPtr<BlankMediaDataCreator> mCreator;
    85   nsAutoPtr<MediaData> mOutput;
    86   RefPtr<MediaTaskQueue> mTaskQueue;
    87   MediaDataDecoderCallback* mCallback;
    88 };
    90 class BlankVideoDataCreator {
    91 public:
    92   BlankVideoDataCreator(uint32_t aFrameWidth,
    93                         uint32_t aFrameHeight,
    94                         layers::ImageContainer* aImageContainer)
    95     : mFrameWidth(aFrameWidth)
    96     , mFrameHeight(aFrameHeight)
    97     , mImageContainer(aImageContainer)
    98   {
    99     mInfo.mDisplay = nsIntSize(mFrameWidth, mFrameHeight);
   100     mPicture = gfx::IntRect(0, 0, mFrameWidth, mFrameHeight);
   101   }
   103   MediaData* Create(Microseconds aDTS,
   104                     Microseconds aDuration,
   105                     int64_t aOffsetInStream)
   106   {
   107     // Create a fake YUV buffer in a 420 format. That is, an 8bpp Y plane,
   108     // with a U and V plane that are half the size of the Y plane, i.e 8 bit,
   109     // 2x2 subsampled. Have the data pointers of each frame point to the
   110     // first plane, they'll always be zero'd memory anyway.
   111     uint8_t* frame = new uint8_t[mFrameWidth * mFrameHeight];
   112     memset(frame, 0, mFrameWidth * mFrameHeight);
   113     VideoData::YCbCrBuffer buffer;
   115     // Y plane.
   116     buffer.mPlanes[0].mData = frame;
   117     buffer.mPlanes[0].mStride = mFrameWidth;
   118     buffer.mPlanes[0].mHeight = mFrameHeight;
   119     buffer.mPlanes[0].mWidth = mFrameWidth;
   120     buffer.mPlanes[0].mOffset = 0;
   121     buffer.mPlanes[0].mSkip = 0;
   123     // Cb plane.
   124     buffer.mPlanes[1].mData = frame;
   125     buffer.mPlanes[1].mStride = mFrameWidth / 2;
   126     buffer.mPlanes[1].mHeight = mFrameHeight / 2;
   127     buffer.mPlanes[1].mWidth = mFrameWidth / 2;
   128     buffer.mPlanes[1].mOffset = 0;
   129     buffer.mPlanes[1].mSkip = 0;
   131     // Cr plane.
   132     buffer.mPlanes[2].mData = frame;
   133     buffer.mPlanes[2].mStride = mFrameWidth / 2;
   134     buffer.mPlanes[2].mHeight = mFrameHeight / 2;
   135     buffer.mPlanes[2].mWidth = mFrameWidth / 2;
   136     buffer.mPlanes[2].mOffset = 0;
   137     buffer.mPlanes[2].mSkip = 0;
   139     return VideoData::Create(mInfo,
   140                              mImageContainer,
   141                              nullptr,
   142                              aOffsetInStream,
   143                              aDTS,
   144                              aDuration,
   145                              buffer,
   146                              true,
   147                              aDTS,
   148                              mPicture);
   149   }
   150 private:
   151   VideoInfo mInfo;
   152   gfx::IntRect mPicture;
   153   uint32_t mFrameWidth;
   154   uint32_t mFrameHeight;
   155   RefPtr<layers::ImageContainer> mImageContainer;
   156 };
   159 class BlankAudioDataCreator {
   160 public:
   161   BlankAudioDataCreator(uint32_t aChannelCount,
   162                         uint32_t aSampleRate,
   163                         uint16_t aBitsPerSample)
   164     : mFrameSum(0)
   165     , mChannelCount(aChannelCount)
   166     , mSampleRate(aSampleRate)
   167   {
   168   }
   170   MediaData* Create(Microseconds aDTS,
   171                     Microseconds aDuration,
   172                     int64_t aOffsetInStream)
   173   {
   174     // Convert duration to frames. We add 1 to duration to account for
   175     // rounding errors, so we get a consistent tone.
   176     CheckedInt64 frames = UsecsToFrames(aDuration+1, mSampleRate);
   177     if (!frames.isValid() ||
   178         !mChannelCount ||
   179         !mSampleRate ||
   180         frames.value() > (UINT32_MAX / mChannelCount)) {
   181       return nullptr;
   182     }
   183     AudioDataValue* samples = new AudioDataValue[frames.value() * mChannelCount];
   184     // Fill the sound buffer with an A4 tone.
   185     static const float pi = 3.14159265f;
   186     static const float noteHz = 440.0f;
   187     for (int i = 0; i < frames.value(); i++) {
   188       float f = sin(2 * pi * noteHz * mFrameSum / mSampleRate);
   189       for (unsigned c = 0; c < mChannelCount; c++) {
   190         samples[i * mChannelCount + c] = AudioDataValue(f);
   191       }
   192       mFrameSum++;
   193     }
   194     return new AudioData(aOffsetInStream,
   195                          aDTS,
   196                          aDuration,
   197                          uint32_t(frames.value()),
   198                          samples,
   199                          mChannelCount);
   200   }
   202 private:
   203   int64_t mFrameSum;
   204   uint32_t mChannelCount;
   205   uint32_t mSampleRate;
   206 };
   208 class BlankDecoderModule : public PlatformDecoderModule {
   209 public:
   211   // Called when the decoders have shutdown. Main thread only.
   212   virtual nsresult Shutdown() MOZ_OVERRIDE {
   213     return NS_OK;
   214   }
   216   // Decode thread.
   217   virtual MediaDataDecoder* CreateH264Decoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
   218                                               layers::LayersBackend aLayersBackend,
   219                                               layers::ImageContainer* aImageContainer,
   220                                               MediaTaskQueue* aVideoTaskQueue,
   221                                               MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE {
   222     BlankVideoDataCreator* decoder = new BlankVideoDataCreator(aConfig.visible_rect().width(),
   223                                                                aConfig.visible_rect().height(),
   224                                                                aImageContainer);
   225     return new BlankMediaDataDecoder<BlankVideoDataCreator>(decoder,
   226                                                             aVideoTaskQueue,
   227                                                             aCallback);
   228   }
   230   // Decode thread.
   231   virtual MediaDataDecoder* CreateAACDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
   232                                              MediaTaskQueue* aAudioTaskQueue,
   233                                              MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE {
   234     BlankAudioDataCreator* decoder =
   235       new BlankAudioDataCreator(ChannelLayoutToChannelCount(aConfig.channel_layout()),
   236                                 aConfig.samples_per_second(),
   237                                 aConfig.bits_per_channel());
   238     return new BlankMediaDataDecoder<BlankAudioDataCreator>(decoder,
   239                                                             aAudioTaskQueue,
   240                                                             aCallback);
   241   }
   242 };
   244 PlatformDecoderModule* CreateBlankDecoderModule()
   245 {
   246   return new BlankDecoderModule();
   247 }
   249 } // namespace mozilla

mercurial