Revert of Cleanup NQE (patchset #5 id:80001 of https://codereview.chromium.org/127748...
[chromium-blink-merge.git] / media / base / video_util.cc
blobd43727f64eda0832fa2111d49d1ab90b42f9539d
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 "base/numerics/safe_conversions.h"
11 #include "base/numerics/safe_math.h"
12 #include "media/base/video_frame.h"
13 #include "media/base/yuv_convert.h"
15 namespace media {
17 gfx::Size GetNaturalSize(const gfx::Size& visible_size,
18 int aspect_ratio_numerator,
19 int aspect_ratio_denominator) {
20 if (aspect_ratio_denominator == 0 ||
21 aspect_ratio_numerator < 0 ||
22 aspect_ratio_denominator < 0)
23 return gfx::Size();
25 double aspect_ratio = aspect_ratio_numerator /
26 static_cast<double>(aspect_ratio_denominator);
28 int width = floor(visible_size.width() * aspect_ratio + 0.5);
29 int height = visible_size.height();
31 // An even width makes things easier for YV12 and appears to be the behavior
32 // expected by WebKit layout tests.
33 return gfx::Size(width & ~1, height);
36 void CopyPlane(size_t plane, const uint8* source, int stride, int rows,
37 VideoFrame* frame) {
38 uint8* dest = frame->data(plane);
39 int dest_stride = frame->stride(plane);
41 // Clamp in case source frame has smaller stride.
42 int bytes_to_copy_per_row = std::min(frame->row_bytes(plane), stride);
44 // Clamp in case source frame has smaller height.
45 int rows_to_copy = std::min(frame->rows(plane), rows);
47 // Copy!
48 for (int row = 0; row < rows_to_copy; ++row) {
49 memcpy(dest, source, bytes_to_copy_per_row);
50 source += stride;
51 dest += dest_stride;
55 void CopyYPlane(const uint8* source, int stride, int rows, VideoFrame* frame) {
56 CopyPlane(VideoFrame::kYPlane, source, stride, rows, frame);
59 void CopyUPlane(const uint8* source, int stride, int rows, VideoFrame* frame) {
60 CopyPlane(VideoFrame::kUPlane, source, stride, rows, frame);
63 void CopyVPlane(const uint8* source, int stride, int rows, VideoFrame* frame) {
64 CopyPlane(VideoFrame::kVPlane, source, stride, rows, frame);
67 void CopyAPlane(const uint8* source, int stride, int rows, VideoFrame* frame) {
68 CopyPlane(VideoFrame::kAPlane, source, stride, rows, frame);
71 void MakeOpaqueAPlane(int stride, int rows, VideoFrame* frame) {
72 int rows_to_clear = std::min(frame->rows(VideoFrame::kAPlane), rows);
73 memset(frame->data(VideoFrame::kAPlane), 255,
74 frame->stride(VideoFrame::kAPlane) * rows_to_clear);
77 void FillYUV(VideoFrame* frame, uint8 y, uint8 u, uint8 v) {
78 // Fill the Y plane.
79 uint8* y_plane = frame->data(VideoFrame::kYPlane);
80 int y_rows = frame->rows(VideoFrame::kYPlane);
81 int y_row_bytes = frame->row_bytes(VideoFrame::kYPlane);
82 for (int i = 0; i < y_rows; ++i) {
83 memset(y_plane, y, y_row_bytes);
84 y_plane += frame->stride(VideoFrame::kYPlane);
87 // Fill the U and V planes.
88 uint8* u_plane = frame->data(VideoFrame::kUPlane);
89 uint8* v_plane = frame->data(VideoFrame::kVPlane);
90 int uv_rows = frame->rows(VideoFrame::kUPlane);
91 int u_row_bytes = frame->row_bytes(VideoFrame::kUPlane);
92 int v_row_bytes = frame->row_bytes(VideoFrame::kVPlane);
93 for (int i = 0; i < uv_rows; ++i) {
94 memset(u_plane, u, u_row_bytes);
95 memset(v_plane, v, v_row_bytes);
96 u_plane += frame->stride(VideoFrame::kUPlane);
97 v_plane += frame->stride(VideoFrame::kVPlane);
101 void FillYUVA(VideoFrame* frame, uint8 y, uint8 u, uint8 v, uint8 a) {
102 // Fill Y, U and V planes.
103 FillYUV(frame, y, u, v);
105 // Fill the A plane.
106 uint8* a_plane = frame->data(VideoFrame::kAPlane);
107 int a_rows = frame->rows(VideoFrame::kAPlane);
108 int a_row_bytes = frame->row_bytes(VideoFrame::kAPlane);
109 for (int i = 0; i < a_rows; ++i) {
110 memset(a_plane, a, a_row_bytes);
111 a_plane += frame->stride(VideoFrame::kAPlane);
115 static void LetterboxPlane(VideoFrame* frame,
116 int plane,
117 const gfx::Rect& view_area,
118 uint8 fill_byte) {
119 uint8* ptr = frame->data(plane);
120 const int rows = frame->rows(plane);
121 const int row_bytes = frame->row_bytes(plane);
122 const int stride = frame->stride(plane);
124 CHECK_GE(stride, row_bytes);
125 CHECK_GE(view_area.x(), 0);
126 CHECK_GE(view_area.y(), 0);
127 CHECK_LE(view_area.right(), row_bytes);
128 CHECK_LE(view_area.bottom(), rows);
130 int y = 0;
131 for (; y < view_area.y(); y++) {
132 memset(ptr, fill_byte, row_bytes);
133 ptr += stride;
135 if (view_area.width() < row_bytes) {
136 for (; y < view_area.bottom(); y++) {
137 if (view_area.x() > 0) {
138 memset(ptr, fill_byte, view_area.x());
140 if (view_area.right() < row_bytes) {
141 memset(ptr + view_area.right(),
142 fill_byte,
143 row_bytes - view_area.right());
145 ptr += stride;
147 } else {
148 y += view_area.height();
149 ptr += stride * view_area.height();
151 for (; y < rows; y++) {
152 memset(ptr, fill_byte, row_bytes);
153 ptr += stride;
157 void LetterboxYUV(VideoFrame* frame, const gfx::Rect& view_area) {
158 DCHECK(!(view_area.x() & 1));
159 DCHECK(!(view_area.y() & 1));
160 DCHECK(!(view_area.width() & 1));
161 DCHECK(!(view_area.height() & 1));
162 DCHECK(frame->format() == PIXEL_FORMAT_YV12 ||
163 frame->format() == PIXEL_FORMAT_I420);
164 LetterboxPlane(frame, VideoFrame::kYPlane, view_area, 0x00);
165 gfx::Rect half_view_area(view_area.x() / 2,
166 view_area.y() / 2,
167 view_area.width() / 2,
168 view_area.height() / 2);
169 LetterboxPlane(frame, VideoFrame::kUPlane, half_view_area, 0x80);
170 LetterboxPlane(frame, VideoFrame::kVPlane, half_view_area, 0x80);
173 void RotatePlaneByPixels(
174 const uint8* src,
175 uint8* dest,
176 int width,
177 int height,
178 int rotation, // Clockwise.
179 bool flip_vert,
180 bool flip_horiz) {
181 DCHECK((width > 0) && (height > 0) &&
182 ((width & 1) == 0) && ((height & 1) == 0) &&
183 (rotation >= 0) && (rotation < 360) && (rotation % 90 == 0));
185 // Consolidate cases. Only 0 and 90 are left.
186 if (rotation == 180 || rotation == 270) {
187 rotation -= 180;
188 flip_vert = !flip_vert;
189 flip_horiz = !flip_horiz;
192 int num_rows = height;
193 int num_cols = width;
194 int src_stride = width;
195 // During pixel copying, the corresponding incremental of dest pointer
196 // when src pointer moves to next row.
197 int dest_row_step = width;
198 // During pixel copying, the corresponding incremental of dest pointer
199 // when src pointer moves to next column.
200 int dest_col_step = 1;
202 if (rotation == 0) {
203 if (flip_horiz) {
204 // Use pixel copying.
205 dest_col_step = -1;
206 if (flip_vert) {
207 // Rotation 180.
208 dest_row_step = -width;
209 dest += height * width - 1;
210 } else {
211 dest += width - 1;
213 } else {
214 if (flip_vert) {
215 // Fast copy by rows.
216 dest += width * (height - 1);
217 for (int row = 0; row < height; ++row) {
218 memcpy(dest, src, width);
219 src += width;
220 dest -= width;
222 } else {
223 memcpy(dest, src, width * height);
225 return;
227 } else if (rotation == 90) {
228 int offset;
229 if (width > height) {
230 offset = (width - height) / 2;
231 src += offset;
232 num_rows = num_cols = height;
233 } else {
234 offset = (height - width) / 2;
235 src += width * offset;
236 num_rows = num_cols = width;
239 dest_col_step = (flip_vert ? -width : width);
240 dest_row_step = (flip_horiz ? 1 : -1);
241 if (flip_horiz) {
242 if (flip_vert) {
243 dest += (width > height ? width * (height - 1) + offset :
244 width * (height - offset - 1));
245 } else {
246 dest += (width > height ? offset : width * offset);
248 } else {
249 if (flip_vert) {
250 dest += (width > height ? width * height - offset - 1 :
251 width * (height - offset) - 1);
252 } else {
253 dest += (width > height ? width - offset - 1 :
254 width * (offset + 1) - 1);
257 } else {
258 NOTREACHED();
261 // Copy pixels.
262 for (int row = 0; row < num_rows; ++row) {
263 const uint8* src_ptr = src;
264 uint8* dest_ptr = dest;
265 for (int col = 0; col < num_cols; ++col) {
266 *dest_ptr = *src_ptr++;
267 dest_ptr += dest_col_step;
269 src += src_stride;
270 dest += dest_row_step;
274 // Helper function to return |a| divided by |b|, rounded to the nearest integer.
275 static int RoundedDivision(int64 a, int b) {
276 DCHECK_GE(a, 0);
277 DCHECK_GT(b, 0);
278 base::CheckedNumeric<uint64> result(a);
279 result += b / 2;
280 result /= b;
281 return base::checked_cast<int>(result.ValueOrDie());
284 // Common logic for the letterboxing and scale-within/scale-encompassing
285 // functions. Scales |size| to either fit within or encompass |target|,
286 // depending on whether |fit_within_target| is true.
287 static gfx::Size ScaleSizeToTarget(const gfx::Size& size,
288 const gfx::Size& target,
289 bool fit_within_target) {
290 if (size.IsEmpty())
291 return gfx::Size(); // Corner case: Aspect ratio is undefined.
293 const int64 x = static_cast<int64>(size.width()) * target.height();
294 const int64 y = static_cast<int64>(size.height()) * target.width();
295 const bool use_target_width = fit_within_target ? (y < x) : (x < y);
296 return use_target_width ?
297 gfx::Size(target.width(), RoundedDivision(y, size.width())) :
298 gfx::Size(RoundedDivision(x, size.height()), target.height());
301 gfx::Rect ComputeLetterboxRegion(const gfx::Rect& bounds,
302 const gfx::Size& content) {
303 // If |content| has an undefined aspect ratio, let's not try to divide by
304 // zero.
305 if (content.IsEmpty())
306 return gfx::Rect();
308 gfx::Rect result = bounds;
309 result.ClampToCenteredSize(ScaleSizeToTarget(content, bounds.size(), true));
310 return result;
313 gfx::Size ScaleSizeToFitWithinTarget(const gfx::Size& size,
314 const gfx::Size& target) {
315 return ScaleSizeToTarget(size, target, true);
318 gfx::Size ScaleSizeToEncompassTarget(const gfx::Size& size,
319 const gfx::Size& target) {
320 return ScaleSizeToTarget(size, target, false);
323 gfx::Size PadToMatchAspectRatio(const gfx::Size& size,
324 const gfx::Size& target) {
325 if (target.IsEmpty())
326 return gfx::Size(); // Aspect ratio is undefined.
328 const int64 x = static_cast<int64>(size.width()) * target.height();
329 const int64 y = static_cast<int64>(size.height()) * target.width();
330 if (x < y)
331 return gfx::Size(RoundedDivision(y, target.height()), size.height());
332 return gfx::Size(size.width(), RoundedDivision(x, target.width()));
335 void CopyRGBToVideoFrame(const uint8* source,
336 int stride,
337 const gfx::Rect& region_in_frame,
338 VideoFrame* frame) {
339 const int kY = VideoFrame::kYPlane;
340 const int kU = VideoFrame::kUPlane;
341 const int kV = VideoFrame::kVPlane;
342 CHECK_EQ(frame->stride(kU), frame->stride(kV));
343 const int uv_stride = frame->stride(kU);
345 if (region_in_frame != gfx::Rect(frame->coded_size())) {
346 LetterboxYUV(frame, region_in_frame);
349 const int y_offset = region_in_frame.x()
350 + (region_in_frame.y() * frame->stride(kY));
351 const int uv_offset = region_in_frame.x() / 2
352 + (region_in_frame.y() / 2 * uv_stride);
354 ConvertRGB32ToYUV(source,
355 frame->data(kY) + y_offset,
356 frame->data(kU) + uv_offset,
357 frame->data(kV) + uv_offset,
358 region_in_frame.width(),
359 region_in_frame.height(),
360 stride,
361 frame->stride(kY),
362 uv_stride);
365 } // namespace media