/src/mozilla-central/dom/media/gmp/GMPVideoi420FrameImpl.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
3 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
5 | | |
6 | | #include "GMPVideoi420FrameImpl.h" |
7 | | #include "mozilla/gmp/GMPTypes.h" |
8 | | #include "mozilla/CheckedInt.h" |
9 | | |
10 | | namespace mozilla { |
11 | | namespace gmp { |
12 | | |
13 | | GMPVideoi420FrameImpl::GMPVideoi420FrameImpl(GMPVideoHostImpl* aHost) |
14 | | : mYPlane(aHost), |
15 | | mUPlane(aHost), |
16 | | mVPlane(aHost), |
17 | | mWidth(0), |
18 | | mHeight(0), |
19 | | mTimestamp(0ll), |
20 | | mDuration(0ll) |
21 | 0 | { |
22 | 0 | MOZ_ASSERT(aHost); |
23 | 0 | } |
24 | | |
25 | | GMPVideoi420FrameImpl::GMPVideoi420FrameImpl(const GMPVideoi420FrameData& aFrameData, |
26 | | GMPVideoHostImpl* aHost) |
27 | | : mYPlane(aFrameData.mYPlane(), aHost), |
28 | | mUPlane(aFrameData.mUPlane(), aHost), |
29 | | mVPlane(aFrameData.mVPlane(), aHost), |
30 | | mWidth(aFrameData.mWidth()), |
31 | | mHeight(aFrameData.mHeight()), |
32 | | mTimestamp(aFrameData.mTimestamp()), |
33 | | mDuration(aFrameData.mDuration()) |
34 | 0 | { |
35 | 0 | MOZ_ASSERT(aHost); |
36 | 0 | } |
37 | | |
38 | | GMPVideoi420FrameImpl::~GMPVideoi420FrameImpl() |
39 | 0 | { |
40 | 0 | } |
41 | | |
42 | | bool |
43 | | GMPVideoi420FrameImpl::InitFrameData(GMPVideoi420FrameData& aFrameData) |
44 | 0 | { |
45 | 0 | mYPlane.InitPlaneData(aFrameData.mYPlane()); |
46 | 0 | mUPlane.InitPlaneData(aFrameData.mUPlane()); |
47 | 0 | mVPlane.InitPlaneData(aFrameData.mVPlane()); |
48 | 0 | aFrameData.mWidth() = mWidth; |
49 | 0 | aFrameData.mHeight() = mHeight; |
50 | 0 | aFrameData.mTimestamp() = mTimestamp; |
51 | 0 | aFrameData.mDuration() = mDuration; |
52 | 0 | return true; |
53 | 0 | } |
54 | | |
55 | | GMPVideoFrameFormat |
56 | | GMPVideoi420FrameImpl::GetFrameFormat() |
57 | 0 | { |
58 | 0 | return kGMPI420VideoFrame; |
59 | 0 | } |
60 | | |
61 | | void |
62 | | GMPVideoi420FrameImpl::Destroy() |
63 | 0 | { |
64 | 0 | delete this; |
65 | 0 | } |
66 | | |
67 | | /* static */ bool |
68 | | GMPVideoi420FrameImpl::CheckFrameData(const GMPVideoi420FrameData& aFrameData) |
69 | 0 | { |
70 | 0 | // We may be passed the "wrong" shmem (one smaller than the actual size). |
71 | 0 | // This implies a bug or serious error on the child size. Ignore this frame if so. |
72 | 0 | // Note: Size() greater than expected is also an error, but with no negative consequences |
73 | 0 | int32_t half_width = (aFrameData.mWidth() + 1) / 2; |
74 | 0 | if ((aFrameData.mYPlane().mStride() <= 0) || (aFrameData.mYPlane().mSize() <= 0) || |
75 | 0 | (aFrameData.mUPlane().mStride() <= 0) || (aFrameData.mUPlane().mSize() <= 0) || |
76 | 0 | (aFrameData.mVPlane().mStride() <= 0) || (aFrameData.mVPlane().mSize() <= 0) || |
77 | 0 | (aFrameData.mYPlane().mSize() > (int32_t) aFrameData.mYPlane().mBuffer().Size<uint8_t>()) || |
78 | 0 | (aFrameData.mUPlane().mSize() > (int32_t) aFrameData.mUPlane().mBuffer().Size<uint8_t>()) || |
79 | 0 | (aFrameData.mVPlane().mSize() > (int32_t) aFrameData.mVPlane().mBuffer().Size<uint8_t>()) || |
80 | 0 | (aFrameData.mYPlane().mStride() < aFrameData.mWidth()) || |
81 | 0 | (aFrameData.mUPlane().mStride() < half_width) || |
82 | 0 | (aFrameData.mVPlane().mStride() < half_width) || |
83 | 0 | (aFrameData.mYPlane().mSize() < aFrameData.mYPlane().mStride() * aFrameData.mHeight()) || |
84 | 0 | (aFrameData.mUPlane().mSize() < aFrameData.mUPlane().mStride() * ((aFrameData.mHeight()+1)/2)) || |
85 | 0 | (aFrameData.mVPlane().mSize() < aFrameData.mVPlane().mStride() * ((aFrameData.mHeight()+1)/2))) |
86 | 0 | { |
87 | 0 | return false; |
88 | 0 | } |
89 | 0 | return true; |
90 | 0 | } |
91 | | |
92 | | bool |
93 | | GMPVideoi420FrameImpl::CheckDimensions(int32_t aWidth, int32_t aHeight, |
94 | | int32_t aStride_y, int32_t aStride_u, int32_t aStride_v) |
95 | 0 | { |
96 | 0 | int32_t half_width = (aWidth + 1) / 2; |
97 | 0 | if (aWidth < 1 || aHeight < 1 || |
98 | 0 | aStride_y < aWidth || aStride_u < half_width || aStride_v < half_width || |
99 | 0 | !(CheckedInt<int32_t>(aHeight) * aStride_y |
100 | 0 | + ((CheckedInt<int32_t>(aHeight) + 1) / 2) |
101 | 0 | * (CheckedInt<int32_t>(aStride_u) + aStride_v)).isValid()) { |
102 | 0 | return false; |
103 | 0 | } |
104 | 0 | return true; |
105 | 0 | } |
106 | | |
107 | | const GMPPlaneImpl* |
108 | 0 | GMPVideoi420FrameImpl::GetPlane(GMPPlaneType aType) const { |
109 | 0 | switch (aType) { |
110 | 0 | case kGMPYPlane: |
111 | 0 | return &mYPlane; |
112 | 0 | case kGMPUPlane: |
113 | 0 | return &mUPlane; |
114 | 0 | case kGMPVPlane: |
115 | 0 | return &mVPlane; |
116 | 0 | default: |
117 | 0 | MOZ_CRASH("Unknown plane type!"); |
118 | 0 | } |
119 | 0 | return nullptr; |
120 | 0 | } |
121 | | |
122 | | GMPPlaneImpl* |
123 | 0 | GMPVideoi420FrameImpl::GetPlane(GMPPlaneType aType) { |
124 | 0 | switch (aType) { |
125 | 0 | case kGMPYPlane : |
126 | 0 | return &mYPlane; |
127 | 0 | case kGMPUPlane : |
128 | 0 | return &mUPlane; |
129 | 0 | case kGMPVPlane : |
130 | 0 | return &mVPlane; |
131 | 0 | default: |
132 | 0 | MOZ_CRASH("Unknown plane type!"); |
133 | 0 | } |
134 | 0 | return nullptr; |
135 | 0 | } |
136 | | |
137 | | GMPErr |
138 | | GMPVideoi420FrameImpl::CreateEmptyFrame(int32_t aWidth, int32_t aHeight, |
139 | | int32_t aStride_y, int32_t aStride_u, int32_t aStride_v) |
140 | 0 | { |
141 | 0 | if (!CheckDimensions(aWidth, aHeight, aStride_y, aStride_u, aStride_v)) { |
142 | 0 | return GMPGenericErr; |
143 | 0 | } |
144 | 0 | |
145 | 0 | int32_t size_y = aStride_y * aHeight; |
146 | 0 | int32_t half_height = (aHeight + 1) / 2; |
147 | 0 | int32_t size_u = aStride_u * half_height; |
148 | 0 | int32_t size_v = aStride_v * half_height; |
149 | 0 |
|
150 | 0 | GMPErr err = mYPlane.CreateEmptyPlane(size_y, aStride_y, size_y); |
151 | 0 | if (err != GMPNoErr) { |
152 | 0 | return err; |
153 | 0 | } |
154 | 0 | err = mUPlane.CreateEmptyPlane(size_u, aStride_u, size_u); |
155 | 0 | if (err != GMPNoErr) { |
156 | 0 | return err; |
157 | 0 | } |
158 | 0 | err = mVPlane.CreateEmptyPlane(size_v, aStride_v, size_v); |
159 | 0 | if (err != GMPNoErr) { |
160 | 0 | return err; |
161 | 0 | } |
162 | 0 | |
163 | 0 | mWidth = aWidth; |
164 | 0 | mHeight = aHeight; |
165 | 0 | mTimestamp = 0ll; |
166 | 0 | mDuration = 0ll; |
167 | 0 |
|
168 | 0 | return GMPNoErr; |
169 | 0 | } |
170 | | |
171 | | GMPErr |
172 | | GMPVideoi420FrameImpl::CreateFrame(int32_t aSize_y, const uint8_t* aBuffer_y, |
173 | | int32_t aSize_u, const uint8_t* aBuffer_u, |
174 | | int32_t aSize_v, const uint8_t* aBuffer_v, |
175 | | int32_t aWidth, int32_t aHeight, |
176 | | int32_t aStride_y, int32_t aStride_u, int32_t aStride_v) |
177 | 0 | { |
178 | 0 | MOZ_ASSERT(aBuffer_y); |
179 | 0 | MOZ_ASSERT(aBuffer_u); |
180 | 0 | MOZ_ASSERT(aBuffer_v); |
181 | 0 |
|
182 | 0 | if (aSize_y < 1 || aSize_u < 1 || aSize_v < 1) { |
183 | 0 | return GMPGenericErr; |
184 | 0 | } |
185 | 0 | |
186 | 0 | if (!CheckDimensions(aWidth, aHeight, aStride_y, aStride_u, aStride_v)) { |
187 | 0 | return GMPGenericErr; |
188 | 0 | } |
189 | 0 | |
190 | 0 | GMPErr err = mYPlane.Copy(aSize_y, aStride_y, aBuffer_y); |
191 | 0 | if (err != GMPNoErr) { |
192 | 0 | return err; |
193 | 0 | } |
194 | 0 | err = mUPlane.Copy(aSize_u, aStride_u, aBuffer_u); |
195 | 0 | if (err != GMPNoErr) { |
196 | 0 | return err; |
197 | 0 | } |
198 | 0 | err = mVPlane.Copy(aSize_v, aStride_v, aBuffer_v); |
199 | 0 | if (err != GMPNoErr) { |
200 | 0 | return err; |
201 | 0 | } |
202 | 0 | |
203 | 0 | mWidth = aWidth; |
204 | 0 | mHeight = aHeight; |
205 | 0 |
|
206 | 0 | return GMPNoErr; |
207 | 0 | } |
208 | | |
209 | | GMPErr |
210 | | GMPVideoi420FrameImpl::CopyFrame(const GMPVideoi420Frame& aFrame) |
211 | 0 | { |
212 | 0 | auto& f = static_cast<const GMPVideoi420FrameImpl&>(aFrame); |
213 | 0 |
|
214 | 0 | GMPErr err = mYPlane.Copy(f.mYPlane); |
215 | 0 | if (err != GMPNoErr) { |
216 | 0 | return err; |
217 | 0 | } |
218 | 0 | |
219 | 0 | err = mUPlane.Copy(f.mUPlane); |
220 | 0 | if (err != GMPNoErr) { |
221 | 0 | return err; |
222 | 0 | } |
223 | 0 | |
224 | 0 | err = mVPlane.Copy(f.mVPlane); |
225 | 0 | if (err != GMPNoErr) { |
226 | 0 | return err; |
227 | 0 | } |
228 | 0 | |
229 | 0 | mWidth = f.mWidth; |
230 | 0 | mHeight = f.mHeight; |
231 | 0 | mTimestamp = f.mTimestamp; |
232 | 0 | mDuration = f.mDuration; |
233 | 0 |
|
234 | 0 | return GMPNoErr; |
235 | 0 | } |
236 | | |
237 | | void |
238 | | GMPVideoi420FrameImpl::SwapFrame(GMPVideoi420Frame* aFrame) |
239 | 0 | { |
240 | 0 | auto f = static_cast<GMPVideoi420FrameImpl*>(aFrame); |
241 | 0 | mYPlane.Swap(f->mYPlane); |
242 | 0 | mUPlane.Swap(f->mUPlane); |
243 | 0 | mVPlane.Swap(f->mVPlane); |
244 | 0 | std::swap(mWidth, f->mWidth); |
245 | 0 | std::swap(mHeight, f->mHeight); |
246 | 0 | std::swap(mTimestamp, f->mTimestamp); |
247 | 0 | std::swap(mDuration, f->mDuration); |
248 | 0 | } |
249 | | |
250 | | uint8_t* |
251 | | GMPVideoi420FrameImpl::Buffer(GMPPlaneType aType) |
252 | 0 | { |
253 | 0 | GMPPlane* p = GetPlane(aType); |
254 | 0 | if (p) { |
255 | 0 | return p->Buffer(); |
256 | 0 | } |
257 | 0 | return nullptr; |
258 | 0 | } |
259 | | |
260 | | const uint8_t* |
261 | | GMPVideoi420FrameImpl::Buffer(GMPPlaneType aType) const |
262 | 0 | { |
263 | 0 | const GMPPlane* p = GetPlane(aType); |
264 | 0 | if (p) { |
265 | 0 | return p->Buffer(); |
266 | 0 | } |
267 | 0 | return nullptr; |
268 | 0 | } |
269 | | |
270 | | int32_t |
271 | | GMPVideoi420FrameImpl::AllocatedSize(GMPPlaneType aType) const |
272 | 0 | { |
273 | 0 | const GMPPlane* p = GetPlane(aType); |
274 | 0 | if (p) { |
275 | 0 | return p->AllocatedSize(); |
276 | 0 | } |
277 | 0 | return -1; |
278 | 0 | } |
279 | | |
280 | | int32_t |
281 | | GMPVideoi420FrameImpl::Stride(GMPPlaneType aType) const |
282 | 0 | { |
283 | 0 | const GMPPlane* p = GetPlane(aType); |
284 | 0 | if (p) { |
285 | 0 | return p->Stride(); |
286 | 0 | } |
287 | 0 | return -1; |
288 | 0 | } |
289 | | |
290 | | GMPErr |
291 | | GMPVideoi420FrameImpl::SetWidth(int32_t aWidth) |
292 | 0 | { |
293 | 0 | if (!CheckDimensions(aWidth, mHeight, |
294 | 0 | mYPlane.Stride(), mUPlane.Stride(), |
295 | 0 | mVPlane.Stride())) { |
296 | 0 | return GMPGenericErr; |
297 | 0 | } |
298 | 0 | mWidth = aWidth; |
299 | 0 | return GMPNoErr; |
300 | 0 | } |
301 | | |
302 | | GMPErr |
303 | | GMPVideoi420FrameImpl::SetHeight(int32_t aHeight) |
304 | 0 | { |
305 | 0 | if (!CheckDimensions(mWidth, aHeight, |
306 | 0 | mYPlane.Stride(), mUPlane.Stride(), |
307 | 0 | mVPlane.Stride())) { |
308 | 0 | return GMPGenericErr; |
309 | 0 | } |
310 | 0 | mHeight = aHeight; |
311 | 0 | return GMPNoErr; |
312 | 0 | } |
313 | | |
314 | | int32_t |
315 | | GMPVideoi420FrameImpl::Width() const |
316 | 0 | { |
317 | 0 | return mWidth; |
318 | 0 | } |
319 | | |
320 | | int32_t |
321 | | GMPVideoi420FrameImpl::Height() const |
322 | 0 | { |
323 | 0 | return mHeight; |
324 | 0 | } |
325 | | |
326 | | void |
327 | | GMPVideoi420FrameImpl::SetTimestamp(uint64_t aTimestamp) |
328 | 0 | { |
329 | 0 | mTimestamp = aTimestamp; |
330 | 0 | } |
331 | | |
332 | | uint64_t |
333 | | GMPVideoi420FrameImpl::Timestamp() const |
334 | 0 | { |
335 | 0 | return mTimestamp; |
336 | 0 | } |
337 | | |
338 | | void |
339 | | GMPVideoi420FrameImpl::SetDuration(uint64_t aDuration) |
340 | 0 | { |
341 | 0 | mDuration = aDuration; |
342 | 0 | } |
343 | | |
344 | | uint64_t |
345 | | GMPVideoi420FrameImpl::Duration() const |
346 | 0 | { |
347 | 0 | return mDuration; |
348 | 0 | } |
349 | | |
350 | | bool |
351 | | GMPVideoi420FrameImpl::IsZeroSize() const |
352 | 0 | { |
353 | 0 | return (mYPlane.IsZeroSize() && mUPlane.IsZeroSize() && mVPlane.IsZeroSize()); |
354 | 0 | } |
355 | | |
356 | | void |
357 | | GMPVideoi420FrameImpl::ResetSize() |
358 | 0 | { |
359 | 0 | mYPlane.ResetSize(); |
360 | 0 | mUPlane.ResetSize(); |
361 | 0 | mVPlane.ResetSize(); |
362 | 0 | } |
363 | | |
364 | | } // namespace gmp |
365 | | } // namespace mozilla |