blob: dd5863dac66ba963adde40bc5e6324e02d99cde6 [file] [log] [blame]
mikhal@webrtc.org2cdb2d32011-11-28 18:09:41 +00001/*
mflodman@webrtc.orgc80d9d92012-02-06 10:11:25 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
mikhal@webrtc.org2cdb2d32011-11-28 18:09:41 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
pbos@webrtc.orgc69ae692013-06-04 09:02:37 +000011#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
mikhal@webrtc.org2cdb2d32011-11-28 18:09:41 +000012
13#include <assert.h>
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000014#include <string.h>
mikhal@webrtc.org2cdb2d32011-11-28 18:09:41 +000015
andrew@webrtc.orgb2d29bd2013-06-04 23:53:48 +000016// NOTE(ajm): Path provided by gyp.
17#include "libyuv.h" // NOLINT
mikhal@webrtc.org2cdb2d32011-11-28 18:09:41 +000018
19namespace webrtc {
20
mikhal@webrtc.orge39de162011-12-27 23:45:30 +000021VideoType RawVideoTypeToCommonVideoVideoType(RawVideoType type) {
22 switch (type) {
23 case kVideoI420:
24 return kI420;
25 case kVideoIYUV:
26 return kIYUV;
27 case kVideoRGB24:
28 return kRGB24;
29 case kVideoARGB:
30 return kARGB;
31 case kVideoARGB4444:
32 return kARGB4444;
33 case kVideoRGB565:
34 return kRGB565;
35 case kVideoARGB1555:
36 return kARGB1555;
37 case kVideoYUY2:
38 return kYUY2;
39 case kVideoYV12:
40 return kYV12;
41 case kVideoUYVY:
42 return kUYVY;
43 case kVideoNV21:
44 return kNV21;
45 case kVideoNV12:
46 return kNV12;
mikhal@webrtc.orgc00f91d2012-01-03 18:49:15 +000047 case kVideoBGRA:
48 return kBGRA;
mflodman@webrtc.org2f6104b2012-02-24 11:53:49 +000049 case kVideoMJPEG:
50 return kMJPG;
mikhal@webrtc.orge39de162011-12-27 23:45:30 +000051 default:
52 assert(false);
53 }
54 return kUnknown;
55}
56
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000057size_t CalcBufferSize(VideoType type, int width, int height) {
58 assert(width >= 0);
59 assert(height >= 0);
60 size_t buffer_size = 0;
mikhal@webrtc.org2cdb2d32011-11-28 18:09:41 +000061 switch (type) {
62 case kI420:
63 case kNV12:
64 case kNV21:
65 case kIYUV:
mikhal@webrtc.org0bb817d2012-07-10 20:48:48 +000066 case kYV12: {
67 int half_width = (width + 1) >> 1;
68 int half_height = (height + 1) >> 1;
69 buffer_size = width * height + half_width * half_height * 2;
mikhal@webrtc.org2cdb2d32011-11-28 18:09:41 +000070 break;
mikhal@webrtc.org0bb817d2012-07-10 20:48:48 +000071 }
mikhal@webrtc.org2cdb2d32011-11-28 18:09:41 +000072 case kARGB4444:
73 case kRGB565:
74 case kARGB1555:
75 case kYUY2:
76 case kUYVY:
mikhal@webrtc.org0bb817d2012-07-10 20:48:48 +000077 buffer_size = width * height * 2;
mikhal@webrtc.org2cdb2d32011-11-28 18:09:41 +000078 break;
79 case kRGB24:
mikhal@webrtc.org0bb817d2012-07-10 20:48:48 +000080 buffer_size = width * height * 3;
mikhal@webrtc.org2cdb2d32011-11-28 18:09:41 +000081 break;
mikhal@webrtc.orgc00f91d2012-01-03 18:49:15 +000082 case kBGRA:
mikhal@webrtc.org2cdb2d32011-11-28 18:09:41 +000083 case kARGB:
mikhal@webrtc.org0bb817d2012-07-10 20:48:48 +000084 buffer_size = width * height * 4;
mikhal@webrtc.org2cdb2d32011-11-28 18:09:41 +000085 break;
86 default:
87 assert(false);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000088 break;
mikhal@webrtc.org2cdb2d32011-11-28 18:09:41 +000089 }
mikhal@webrtc.org0bb817d2012-07-10 20:48:48 +000090 return buffer_size;
mikhal@webrtc.org2cdb2d32011-11-28 18:09:41 +000091}
92
nissec9c142f2016-05-17 04:05:47 -070093static int PrintPlane(const uint8_t* buf,
94 int width,
95 int height,
96 int stride,
97 FILE* file) {
98 for (int i = 0; i < height; i++, buf += stride) {
99 if (fwrite(buf, 1, width, file) != static_cast<unsigned int>(width))
100 return -1;
101 }
102 return 0;
103}
104
105// TODO(nisse): Belongs with the test code?
nisse64ec8f82016-09-27 00:17:25 -0700106int PrintVideoFrame(const VideoFrameBuffer& frame, FILE* file) {
107 int width = frame.width();
108 int height = frame.height();
nissec9c142f2016-05-17 04:05:47 -0700109 int chroma_width = (width + 1) / 2;
110 int chroma_height = (height + 1) / 2;
111
nisse64ec8f82016-09-27 00:17:25 -0700112 if (PrintPlane(frame.DataY(), width, height,
113 frame.StrideY(), file) < 0) {
nissec9c142f2016-05-17 04:05:47 -0700114 return -1;
115 }
nisse64ec8f82016-09-27 00:17:25 -0700116 if (PrintPlane(frame.DataU(),
nissec9c142f2016-05-17 04:05:47 -0700117 chroma_width, chroma_height,
nisse64ec8f82016-09-27 00:17:25 -0700118 frame.StrideU(), file) < 0) {
nissec9c142f2016-05-17 04:05:47 -0700119 return -1;
120 }
nisse64ec8f82016-09-27 00:17:25 -0700121 if (PrintPlane(frame.DataV(),
nissec9c142f2016-05-17 04:05:47 -0700122 chroma_width, chroma_height,
nisse64ec8f82016-09-27 00:17:25 -0700123 frame.StrideV(), file) < 0) {
nissec9c142f2016-05-17 04:05:47 -0700124 return -1;
jbauch0f2e9392015-12-10 03:11:42 -0800125 }
126 return 0;
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000127}
128
nisse64ec8f82016-09-27 00:17:25 -0700129int PrintVideoFrame(const VideoFrame& frame, FILE* file) {
130 if (frame.IsZeroSize())
131 return -1;
132 return PrintVideoFrame(*frame.video_frame_buffer(), file);
133}
134
Niels Möller718a7632016-06-13 13:06:01 +0200135int ExtractBuffer(const rtc::scoped_refptr<VideoFrameBuffer>& input_frame,
136 size_t size,
137 uint8_t* buffer) {
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000138 assert(buffer);
Niels Möller718a7632016-06-13 13:06:01 +0200139 if (!input_frame)
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000140 return -1;
Niels Möller718a7632016-06-13 13:06:01 +0200141 int width = input_frame->width();
142 int height = input_frame->height();
143 size_t length = CalcBufferSize(kI420, width, height);
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000144 if (size < length) {
145 return -1;
146 }
147
nissec9c142f2016-05-17 04:05:47 -0700148 int chroma_width = (width + 1) / 2;
149 int chroma_height = (height + 1) / 2;
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000150
Niels Möller718a7632016-06-13 13:06:01 +0200151 libyuv::I420Copy(input_frame->DataY(),
152 input_frame->StrideY(),
153 input_frame->DataU(),
154 input_frame->StrideU(),
155 input_frame->DataV(),
156 input_frame->StrideV(),
nissec9c142f2016-05-17 04:05:47 -0700157 buffer, width,
158 buffer + width*height, chroma_width,
159 buffer + width*height + chroma_width*chroma_height,
160 chroma_width,
161 width, height);
162
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000163 return static_cast<int>(length);
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000164}
165
Niels Möller718a7632016-06-13 13:06:01 +0200166int ExtractBuffer(const VideoFrame& input_frame, size_t size, uint8_t* buffer) {
167 return ExtractBuffer(input_frame.video_frame_buffer(), size, buffer);
168}
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000169
mikhal@webrtc.org2cdb2d32011-11-28 18:09:41 +0000170int ConvertNV12ToRGB565(const uint8_t* src_frame,
171 uint8_t* dst_frame,
172 int width, int height) {
mikhal@webrtc.org0bb817d2012-07-10 20:48:48 +0000173 int abs_height = (height < 0) ? -height : height;
mikhal@webrtc.org2cdb2d32011-11-28 18:09:41 +0000174 const uint8_t* yplane = src_frame;
mikhal@webrtc.org0bb817d2012-07-10 20:48:48 +0000175 const uint8_t* uvInterlaced = src_frame + (width * abs_height);
mikhal@webrtc.org2cdb2d32011-11-28 18:09:41 +0000176
177 return libyuv::NV12ToRGB565(yplane, width,
mikhal@webrtc.org0bb817d2012-07-10 20:48:48 +0000178 uvInterlaced, (width + 1) >> 1,
mikhal@webrtc.org2cdb2d32011-11-28 18:09:41 +0000179 dst_frame, width,
180 width, height);
181}
182
mikhal@webrtc.org2cdb2d32011-11-28 18:09:41 +0000183int ConvertRGB24ToARGB(const uint8_t* src_frame, uint8_t* dst_frame,
184 int width, int height, int dst_stride) {
mikhal@webrtc.org0bb817d2012-07-10 20:48:48 +0000185 if (dst_stride == 0)
mikhal@webrtc.org2cdb2d32011-11-28 18:09:41 +0000186 dst_stride = width;
mikhal@webrtc.org2cdb2d32011-11-28 18:09:41 +0000187 return libyuv::RGB24ToARGB(src_frame, width,
188 dst_frame, dst_stride,
189 width, height);
190}
191
guoweis@webrtc.org59140d62015-03-09 17:07:31 +0000192libyuv::RotationMode ConvertRotationMode(VideoRotation rotation) {
jbauch0f2e9392015-12-10 03:11:42 -0800193 switch (rotation) {
guoweis@webrtc.org59140d62015-03-09 17:07:31 +0000194 case kVideoRotation_0:
mikhal@webrtc.orge2642492011-12-28 21:21:40 +0000195 return libyuv::kRotate0;
guoweis@webrtc.org59140d62015-03-09 17:07:31 +0000196 case kVideoRotation_90:
mikhal@webrtc.orge2642492011-12-28 21:21:40 +0000197 return libyuv::kRotate90;
guoweis@webrtc.org59140d62015-03-09 17:07:31 +0000198 case kVideoRotation_180:
mikhal@webrtc.orge2642492011-12-28 21:21:40 +0000199 return libyuv::kRotate180;
guoweis@webrtc.org59140d62015-03-09 17:07:31 +0000200 case kVideoRotation_270:
mikhal@webrtc.orge2642492011-12-28 21:21:40 +0000201 return libyuv::kRotate270;
mikhal@webrtc.orge2642492011-12-28 21:21:40 +0000202 }
mflodman@webrtc.org657b2a42012-02-06 11:06:01 +0000203 assert(false);
204 return libyuv::kRotate0;
mikhal@webrtc.orge2642492011-12-28 21:21:40 +0000205}
206
207int ConvertVideoType(VideoType video_type) {
jbauch0f2e9392015-12-10 03:11:42 -0800208 switch (video_type) {
mikhal@webrtc.orge2642492011-12-28 21:21:40 +0000209 case kUnknown:
210 return libyuv::FOURCC_ANY;
mikhal@webrtc.orge2642492011-12-28 21:21:40 +0000211 case kI420:
212 return libyuv::FOURCC_I420;
mikhal@webrtc.orge2642492011-12-28 21:21:40 +0000213 case kIYUV: // same as KYV12
214 case kYV12:
215 return libyuv::FOURCC_YV12;
mikhal@webrtc.orge2642492011-12-28 21:21:40 +0000216 case kRGB24:
217 return libyuv::FOURCC_24BG;
mikhal@webrtc.orge2642492011-12-28 21:21:40 +0000218 case kABGR:
219 return libyuv::FOURCC_ABGR;
mikhal@webrtc.orga2026ba2012-01-05 18:19:32 +0000220 case kRGB565:
leozwang@webrtc.org3ebff4c2012-05-04 17:07:30 +0000221 return libyuv::FOURCC_RGBP;
mikhal@webrtc.orge2642492011-12-28 21:21:40 +0000222 case kYUY2:
223 return libyuv::FOURCC_YUY2;
mikhal@webrtc.orge2642492011-12-28 21:21:40 +0000224 case kUYVY:
225 return libyuv::FOURCC_UYVY;
mikhal@webrtc.orge2642492011-12-28 21:21:40 +0000226 case kMJPG:
227 return libyuv::FOURCC_MJPG;
mikhal@webrtc.orge2642492011-12-28 21:21:40 +0000228 case kNV21:
229 return libyuv::FOURCC_NV21;
mikhal@webrtc.orge2642492011-12-28 21:21:40 +0000230 case kNV12:
231 return libyuv::FOURCC_NV12;
mikhal@webrtc.orge2642492011-12-28 21:21:40 +0000232 case kARGB:
233 return libyuv::FOURCC_ARGB;
mikhal@webrtc.orge2642492011-12-28 21:21:40 +0000234 case kBGRA:
235 return libyuv::FOURCC_BGRA;
mikhal@webrtc.org73db8db2012-07-14 00:03:55 +0000236 case kARGB4444:
237 return libyuv::FOURCC_R444;
238 case kARGB1555:
239 return libyuv::FOURCC_RGBO;
mikhal@webrtc.orge2642492011-12-28 21:21:40 +0000240 }
mflodman@webrtc.org657b2a42012-02-06 11:06:01 +0000241 assert(false);
242 return libyuv::FOURCC_ANY;
mikhal@webrtc.orge2642492011-12-28 21:21:40 +0000243}
244
nissec9c142f2016-05-17 04:05:47 -0700245// TODO(nisse): Delete this wrapper, let callers use libyuv directly.
mikhal@webrtc.orge2642492011-12-28 21:21:40 +0000246int ConvertToI420(VideoType src_video_type,
247 const uint8_t* src_frame,
guoweis@webrtc.org59140d62015-03-09 17:07:31 +0000248 int crop_x,
249 int crop_y,
250 int src_width,
251 int src_height,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000252 size_t sample_size,
guoweis@webrtc.org59140d62015-03-09 17:07:31 +0000253 VideoRotation rotation,
nisse64ec8f82016-09-27 00:17:25 -0700254 I420Buffer* dst_buffer) {
255 int dst_width = dst_buffer->width();
256 int dst_height = dst_buffer->height();
mikhal@webrtc.org737ed3b2012-11-01 15:45:38 +0000257 // LibYuv expects pre-rotation values for dst.
258 // Stride values should correspond to the destination values.
guoweis@webrtc.org59140d62015-03-09 17:07:31 +0000259 if (rotation == kVideoRotation_90 || rotation == kVideoRotation_270) {
nisse64ec8f82016-09-27 00:17:25 -0700260 std::swap(dst_width, dst_height);
mikhal@webrtc.org737ed3b2012-11-01 15:45:38 +0000261 }
nissec9c142f2016-05-17 04:05:47 -0700262 return libyuv::ConvertToI420(
263 src_frame, sample_size,
nisse64ec8f82016-09-27 00:17:25 -0700264 dst_buffer->MutableDataY(), dst_buffer->StrideY(),
265 dst_buffer->MutableDataU(), dst_buffer->StrideU(),
266 dst_buffer->MutableDataV(), dst_buffer->StrideV(),
nissec9c142f2016-05-17 04:05:47 -0700267 crop_x, crop_y,
268 src_width, src_height,
269 dst_width, dst_height,
270 ConvertRotationMode(rotation),
271 ConvertVideoType(src_video_type));
mikhal@webrtc.orge2642492011-12-28 21:21:40 +0000272}
273
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -0700274int ConvertFromI420(const VideoFrame& src_frame,
275 VideoType dst_video_type,
276 int dst_sample_size,
mikhal@webrtc.orge2642492011-12-28 21:21:40 +0000277 uint8_t* dst_frame) {
nissec9c142f2016-05-17 04:05:47 -0700278 return libyuv::ConvertFromI420(
279 src_frame.video_frame_buffer()->DataY(),
280 src_frame.video_frame_buffer()->StrideY(),
281 src_frame.video_frame_buffer()->DataU(),
282 src_frame.video_frame_buffer()->StrideU(),
283 src_frame.video_frame_buffer()->DataV(),
284 src_frame.video_frame_buffer()->StrideV(),
285 dst_frame, dst_sample_size,
286 src_frame.width(), src_frame.height(),
287 ConvertVideoType(dst_video_type));
mikhal@webrtc.orge2642492011-12-28 21:21:40 +0000288}
289
mikhal@webrtc.org6f7fbc72011-12-20 17:38:28 +0000290// Compute PSNR for an I420 frame (all planes)
nisse1996e3f2016-09-19 00:34:46 -0700291double I420PSNR(const VideoFrameBuffer& ref_buffer,
292 const VideoFrameBuffer& test_buffer) {
293 if ((ref_buffer.width() != test_buffer.width()) ||
294 (ref_buffer.height() != test_buffer.height()))
mikhal@webrtc.org3f9a7212012-10-04 17:22:32 +0000295 return -1;
nisse1996e3f2016-09-19 00:34:46 -0700296 else if (ref_buffer.width() < 0 || ref_buffer.height() < 0)
magjed@webrtc.org2056ee32015-03-16 13:46:52 +0000297 return -1;
298
nisse1996e3f2016-09-19 00:34:46 -0700299 double psnr = libyuv::I420Psnr(ref_buffer.DataY(), ref_buffer.StrideY(),
300 ref_buffer.DataU(), ref_buffer.StrideU(),
301 ref_buffer.DataV(), ref_buffer.StrideV(),
302 test_buffer.DataY(), test_buffer.StrideY(),
303 test_buffer.DataU(), test_buffer.StrideU(),
304 test_buffer.DataV(), test_buffer.StrideV(),
305 test_buffer.width(), test_buffer.height());
phoglund@webrtc.org273ccad2012-11-29 10:08:16 +0000306 // LibYuv sets the max psnr value to 128, we restrict it here.
mikhal@webrtc.org3f9a7212012-10-04 17:22:32 +0000307 // In case of 0 mse in one frame, 128 can skew the results significantly.
phoglund@webrtc.org5b689ef2012-12-13 10:15:06 +0000308 return (psnr > kPerfectPSNR) ? kPerfectPSNR : psnr;
mikhal@webrtc.org3f9a7212012-10-04 17:22:32 +0000309}
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000310
nisse1996e3f2016-09-19 00:34:46 -0700311// Compute PSNR for an I420 frame (all planes)
312double I420PSNR(const VideoFrame* ref_frame, const VideoFrame* test_frame) {
313 if (!ref_frame || !test_frame)
314 return -1;
315 return I420PSNR(*ref_frame->video_frame_buffer(),
316 *test_frame->video_frame_buffer());
317}
318
mikhal@webrtc.org3f9a7212012-10-04 17:22:32 +0000319// Compute SSIM for an I420 frame (all planes)
nisse1996e3f2016-09-19 00:34:46 -0700320double I420SSIM(const VideoFrameBuffer& ref_buffer,
321 const VideoFrameBuffer& test_buffer) {
322 if ((ref_buffer.width() != test_buffer.width()) ||
323 (ref_buffer.height() != test_buffer.height()))
324 return -1;
325 else if (ref_buffer.width() < 0 || ref_buffer.height() < 0)
326 return -1;
327
328 return libyuv::I420Ssim(ref_buffer.DataY(), ref_buffer.StrideY(),
329 ref_buffer.DataU(), ref_buffer.StrideU(),
330 ref_buffer.DataV(), ref_buffer.StrideV(),
331 test_buffer.DataY(), test_buffer.StrideY(),
332 test_buffer.DataU(), test_buffer.StrideU(),
333 test_buffer.DataV(), test_buffer.StrideV(),
334 test_buffer.width(), test_buffer.height());
335}
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -0700336double I420SSIM(const VideoFrame* ref_frame, const VideoFrame* test_frame) {
magjed@webrtc.org2056ee32015-03-16 13:46:52 +0000337 if (!ref_frame || !test_frame)
mikhal@webrtc.org3f9a7212012-10-04 17:22:32 +0000338 return -1;
nisse1996e3f2016-09-19 00:34:46 -0700339 return I420SSIM(*ref_frame->video_frame_buffer(),
340 *test_frame->video_frame_buffer());
mikhal@webrtc.org3f9a7212012-10-04 17:22:32 +0000341}
magjed1a7ef1f2016-09-17 02:39:03 -0700342
magjed5a872452016-10-20 03:34:29 -0700343void NV12Scale(std::vector<uint8_t>* tmp_buffer,
344 const uint8_t* src_y, int src_stride_y,
345 const uint8_t* src_uv, int src_stride_uv,
346 int src_width, int src_height,
347 uint8_t* dst_y, int dst_stride_y,
348 uint8_t* dst_uv, int dst_stride_uv,
349 int dst_width, int dst_height) {
350 const int src_chroma_width = (src_width + 1) / 2;
351 const int src_chroma_height = (src_height + 1) / 2;
352
353 if (src_width == dst_width && src_height == dst_height) {
354 // No scaling.
355 tmp_buffer->clear();
356 tmp_buffer->shrink_to_fit();
357 libyuv::CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, src_width,
358 src_height);
359 libyuv::CopyPlane(src_uv, src_stride_uv, dst_uv, dst_stride_uv,
360 src_chroma_width * 2, src_chroma_height);
361 return;
362 }
363
364 // Scaling.
365 // Allocate temporary memory for spitting UV planes and scaling them.
366 const int dst_chroma_width = (dst_width + 1) / 2;
367 const int dst_chroma_height = (dst_height + 1) / 2;
368 tmp_buffer->resize(src_chroma_width * src_chroma_height * 2 +
369 dst_chroma_width * dst_chroma_height * 2);
370 tmp_buffer->shrink_to_fit();
371
372 uint8_t* const src_u = tmp_buffer->data();
373 uint8_t* const src_v = src_u + src_chroma_width * src_chroma_height;
374 uint8_t* const dst_u = src_v + src_chroma_width * src_chroma_height;
375 uint8_t* const dst_v = dst_u + dst_chroma_width * dst_chroma_height;
376
377 // Split source UV plane into separate U and V plane using the temporary data.
378 libyuv::SplitUVPlane(src_uv, src_stride_uv,
379 src_u, src_chroma_width,
380 src_v, src_chroma_width,
381 src_chroma_width, src_chroma_height);
382
383 // Scale the planes.
384 libyuv::I420Scale(src_y, src_stride_y,
385 src_u, src_chroma_width,
386 src_v, src_chroma_width,
387 src_width, src_height,
388 dst_y, dst_stride_y,
389 dst_u, dst_chroma_width,
390 dst_v, dst_chroma_width,
391 dst_width, dst_height,
392 libyuv::kFilterBox);
393
394 // Merge the UV planes into the destination.
395 libyuv::MergeUVPlane(dst_u, dst_chroma_width,
396 dst_v, dst_chroma_width,
397 dst_uv, dst_stride_uv,
398 dst_chroma_width, dst_chroma_height);
399}
400
magjed1a7ef1f2016-09-17 02:39:03 -0700401void NV12ToI420Scaler::NV12ToI420Scale(
402 const uint8_t* src_y, int src_stride_y,
403 const uint8_t* src_uv, int src_stride_uv,
404 int src_width, int src_height,
405 uint8_t* dst_y, int dst_stride_y,
406 uint8_t* dst_u, int dst_stride_u,
407 uint8_t* dst_v, int dst_stride_v,
408 int dst_width, int dst_height) {
409 if (src_width == dst_width && src_height == dst_height) {
410 // No scaling.
411 tmp_uv_planes_.clear();
412 tmp_uv_planes_.shrink_to_fit();
413 libyuv::NV12ToI420(
414 src_y, src_stride_y,
415 src_uv, src_stride_uv,
416 dst_y, dst_stride_y,
417 dst_u, dst_stride_u,
418 dst_v, dst_stride_v,
419 src_width, src_height);
420 return;
421 }
422
423 // Scaling.
424 // Allocate temporary memory for spitting UV planes.
425 const int src_uv_width = (src_width + 1) / 2;
426 const int src_uv_height = (src_height + 1) / 2;
427 tmp_uv_planes_.resize(src_uv_width * src_uv_height * 2);
428 tmp_uv_planes_.shrink_to_fit();
429
430 // Split source UV plane into separate U and V plane using the temporary data.
431 uint8_t* const src_u = tmp_uv_planes_.data();
432 uint8_t* const src_v = tmp_uv_planes_.data() + src_uv_width * src_uv_height;
433 libyuv::SplitUVPlane(src_uv, src_stride_uv,
434 src_u, src_uv_width,
435 src_v, src_uv_width,
436 src_uv_width, src_uv_height);
437
438 // Scale the planes into the destination.
439 libyuv::I420Scale(src_y, src_stride_y,
440 src_u, src_uv_width,
441 src_v, src_uv_width,
442 src_width, src_height,
443 dst_y, dst_stride_y,
444 dst_u, dst_stride_u,
445 dst_v, dst_stride_v,
446 dst_width, dst_height,
447 libyuv::kFilterBox);
448}
449
mikhal@webrtc.org2cdb2d32011-11-28 18:09:41 +0000450} // namespace webrtc