1/* 2 * Copyright (C) 2003 Michael Niedermayer <michaelni@gmx.at> 3 * 4 * This file is part of FFmpeg. 5 * 6 * FFmpeg is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * FFmpeg is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with FFmpeg; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21#include <stdio.h> 22#include <stdlib.h> 23#include <string.h> 24#include <inttypes.h> 25#include <stdarg.h> 26 27#undef HAVE_AV_CONFIG_H 28#include "libavutil/mem.h" 29#include "libavutil/avutil.h" 30#include "libavutil/lfg.h" 31#include "swscale.h" 32 33/* HACK Duplicated from swscale_internal.h. 34 * Should be removed when a cleaner pixel format system exists. */ 35const char *sws_format_name(enum PixelFormat format); 36#define isGray(x) ( \ 37 (x)==PIX_FMT_GRAY8 \ 38 || (x)==PIX_FMT_GRAY16BE \ 39 || (x)==PIX_FMT_GRAY16LE \ 40 ) 41#define hasChroma(x) (!( \ 42 isGray(x) \ 43 || (x)==PIX_FMT_MONOBLACK \ 44 || (x)==PIX_FMT_MONOWHITE \ 45 )) 46#define isALPHA(x) ( \ 47 (x)==PIX_FMT_BGR32 \ 48 || (x)==PIX_FMT_BGR32_1 \ 49 || (x)==PIX_FMT_RGB32 \ 50 || (x)==PIX_FMT_RGB32_1 \ 51 || (x)==PIX_FMT_YUVA420P \ 52 ) 53 54static uint64_t getSSD(uint8_t *src1, uint8_t *src2, int stride1, int stride2, int w, int h) 55{ 56 int x,y; 57 uint64_t ssd=0; 58 59//printf("%d %d\n", w, h); 60 61 for (y=0; y<h; y++) { 62 for (x=0; x<w; x++) { 63 int d= src1[x + y*stride1] - src2[x + y*stride2]; 64 ssd+= d*d; 65//printf("%d", abs(src1[x + y*stride1] - src2[x + y*stride2])/26 ); 66 } 67//printf("\n"); 68 } 69 return ssd; 70} 71 72// test by ref -> src -> dst -> out & compare out against ref 73// ref & out are YV12 74static int doTest(uint8_t *ref[4], int refStride[4], int w, int h, 75 enum PixelFormat srcFormat, enum PixelFormat dstFormat, 76 int srcW, int srcH, int dstW, int dstH, int flags) 77{ 78 uint8_t *src[4] = {0}; 79 uint8_t *dst[4] = {0}; 80 uint8_t *out[4] = {0}; 81 int srcStride[4], dstStride[4]; 82 int i; 83 uint64_t ssdY, ssdU=0, ssdV=0, ssdA=0; 84 struct SwsContext *srcContext = NULL, *dstContext = NULL, 85 *outContext = NULL; 86 int res; 87 88 res = 0; 89 for (i=0; i<4; i++) { 90 // avoid stride % bpp != 0 91 if (srcFormat==PIX_FMT_RGB24 || srcFormat==PIX_FMT_BGR24) 92 srcStride[i]= srcW*3; 93 else if (srcFormat==PIX_FMT_RGB48BE || srcFormat==PIX_FMT_RGB48LE) 94 srcStride[i]= srcW*6; 95 else 96 srcStride[i]= srcW*4; 97 98 if (dstFormat==PIX_FMT_RGB24 || dstFormat==PIX_FMT_BGR24) 99 dstStride[i]= dstW*3; 100 else if (dstFormat==PIX_FMT_RGB48BE || dstFormat==PIX_FMT_RGB48LE) 101 dstStride[i]= dstW*6; 102 else 103 dstStride[i]= dstW*4; 104 105 /* Image buffers passed into libswscale can be allocated any way you 106 * prefer, as long as they're aligned enough for the architecture, and 107 * they're freed appropriately (such as using av_free for buffers 108 * allocated with av_malloc). */ 109 src[i]= av_mallocz(srcStride[i]*srcH); 110 dst[i]= av_mallocz(dstStride[i]*dstH); 111 out[i]= av_mallocz(refStride[i]*h); 112 if (!src[i] || !dst[i] || !out[i]) { 113 perror("Malloc"); 114 res = -1; 115 116 goto end; 117 } 118 } 119 120 srcContext= sws_getContext(w, h, PIX_FMT_YUVA420P, srcW, srcH, srcFormat, flags, NULL, NULL, NULL); 121 if (!srcContext) { 122 fprintf(stderr, "Failed to get %s ---> %s\n", 123 sws_format_name(PIX_FMT_YUVA420P), 124 sws_format_name(srcFormat)); 125 res = -1; 126 127 goto end; 128 } 129 dstContext= sws_getContext(srcW, srcH, srcFormat, dstW, dstH, dstFormat, flags, NULL, NULL, NULL); 130 if (!dstContext) { 131 fprintf(stderr, "Failed to get %s ---> %s\n", 132 sws_format_name(srcFormat), 133 sws_format_name(dstFormat)); 134 res = -1; 135 136 goto end; 137 } 138 outContext= sws_getContext(dstW, dstH, dstFormat, w, h, PIX_FMT_YUVA420P, flags, NULL, NULL, NULL); 139 if (!outContext) { 140 fprintf(stderr, "Failed to get %s ---> %s\n", 141 sws_format_name(dstFormat), 142 sws_format_name(PIX_FMT_YUVA420P)); 143 res = -1; 144 145 goto end; 146 } 147// printf("test %X %X %X -> %X %X %X\n", (int)ref[0], (int)ref[1], (int)ref[2], 148// (int)src[0], (int)src[1], (int)src[2]); 149 150 sws_scale(srcContext, ref, refStride, 0, h , src, srcStride); 151 sws_scale(dstContext, src, srcStride, 0, srcH, dst, dstStride); 152 sws_scale(outContext, dst, dstStride, 0, dstH, out, refStride); 153 154 ssdY= getSSD(ref[0], out[0], refStride[0], refStride[0], w, h); 155 if (hasChroma(srcFormat) && hasChroma(dstFormat)) { 156 //FIXME check that output is really gray 157 ssdU= getSSD(ref[1], out[1], refStride[1], refStride[1], (w+1)>>1, (h+1)>>1); 158 ssdV= getSSD(ref[2], out[2], refStride[2], refStride[2], (w+1)>>1, (h+1)>>1); 159 } 160 if (isALPHA(srcFormat) && isALPHA(dstFormat)) 161 ssdA= getSSD(ref[3], out[3], refStride[3], refStride[3], w, h); 162 163 ssdY/= w*h; 164 ssdU/= w*h/4; 165 ssdV/= w*h/4; 166 ssdA/= w*h; 167 168 printf(" %s %dx%d -> %s %4dx%4d flags=%2d SSD=%5"PRId64",%5"PRId64",%5"PRId64",%5"PRId64"\n", 169 sws_format_name(srcFormat), srcW, srcH, 170 sws_format_name(dstFormat), dstW, dstH, 171 flags, ssdY, ssdU, ssdV, ssdA); 172 fflush(stdout); 173 174end: 175 176 sws_freeContext(srcContext); 177 sws_freeContext(dstContext); 178 sws_freeContext(outContext); 179 180 for (i=0; i<4; i++) { 181 av_free(src[i]); 182 av_free(dst[i]); 183 av_free(out[i]); 184 } 185 186 return res; 187} 188 189static void selfTest(uint8_t *ref[4], int refStride[4], int w, int h) 190{ 191 const int flags[] = { SWS_FAST_BILINEAR, 192 SWS_BILINEAR, SWS_BICUBIC, 193 SWS_X , SWS_POINT , SWS_AREA, 0 }; 194 const int srcW = w; 195 const int srcH = h; 196 const int dstW[] = { srcW - srcW/3, srcW, srcW + srcW/3, 0 }; 197 const int dstH[] = { srcH - srcH/3, srcH, srcH + srcH/3, 0 }; 198 enum PixelFormat srcFormat, dstFormat; 199 200 for (srcFormat = 0; srcFormat < PIX_FMT_NB; srcFormat++) { 201 if (!sws_isSupportedInput(srcFormat) || !sws_isSupportedOutput(srcFormat)) 202 continue; 203 204 for (dstFormat = 0; dstFormat < PIX_FMT_NB; dstFormat++) { 205 int i, j, k; 206 int res = 0; 207 208 if (!sws_isSupportedInput(dstFormat) || !sws_isSupportedOutput(dstFormat)) 209 continue; 210 211 printf("%s -> %s\n", 212 sws_format_name(srcFormat), 213 sws_format_name(dstFormat)); 214 fflush(stdout); 215 216 for (i = 0; dstW[i] && !res; i++) 217 for (j = 0; dstH[j] && !res; j++) 218 for (k = 0; flags[k] && !res; k++) 219 res = doTest(ref, refStride, w, h, srcFormat, dstFormat, 220 srcW, srcH, dstW[i], dstH[j], flags[k]); 221 } 222 } 223} 224 225#define W 96 226#define H 96 227 228int main(int argc, char **argv) 229{ 230 uint8_t *rgb_data = av_malloc (W*H*4); 231 uint8_t *rgb_src[3]= {rgb_data, NULL, NULL}; 232 int rgb_stride[3]={4*W, 0, 0}; 233 uint8_t *data = av_malloc (4*W*H); 234 uint8_t *src[4]= {data, data+W*H, data+W*H*2, data+W*H*3}; 235 int stride[4]={W, W, W, W}; 236 int x, y; 237 struct SwsContext *sws; 238 AVLFG rand; 239 240 if (!rgb_data || !data) 241 return -1; 242 243 sws= sws_getContext(W/12, H/12, PIX_FMT_RGB32, W, H, PIX_FMT_YUVA420P, SWS_BILINEAR, NULL, NULL, NULL); 244 245 av_lfg_init(&rand, 1); 246 247 for (y=0; y<H; y++) { 248 for (x=0; x<W*4; x++) { 249 rgb_data[ x + y*4*W]= av_lfg_get(&rand); 250 } 251 } 252 sws_scale(sws, rgb_src, rgb_stride, 0, H, src, stride); 253 sws_freeContext(sws); 254 av_free(rgb_data); 255 256 selfTest(src, stride, W, H); 257 av_free(data); 258 259 return 0; 260} 261