tools_common.c 24 KB

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