Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / media / base / video_util.cc
blobfb8a715f43395a11c47f50bba82dd2c6a155d773
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/base/video_util.h"
7 #include <cmath>
9 #include "base/logging.h"
10 #include "media/base/video_frame.h"
11 #include "media/base/yuv_convert.h"
13 namespace media {
15 gfx::Size GetNaturalSize(const gfx::Size& visible_size,
16 int aspect_ratio_numerator,
17 int aspect_ratio_denominator) {
18 if (aspect_ratio_denominator == 0 ||
19 aspect_ratio_numerator < 0 ||
20 aspect_ratio_denominator < 0)
21 return gfx::Size();
23 double aspect_ratio = aspect_ratio_numerator /
24 static_cast<double>(aspect_ratio_denominator);
26 int width = floor(visible_size.width() * aspect_ratio + 0.5);
27 int height = visible_size.height();
29 // An even width makes things easier for YV12 and appears to be the behavior
30 // expected by WebKit layout tests.
31 return gfx::Size(width & ~1, height);
34 void CopyPlane(size_t plane, const uint8* source, int stride, int rows,
35 VideoFrame* frame) {
36 uint8* dest = frame->data(plane);
37 int dest_stride = frame->stride(plane);
39 // Clamp in case source frame has smaller stride.
40 int bytes_to_copy_per_row = std::min(frame->row_bytes(plane), stride);
42 // Clamp in case source frame has smaller height.
43 int rows_to_copy = std::min(frame->rows(plane), rows);
45 // Copy!
46 for (int row = 0; row < rows_to_copy; ++row) {
47 memcpy(dest, source, bytes_to_copy_per_row);
48 source += stride;
49 dest += dest_stride;
53 void CopyYPlane(const uint8* source, int stride, int rows, VideoFrame* frame) {
54 CopyPlane(VideoFrame::kYPlane, source, stride, rows, frame);
57 void CopyUPlane(const uint8* source, int stride, int rows, VideoFrame* frame) {
58 CopyPlane(VideoFrame::kUPlane, source, stride, rows, frame);
61 void CopyVPlane(const uint8* source, int stride, int rows, VideoFrame* frame) {
62 CopyPlane(VideoFrame::kVPlane, source, stride, rows, frame);
65 void CopyAPlane(const uint8* source, int stride, int rows, VideoFrame* frame) {
66 CopyPlane(VideoFrame::kAPlane, source, stride, rows, frame);
69 void MakeOpaqueAPlane(int stride, int rows, VideoFrame* frame) {
70 int rows_to_clear = std::min(frame->rows(VideoFrame::kAPlane), rows);
71 memset(frame->data(VideoFrame::kAPlane), 255,
72 frame->stride(VideoFrame::kAPlane) * rows_to_clear);
75 void FillYUV(VideoFrame* frame, uint8 y, uint8 u, uint8 v) {
76 // Fill the Y plane.
77 uint8* y_plane = frame->data(VideoFrame::kYPlane);
78 int y_rows = frame->rows(VideoFrame::kYPlane);
79 int y_row_bytes = frame->row_bytes(VideoFrame::kYPlane);
80 for (int i = 0; i < y_rows; ++i) {
81 memset(y_plane, y, y_row_bytes);
82 y_plane += frame->stride(VideoFrame::kYPlane);
85 // Fill the U and V planes.
86 uint8* u_plane = frame->data(VideoFrame::kUPlane);
87 uint8* v_plane = frame->data(VideoFrame::kVPlane);
88 int uv_rows = frame->rows(VideoFrame::kUPlane);
89 int u_row_bytes = frame->row_bytes(VideoFrame::kUPlane);
90 int v_row_bytes = frame->row_bytes(VideoFrame::kVPlane);
91 for (int i = 0; i < uv_rows; ++i) {
92 memset(u_plane, u, u_row_bytes);
93 memset(v_plane, v, v_row_bytes);
94 u_plane += frame->stride(VideoFrame::kUPlane);
95 v_plane += frame->stride(VideoFrame::kVPlane);
99 void FillYUVA(VideoFrame* frame, uint8 y, uint8 u, uint8 v, uint8 a) {
100 // Fill Y, U and V planes.
101 FillYUV(frame, y, u, v);
103 // Fill the A plane.
104 uint8* a_plane = frame->data(VideoFrame::kAPlane);
105 int a_rows = frame->rows(VideoFrame::kAPlane);
106 int a_row_bytes = frame->row_bytes(VideoFrame::kAPlane);
107 for (int i = 0; i < a_rows; ++i) {
108 memset(a_plane, a, a_row_bytes);
109 a_plane += frame->stride(VideoFrame::kAPlane);
113 static void LetterboxPlane(VideoFrame* frame,
114 int plane,
115 const gfx::Rect& view_area,
116 uint8 fill_byte) {
117 uint8* ptr = frame->data(plane);
118 const int rows = frame->rows(plane);
119 const int row_bytes = frame->row_bytes(plane);
120 const int stride = frame->stride(plane);
122 CHECK_GE(stride, row_bytes);
123 CHECK_GE(view_area.x(), 0);
124 CHECK_GE(view_area.y(), 0);
125 CHECK_LE(view_area.right(), row_bytes);
126 CHECK_LE(view_area.bottom(), rows);
128 int y = 0;
129 for (; y < view_area.y(); y++) {
130 memset(ptr, fill_byte, row_bytes);
131 ptr += stride;
133 if (view_area.width() < row_bytes) {
134 for (; y < view_area.bottom(); y++) {
135 if (view_area.x() > 0) {
136 memset(ptr, fill_byte, view_area.x());
138 if (view_area.right() < row_bytes) {
139 memset(ptr + view_area.right(),
140 fill_byte,
141 row_bytes - view_area.right());
143 ptr += stride;
145 } else {
146 y += view_area.height();
147 ptr += stride * view_area.height();
149 for (; y < rows; y++) {
150 memset(ptr, fill_byte, row_bytes);
151 ptr += stride;
155 void LetterboxYUV(VideoFrame* frame, const gfx::Rect& view_area) {
156 DCHECK(!(view_area.x() & 1));
157 DCHECK(!(view_area.y() & 1));
158 DCHECK(!(view_area.width() & 1));
159 DCHECK(!(view_area.height() & 1));
160 DCHECK(frame->format() == VideoFrame::YV12 ||
161 frame->format() == VideoFrame::I420);
162 LetterboxPlane(frame, VideoFrame::kYPlane, view_area, 0x00);
163 gfx::Rect half_view_area(view_area.x() / 2,
164 view_area.y() / 2,
165 view_area.width() / 2,
166 view_area.height() / 2);
167 LetterboxPlane(frame, VideoFrame::kUPlane, half_view_area, 0x80);
168 LetterboxPlane(frame, VideoFrame::kVPlane, half_view_area, 0x80);
171 void RotatePlaneByPixels(
172 const uint8* src,
173 uint8* dest,
174 int width,
175 int height,
176 int rotation, // Clockwise.
177 bool flip_vert,
178 bool flip_horiz) {
179 DCHECK((width > 0) && (height > 0) &&
180 ((width & 1) == 0) && ((height & 1) == 0) &&
181 (rotation >= 0) && (rotation < 360) && (rotation % 90 == 0));
183 // Consolidate cases. Only 0 and 90 are left.
184 if (rotation == 180 || rotation == 270) {
185 rotation -= 180;
186 flip_vert = !flip_vert;
187 flip_horiz = !flip_horiz;
190 int num_rows = height;
191 int num_cols = width;
192 int src_stride = width;
193 // During pixel copying, the corresponding incremental of dest pointer
194 // when src pointer moves to next row.
195 int dest_row_step = width;
196 // During pixel copying, the corresponding incremental of dest pointer
197 // when src pointer moves to next column.
198 int dest_col_step = 1;
200 if (rotation == 0) {
201 if (flip_horiz) {
202 // Use pixel copying.
203 dest_col_step = -1;
204 if (flip_vert) {
205 // Rotation 180.
206 dest_row_step = -width;
207 dest += height * width - 1;
208 } else {
209 dest += width - 1;
211 } else {
212 if (flip_vert) {
213 // Fast copy by rows.
214 dest += width * (height - 1);
215 for (int row = 0; row < height; ++row) {
216 memcpy(dest, src, width);
217 src += width;
218 dest -= width;
220 } else {
221 memcpy(dest, src, width * height);
223 return;
225 } else if (rotation == 90) {
226 int offset;
227 if (width > height) {
228 offset = (width - height) / 2;
229 src += offset;
230 num_rows = num_cols = height;
231 } else {
232 offset = (height - width) / 2;
233 src += width * offset;
234 num_rows = num_cols = width;
237 dest_col_step = (flip_vert ? -width : width);
238 dest_row_step = (flip_horiz ? 1 : -1);
239 if (flip_horiz) {
240 if (flip_vert) {
241 dest += (width > height ? width * (height - 1) + offset :
242 width * (height - offset - 1));
243 } else {
244 dest += (width > height ? offset : width * offset);
246 } else {
247 if (flip_vert) {
248 dest += (width > height ? width * height - offset - 1 :
249 width * (height - offset) - 1);
250 } else {
251 dest += (width > height ? width - offset - 1 :
252 width * (offset + 1) - 1);
255 } else {
256 NOTREACHED();
259 // Copy pixels.
260 for (int row = 0; row < num_rows; ++row) {
261 const uint8* src_ptr = src;
262 uint8* dest_ptr = dest;
263 for (int col = 0; col < num_cols; ++col) {
264 *dest_ptr = *src_ptr++;
265 dest_ptr += dest_col_step;
267 src += src_stride;
268 dest += dest_row_step;
272 // Common logic for the letterboxing and scale-within/scale-encompassing
273 // functions. Scales |size| to either fit within or encompass |target|,
274 // depending on whether |fit_within_target| is true.
275 static gfx::Size ScaleSizeToTarget(const gfx::Size& size,
276 const gfx::Size& target,
277 bool fit_within_target) {
278 if (size.IsEmpty())
279 return gfx::Size(); // Corner case: Aspect ratio is undefined.
281 const int64 x = static_cast<int64>(size.width()) * target.height();
282 const int64 y = static_cast<int64>(size.height()) * target.width();
283 const bool use_target_width = fit_within_target ? (y < x) : (x < y);
284 return use_target_width ?
285 gfx::Size(target.width(), static_cast<int>(y / size.width())) :
286 gfx::Size(static_cast<int>(x / size.height()), target.height());
289 gfx::Rect ComputeLetterboxRegion(const gfx::Rect& bounds,
290 const gfx::Size& content) {
291 // If |content| has an undefined aspect ratio, let's not try to divide by
292 // zero.
293 if (content.IsEmpty())
294 return gfx::Rect();
296 gfx::Rect result = bounds;
297 result.ClampToCenteredSize(ScaleSizeToTarget(content, bounds.size(), true));
298 return result;
301 gfx::Size ScaleSizeToFitWithinTarget(const gfx::Size& size,
302 const gfx::Size& target) {
303 return ScaleSizeToTarget(size, target, true);
306 gfx::Size ScaleSizeToEncompassTarget(const gfx::Size& size,
307 const gfx::Size& target) {
308 return ScaleSizeToTarget(size, target, false);
311 gfx::Size PadToMatchAspectRatio(const gfx::Size& size,
312 const gfx::Size& target) {
313 if (target.IsEmpty())
314 return gfx::Size(); // Aspect ratio is undefined.
316 const int64 x = static_cast<int64>(size.width()) * target.height();
317 const int64 y = static_cast<int64>(size.height()) * target.width();
318 if (x < y)
319 return gfx::Size(static_cast<int>(y / target.height()), size.height());
320 return gfx::Size(size.width(), static_cast<int>(x / target.width()));
323 void CopyRGBToVideoFrame(const uint8* source,
324 int stride,
325 const gfx::Rect& region_in_frame,
326 VideoFrame* frame) {
327 const int kY = VideoFrame::kYPlane;
328 const int kU = VideoFrame::kUPlane;
329 const int kV = VideoFrame::kVPlane;
330 CHECK_EQ(frame->stride(kU), frame->stride(kV));
331 const int uv_stride = frame->stride(kU);
333 if (region_in_frame != gfx::Rect(frame->coded_size())) {
334 LetterboxYUV(frame, region_in_frame);
337 const int y_offset = region_in_frame.x()
338 + (region_in_frame.y() * frame->stride(kY));
339 const int uv_offset = region_in_frame.x() / 2
340 + (region_in_frame.y() / 2 * uv_stride);
342 ConvertRGB32ToYUV(source,
343 frame->data(kY) + y_offset,
344 frame->data(kU) + uv_offset,
345 frame->data(kV) + uv_offset,
346 region_in_frame.width(),
347 region_in_frame.height(),
348 stride,
349 frame->stride(kY),
350 uv_stride);
353 } // namespace media