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