1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/media/fmp4/BlankDecoderModule.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,249 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "MediaDecoderReader.h" 1.11 +#include "PlatformDecoderModule.h" 1.12 +#include "nsRect.h" 1.13 +#include "mozilla/RefPtr.h" 1.14 +#include "mozilla/CheckedInt.h" 1.15 +#include "VideoUtils.h" 1.16 +#include "ImageContainer.h" 1.17 +#include "mp4_demuxer/mp4_demuxer.h" 1.18 +#include "MediaTaskQueue.h" 1.19 + 1.20 +namespace mozilla { 1.21 + 1.22 +// Decoder that uses a passed in object's Create function to create blank 1.23 +// MediaData objects. 1.24 +template<class BlankMediaDataCreator> 1.25 +class BlankMediaDataDecoder : public MediaDataDecoder { 1.26 +public: 1.27 + 1.28 + BlankMediaDataDecoder(BlankMediaDataCreator* aCreator, 1.29 + MediaTaskQueue* aTaskQueue, 1.30 + MediaDataDecoderCallback* aCallback) 1.31 + : mCreator(aCreator) 1.32 + , mTaskQueue(aTaskQueue) 1.33 + , mCallback(aCallback) 1.34 + { 1.35 + } 1.36 + 1.37 + virtual nsresult Init() MOZ_OVERRIDE { 1.38 + return NS_OK; 1.39 + } 1.40 + 1.41 + virtual nsresult Shutdown() MOZ_OVERRIDE { 1.42 + return NS_OK; 1.43 + } 1.44 + 1.45 + class OutputEvent : public nsRunnable { 1.46 + public: 1.47 + OutputEvent(mp4_demuxer::MP4Sample* aSample, 1.48 + MediaDataDecoderCallback* aCallback, 1.49 + BlankMediaDataCreator* aCreator) 1.50 + : mSample(aSample) 1.51 + , mCreator(aCreator) 1.52 + , mCallback(aCallback) 1.53 + { 1.54 + } 1.55 + NS_IMETHOD Run() MOZ_OVERRIDE 1.56 + { 1.57 + mCallback->Output(mCreator->Create(mSample->composition_timestamp, 1.58 + mSample->duration, 1.59 + mSample->byte_offset)); 1.60 + return NS_OK; 1.61 + } 1.62 + private: 1.63 + nsAutoPtr<mp4_demuxer::MP4Sample> mSample; 1.64 + BlankMediaDataCreator* mCreator; 1.65 + MediaDataDecoderCallback* mCallback; 1.66 + }; 1.67 + 1.68 + virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE 1.69 + { 1.70 + // The MediaDataDecoder must delete the sample when we're finished 1.71 + // with it, so the OutputEvent stores it in an nsAutoPtr and deletes 1.72 + // it once it's run. 1.73 + RefPtr<nsIRunnable> r(new OutputEvent(aSample, mCallback, mCreator)); 1.74 + mTaskQueue->Dispatch(r); 1.75 + return NS_OK; 1.76 + } 1.77 + 1.78 + virtual nsresult Flush() MOZ_OVERRIDE { 1.79 + return NS_OK; 1.80 + } 1.81 + 1.82 + virtual nsresult Drain() MOZ_OVERRIDE { 1.83 + return NS_OK; 1.84 + } 1.85 + 1.86 +private: 1.87 + nsAutoPtr<BlankMediaDataCreator> mCreator; 1.88 + nsAutoPtr<MediaData> mOutput; 1.89 + RefPtr<MediaTaskQueue> mTaskQueue; 1.90 + MediaDataDecoderCallback* mCallback; 1.91 +}; 1.92 + 1.93 +class BlankVideoDataCreator { 1.94 +public: 1.95 + BlankVideoDataCreator(uint32_t aFrameWidth, 1.96 + uint32_t aFrameHeight, 1.97 + layers::ImageContainer* aImageContainer) 1.98 + : mFrameWidth(aFrameWidth) 1.99 + , mFrameHeight(aFrameHeight) 1.100 + , mImageContainer(aImageContainer) 1.101 + { 1.102 + mInfo.mDisplay = nsIntSize(mFrameWidth, mFrameHeight); 1.103 + mPicture = gfx::IntRect(0, 0, mFrameWidth, mFrameHeight); 1.104 + } 1.105 + 1.106 + MediaData* Create(Microseconds aDTS, 1.107 + Microseconds aDuration, 1.108 + int64_t aOffsetInStream) 1.109 + { 1.110 + // Create a fake YUV buffer in a 420 format. That is, an 8bpp Y plane, 1.111 + // with a U and V plane that are half the size of the Y plane, i.e 8 bit, 1.112 + // 2x2 subsampled. Have the data pointers of each frame point to the 1.113 + // first plane, they'll always be zero'd memory anyway. 1.114 + uint8_t* frame = new uint8_t[mFrameWidth * mFrameHeight]; 1.115 + memset(frame, 0, mFrameWidth * mFrameHeight); 1.116 + VideoData::YCbCrBuffer buffer; 1.117 + 1.118 + // Y plane. 1.119 + buffer.mPlanes[0].mData = frame; 1.120 + buffer.mPlanes[0].mStride = mFrameWidth; 1.121 + buffer.mPlanes[0].mHeight = mFrameHeight; 1.122 + buffer.mPlanes[0].mWidth = mFrameWidth; 1.123 + buffer.mPlanes[0].mOffset = 0; 1.124 + buffer.mPlanes[0].mSkip = 0; 1.125 + 1.126 + // Cb plane. 1.127 + buffer.mPlanes[1].mData = frame; 1.128 + buffer.mPlanes[1].mStride = mFrameWidth / 2; 1.129 + buffer.mPlanes[1].mHeight = mFrameHeight / 2; 1.130 + buffer.mPlanes[1].mWidth = mFrameWidth / 2; 1.131 + buffer.mPlanes[1].mOffset = 0; 1.132 + buffer.mPlanes[1].mSkip = 0; 1.133 + 1.134 + // Cr plane. 1.135 + buffer.mPlanes[2].mData = frame; 1.136 + buffer.mPlanes[2].mStride = mFrameWidth / 2; 1.137 + buffer.mPlanes[2].mHeight = mFrameHeight / 2; 1.138 + buffer.mPlanes[2].mWidth = mFrameWidth / 2; 1.139 + buffer.mPlanes[2].mOffset = 0; 1.140 + buffer.mPlanes[2].mSkip = 0; 1.141 + 1.142 + return VideoData::Create(mInfo, 1.143 + mImageContainer, 1.144 + nullptr, 1.145 + aOffsetInStream, 1.146 + aDTS, 1.147 + aDuration, 1.148 + buffer, 1.149 + true, 1.150 + aDTS, 1.151 + mPicture); 1.152 + } 1.153 +private: 1.154 + VideoInfo mInfo; 1.155 + gfx::IntRect mPicture; 1.156 + uint32_t mFrameWidth; 1.157 + uint32_t mFrameHeight; 1.158 + RefPtr<layers::ImageContainer> mImageContainer; 1.159 +}; 1.160 + 1.161 + 1.162 +class BlankAudioDataCreator { 1.163 +public: 1.164 + BlankAudioDataCreator(uint32_t aChannelCount, 1.165 + uint32_t aSampleRate, 1.166 + uint16_t aBitsPerSample) 1.167 + : mFrameSum(0) 1.168 + , mChannelCount(aChannelCount) 1.169 + , mSampleRate(aSampleRate) 1.170 + { 1.171 + } 1.172 + 1.173 + MediaData* Create(Microseconds aDTS, 1.174 + Microseconds aDuration, 1.175 + int64_t aOffsetInStream) 1.176 + { 1.177 + // Convert duration to frames. We add 1 to duration to account for 1.178 + // rounding errors, so we get a consistent tone. 1.179 + CheckedInt64 frames = UsecsToFrames(aDuration+1, mSampleRate); 1.180 + if (!frames.isValid() || 1.181 + !mChannelCount || 1.182 + !mSampleRate || 1.183 + frames.value() > (UINT32_MAX / mChannelCount)) { 1.184 + return nullptr; 1.185 + } 1.186 + AudioDataValue* samples = new AudioDataValue[frames.value() * mChannelCount]; 1.187 + // Fill the sound buffer with an A4 tone. 1.188 + static const float pi = 3.14159265f; 1.189 + static const float noteHz = 440.0f; 1.190 + for (int i = 0; i < frames.value(); i++) { 1.191 + float f = sin(2 * pi * noteHz * mFrameSum / mSampleRate); 1.192 + for (unsigned c = 0; c < mChannelCount; c++) { 1.193 + samples[i * mChannelCount + c] = AudioDataValue(f); 1.194 + } 1.195 + mFrameSum++; 1.196 + } 1.197 + return new AudioData(aOffsetInStream, 1.198 + aDTS, 1.199 + aDuration, 1.200 + uint32_t(frames.value()), 1.201 + samples, 1.202 + mChannelCount); 1.203 + } 1.204 + 1.205 +private: 1.206 + int64_t mFrameSum; 1.207 + uint32_t mChannelCount; 1.208 + uint32_t mSampleRate; 1.209 +}; 1.210 + 1.211 +class BlankDecoderModule : public PlatformDecoderModule { 1.212 +public: 1.213 + 1.214 + // Called when the decoders have shutdown. Main thread only. 1.215 + virtual nsresult Shutdown() MOZ_OVERRIDE { 1.216 + return NS_OK; 1.217 + } 1.218 + 1.219 + // Decode thread. 1.220 + virtual MediaDataDecoder* CreateH264Decoder(const mp4_demuxer::VideoDecoderConfig& aConfig, 1.221 + layers::LayersBackend aLayersBackend, 1.222 + layers::ImageContainer* aImageContainer, 1.223 + MediaTaskQueue* aVideoTaskQueue, 1.224 + MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE { 1.225 + BlankVideoDataCreator* decoder = new BlankVideoDataCreator(aConfig.visible_rect().width(), 1.226 + aConfig.visible_rect().height(), 1.227 + aImageContainer); 1.228 + return new BlankMediaDataDecoder<BlankVideoDataCreator>(decoder, 1.229 + aVideoTaskQueue, 1.230 + aCallback); 1.231 + } 1.232 + 1.233 + // Decode thread. 1.234 + virtual MediaDataDecoder* CreateAACDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig, 1.235 + MediaTaskQueue* aAudioTaskQueue, 1.236 + MediaDataDecoderCallback* aCallback) MOZ_OVERRIDE { 1.237 + BlankAudioDataCreator* decoder = 1.238 + new BlankAudioDataCreator(ChannelLayoutToChannelCount(aConfig.channel_layout()), 1.239 + aConfig.samples_per_second(), 1.240 + aConfig.bits_per_channel()); 1.241 + return new BlankMediaDataDecoder<BlankAudioDataCreator>(decoder, 1.242 + aAudioTaskQueue, 1.243 + aCallback); 1.244 + } 1.245 +}; 1.246 + 1.247 +PlatformDecoderModule* CreateBlankDecoderModule() 1.248 +{ 1.249 + return new BlankDecoderModule(); 1.250 +} 1.251 + 1.252 +} // namespace mozilla