Libav 0.7.1
|
00001 /* 00002 * Copyright (C) 2003 Michael Niedermayer <michaelni@gmx.at> 00003 * 00004 * This file is part of Libav. 00005 * 00006 * Libav is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * Libav is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with Libav; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 00021 #include <stdio.h> 00022 #include <stdlib.h> 00023 #include <string.h> 00024 #include <inttypes.h> 00025 #include <stdarg.h> 00026 00027 #undef HAVE_AV_CONFIG_H 00028 #include "libavutil/imgutils.h" 00029 #include "libavutil/mem.h" 00030 #include "libavutil/avutil.h" 00031 #include "libavutil/crc.h" 00032 #include "libavutil/pixdesc.h" 00033 #include "libavutil/lfg.h" 00034 #include "swscale.h" 00035 00036 /* HACK Duplicated from swscale_internal.h. 00037 * Should be removed when a cleaner pixel format system exists. */ 00038 #define isGray(x) ( \ 00039 (x)==PIX_FMT_GRAY8 \ 00040 || (x)==PIX_FMT_GRAY16BE \ 00041 || (x)==PIX_FMT_GRAY16LE \ 00042 ) 00043 #define hasChroma(x) (!( \ 00044 isGray(x) \ 00045 || (x)==PIX_FMT_MONOBLACK \ 00046 || (x)==PIX_FMT_MONOWHITE \ 00047 )) 00048 #define isALPHA(x) ( \ 00049 (x)==PIX_FMT_BGR32 \ 00050 || (x)==PIX_FMT_BGR32_1 \ 00051 || (x)==PIX_FMT_RGB32 \ 00052 || (x)==PIX_FMT_RGB32_1 \ 00053 || (x)==PIX_FMT_YUVA420P \ 00054 ) 00055 00056 static uint64_t getSSD(uint8_t *src1, uint8_t *src2, int stride1, int stride2, int w, int h) 00057 { 00058 int x,y; 00059 uint64_t ssd=0; 00060 00061 for (y=0; y<h; y++) { 00062 for (x=0; x<w; x++) { 00063 int d= src1[x + y*stride1] - src2[x + y*stride2]; 00064 ssd+= d*d; 00065 } 00066 } 00067 return ssd; 00068 } 00069 00070 struct Results { 00071 uint64_t ssdY; 00072 uint64_t ssdU; 00073 uint64_t ssdV; 00074 uint64_t ssdA; 00075 uint32_t crc; 00076 }; 00077 00078 // test by ref -> src -> dst -> out & compare out against ref 00079 // ref & out are YV12 00080 static int doTest(uint8_t *ref[4], int refStride[4], int w, int h, 00081 enum PixelFormat srcFormat, enum PixelFormat dstFormat, 00082 int srcW, int srcH, int dstW, int dstH, int flags, 00083 struct Results *r) 00084 { 00085 static enum PixelFormat cur_srcFormat; 00086 static int cur_srcW, cur_srcH; 00087 static uint8_t *src[4]; 00088 static int srcStride[4]; 00089 uint8_t *dst[4] = {0}; 00090 uint8_t *out[4] = {0}; 00091 int dstStride[4]; 00092 int i; 00093 uint64_t ssdY, ssdU=0, ssdV=0, ssdA=0; 00094 struct SwsContext *dstContext = NULL, *outContext = NULL; 00095 uint32_t crc = 0; 00096 int res = 0; 00097 00098 if (cur_srcFormat != srcFormat || cur_srcW != srcW || cur_srcH != srcH) { 00099 struct SwsContext *srcContext = NULL; 00100 int p; 00101 00102 for (p = 0; p < 4; p++) 00103 av_freep(&src[p]); 00104 00105 av_image_fill_linesizes(srcStride, srcFormat, srcW); 00106 for (p = 0; p < 4; p++) { 00107 if (srcStride[p]) 00108 src[p] = av_mallocz(srcStride[p]*srcH+16); 00109 if (srcStride[p] && !src[p]) { 00110 perror("Malloc"); 00111 res = -1; 00112 00113 goto end; 00114 } 00115 } 00116 srcContext = sws_getContext(w, h, PIX_FMT_YUVA420P, srcW, srcH, 00117 srcFormat, SWS_BILINEAR, NULL, NULL, NULL); 00118 if (!srcContext) { 00119 fprintf(stderr, "Failed to get %s ---> %s\n", 00120 av_pix_fmt_descriptors[PIX_FMT_YUVA420P].name, 00121 av_pix_fmt_descriptors[srcFormat].name); 00122 res = -1; 00123 00124 goto end; 00125 } 00126 sws_scale(srcContext, ref, refStride, 0, h, src, srcStride); 00127 sws_freeContext(srcContext); 00128 00129 cur_srcFormat = srcFormat; 00130 cur_srcW = srcW; 00131 cur_srcH = srcH; 00132 } 00133 00134 av_image_fill_linesizes(dstStride, dstFormat, dstW); 00135 for (i=0; i<4; i++) { 00136 /* Image buffers passed into libswscale can be allocated any way you 00137 * prefer, as long as they're aligned enough for the architecture, and 00138 * they're freed appropriately (such as using av_free for buffers 00139 * allocated with av_malloc). */ 00140 /* An extra 16 bytes is being allocated because some scalers may write 00141 * out of bounds. */ 00142 if (dstStride[i]) 00143 dst[i]= av_mallocz(dstStride[i]*dstH+16); 00144 if (dstStride[i] && !dst[i]) { 00145 perror("Malloc"); 00146 res = -1; 00147 00148 goto end; 00149 } 00150 } 00151 00152 dstContext= sws_getContext(srcW, srcH, srcFormat, dstW, dstH, dstFormat, flags, NULL, NULL, NULL); 00153 if (!dstContext) { 00154 fprintf(stderr, "Failed to get %s ---> %s\n", 00155 av_pix_fmt_descriptors[srcFormat].name, 00156 av_pix_fmt_descriptors[dstFormat].name); 00157 res = -1; 00158 00159 goto end; 00160 } 00161 00162 printf(" %s %dx%d -> %s %3dx%3d flags=%2d", 00163 av_pix_fmt_descriptors[srcFormat].name, srcW, srcH, 00164 av_pix_fmt_descriptors[dstFormat].name, dstW, dstH, 00165 flags); 00166 fflush(stdout); 00167 00168 sws_scale(dstContext, src, srcStride, 0, srcH, dst, dstStride); 00169 00170 for (i = 0; i < 4 && dstStride[i]; i++) { 00171 crc = av_crc(av_crc_get_table(AV_CRC_32_IEEE), crc, dst[i], dstStride[i] * dstH); 00172 } 00173 00174 if (r && crc == r->crc) { 00175 ssdY = r->ssdY; 00176 ssdU = r->ssdU; 00177 ssdV = r->ssdV; 00178 ssdA = r->ssdA; 00179 } else { 00180 for (i=0; i<4; i++) { 00181 if (refStride[i]) 00182 out[i]= av_mallocz(refStride[i]*h); 00183 if (refStride[i] && !out[i]) { 00184 perror("Malloc"); 00185 res = -1; 00186 00187 goto end; 00188 } 00189 } 00190 outContext= sws_getContext(dstW, dstH, dstFormat, w, h, PIX_FMT_YUVA420P, SWS_BILINEAR, NULL, NULL, NULL); 00191 if (!outContext) { 00192 fprintf(stderr, "Failed to get %s ---> %s\n", 00193 av_pix_fmt_descriptors[dstFormat].name, 00194 av_pix_fmt_descriptors[PIX_FMT_YUVA420P].name); 00195 res = -1; 00196 00197 goto end; 00198 } 00199 sws_scale(outContext, dst, dstStride, 0, dstH, out, refStride); 00200 00201 ssdY= getSSD(ref[0], out[0], refStride[0], refStride[0], w, h); 00202 if (hasChroma(srcFormat) && hasChroma(dstFormat)) { 00203 //FIXME check that output is really gray 00204 ssdU= getSSD(ref[1], out[1], refStride[1], refStride[1], (w+1)>>1, (h+1)>>1); 00205 ssdV= getSSD(ref[2], out[2], refStride[2], refStride[2], (w+1)>>1, (h+1)>>1); 00206 } 00207 if (isALPHA(srcFormat) && isALPHA(dstFormat)) 00208 ssdA= getSSD(ref[3], out[3], refStride[3], refStride[3], w, h); 00209 00210 ssdY/= w*h; 00211 ssdU/= w*h/4; 00212 ssdV/= w*h/4; 00213 ssdA/= w*h; 00214 00215 sws_freeContext(outContext); 00216 00217 for (i=0; i<4; i++) { 00218 if (refStride[i]) 00219 av_free(out[i]); 00220 } 00221 } 00222 00223 printf(" CRC=%08x SSD=%5"PRId64",%5"PRId64",%5"PRId64",%5"PRId64"\n", 00224 crc, ssdY, ssdU, ssdV, ssdA); 00225 00226 end: 00227 00228 sws_freeContext(dstContext); 00229 00230 for (i=0; i<4; i++) { 00231 if (dstStride[i]) 00232 av_free(dst[i]); 00233 } 00234 00235 return res; 00236 } 00237 00238 static void selfTest(uint8_t *ref[4], int refStride[4], int w, int h, 00239 enum PixelFormat srcFormat_in, 00240 enum PixelFormat dstFormat_in) 00241 { 00242 const int flags[] = { SWS_FAST_BILINEAR, 00243 SWS_BILINEAR, SWS_BICUBIC, 00244 SWS_X , SWS_POINT , SWS_AREA, 0 }; 00245 const int srcW = w; 00246 const int srcH = h; 00247 const int dstW[] = { srcW - srcW/3, srcW, srcW + srcW/3, 0 }; 00248 const int dstH[] = { srcH - srcH/3, srcH, srcH + srcH/3, 0 }; 00249 enum PixelFormat srcFormat, dstFormat; 00250 00251 for (srcFormat = srcFormat_in != PIX_FMT_NONE ? srcFormat_in : 0; 00252 srcFormat < PIX_FMT_NB; srcFormat++) { 00253 if (!sws_isSupportedInput(srcFormat) || !sws_isSupportedOutput(srcFormat)) 00254 continue; 00255 00256 for (dstFormat = dstFormat_in != PIX_FMT_NONE ? dstFormat_in : 0; 00257 dstFormat < PIX_FMT_NB; dstFormat++) { 00258 int i, j, k; 00259 int res = 0; 00260 00261 if (!sws_isSupportedInput(dstFormat) || !sws_isSupportedOutput(dstFormat)) 00262 continue; 00263 00264 printf("%s -> %s\n", 00265 av_pix_fmt_descriptors[srcFormat].name, 00266 av_pix_fmt_descriptors[dstFormat].name); 00267 fflush(stdout); 00268 00269 for (k = 0; flags[k] && !res; k++) { 00270 for (i = 0; dstW[i] && !res; i++) 00271 for (j = 0; dstH[j] && !res; j++) 00272 res = doTest(ref, refStride, w, h, 00273 srcFormat, dstFormat, 00274 srcW, srcH, dstW[i], dstH[j], flags[k], 00275 NULL); 00276 } 00277 if (dstFormat_in != PIX_FMT_NONE) 00278 break; 00279 } 00280 if (srcFormat_in != PIX_FMT_NONE) 00281 break; 00282 } 00283 } 00284 00285 static int fileTest(uint8_t *ref[4], int refStride[4], int w, int h, FILE *fp, 00286 enum PixelFormat srcFormat_in, 00287 enum PixelFormat dstFormat_in) 00288 { 00289 char buf[256]; 00290 00291 while (fgets(buf, sizeof(buf), fp)) { 00292 struct Results r; 00293 enum PixelFormat srcFormat; 00294 char srcStr[12]; 00295 int srcW, srcH; 00296 enum PixelFormat dstFormat; 00297 char dstStr[12]; 00298 int dstW, dstH; 00299 int flags; 00300 int ret; 00301 00302 ret = sscanf(buf, " %12s %dx%d -> %12s %dx%d flags=%d CRC=%x" 00303 " SSD=%"PRId64", %"PRId64", %"PRId64", %"PRId64"\n", 00304 srcStr, &srcW, &srcH, dstStr, &dstW, &dstH, 00305 &flags, &r.crc, &r.ssdY, &r.ssdU, &r.ssdV, &r.ssdA); 00306 if (ret != 12) { 00307 srcStr[0] = dstStr[0] = 0; 00308 ret = sscanf(buf, "%12s -> %12s\n", srcStr, dstStr); 00309 } 00310 00311 srcFormat = av_get_pix_fmt(srcStr); 00312 dstFormat = av_get_pix_fmt(dstStr); 00313 00314 if (srcFormat == PIX_FMT_NONE || dstFormat == PIX_FMT_NONE) { 00315 fprintf(stderr, "malformed input file\n"); 00316 return -1; 00317 } 00318 if ((srcFormat_in != PIX_FMT_NONE && srcFormat_in != srcFormat) || 00319 (dstFormat_in != PIX_FMT_NONE && dstFormat_in != dstFormat)) 00320 continue; 00321 if (ret != 12) { 00322 printf("%s", buf); 00323 continue; 00324 } 00325 00326 doTest(ref, refStride, w, h, 00327 srcFormat, dstFormat, 00328 srcW, srcH, dstW, dstH, flags, 00329 &r); 00330 } 00331 00332 return 0; 00333 } 00334 00335 #define W 96 00336 #define H 96 00337 00338 int main(int argc, char **argv) 00339 { 00340 enum PixelFormat srcFormat = PIX_FMT_NONE; 00341 enum PixelFormat dstFormat = PIX_FMT_NONE; 00342 uint8_t *rgb_data = av_malloc (W*H*4); 00343 uint8_t *rgb_src[3]= {rgb_data, NULL, NULL}; 00344 int rgb_stride[3]={4*W, 0, 0}; 00345 uint8_t *data = av_malloc (4*W*H); 00346 uint8_t *src[4]= {data, data+W*H, data+W*H*2, data+W*H*3}; 00347 int stride[4]={W, W, W, W}; 00348 int x, y; 00349 struct SwsContext *sws; 00350 AVLFG rand; 00351 int res = -1; 00352 int i; 00353 00354 if (!rgb_data || !data) 00355 return -1; 00356 00357 sws= sws_getContext(W/12, H/12, PIX_FMT_RGB32, W, H, PIX_FMT_YUVA420P, SWS_BILINEAR, NULL, NULL, NULL); 00358 00359 av_lfg_init(&rand, 1); 00360 00361 for (y=0; y<H; y++) { 00362 for (x=0; x<W*4; x++) { 00363 rgb_data[ x + y*4*W]= av_lfg_get(&rand); 00364 } 00365 } 00366 sws_scale(sws, rgb_src, rgb_stride, 0, H, src, stride); 00367 sws_freeContext(sws); 00368 av_free(rgb_data); 00369 00370 for (i = 1; i < argc; i += 2) { 00371 if (argv[i][0] != '-' || i+1 == argc) 00372 goto bad_option; 00373 if (!strcmp(argv[i], "-ref")) { 00374 FILE *fp = fopen(argv[i+1], "r"); 00375 if (!fp) { 00376 fprintf(stderr, "could not open '%s'\n", argv[i+1]); 00377 goto error; 00378 } 00379 res = fileTest(src, stride, W, H, fp, srcFormat, dstFormat); 00380 fclose(fp); 00381 goto end; 00382 } else if (!strcmp(argv[i], "-src")) { 00383 srcFormat = av_get_pix_fmt(argv[i+1]); 00384 if (srcFormat == PIX_FMT_NONE) { 00385 fprintf(stderr, "invalid pixel format %s\n", argv[i+1]); 00386 return -1; 00387 } 00388 } else if (!strcmp(argv[i], "-dst")) { 00389 dstFormat = av_get_pix_fmt(argv[i+1]); 00390 if (dstFormat == PIX_FMT_NONE) { 00391 fprintf(stderr, "invalid pixel format %s\n", argv[i+1]); 00392 return -1; 00393 } 00394 } else { 00395 bad_option: 00396 fprintf(stderr, "bad option or argument missing (%s)\n", argv[i]); 00397 goto error; 00398 } 00399 } 00400 00401 selfTest(src, stride, W, H, srcFormat, dstFormat); 00402 end: 00403 res = 0; 00404 error: 00405 av_free(data); 00406 00407 return res; 00408 }