Thu, 15 Jan 2015 15:55:04 +0100
Back out 97036ab72558 which inappropriately compared turds to third parties.
michael@0 | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
michael@0 | 2 | // Use of this source code is governed by a BSD-style license that can be |
michael@0 | 3 | // found in the LICENSE file. |
michael@0 | 4 | |
michael@0 | 5 | #include "mp4_demuxer/video_util.h" |
michael@0 | 6 | |
michael@0 | 7 | #include <cmath> |
michael@0 | 8 | |
michael@0 | 9 | namespace mp4_demuxer { |
michael@0 | 10 | |
michael@0 | 11 | IntSize GetNaturalSize(const IntSize& visible_size, |
michael@0 | 12 | int aspect_ratio_numerator, |
michael@0 | 13 | int aspect_ratio_denominator) { |
michael@0 | 14 | if (aspect_ratio_denominator == 0 || |
michael@0 | 15 | aspect_ratio_numerator < 0 || |
michael@0 | 16 | aspect_ratio_denominator < 0) |
michael@0 | 17 | return IntSize(); |
michael@0 | 18 | |
michael@0 | 19 | double aspect_ratio = aspect_ratio_numerator / |
michael@0 | 20 | static_cast<double>(aspect_ratio_denominator); |
michael@0 | 21 | |
michael@0 | 22 | int width = floor(visible_size.width() * aspect_ratio + 0.5); |
michael@0 | 23 | int height = visible_size.height(); |
michael@0 | 24 | |
michael@0 | 25 | // An even width makes things easier for YV12 and appears to be the behavior |
michael@0 | 26 | // expected by WebKit layout tests. |
michael@0 | 27 | return IntSize(width & ~1, height); |
michael@0 | 28 | } |
michael@0 | 29 | |
michael@0 | 30 | /* |
michael@0 | 31 | void CopyPlane(size_t plane, const uint8_t* source, int stride, int rows, |
michael@0 | 32 | VideoFrame* frame) { |
michael@0 | 33 | uint8_t* dest = frame->data(plane); |
michael@0 | 34 | int dest_stride = frame->stride(plane); |
michael@0 | 35 | |
michael@0 | 36 | // Clamp in case source frame has smaller stride. |
michael@0 | 37 | int bytes_to_copy_per_row = std::min(frame->row_bytes(plane), stride); |
michael@0 | 38 | |
michael@0 | 39 | // Clamp in case source frame has smaller height. |
michael@0 | 40 | int rows_to_copy = std::min(frame->rows(plane), rows); |
michael@0 | 41 | |
michael@0 | 42 | // Copy! |
michael@0 | 43 | for (int row = 0; row < rows_to_copy; ++row) { |
michael@0 | 44 | memcpy(dest, source, bytes_to_copy_per_row); |
michael@0 | 45 | source += stride; |
michael@0 | 46 | dest += dest_stride; |
michael@0 | 47 | } |
michael@0 | 48 | } |
michael@0 | 49 | |
michael@0 | 50 | void CopyYPlane(const uint8_t* source, int stride, int rows, VideoFrame* frame) { |
michael@0 | 51 | CopyPlane(VideoFrame::kYPlane, source, stride, rows, frame); |
michael@0 | 52 | } |
michael@0 | 53 | |
michael@0 | 54 | void CopyUPlane(const uint8_t* source, int stride, int rows, VideoFrame* frame) { |
michael@0 | 55 | CopyPlane(VideoFrame::kUPlane, source, stride, rows, frame); |
michael@0 | 56 | } |
michael@0 | 57 | |
michael@0 | 58 | void CopyVPlane(const uint8_t* source, int stride, int rows, VideoFrame* frame) { |
michael@0 | 59 | CopyPlane(VideoFrame::kVPlane, source, stride, rows, frame); |
michael@0 | 60 | } |
michael@0 | 61 | |
michael@0 | 62 | void CopyAPlane(const uint8_t* source, int stride, int rows, VideoFrame* frame) { |
michael@0 | 63 | CopyPlane(VideoFrame::kAPlane, source, stride, rows, frame); |
michael@0 | 64 | } |
michael@0 | 65 | |
michael@0 | 66 | void MakeOpaqueAPlane(int stride, int rows, VideoFrame* frame) { |
michael@0 | 67 | int rows_to_clear = std::min(frame->rows(VideoFrame::kAPlane), rows); |
michael@0 | 68 | memset(frame->data(VideoFrame::kAPlane), 255, |
michael@0 | 69 | frame->stride(VideoFrame::kAPlane) * rows_to_clear); |
michael@0 | 70 | } |
michael@0 | 71 | |
michael@0 | 72 | void FillYUV(VideoFrame* frame, uint8_t y, uint8_t u, uint8_t v) { |
michael@0 | 73 | // Fill the Y plane. |
michael@0 | 74 | uint8_t* y_plane = frame->data(VideoFrame::kYPlane); |
michael@0 | 75 | int y_rows = frame->rows(VideoFrame::kYPlane); |
michael@0 | 76 | int y_row_bytes = frame->row_bytes(VideoFrame::kYPlane); |
michael@0 | 77 | for (int i = 0; i < y_rows; ++i) { |
michael@0 | 78 | memset(y_plane, y, y_row_bytes); |
michael@0 | 79 | y_plane += frame->stride(VideoFrame::kYPlane); |
michael@0 | 80 | } |
michael@0 | 81 | |
michael@0 | 82 | // Fill the U and V planes. |
michael@0 | 83 | uint8_t* u_plane = frame->data(VideoFrame::kUPlane); |
michael@0 | 84 | uint8_t* v_plane = frame->data(VideoFrame::kVPlane); |
michael@0 | 85 | int uv_rows = frame->rows(VideoFrame::kUPlane); |
michael@0 | 86 | int u_row_bytes = frame->row_bytes(VideoFrame::kUPlane); |
michael@0 | 87 | int v_row_bytes = frame->row_bytes(VideoFrame::kVPlane); |
michael@0 | 88 | for (int i = 0; i < uv_rows; ++i) { |
michael@0 | 89 | memset(u_plane, u, u_row_bytes); |
michael@0 | 90 | memset(v_plane, v, v_row_bytes); |
michael@0 | 91 | u_plane += frame->stride(VideoFrame::kUPlane); |
michael@0 | 92 | v_plane += frame->stride(VideoFrame::kVPlane); |
michael@0 | 93 | } |
michael@0 | 94 | } |
michael@0 | 95 | |
michael@0 | 96 | static void LetterboxPlane(VideoFrame* frame, |
michael@0 | 97 | int plane, |
michael@0 | 98 | const gfx::Rect& view_area, |
michael@0 | 99 | uint8_t fill_byte) { |
michael@0 | 100 | uint8_t* ptr = frame->data(plane); |
michael@0 | 101 | const int rows = frame->rows(plane); |
michael@0 | 102 | const int row_bytes = frame->row_bytes(plane); |
michael@0 | 103 | const int stride = frame->stride(plane); |
michael@0 | 104 | |
michael@0 | 105 | CHECK_GE(stride, row_bytes); |
michael@0 | 106 | CHECK_GE(view_area.x(), 0); |
michael@0 | 107 | CHECK_GE(view_area.y(), 0); |
michael@0 | 108 | CHECK_LE(view_area.right(), row_bytes); |
michael@0 | 109 | CHECK_LE(view_area.bottom(), rows); |
michael@0 | 110 | |
michael@0 | 111 | int y = 0; |
michael@0 | 112 | for (; y < view_area.y(); y++) { |
michael@0 | 113 | memset(ptr, fill_byte, row_bytes); |
michael@0 | 114 | ptr += stride; |
michael@0 | 115 | } |
michael@0 | 116 | if (view_area.width() < row_bytes) { |
michael@0 | 117 | for (; y < view_area.bottom(); y++) { |
michael@0 | 118 | if (view_area.x() > 0) { |
michael@0 | 119 | memset(ptr, fill_byte, view_area.x()); |
michael@0 | 120 | } |
michael@0 | 121 | if (view_area.right() < row_bytes) { |
michael@0 | 122 | memset(ptr + view_area.right(), |
michael@0 | 123 | fill_byte, |
michael@0 | 124 | row_bytes - view_area.right()); |
michael@0 | 125 | } |
michael@0 | 126 | ptr += stride; |
michael@0 | 127 | } |
michael@0 | 128 | } else { |
michael@0 | 129 | y += view_area.height(); |
michael@0 | 130 | ptr += stride * view_area.height(); |
michael@0 | 131 | } |
michael@0 | 132 | for (; y < rows; y++) { |
michael@0 | 133 | memset(ptr, fill_byte, row_bytes); |
michael@0 | 134 | ptr += stride; |
michael@0 | 135 | } |
michael@0 | 136 | } |
michael@0 | 137 | |
michael@0 | 138 | void LetterboxYUV(VideoFrame* frame, const gfx::Rect& view_area) { |
michael@0 | 139 | DCHECK(!(view_area.x() & 1)); |
michael@0 | 140 | DCHECK(!(view_area.y() & 1)); |
michael@0 | 141 | DCHECK(!(view_area.width() & 1)); |
michael@0 | 142 | DCHECK(!(view_area.height() & 1)); |
michael@0 | 143 | DCHECK_EQ(frame->format(), VideoFrame::YV12); |
michael@0 | 144 | LetterboxPlane(frame, VideoFrame::kYPlane, view_area, 0x00); |
michael@0 | 145 | gfx::Rect half_view_area(view_area.x() / 2, |
michael@0 | 146 | view_area.y() / 2, |
michael@0 | 147 | view_area.width() / 2, |
michael@0 | 148 | view_area.height() / 2); |
michael@0 | 149 | LetterboxPlane(frame, VideoFrame::kUPlane, half_view_area, 0x80); |
michael@0 | 150 | LetterboxPlane(frame, VideoFrame::kVPlane, half_view_area, 0x80); |
michael@0 | 151 | } |
michael@0 | 152 | |
michael@0 | 153 | void RotatePlaneByPixels( |
michael@0 | 154 | const uint8_t* src, |
michael@0 | 155 | uint8_t* dest, |
michael@0 | 156 | int width, |
michael@0 | 157 | int height, |
michael@0 | 158 | int rotation, // Clockwise. |
michael@0 | 159 | bool flip_vert, |
michael@0 | 160 | bool flip_horiz) { |
michael@0 | 161 | DCHECK((width > 0) && (height > 0) && |
michael@0 | 162 | ((width & 1) == 0) && ((height & 1) == 0) && |
michael@0 | 163 | (rotation >= 0) && (rotation < 360) && (rotation % 90 == 0)); |
michael@0 | 164 | |
michael@0 | 165 | // Consolidate cases. Only 0 and 90 are left. |
michael@0 | 166 | if (rotation == 180 || rotation == 270) { |
michael@0 | 167 | rotation -= 180; |
michael@0 | 168 | flip_vert = !flip_vert; |
michael@0 | 169 | flip_horiz = !flip_horiz; |
michael@0 | 170 | } |
michael@0 | 171 | |
michael@0 | 172 | int num_rows = height; |
michael@0 | 173 | int num_cols = width; |
michael@0 | 174 | int src_stride = width; |
michael@0 | 175 | // During pixel copying, the corresponding incremental of dest pointer |
michael@0 | 176 | // when src pointer moves to next row. |
michael@0 | 177 | int dest_row_step = width; |
michael@0 | 178 | // During pixel copying, the corresponding incremental of dest pointer |
michael@0 | 179 | // when src pointer moves to next column. |
michael@0 | 180 | int dest_col_step = 1; |
michael@0 | 181 | |
michael@0 | 182 | if (rotation == 0) { |
michael@0 | 183 | if (flip_horiz) { |
michael@0 | 184 | // Use pixel copying. |
michael@0 | 185 | dest_col_step = -1; |
michael@0 | 186 | if (flip_vert) { |
michael@0 | 187 | // Rotation 180. |
michael@0 | 188 | dest_row_step = -width; |
michael@0 | 189 | dest += height * width - 1; |
michael@0 | 190 | } else { |
michael@0 | 191 | dest += width - 1; |
michael@0 | 192 | } |
michael@0 | 193 | } else { |
michael@0 | 194 | if (flip_vert) { |
michael@0 | 195 | // Fast copy by rows. |
michael@0 | 196 | dest += width * (height - 1); |
michael@0 | 197 | for (int row = 0; row < height; ++row) { |
michael@0 | 198 | memcpy(dest, src, width); |
michael@0 | 199 | src += width; |
michael@0 | 200 | dest -= width; |
michael@0 | 201 | } |
michael@0 | 202 | } else { |
michael@0 | 203 | memcpy(dest, src, width * height); |
michael@0 | 204 | } |
michael@0 | 205 | return; |
michael@0 | 206 | } |
michael@0 | 207 | } else if (rotation == 90) { |
michael@0 | 208 | int offset; |
michael@0 | 209 | if (width > height) { |
michael@0 | 210 | offset = (width - height) / 2; |
michael@0 | 211 | src += offset; |
michael@0 | 212 | num_rows = num_cols = height; |
michael@0 | 213 | } else { |
michael@0 | 214 | offset = (height - width) / 2; |
michael@0 | 215 | src += width * offset; |
michael@0 | 216 | num_rows = num_cols = width; |
michael@0 | 217 | } |
michael@0 | 218 | |
michael@0 | 219 | dest_col_step = (flip_vert ? -width : width); |
michael@0 | 220 | dest_row_step = (flip_horiz ? 1 : -1); |
michael@0 | 221 | if (flip_horiz) { |
michael@0 | 222 | if (flip_vert) { |
michael@0 | 223 | dest += (width > height ? width * (height - 1) + offset : |
michael@0 | 224 | width * (height - offset - 1)); |
michael@0 | 225 | } else { |
michael@0 | 226 | dest += (width > height ? offset : width * offset); |
michael@0 | 227 | } |
michael@0 | 228 | } else { |
michael@0 | 229 | if (flip_vert) { |
michael@0 | 230 | dest += (width > height ? width * height - offset - 1 : |
michael@0 | 231 | width * (height - offset) - 1); |
michael@0 | 232 | } else { |
michael@0 | 233 | dest += (width > height ? width - offset - 1 : |
michael@0 | 234 | width * (offset + 1) - 1); |
michael@0 | 235 | } |
michael@0 | 236 | } |
michael@0 | 237 | } else { |
michael@0 | 238 | NOTREACHED(); |
michael@0 | 239 | } |
michael@0 | 240 | |
michael@0 | 241 | // Copy pixels. |
michael@0 | 242 | for (int row = 0; row < num_rows; ++row) { |
michael@0 | 243 | const uint8_t* src_ptr = src; |
michael@0 | 244 | uint8_t* dest_ptr = dest; |
michael@0 | 245 | for (int col = 0; col < num_cols; ++col) { |
michael@0 | 246 | *dest_ptr = *src_ptr++; |
michael@0 | 247 | dest_ptr += dest_col_step; |
michael@0 | 248 | } |
michael@0 | 249 | src += src_stride; |
michael@0 | 250 | dest += dest_row_step; |
michael@0 | 251 | } |
michael@0 | 252 | } |
michael@0 | 253 | |
michael@0 | 254 | gfx::Rect ComputeLetterboxRegion(const gfx::Rect& bounds, |
michael@0 | 255 | const IntSize& content) { |
michael@0 | 256 | int64_t x = static_cast<int64_t>(content.width()) * bounds.height(); |
michael@0 | 257 | int64_t y = static_cast<int64_t>(content.height()) * bounds.width(); |
michael@0 | 258 | |
michael@0 | 259 | IntSize letterbox(bounds.width(), bounds.height()); |
michael@0 | 260 | if (y < x) |
michael@0 | 261 | letterbox.set_height(static_cast<int>(y / content.width())); |
michael@0 | 262 | else |
michael@0 | 263 | letterbox.set_width(static_cast<int>(x / content.height())); |
michael@0 | 264 | gfx::Rect result = bounds; |
michael@0 | 265 | result.ClampToCenteredSize(letterbox); |
michael@0 | 266 | return result; |
michael@0 | 267 | } |
michael@0 | 268 | |
michael@0 | 269 | void CopyRGBToVideoFrame(const uint8_t* source, |
michael@0 | 270 | int stride, |
michael@0 | 271 | const gfx::Rect& region_in_frame, |
michael@0 | 272 | VideoFrame* frame) { |
michael@0 | 273 | const int kY = VideoFrame::kYPlane; |
michael@0 | 274 | const int kU = VideoFrame::kUPlane; |
michael@0 | 275 | const int kV = VideoFrame::kVPlane; |
michael@0 | 276 | CHECK_EQ(frame->stride(kU), frame->stride(kV)); |
michael@0 | 277 | const int uv_stride = frame->stride(kU); |
michael@0 | 278 | |
michael@0 | 279 | if (region_in_frame != gfx::Rect(frame->coded_size())) { |
michael@0 | 280 | LetterboxYUV(frame, region_in_frame); |
michael@0 | 281 | } |
michael@0 | 282 | |
michael@0 | 283 | const int y_offset = region_in_frame.x() |
michael@0 | 284 | + (region_in_frame.y() * frame->stride(kY)); |
michael@0 | 285 | const int uv_offset = region_in_frame.x() / 2 |
michael@0 | 286 | + (region_in_frame.y() / 2 * uv_stride); |
michael@0 | 287 | |
michael@0 | 288 | ConvertRGB32ToYUV(source, |
michael@0 | 289 | frame->data(kY) + y_offset, |
michael@0 | 290 | frame->data(kU) + uv_offset, |
michael@0 | 291 | frame->data(kV) + uv_offset, |
michael@0 | 292 | region_in_frame.width(), |
michael@0 | 293 | region_in_frame.height(), |
michael@0 | 294 | stride, |
michael@0 | 295 | frame->stride(kY), |
michael@0 | 296 | uv_stride); |
michael@0 | 297 | } |
michael@0 | 298 | */ |
michael@0 | 299 | } // namespace mp4_demuxer |