Allow overlapping sync and async startup requests
[chromium-blink-merge.git] / media / base / video_util.cc
blobfda758efecb39ebcbb318767c3e10c2b1a51779d
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 static void LetterboxPlane(VideoFrame* frame,
100 int plane,
101 const gfx::Rect& view_area,
102 uint8 fill_byte) {
103 uint8* ptr = frame->data(plane);
104 const int rows = frame->rows(plane);
105 const int row_bytes = frame->row_bytes(plane);
106 const int stride = frame->stride(plane);
108 CHECK_GE(stride, row_bytes);
109 CHECK_GE(view_area.x(), 0);
110 CHECK_GE(view_area.y(), 0);
111 CHECK_LE(view_area.right(), row_bytes);
112 CHECK_LE(view_area.bottom(), rows);
114 int y = 0;
115 for (; y < view_area.y(); y++) {
116 memset(ptr, fill_byte, row_bytes);
117 ptr += stride;
119 if (view_area.width() < row_bytes) {
120 for (; y < view_area.bottom(); y++) {
121 if (view_area.x() > 0) {
122 memset(ptr, fill_byte, view_area.x());
124 if (view_area.right() < row_bytes) {
125 memset(ptr + view_area.right(),
126 fill_byte,
127 row_bytes - view_area.right());
129 ptr += stride;
131 } else {
132 y += view_area.height();
133 ptr += stride * view_area.height();
135 for (; y < rows; y++) {
136 memset(ptr, fill_byte, row_bytes);
137 ptr += stride;
141 void LetterboxYUV(VideoFrame* frame, const gfx::Rect& view_area) {
142 DCHECK(!(view_area.x() & 1));
143 DCHECK(!(view_area.y() & 1));
144 DCHECK(!(view_area.width() & 1));
145 DCHECK(!(view_area.height() & 1));
146 DCHECK(frame->format() == VideoFrame::YV12 ||
147 frame->format() == VideoFrame::I420);
148 LetterboxPlane(frame, VideoFrame::kYPlane, view_area, 0x00);
149 gfx::Rect half_view_area(view_area.x() / 2,
150 view_area.y() / 2,
151 view_area.width() / 2,
152 view_area.height() / 2);
153 LetterboxPlane(frame, VideoFrame::kUPlane, half_view_area, 0x80);
154 LetterboxPlane(frame, VideoFrame::kVPlane, half_view_area, 0x80);
157 void RotatePlaneByPixels(
158 const uint8* src,
159 uint8* dest,
160 int width,
161 int height,
162 int rotation, // Clockwise.
163 bool flip_vert,
164 bool flip_horiz) {
165 DCHECK((width > 0) && (height > 0) &&
166 ((width & 1) == 0) && ((height & 1) == 0) &&
167 (rotation >= 0) && (rotation < 360) && (rotation % 90 == 0));
169 // Consolidate cases. Only 0 and 90 are left.
170 if (rotation == 180 || rotation == 270) {
171 rotation -= 180;
172 flip_vert = !flip_vert;
173 flip_horiz = !flip_horiz;
176 int num_rows = height;
177 int num_cols = width;
178 int src_stride = width;
179 // During pixel copying, the corresponding incremental of dest pointer
180 // when src pointer moves to next row.
181 int dest_row_step = width;
182 // During pixel copying, the corresponding incremental of dest pointer
183 // when src pointer moves to next column.
184 int dest_col_step = 1;
186 if (rotation == 0) {
187 if (flip_horiz) {
188 // Use pixel copying.
189 dest_col_step = -1;
190 if (flip_vert) {
191 // Rotation 180.
192 dest_row_step = -width;
193 dest += height * width - 1;
194 } else {
195 dest += width - 1;
197 } else {
198 if (flip_vert) {
199 // Fast copy by rows.
200 dest += width * (height - 1);
201 for (int row = 0; row < height; ++row) {
202 memcpy(dest, src, width);
203 src += width;
204 dest -= width;
206 } else {
207 memcpy(dest, src, width * height);
209 return;
211 } else if (rotation == 90) {
212 int offset;
213 if (width > height) {
214 offset = (width - height) / 2;
215 src += offset;
216 num_rows = num_cols = height;
217 } else {
218 offset = (height - width) / 2;
219 src += width * offset;
220 num_rows = num_cols = width;
223 dest_col_step = (flip_vert ? -width : width);
224 dest_row_step = (flip_horiz ? 1 : -1);
225 if (flip_horiz) {
226 if (flip_vert) {
227 dest += (width > height ? width * (height - 1) + offset :
228 width * (height - offset - 1));
229 } else {
230 dest += (width > height ? offset : width * offset);
232 } else {
233 if (flip_vert) {
234 dest += (width > height ? width * height - offset - 1 :
235 width * (height - offset) - 1);
236 } else {
237 dest += (width > height ? width - offset - 1 :
238 width * (offset + 1) - 1);
241 } else {
242 NOTREACHED();
245 // Copy pixels.
246 for (int row = 0; row < num_rows; ++row) {
247 const uint8* src_ptr = src;
248 uint8* dest_ptr = dest;
249 for (int col = 0; col < num_cols; ++col) {
250 *dest_ptr = *src_ptr++;
251 dest_ptr += dest_col_step;
253 src += src_stride;
254 dest += dest_row_step;
258 gfx::Rect ComputeLetterboxRegion(const gfx::Rect& bounds,
259 const gfx::Size& content) {
260 // If |content| has an undefined aspect ratio, let's not try to divide by
261 // zero.
262 if (content.IsEmpty())
263 return gfx::Rect();
265 int64 x = static_cast<int64>(content.width()) * bounds.height();
266 int64 y = static_cast<int64>(content.height()) * bounds.width();
268 gfx::Size letterbox(bounds.width(), bounds.height());
269 if (y < x)
270 letterbox.set_height(static_cast<int>(y / content.width()));
271 else
272 letterbox.set_width(static_cast<int>(x / content.height()));
273 gfx::Rect result = bounds;
274 result.ClampToCenteredSize(letterbox);
275 return result;
278 void CopyRGBToVideoFrame(const uint8* source,
279 int stride,
280 const gfx::Rect& region_in_frame,
281 VideoFrame* frame) {
282 const int kY = VideoFrame::kYPlane;
283 const int kU = VideoFrame::kUPlane;
284 const int kV = VideoFrame::kVPlane;
285 CHECK_EQ(frame->stride(kU), frame->stride(kV));
286 const int uv_stride = frame->stride(kU);
288 if (region_in_frame != gfx::Rect(frame->coded_size())) {
289 LetterboxYUV(frame, region_in_frame);
292 const int y_offset = region_in_frame.x()
293 + (region_in_frame.y() * frame->stride(kY));
294 const int uv_offset = region_in_frame.x() / 2
295 + (region_in_frame.y() / 2 * uv_stride);
297 ConvertRGB32ToYUV(source,
298 frame->data(kY) + y_offset,
299 frame->data(kU) + uv_offset,
300 frame->data(kV) + uv_offset,
301 region_in_frame.width(),
302 region_in_frame.height(),
303 stride,
304 frame->stride(kY),
305 uv_stride);
308 } // namespace media