Backed out 35 changesets (bug 941158, bug 972518, bug 959520, bug 986063, bug 948895...
[gecko.git] / content / media / MediaData.cpp
blobb1a3d732cced09d83c11250aae32790ad29a435c
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 #endif
11 #include "VideoUtils.h"
12 #include "ImageContainer.h"
14 namespace mozilla {
16 using namespace mozilla::gfx;
17 using layers::ImageContainer;
18 using layers::PlanarYCbCrImage;
19 using layers::PlanarYCbCrData;
21 // Verify these values are sane. Once we've checked the frame sizes, we then
22 // can do less integer overflow checking.
23 static_assert(MAX_VIDEO_WIDTH < PlanarYCbCrImage::MAX_DIMENSION,
24 "MAX_VIDEO_WIDTH is too large");
25 static_assert(MAX_VIDEO_HEIGHT < PlanarYCbCrImage::MAX_DIMENSION,
26 "MAX_VIDEO_HEIGHT is too large");
27 static_assert(PlanarYCbCrImage::MAX_DIMENSION < UINT32_MAX / PlanarYCbCrImage::MAX_DIMENSION,
28 "MAX_DIMENSION*MAX_DIMENSION doesn't fit in 32 bits");
30 void
31 AudioData::EnsureAudioBuffer()
33 if (mAudioBuffer)
34 return;
35 mAudioBuffer = SharedBuffer::Create(mFrames*mChannels*sizeof(AudioDataValue));
37 AudioDataValue* data = static_cast<AudioDataValue*>(mAudioBuffer->Data());
38 for (uint32_t i = 0; i < mFrames; ++i) {
39 for (uint32_t j = 0; j < mChannels; ++j) {
40 data[j*mFrames + i] = mAudioData[i*mChannels + j];
45 static bool
46 ValidatePlane(const VideoData::YCbCrBuffer::Plane& aPlane)
48 return aPlane.mWidth <= PlanarYCbCrImage::MAX_DIMENSION &&
49 aPlane.mHeight <= PlanarYCbCrImage::MAX_DIMENSION &&
50 aPlane.mWidth * aPlane.mHeight < MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
51 aPlane.mStride > 0;
54 static bool
55 IsYV12Format(const VideoData::YCbCrBuffer::Plane& aYPlane,
56 const VideoData::YCbCrBuffer::Plane& aCbPlane,
57 const VideoData::YCbCrBuffer::Plane& aCrPlane)
59 return
60 aYPlane.mWidth % 2 == 0 &&
61 aYPlane.mHeight % 2 == 0 &&
62 aYPlane.mWidth / 2 == aCbPlane.mWidth &&
63 aYPlane.mHeight / 2 == aCbPlane.mHeight &&
64 aCbPlane.mWidth == aCrPlane.mWidth &&
65 aCbPlane.mHeight == aCrPlane.mHeight;
68 VideoData::VideoData(int64_t aOffset, int64_t aTime, int64_t aDuration, int64_t aTimecode)
69 : MediaData(VIDEO_FRAME, aOffset, aTime, aDuration),
70 mTimecode(aTimecode),
71 mDuplicate(true),
72 mKeyframe(false)
74 MOZ_COUNT_CTOR(VideoData);
75 NS_ASSERTION(mDuration >= 0, "Frame must have non-negative duration.");
78 VideoData::VideoData(int64_t aOffset,
79 int64_t aTime,
80 int64_t aDuration,
81 bool aKeyframe,
82 int64_t aTimecode,
83 nsIntSize aDisplay)
84 : MediaData(VIDEO_FRAME, aOffset, aTime, aDuration),
85 mDisplay(aDisplay),
86 mTimecode(aTimecode),
87 mDuplicate(false),
88 mKeyframe(aKeyframe)
90 MOZ_COUNT_CTOR(VideoData);
91 NS_ASSERTION(mDuration >= 0, "Frame must have non-negative duration.");
94 VideoData::~VideoData()
96 MOZ_COUNT_DTOR(VideoData);
99 /* static */
100 VideoData* VideoData::ShallowCopyUpdateDuration(VideoData* aOther,
101 int64_t aDuration)
103 VideoData* v = new VideoData(aOther->mOffset,
104 aOther->mTime,
105 aDuration,
106 aOther->mKeyframe,
107 aOther->mTimecode,
108 aOther->mDisplay);
109 v->mImage = aOther->mImage;
110 return v;
113 VideoData* VideoData::Create(VideoInfo& aInfo,
114 ImageContainer* aContainer,
115 Image* aImage,
116 int64_t aOffset,
117 int64_t aTime,
118 int64_t aDuration,
119 const YCbCrBuffer& aBuffer,
120 bool aKeyframe,
121 int64_t aTimecode,
122 nsIntRect aPicture)
124 if (!aImage && !aContainer) {
125 // Create a dummy VideoData with no image. This gives us something to
126 // send to media streams if necessary.
127 nsAutoPtr<VideoData> v(new VideoData(aOffset,
128 aTime,
129 aDuration,
130 aKeyframe,
131 aTimecode,
132 aInfo.mDisplay));
133 return v.forget();
136 // The following situation should never happen unless there is a bug
137 // in the decoder
138 if (aBuffer.mPlanes[1].mWidth != aBuffer.mPlanes[2].mWidth ||
139 aBuffer.mPlanes[1].mHeight != aBuffer.mPlanes[2].mHeight) {
140 NS_ERROR("C planes with different sizes");
141 return nullptr;
144 // The following situations could be triggered by invalid input
145 if (aPicture.width <= 0 || aPicture.height <= 0) {
146 NS_WARNING("Empty picture rect");
147 return nullptr;
149 if (!ValidatePlane(aBuffer.mPlanes[0]) || !ValidatePlane(aBuffer.mPlanes[1]) ||
150 !ValidatePlane(aBuffer.mPlanes[2])) {
151 NS_WARNING("Invalid plane size");
152 return nullptr;
155 // Ensure the picture size specified in the headers can be extracted out of
156 // the frame we've been supplied without indexing out of bounds.
157 CheckedUint32 xLimit = aPicture.x + CheckedUint32(aPicture.width);
158 CheckedUint32 yLimit = aPicture.y + CheckedUint32(aPicture.height);
159 if (!xLimit.isValid() || xLimit.value() > aBuffer.mPlanes[0].mStride ||
160 !yLimit.isValid() || yLimit.value() > aBuffer.mPlanes[0].mHeight)
162 // The specified picture dimensions can't be contained inside the video
163 // frame, we'll stomp memory if we try to copy it. Fail.
164 NS_WARNING("Overflowing picture rect");
165 return nullptr;
168 nsAutoPtr<VideoData> v(new VideoData(aOffset,
169 aTime,
170 aDuration,
171 aKeyframe,
172 aTimecode,
173 aInfo.mDisplay));
174 const YCbCrBuffer::Plane &Y = aBuffer.mPlanes[0];
175 const YCbCrBuffer::Plane &Cb = aBuffer.mPlanes[1];
176 const YCbCrBuffer::Plane &Cr = aBuffer.mPlanes[2];
178 if (!aImage) {
179 // Currently our decoder only knows how to output to PLANAR_YCBCR
180 // format.
181 ImageFormat format[2] = {PLANAR_YCBCR, GRALLOC_PLANAR_YCBCR};
182 if (IsYV12Format(Y, Cb, Cr)) {
183 v->mImage = aContainer->CreateImage(format, 2);
184 } else {
185 v->mImage = aContainer->CreateImage(format, 1);
187 } else {
188 v->mImage = aImage;
191 if (!v->mImage) {
192 return nullptr;
194 NS_ASSERTION(v->mImage->GetFormat() == PLANAR_YCBCR ||
195 v->mImage->GetFormat() == GRALLOC_PLANAR_YCBCR,
196 "Wrong format?");
197 PlanarYCbCrImage* videoImage = static_cast<PlanarYCbCrImage*>(v->mImage.get());
199 PlanarYCbCrData data;
200 data.mYChannel = Y.mData + Y.mOffset;
201 data.mYSize = gfxIntSize(Y.mWidth, Y.mHeight);
202 data.mYStride = Y.mStride;
203 data.mYSkip = Y.mSkip;
204 data.mCbChannel = Cb.mData + Cb.mOffset;
205 data.mCrChannel = Cr.mData + Cr.mOffset;
206 data.mCbCrSize = gfxIntSize(Cb.mWidth, Cb.mHeight);
207 data.mCbCrStride = Cb.mStride;
208 data.mCbSkip = Cb.mSkip;
209 data.mCrSkip = Cr.mSkip;
210 data.mPicX = aPicture.x;
211 data.mPicY = aPicture.y;
212 data.mPicSize = gfxIntSize(aPicture.width, aPicture.height);
213 data.mStereoMode = aInfo.mStereoMode;
215 videoImage->SetDelayedConversion(true);
216 if (!aImage) {
217 videoImage->SetData(data);
218 } else {
219 videoImage->SetDataNoCopy(data);
222 return v.forget();
225 VideoData* VideoData::Create(VideoInfo& aInfo,
226 ImageContainer* aContainer,
227 int64_t aOffset,
228 int64_t aTime,
229 int64_t aDuration,
230 const YCbCrBuffer& aBuffer,
231 bool aKeyframe,
232 int64_t aTimecode,
233 nsIntRect aPicture)
235 return Create(aInfo, aContainer, nullptr, aOffset, aTime, aDuration, aBuffer,
236 aKeyframe, aTimecode, aPicture);
239 VideoData* VideoData::Create(VideoInfo& aInfo,
240 Image* aImage,
241 int64_t aOffset,
242 int64_t aTime,
243 int64_t aDuration,
244 const YCbCrBuffer& aBuffer,
245 bool aKeyframe,
246 int64_t aTimecode,
247 nsIntRect aPicture)
249 return Create(aInfo, nullptr, aImage, aOffset, aTime, aDuration, aBuffer,
250 aKeyframe, aTimecode, aPicture);
253 VideoData* VideoData::CreateFromImage(VideoInfo& aInfo,
254 ImageContainer* aContainer,
255 int64_t aOffset,
256 int64_t aTime,
257 int64_t aDuration,
258 const nsRefPtr<Image>& aImage,
259 bool aKeyframe,
260 int64_t aTimecode,
261 nsIntRect aPicture)
263 nsAutoPtr<VideoData> v(new VideoData(aOffset,
264 aTime,
265 aDuration,
266 aKeyframe,
267 aTimecode,
268 aInfo.mDisplay));
269 v->mImage = aImage;
270 return v.forget();
273 #ifdef MOZ_OMX_DECODER
274 VideoData* VideoData::Create(VideoInfo& aInfo,
275 ImageContainer* aContainer,
276 int64_t aOffset,
277 int64_t aTime,
278 int64_t aDuration,
279 mozilla::layers::GraphicBufferLocked* aBuffer,
280 bool aKeyframe,
281 int64_t aTimecode,
282 nsIntRect aPicture)
284 if (!aContainer) {
285 // Create a dummy VideoData with no image. This gives us something to
286 // send to media streams if necessary.
287 nsAutoPtr<VideoData> v(new VideoData(aOffset,
288 aTime,
289 aDuration,
290 aKeyframe,
291 aTimecode,
292 aInfo.mDisplay));
293 return v.forget();
296 // The following situations could be triggered by invalid input
297 if (aPicture.width <= 0 || aPicture.height <= 0) {
298 NS_WARNING("Empty picture rect");
299 return nullptr;
302 // Ensure the picture size specified in the headers can be extracted out of
303 // the frame we've been supplied without indexing out of bounds.
304 CheckedUint32 xLimit = aPicture.x + CheckedUint32(aPicture.width);
305 CheckedUint32 yLimit = aPicture.y + CheckedUint32(aPicture.height);
306 if (!xLimit.isValid() || !yLimit.isValid())
308 // The specified picture dimensions can't be contained inside the video
309 // frame, we'll stomp memory if we try to copy it. Fail.
310 NS_WARNING("Overflowing picture rect");
311 return nullptr;
314 nsAutoPtr<VideoData> v(new VideoData(aOffset,
315 aTime,
316 aDuration,
317 aKeyframe,
318 aTimecode,
319 aInfo.mDisplay));
321 ImageFormat format = GRALLOC_PLANAR_YCBCR;
322 v->mImage = aContainer->CreateImage(&format, 1);
323 if (!v->mImage) {
324 return nullptr;
326 NS_ASSERTION(v->mImage->GetFormat() == GRALLOC_PLANAR_YCBCR,
327 "Wrong format?");
328 typedef mozilla::layers::GrallocImage GrallocImage;
329 GrallocImage* videoImage = static_cast<GrallocImage*>(v->mImage.get());
330 GrallocImage::GrallocData data;
332 data.mPicSize = gfxIntSize(aPicture.width, aPicture.height);
333 data.mGraphicBuffer = aBuffer;
335 videoImage->SetData(data);
337 return v.forget();
339 #endif // MOZ_OMX_DECODER
341 } // namespace mozilla