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