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