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