1 /*
2 * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
3 *
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
11 #include <math.h>
12 #include <stdarg.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16
17 #include "./tools_common.h"
18
19 #if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER
20 #include "vpx/vp8cx.h"
21 #endif
22
23 #if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER
24 #include "vpx/vp8dx.h"
25 #endif
26
27 #include "vpx/vpx_codec.h"
28
29 #if defined(_WIN32)
30 #include <io.h>
31 #include <fcntl.h>
32 #endif
33
34 #define LOG_ERROR(label) \
35 do { \
36 const char *l = label; \
37 va_list ap; \
38 va_start(ap, fmt); \
39 if (l) fprintf(stderr, "%s: ", l); \
40 vfprintf(stderr, fmt, ap); \
41 fprintf(stderr, "\n"); \
42 va_end(ap); \
43 } while (0)
44
45 #if CONFIG_ENCODERS
46 /* Swallow warnings about unused results of fread/fwrite */
wrap_fread(void * ptr,size_t size,size_t nmemb,FILE * stream)47 static size_t wrap_fread(void *ptr, size_t size, size_t nmemb, FILE *stream) {
48 return fread(ptr, size, nmemb, stream);
49 }
50 #define fread wrap_fread
51 #endif
52
set_binary_mode(FILE * stream)53 FILE *set_binary_mode(FILE *stream) {
54 (void)stream;
55 #if defined(_WIN32)
56 _setmode(_fileno(stream), _O_BINARY);
57 #endif
58 return stream;
59 }
60
die(const char * fmt,...)61 void die(const char *fmt, ...) {
62 LOG_ERROR(NULL);
63 usage_exit();
64 }
65
fatal(const char * fmt,...)66 void fatal(const char *fmt, ...) {
67 LOG_ERROR("Fatal");
68 exit(EXIT_FAILURE);
69 }
70
warn(const char * fmt,...)71 void warn(const char *fmt, ...) { LOG_ERROR("Warning"); }
72
die_codec(vpx_codec_ctx_t * ctx,const char * s)73 void die_codec(vpx_codec_ctx_t *ctx, const char *s) {
74 const char *detail = vpx_codec_error_detail(ctx);
75
76 fprintf(stderr, "%s: %s\n", s, vpx_codec_error(ctx));
77 if (detail) fprintf(stderr, " %s\n", detail);
78 exit(EXIT_FAILURE);
79 }
80
read_yuv_frame(struct VpxInputContext * input_ctx,vpx_image_t * yuv_frame)81 int read_yuv_frame(struct VpxInputContext *input_ctx, vpx_image_t *yuv_frame) {
82 FILE *f = input_ctx->file;
83 struct FileTypeDetectionBuffer *detect = &input_ctx->detect;
84 int plane = 0;
85 int shortread = 0;
86 const int bytespp = (yuv_frame->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1;
87
88 for (plane = 0; plane < 3; ++plane) {
89 uint8_t *ptr;
90 int w = vpx_img_plane_width(yuv_frame, plane);
91 const int h = vpx_img_plane_height(yuv_frame, plane);
92 int r;
93 // Assuming that for nv12 we read all chroma data at once
94 if (yuv_frame->fmt == VPX_IMG_FMT_NV12 && plane > 1) break;
95 // Fixing NV12 chroma width if it is odd
96 if (yuv_frame->fmt == VPX_IMG_FMT_NV12 && plane == 1) w = (w + 1) & ~1;
97 /* Determine the correct plane based on the image format. The for-loop
98 * always counts in Y,U,V order, but this may not match the order of
99 * the data on disk.
100 */
101 switch (plane) {
102 case 1:
103 ptr =
104 yuv_frame->planes[yuv_frame->fmt == VPX_IMG_FMT_YV12 ? VPX_PLANE_V
105 : VPX_PLANE_U];
106 break;
107 case 2:
108 ptr =
109 yuv_frame->planes[yuv_frame->fmt == VPX_IMG_FMT_YV12 ? VPX_PLANE_U
110 : VPX_PLANE_V];
111 break;
112 default: ptr = yuv_frame->planes[plane];
113 }
114
115 for (r = 0; r < h; ++r) {
116 size_t needed = w * bytespp;
117 size_t buf_position = 0;
118 const size_t left = detect->buf_read - detect->position;
119 if (left > 0) {
120 const size_t more = (left < needed) ? left : needed;
121 memcpy(ptr, detect->buf + detect->position, more);
122 buf_position = more;
123 needed -= more;
124 detect->position += more;
125 }
126 if (needed > 0) {
127 shortread |= (fread(ptr + buf_position, 1, needed, f) < needed);
128 }
129
130 ptr += yuv_frame->stride[plane];
131 }
132 }
133
134 return shortread;
135 }
136
137 #if CONFIG_ENCODERS
138
139 static const VpxInterface vpx_encoders[] = {
140 #if CONFIG_VP8_ENCODER
141 { "vp8", VP8_FOURCC, &vpx_codec_vp8_cx },
142 #endif
143
144 #if CONFIG_VP9_ENCODER
145 { "vp9", VP9_FOURCC, &vpx_codec_vp9_cx },
146 #endif
147 };
148
get_vpx_encoder_count(void)149 int get_vpx_encoder_count(void) {
150 return sizeof(vpx_encoders) / sizeof(vpx_encoders[0]);
151 }
152
get_vpx_encoder_by_index(int i)153 const VpxInterface *get_vpx_encoder_by_index(int i) { return &vpx_encoders[i]; }
154
get_vpx_encoder_by_name(const char * name)155 const VpxInterface *get_vpx_encoder_by_name(const char *name) {
156 int i;
157
158 for (i = 0; i < get_vpx_encoder_count(); ++i) {
159 const VpxInterface *encoder = get_vpx_encoder_by_index(i);
160 if (strcmp(encoder->name, name) == 0) return encoder;
161 }
162
163 return NULL;
164 }
165
166 #endif // CONFIG_ENCODERS
167
168 #if CONFIG_DECODERS
169
170 static const VpxInterface vpx_decoders[] = {
171 #if CONFIG_VP8_DECODER
172 { "vp8", VP8_FOURCC, &vpx_codec_vp8_dx },
173 #endif
174
175 #if CONFIG_VP9_DECODER
176 { "vp9", VP9_FOURCC, &vpx_codec_vp9_dx },
177 #endif
178 };
179
get_vpx_decoder_count(void)180 int get_vpx_decoder_count(void) {
181 return sizeof(vpx_decoders) / sizeof(vpx_decoders[0]);
182 }
183
get_vpx_decoder_by_index(int i)184 const VpxInterface *get_vpx_decoder_by_index(int i) { return &vpx_decoders[i]; }
185
get_vpx_decoder_by_name(const char * name)186 const VpxInterface *get_vpx_decoder_by_name(const char *name) {
187 int i;
188
189 for (i = 0; i < get_vpx_decoder_count(); ++i) {
190 const VpxInterface *const decoder = get_vpx_decoder_by_index(i);
191 if (strcmp(decoder->name, name) == 0) return decoder;
192 }
193
194 return NULL;
195 }
196
get_vpx_decoder_by_fourcc(uint32_t fourcc)197 const VpxInterface *get_vpx_decoder_by_fourcc(uint32_t fourcc) {
198 int i;
199
200 for (i = 0; i < get_vpx_decoder_count(); ++i) {
201 const VpxInterface *const decoder = get_vpx_decoder_by_index(i);
202 if (decoder->fourcc == fourcc) return decoder;
203 }
204
205 return NULL;
206 }
207
208 #endif // CONFIG_DECODERS
209
vpx_img_plane_width(const vpx_image_t * img,int plane)210 int vpx_img_plane_width(const vpx_image_t *img, int plane) {
211 if (plane > 0 && img->x_chroma_shift > 0)
212 return (img->d_w + 1) >> img->x_chroma_shift;
213 else
214 return img->d_w;
215 }
216
vpx_img_plane_height(const vpx_image_t * img,int plane)217 int vpx_img_plane_height(const vpx_image_t *img, int plane) {
218 if (plane > 0 && img->y_chroma_shift > 0)
219 return (img->d_h + 1) >> img->y_chroma_shift;
220 else
221 return img->d_h;
222 }
223
vpx_img_write(const vpx_image_t * img,FILE * file)224 void vpx_img_write(const vpx_image_t *img, FILE *file) {
225 int plane;
226 const int bytespp = (img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1;
227
228 for (plane = 0; plane < 3; ++plane) {
229 const unsigned char *buf = img->planes[plane];
230 const int stride = img->stride[plane];
231 int w = vpx_img_plane_width(img, plane);
232 const int h = vpx_img_plane_height(img, plane);
233 int y;
234
235 // Assuming that for nv12 we write all chroma data at once
236 if (img->fmt == VPX_IMG_FMT_NV12 && plane > 1) break;
237 // Fixing NV12 chroma width if it is odd
238 if (img->fmt == VPX_IMG_FMT_NV12 && plane == 1) w = (w + 1) & ~1;
239
240 for (y = 0; y < h; ++y) {
241 fwrite(buf, bytespp, w, file);
242 buf += stride;
243 }
244 }
245 }
246
vpx_img_read(vpx_image_t * img,FILE * file)247 int vpx_img_read(vpx_image_t *img, FILE *file) {
248 int plane;
249 const int bytespp = (img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1;
250
251 for (plane = 0; plane < 3; ++plane) {
252 unsigned char *buf = img->planes[plane];
253 const int stride = img->stride[plane];
254 int w = vpx_img_plane_width(img, plane);
255 const int h = vpx_img_plane_height(img, plane);
256 int y;
257
258 // Assuming that for nv12 we read all chroma data at once
259 if (img->fmt == VPX_IMG_FMT_NV12 && plane > 1) break;
260 // Fixing NV12 chroma width if it is odd
261 if (img->fmt == VPX_IMG_FMT_NV12 && plane == 1) w = (w + 1) & ~1;
262
263 for (y = 0; y < h; ++y) {
264 if (fread(buf, bytespp, w, file) != (size_t)w) return 0;
265 buf += stride;
266 }
267 }
268
269 return 1;
270 }
271
272 // TODO(dkovalev) change sse_to_psnr signature: double -> int64_t
sse_to_psnr(double samples,double peak,double sse)273 double sse_to_psnr(double samples, double peak, double sse) {
274 static const double kMaxPSNR = 100.0;
275
276 if (sse > 0.0) {
277 const double psnr = 10.0 * log10(samples * peak * peak / sse);
278 return psnr > kMaxPSNR ? kMaxPSNR : psnr;
279 } else {
280 return kMaxPSNR;
281 }
282 }
283
284 #if CONFIG_ENCODERS
read_frame(struct VpxInputContext * input_ctx,vpx_image_t * img)285 int read_frame(struct VpxInputContext *input_ctx, vpx_image_t *img) {
286 FILE *f = input_ctx->file;
287 y4m_input *y4m = &input_ctx->y4m;
288 int shortread = 0;
289
290 if (input_ctx->file_type == FILE_TYPE_Y4M) {
291 if (y4m_input_fetch_frame(y4m, f, img) < 1) return 0;
292 } else {
293 shortread = read_yuv_frame(input_ctx, img);
294 }
295
296 return !shortread;
297 }
298
file_is_y4m(const char detect[4])299 int file_is_y4m(const char detect[4]) {
300 if (memcmp(detect, "YUV4", 4) == 0) {
301 return 1;
302 }
303 return 0;
304 }
305
fourcc_is_ivf(const char detect[4])306 int fourcc_is_ivf(const char detect[4]) {
307 if (memcmp(detect, "DKIF", 4) == 0) {
308 return 1;
309 }
310 return 0;
311 }
312
open_input_file(struct VpxInputContext * input)313 void open_input_file(struct VpxInputContext *input) {
314 /* Parse certain options from the input file, if possible */
315 input->file = strcmp(input->filename, "-") ? fopen(input->filename, "rb")
316 : set_binary_mode(stdin);
317
318 if (!input->file) fatal("Failed to open input file");
319
320 if (!fseeko(input->file, 0, SEEK_END)) {
321 /* Input file is seekable. Figure out how long it is, so we can get
322 * progress info.
323 */
324 input->length = ftello(input->file);
325 rewind(input->file);
326 }
327
328 /* Default to 1:1 pixel aspect ratio. */
329 input->pixel_aspect_ratio.numerator = 1;
330 input->pixel_aspect_ratio.denominator = 1;
331
332 /* For RAW input sources, these bytes will applied on the first frame
333 * in read_frame().
334 */
335 input->detect.buf_read = fread(input->detect.buf, 1, 4, input->file);
336 input->detect.position = 0;
337
338 if (input->detect.buf_read == 4 && file_is_y4m(input->detect.buf)) {
339 if (y4m_input_open(&input->y4m, input->file, input->detect.buf, 4,
340 input->only_i420) >= 0) {
341 input->file_type = FILE_TYPE_Y4M;
342 input->width = input->y4m.pic_w;
343 input->height = input->y4m.pic_h;
344 input->pixel_aspect_ratio.numerator = input->y4m.par_n;
345 input->pixel_aspect_ratio.denominator = input->y4m.par_d;
346 input->framerate.numerator = input->y4m.fps_n;
347 input->framerate.denominator = input->y4m.fps_d;
348 input->fmt = input->y4m.vpx_fmt;
349 input->bit_depth = input->y4m.bit_depth;
350 } else {
351 fatal("Unsupported Y4M stream.");
352 }
353 } else if (input->detect.buf_read == 4 && fourcc_is_ivf(input->detect.buf)) {
354 fatal("IVF is not supported as input.");
355 } else {
356 input->file_type = FILE_TYPE_RAW;
357 }
358 }
359
close_input_file(struct VpxInputContext * input)360 void close_input_file(struct VpxInputContext *input) {
361 fclose(input->file);
362 if (input->file_type == FILE_TYPE_Y4M) y4m_input_close(&input->y4m);
363 }
364 #endif
365
366 // TODO(debargha): Consolidate the functions below into a separate file.
367 #if CONFIG_VP9_HIGHBITDEPTH
highbd_img_upshift(vpx_image_t * dst,vpx_image_t * src,int input_shift)368 static void highbd_img_upshift(vpx_image_t *dst, vpx_image_t *src,
369 int input_shift) {
370 // Note the offset is 1 less than half.
371 const int offset = input_shift > 0 ? (1 << (input_shift - 1)) - 1 : 0;
372 int plane;
373 if (dst->d_w != src->d_w || dst->d_h != src->d_h ||
374 dst->x_chroma_shift != src->x_chroma_shift ||
375 dst->y_chroma_shift != src->y_chroma_shift || dst->fmt != src->fmt ||
376 input_shift < 0) {
377 fatal("Unsupported image conversion");
378 }
379 switch (src->fmt) {
380 case VPX_IMG_FMT_I42016:
381 case VPX_IMG_FMT_I42216:
382 case VPX_IMG_FMT_I44416:
383 case VPX_IMG_FMT_I44016: break;
384 default: fatal("Unsupported image conversion");
385 }
386 for (plane = 0; plane < 3; plane++) {
387 int w = src->d_w;
388 int h = src->d_h;
389 int x, y;
390 if (plane) {
391 w = (w + src->x_chroma_shift) >> src->x_chroma_shift;
392 h = (h + src->y_chroma_shift) >> src->y_chroma_shift;
393 }
394 for (y = 0; y < h; y++) {
395 uint16_t *p_src =
396 (uint16_t *)(src->planes[plane] + y * src->stride[plane]);
397 uint16_t *p_dst =
398 (uint16_t *)(dst->planes[plane] + y * dst->stride[plane]);
399 for (x = 0; x < w; x++) *p_dst++ = (*p_src++ << input_shift) + offset;
400 }
401 }
402 }
403
lowbd_img_upshift(vpx_image_t * dst,vpx_image_t * src,int input_shift)404 static void lowbd_img_upshift(vpx_image_t *dst, vpx_image_t *src,
405 int input_shift) {
406 // Note the offset is 1 less than half.
407 const int offset = input_shift > 0 ? (1 << (input_shift - 1)) - 1 : 0;
408 int plane;
409 if (dst->d_w != src->d_w || dst->d_h != src->d_h ||
410 dst->x_chroma_shift != src->x_chroma_shift ||
411 dst->y_chroma_shift != src->y_chroma_shift ||
412 dst->fmt != src->fmt + VPX_IMG_FMT_HIGHBITDEPTH || input_shift < 0) {
413 fatal("Unsupported image conversion");
414 }
415 switch (src->fmt) {
416 case VPX_IMG_FMT_I420:
417 case VPX_IMG_FMT_I422:
418 case VPX_IMG_FMT_I444:
419 case VPX_IMG_FMT_I440: break;
420 default: fatal("Unsupported image conversion");
421 }
422 for (plane = 0; plane < 3; plane++) {
423 int w = src->d_w;
424 int h = src->d_h;
425 int x, y;
426 if (plane) {
427 w = (w + src->x_chroma_shift) >> src->x_chroma_shift;
428 h = (h + src->y_chroma_shift) >> src->y_chroma_shift;
429 }
430 for (y = 0; y < h; y++) {
431 uint8_t *p_src = src->planes[plane] + y * src->stride[plane];
432 uint16_t *p_dst =
433 (uint16_t *)(dst->planes[plane] + y * dst->stride[plane]);
434 for (x = 0; x < w; x++) {
435 *p_dst++ = (*p_src++ << input_shift) + offset;
436 }
437 }
438 }
439 }
440
vpx_img_upshift(vpx_image_t * dst,vpx_image_t * src,int input_shift)441 void vpx_img_upshift(vpx_image_t *dst, vpx_image_t *src, int input_shift) {
442 if (src->fmt & VPX_IMG_FMT_HIGHBITDEPTH) {
443 highbd_img_upshift(dst, src, input_shift);
444 } else {
445 lowbd_img_upshift(dst, src, input_shift);
446 }
447 }
448
vpx_img_truncate_16_to_8(vpx_image_t * dst,vpx_image_t * src)449 void vpx_img_truncate_16_to_8(vpx_image_t *dst, vpx_image_t *src) {
450 int plane;
451 if (dst->fmt + VPX_IMG_FMT_HIGHBITDEPTH != src->fmt || dst->d_w != src->d_w ||
452 dst->d_h != src->d_h || dst->x_chroma_shift != src->x_chroma_shift ||
453 dst->y_chroma_shift != src->y_chroma_shift) {
454 fatal("Unsupported image conversion");
455 }
456 switch (dst->fmt) {
457 case VPX_IMG_FMT_I420:
458 case VPX_IMG_FMT_I422:
459 case VPX_IMG_FMT_I444:
460 case VPX_IMG_FMT_I440: break;
461 default: fatal("Unsupported image conversion");
462 }
463 for (plane = 0; plane < 3; plane++) {
464 int w = src->d_w;
465 int h = src->d_h;
466 int x, y;
467 if (plane) {
468 w = (w + src->x_chroma_shift) >> src->x_chroma_shift;
469 h = (h + src->y_chroma_shift) >> src->y_chroma_shift;
470 }
471 for (y = 0; y < h; y++) {
472 uint16_t *p_src =
473 (uint16_t *)(src->planes[plane] + y * src->stride[plane]);
474 uint8_t *p_dst = dst->planes[plane] + y * dst->stride[plane];
475 for (x = 0; x < w; x++) {
476 *p_dst++ = (uint8_t)(*p_src++);
477 }
478 }
479 }
480 }
481
highbd_img_downshift(vpx_image_t * dst,vpx_image_t * src,int down_shift)482 static void highbd_img_downshift(vpx_image_t *dst, vpx_image_t *src,
483 int down_shift) {
484 int plane;
485 if (dst->d_w != src->d_w || dst->d_h != src->d_h ||
486 dst->x_chroma_shift != src->x_chroma_shift ||
487 dst->y_chroma_shift != src->y_chroma_shift || dst->fmt != src->fmt ||
488 down_shift < 0) {
489 fatal("Unsupported image conversion");
490 }
491 switch (src->fmt) {
492 case VPX_IMG_FMT_I42016:
493 case VPX_IMG_FMT_I42216:
494 case VPX_IMG_FMT_I44416:
495 case VPX_IMG_FMT_I44016: break;
496 default: fatal("Unsupported image conversion");
497 }
498 for (plane = 0; plane < 3; plane++) {
499 int w = src->d_w;
500 int h = src->d_h;
501 int x, y;
502 if (plane) {
503 w = (w + src->x_chroma_shift) >> src->x_chroma_shift;
504 h = (h + src->y_chroma_shift) >> src->y_chroma_shift;
505 }
506 for (y = 0; y < h; y++) {
507 uint16_t *p_src =
508 (uint16_t *)(src->planes[plane] + y * src->stride[plane]);
509 uint16_t *p_dst =
510 (uint16_t *)(dst->planes[plane] + y * dst->stride[plane]);
511 for (x = 0; x < w; x++) *p_dst++ = *p_src++ >> down_shift;
512 }
513 }
514 }
515
lowbd_img_downshift(vpx_image_t * dst,vpx_image_t * src,int down_shift)516 static void lowbd_img_downshift(vpx_image_t *dst, vpx_image_t *src,
517 int down_shift) {
518 int plane;
519 if (dst->d_w != src->d_w || dst->d_h != src->d_h ||
520 dst->x_chroma_shift != src->x_chroma_shift ||
521 dst->y_chroma_shift != src->y_chroma_shift ||
522 src->fmt != dst->fmt + VPX_IMG_FMT_HIGHBITDEPTH || down_shift < 0) {
523 fatal("Unsupported image conversion");
524 }
525 switch (dst->fmt) {
526 case VPX_IMG_FMT_I420:
527 case VPX_IMG_FMT_I422:
528 case VPX_IMG_FMT_I444:
529 case VPX_IMG_FMT_I440: break;
530 default: fatal("Unsupported image conversion");
531 }
532 for (plane = 0; plane < 3; plane++) {
533 int w = src->d_w;
534 int h = src->d_h;
535 int x, y;
536 if (plane) {
537 w = (w + src->x_chroma_shift) >> src->x_chroma_shift;
538 h = (h + src->y_chroma_shift) >> src->y_chroma_shift;
539 }
540 for (y = 0; y < h; y++) {
541 uint16_t *p_src =
542 (uint16_t *)(src->planes[plane] + y * src->stride[plane]);
543 uint8_t *p_dst = dst->planes[plane] + y * dst->stride[plane];
544 for (x = 0; x < w; x++) {
545 *p_dst++ = *p_src++ >> down_shift;
546 }
547 }
548 }
549 }
550
vpx_img_downshift(vpx_image_t * dst,vpx_image_t * src,int down_shift)551 void vpx_img_downshift(vpx_image_t *dst, vpx_image_t *src, int down_shift) {
552 if (dst->fmt & VPX_IMG_FMT_HIGHBITDEPTH) {
553 highbd_img_downshift(dst, src, down_shift);
554 } else {
555 lowbd_img_downshift(dst, src, down_shift);
556 }
557 }
558 #endif // CONFIG_VP9_HIGHBITDEPTH
559
compare_img(const vpx_image_t * const img1,const vpx_image_t * const img2)560 int compare_img(const vpx_image_t *const img1, const vpx_image_t *const img2) {
561 uint32_t l_w = img1->d_w;
562 uint32_t c_w = (img1->d_w + img1->x_chroma_shift) >> img1->x_chroma_shift;
563 const uint32_t c_h =
564 (img1->d_h + img1->y_chroma_shift) >> img1->y_chroma_shift;
565 uint32_t i;
566 int match = 1;
567
568 match &= (img1->fmt == img2->fmt);
569 match &= (img1->d_w == img2->d_w);
570 match &= (img1->d_h == img2->d_h);
571 #if CONFIG_VP9_HIGHBITDEPTH
572 if (img1->fmt & VPX_IMG_FMT_HIGHBITDEPTH) {
573 l_w *= 2;
574 c_w *= 2;
575 }
576 #endif
577
578 for (i = 0; i < img1->d_h; ++i)
579 match &= (memcmp(img1->planes[VPX_PLANE_Y] + i * img1->stride[VPX_PLANE_Y],
580 img2->planes[VPX_PLANE_Y] + i * img2->stride[VPX_PLANE_Y],
581 l_w) == 0);
582
583 for (i = 0; i < c_h; ++i)
584 match &= (memcmp(img1->planes[VPX_PLANE_U] + i * img1->stride[VPX_PLANE_U],
585 img2->planes[VPX_PLANE_U] + i * img2->stride[VPX_PLANE_U],
586 c_w) == 0);
587
588 for (i = 0; i < c_h; ++i)
589 match &= (memcmp(img1->planes[VPX_PLANE_V] + i * img1->stride[VPX_PLANE_V],
590 img2->planes[VPX_PLANE_V] + i * img2->stride[VPX_PLANE_V],
591 c_w) == 0);
592
593 return match;
594 }
595
596 #define mmin(a, b) ((a) < (b) ? (a) : (b))
597
598 #if CONFIG_VP9_HIGHBITDEPTH
find_mismatch_high(const vpx_image_t * const img1,const vpx_image_t * const img2,int yloc[4],int uloc[4],int vloc[4])599 void find_mismatch_high(const vpx_image_t *const img1,
600 const vpx_image_t *const img2, int yloc[4], int uloc[4],
601 int vloc[4]) {
602 uint16_t *plane1, *plane2;
603 uint32_t stride1, stride2;
604 const uint32_t bsize = 64;
605 const uint32_t bsizey = bsize >> img1->y_chroma_shift;
606 const uint32_t bsizex = bsize >> img1->x_chroma_shift;
607 const uint32_t c_w =
608 (img1->d_w + img1->x_chroma_shift) >> img1->x_chroma_shift;
609 const uint32_t c_h =
610 (img1->d_h + img1->y_chroma_shift) >> img1->y_chroma_shift;
611 int match = 1;
612 uint32_t i, j;
613 yloc[0] = yloc[1] = yloc[2] = yloc[3] = -1;
614 plane1 = (uint16_t *)img1->planes[VPX_PLANE_Y];
615 plane2 = (uint16_t *)img2->planes[VPX_PLANE_Y];
616 stride1 = img1->stride[VPX_PLANE_Y] / 2;
617 stride2 = img2->stride[VPX_PLANE_Y] / 2;
618 for (i = 0, match = 1; match && i < img1->d_h; i += bsize) {
619 for (j = 0; match && j < img1->d_w; j += bsize) {
620 int k, l;
621 const int si = mmin(i + bsize, img1->d_h) - i;
622 const int sj = mmin(j + bsize, img1->d_w) - j;
623 for (k = 0; match && k < si; ++k) {
624 for (l = 0; match && l < sj; ++l) {
625 if (*(plane1 + (i + k) * stride1 + j + l) !=
626 *(plane2 + (i + k) * stride2 + j + l)) {
627 yloc[0] = i + k;
628 yloc[1] = j + l;
629 yloc[2] = *(plane1 + (i + k) * stride1 + j + l);
630 yloc[3] = *(plane2 + (i + k) * stride2 + j + l);
631 match = 0;
632 break;
633 }
634 }
635 }
636 }
637 }
638
639 uloc[0] = uloc[1] = uloc[2] = uloc[3] = -1;
640 plane1 = (uint16_t *)img1->planes[VPX_PLANE_U];
641 plane2 = (uint16_t *)img2->planes[VPX_PLANE_U];
642 stride1 = img1->stride[VPX_PLANE_U] / 2;
643 stride2 = img2->stride[VPX_PLANE_U] / 2;
644 for (i = 0, match = 1; match && i < c_h; i += bsizey) {
645 for (j = 0; match && j < c_w; j += bsizex) {
646 int k, l;
647 const int si = mmin(i + bsizey, c_h - i);
648 const int sj = mmin(j + bsizex, c_w - j);
649 for (k = 0; match && k < si; ++k) {
650 for (l = 0; match && l < sj; ++l) {
651 if (*(plane1 + (i + k) * stride1 + j + l) !=
652 *(plane2 + (i + k) * stride2 + j + l)) {
653 uloc[0] = i + k;
654 uloc[1] = j + l;
655 uloc[2] = *(plane1 + (i + k) * stride1 + j + l);
656 uloc[3] = *(plane2 + (i + k) * stride2 + j + l);
657 match = 0;
658 break;
659 }
660 }
661 }
662 }
663 }
664
665 vloc[0] = vloc[1] = vloc[2] = vloc[3] = -1;
666 plane1 = (uint16_t *)img1->planes[VPX_PLANE_V];
667 plane2 = (uint16_t *)img2->planes[VPX_PLANE_V];
668 stride1 = img1->stride[VPX_PLANE_V] / 2;
669 stride2 = img2->stride[VPX_PLANE_V] / 2;
670 for (i = 0, match = 1; match && i < c_h; i += bsizey) {
671 for (j = 0; match && j < c_w; j += bsizex) {
672 int k, l;
673 const int si = mmin(i + bsizey, c_h - i);
674 const int sj = mmin(j + bsizex, c_w - j);
675 for (k = 0; match && k < si; ++k) {
676 for (l = 0; match && l < sj; ++l) {
677 if (*(plane1 + (i + k) * stride1 + j + l) !=
678 *(plane2 + (i + k) * stride2 + j + l)) {
679 vloc[0] = i + k;
680 vloc[1] = j + l;
681 vloc[2] = *(plane1 + (i + k) * stride1 + j + l);
682 vloc[3] = *(plane2 + (i + k) * stride2 + j + l);
683 match = 0;
684 break;
685 }
686 }
687 }
688 }
689 }
690 }
691 #endif // CONFIG_VP9_HIGHBITDEPTH
692
find_mismatch(const vpx_image_t * const img1,const vpx_image_t * const img2,int yloc[4],int uloc[4],int vloc[4])693 void find_mismatch(const vpx_image_t *const img1, const vpx_image_t *const img2,
694 int yloc[4], int uloc[4], int vloc[4]) {
695 const uint32_t bsize = 64;
696 const uint32_t bsizey = bsize >> img1->y_chroma_shift;
697 const uint32_t bsizex = bsize >> img1->x_chroma_shift;
698 const uint32_t c_w =
699 (img1->d_w + img1->x_chroma_shift) >> img1->x_chroma_shift;
700 const uint32_t c_h =
701 (img1->d_h + img1->y_chroma_shift) >> img1->y_chroma_shift;
702 int match = 1;
703 uint32_t i, j;
704 yloc[0] = yloc[1] = yloc[2] = yloc[3] = -1;
705 for (i = 0, match = 1; match && i < img1->d_h; i += bsize) {
706 for (j = 0; match && j < img1->d_w; j += bsize) {
707 int k, l;
708 const int si = mmin(i + bsize, img1->d_h) - i;
709 const int sj = mmin(j + bsize, img1->d_w) - j;
710 for (k = 0; match && k < si; ++k) {
711 for (l = 0; match && l < sj; ++l) {
712 if (*(img1->planes[VPX_PLANE_Y] +
713 (i + k) * img1->stride[VPX_PLANE_Y] + j + l) !=
714 *(img2->planes[VPX_PLANE_Y] +
715 (i + k) * img2->stride[VPX_PLANE_Y] + j + l)) {
716 yloc[0] = i + k;
717 yloc[1] = j + l;
718 yloc[2] = *(img1->planes[VPX_PLANE_Y] +
719 (i + k) * img1->stride[VPX_PLANE_Y] + j + l);
720 yloc[3] = *(img2->planes[VPX_PLANE_Y] +
721 (i + k) * img2->stride[VPX_PLANE_Y] + j + l);
722 match = 0;
723 break;
724 }
725 }
726 }
727 }
728 }
729
730 uloc[0] = uloc[1] = uloc[2] = uloc[3] = -1;
731 for (i = 0, match = 1; match && i < c_h; i += bsizey) {
732 for (j = 0; match && j < c_w; j += bsizex) {
733 int k, l;
734 const int si = mmin(i + bsizey, c_h - i);
735 const int sj = mmin(j + bsizex, c_w - j);
736 for (k = 0; match && k < si; ++k) {
737 for (l = 0; match && l < sj; ++l) {
738 if (*(img1->planes[VPX_PLANE_U] +
739 (i + k) * img1->stride[VPX_PLANE_U] + j + l) !=
740 *(img2->planes[VPX_PLANE_U] +
741 (i + k) * img2->stride[VPX_PLANE_U] + j + l)) {
742 uloc[0] = i + k;
743 uloc[1] = j + l;
744 uloc[2] = *(img1->planes[VPX_PLANE_U] +
745 (i + k) * img1->stride[VPX_PLANE_U] + j + l);
746 uloc[3] = *(img2->planes[VPX_PLANE_U] +
747 (i + k) * img2->stride[VPX_PLANE_U] + j + l);
748 match = 0;
749 break;
750 }
751 }
752 }
753 }
754 }
755 vloc[0] = vloc[1] = vloc[2] = vloc[3] = -1;
756 for (i = 0, match = 1; match && i < c_h; i += bsizey) {
757 for (j = 0; match && j < c_w; j += bsizex) {
758 int k, l;
759 const int si = mmin(i + bsizey, c_h - i);
760 const int sj = mmin(j + bsizex, c_w - j);
761 for (k = 0; match && k < si; ++k) {
762 for (l = 0; match && l < sj; ++l) {
763 if (*(img1->planes[VPX_PLANE_V] +
764 (i + k) * img1->stride[VPX_PLANE_V] + j + l) !=
765 *(img2->planes[VPX_PLANE_V] +
766 (i + k) * img2->stride[VPX_PLANE_V] + j + l)) {
767 vloc[0] = i + k;
768 vloc[1] = j + l;
769 vloc[2] = *(img1->planes[VPX_PLANE_V] +
770 (i + k) * img1->stride[VPX_PLANE_V] + j + l);
771 vloc[3] = *(img2->planes[VPX_PLANE_V] +
772 (i + k) * img2->stride[VPX_PLANE_V] + j + l);
773 match = 0;
774 break;
775 }
776 }
777 }
778 }
779 }
780 }
781