2 * Copyright (C) 2003 Michael Niedermayer <michaelni@gmx.at>
4 * This file is part of FFmpeg.
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.
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.
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
27 #undef HAVE_AV_CONFIG_H
28 #include "libavcore/imgutils.h"
29 #include "libavutil/mem.h"
30 #include "libavutil/avutil.h"
31 #include "libavutil/crc.h"
32 #include "libavutil/pixdesc.h"
33 #include "libavutil/lfg.h"
36 /* HACK Duplicated from swscale_internal.h.
37 * Should be removed when a cleaner pixel format system exists. */
40 || (x)==PIX_FMT_GRAY16BE \
41 || (x)==PIX_FMT_GRAY16LE \
43 #define hasChroma(x) (!( \
45 || (x)==PIX_FMT_MONOBLACK \
46 || (x)==PIX_FMT_MONOWHITE \
48 #define isALPHA(x) ( \
50 || (x)==PIX_FMT_BGR32_1 \
51 || (x)==PIX_FMT_RGB32 \
52 || (x)==PIX_FMT_RGB32_1 \
53 || (x)==PIX_FMT_YUVA420P \
56 static uint64_t getSSD(uint8_t *src1
, uint8_t *src2
, int stride1
, int stride2
, int w
, int h
)
61 //printf("%d %d\n", w, h);
65 int d
= src1
[x
+ y
*stride1
] - src2
[x
+ y
*stride2
];
67 //printf("%d", abs(src1[x + y*stride1] - src2[x + y*stride2])/26 );
82 // test by ref -> src -> dst -> out & compare out against ref
84 static int doTest(uint8_t *ref
[4], int refStride
[4], int w
, int h
,
85 enum PixelFormat srcFormat
, enum PixelFormat dstFormat
,
86 int srcW
, int srcH
, int dstW
, int dstH
, int flags
,
89 static enum PixelFormat cur_srcFormat
;
90 static int cur_srcW
, cur_srcH
;
91 static uint8_t *src
[4];
92 static int srcStride
[4];
93 uint8_t *dst
[4] = {0};
94 uint8_t *out
[4] = {0};
97 uint64_t ssdY
, ssdU
=0, ssdV
=0, ssdA
=0;
98 struct SwsContext
*dstContext
= NULL
, *outContext
= NULL
;
102 if (cur_srcFormat
!= srcFormat
|| cur_srcW
!= srcW
|| cur_srcH
!= srcH
) {
103 struct SwsContext
*srcContext
= NULL
;
106 for (p
= 0; p
< 4; p
++)
110 av_image_fill_linesizes(srcStride
, srcFormat
, srcW
);
111 for (p
= 0; p
< 4; p
++) {
113 src
[p
] = av_mallocz(srcStride
[p
]*srcH
+16);
114 if (srcStride
[p
] && !src
[p
]) {
121 srcContext
= sws_getContext(w
, h
, PIX_FMT_YUVA420P
, srcW
, srcH
,
122 srcFormat
, SWS_BILINEAR
, NULL
, NULL
, NULL
);
124 fprintf(stderr
, "Failed to get %s ---> %s\n",
125 av_pix_fmt_descriptors
[PIX_FMT_YUVA420P
].name
,
126 av_pix_fmt_descriptors
[srcFormat
].name
);
131 sws_scale(srcContext
, ref
, refStride
, 0, h
, src
, srcStride
);
132 sws_freeContext(srcContext
);
134 cur_srcFormat
= srcFormat
;
139 av_image_fill_linesizes(dstStride
, dstFormat
, dstW
);
140 for (i
=0; i
<4; i
++) {
141 /* Image buffers passed into libswscale can be allocated any way you
142 * prefer, as long as they're aligned enough for the architecture, and
143 * they're freed appropriately (such as using av_free for buffers
144 * allocated with av_malloc). */
145 /* An extra 16 bytes is being allocated because some scalers may write
148 dst
[i
]= av_mallocz(dstStride
[i
]*dstH
+16);
149 if (dstStride
[i
] && !dst
[i
]) {
157 dstContext
= sws_getContext(srcW
, srcH
, srcFormat
, dstW
, dstH
, dstFormat
, flags
, NULL
, NULL
, NULL
);
159 fprintf(stderr
, "Failed to get %s ---> %s\n",
160 av_pix_fmt_descriptors
[srcFormat
].name
,
161 av_pix_fmt_descriptors
[dstFormat
].name
);
166 // printf("test %X %X %X -> %X %X %X\n", (int)ref[0], (int)ref[1], (int)ref[2],
167 // (int)src[0], (int)src[1], (int)src[2]);
169 printf(" %s %dx%d -> %s %3dx%3d flags=%2d",
170 av_pix_fmt_descriptors
[srcFormat
].name
, srcW
, srcH
,
171 av_pix_fmt_descriptors
[dstFormat
].name
, dstW
, dstH
,
175 sws_scale(dstContext
, src
, srcStride
, 0, srcH
, dst
, dstStride
);
177 for (i
= 0; i
< 4 && dstStride
[i
]; i
++) {
178 crc
= av_crc(av_crc_get_table(AV_CRC_32_IEEE
), crc
, dst
[i
], dstStride
[i
] * dstH
);
181 if (r
&& crc
== r
->crc
) {
187 for (i
=0; i
<4; i
++) {
189 out
[i
]= av_mallocz(refStride
[i
]*h
);
190 if (refStride
[i
] && !out
[i
]) {
197 outContext
= sws_getContext(dstW
, dstH
, dstFormat
, w
, h
, PIX_FMT_YUVA420P
, SWS_BILINEAR
, NULL
, NULL
, NULL
);
199 fprintf(stderr
, "Failed to get %s ---> %s\n",
200 av_pix_fmt_descriptors
[dstFormat
].name
,
201 av_pix_fmt_descriptors
[PIX_FMT_YUVA420P
].name
);
206 sws_scale(outContext
, dst
, dstStride
, 0, dstH
, out
, refStride
);
208 ssdY
= getSSD(ref
[0], out
[0], refStride
[0], refStride
[0], w
, h
);
209 if (hasChroma(srcFormat
) && hasChroma(dstFormat
)) {
210 //FIXME check that output is really gray
211 ssdU
= getSSD(ref
[1], out
[1], refStride
[1], refStride
[1], (w
+1)>>1, (h
+1)>>1);
212 ssdV
= getSSD(ref
[2], out
[2], refStride
[2], refStride
[2], (w
+1)>>1, (h
+1)>>1);
214 if (isALPHA(srcFormat
) && isALPHA(dstFormat
))
215 ssdA
= getSSD(ref
[3], out
[3], refStride
[3], refStride
[3], w
, h
);
222 sws_freeContext(outContext
);
224 for (i
=0; i
<4; i
++) {
230 printf(" CRC=%08x SSD=%5"PRId64
",%5"PRId64
",%5"PRId64
",%5"PRId64
"\n",
231 crc
, ssdY
, ssdU
, ssdV
, ssdA
);
235 sws_freeContext(dstContext
);
237 for (i
=0; i
<4; i
++) {
245 static void selfTest(uint8_t *ref
[4], int refStride
[4], int w
, int h
,
246 enum PixelFormat srcFormat_in
,
247 enum PixelFormat dstFormat_in
)
249 const int flags
[] = { SWS_FAST_BILINEAR
,
250 SWS_BILINEAR
, SWS_BICUBIC
,
251 SWS_X
, SWS_POINT
, SWS_AREA
, 0 };
254 const int dstW
[] = { srcW
- srcW
/3, srcW
, srcW
+ srcW
/3, 0 };
255 const int dstH
[] = { srcH
- srcH
/3, srcH
, srcH
+ srcH
/3, 0 };
256 enum PixelFormat srcFormat
, dstFormat
;
258 for (srcFormat
= srcFormat_in
!= PIX_FMT_NONE
? srcFormat_in
: 0;
259 srcFormat
< PIX_FMT_NB
; srcFormat
++) {
260 if (!sws_isSupportedInput(srcFormat
) || !sws_isSupportedOutput(srcFormat
))
263 for (dstFormat
= dstFormat_in
!= PIX_FMT_NONE
? dstFormat_in
: 0;
264 dstFormat
< PIX_FMT_NB
; dstFormat
++) {
268 if (!sws_isSupportedInput(dstFormat
) || !sws_isSupportedOutput(dstFormat
))
272 av_pix_fmt_descriptors
[srcFormat
].name
,
273 av_pix_fmt_descriptors
[dstFormat
].name
);
276 for (k
= 0; flags
[k
] && !res
; k
++) {
277 for (i
= 0; dstW
[i
] && !res
; i
++)
278 for (j
= 0; dstH
[j
] && !res
; j
++)
279 res
= doTest(ref
, refStride
, w
, h
,
280 srcFormat
, dstFormat
,
281 srcW
, srcH
, dstW
[i
], dstH
[j
], flags
[k
],
284 if (dstFormat_in
!= PIX_FMT_NONE
)
287 if (srcFormat_in
!= PIX_FMT_NONE
)
292 static int fileTest(uint8_t *ref
[4], int refStride
[4], int w
, int h
, FILE *fp
,
293 enum PixelFormat srcFormat_in
,
294 enum PixelFormat dstFormat_in
)
298 while (fgets(buf
, sizeof(buf
), fp
)) {
300 enum PixelFormat srcFormat
;
303 enum PixelFormat dstFormat
;
309 ret
= sscanf(buf
, " %12s %dx%d -> %12s %dx%d flags=%d CRC=%x"
310 " SSD=%"PRId64
", %"PRId64
", %"PRId64
", %"PRId64
"\n",
311 srcStr
, &srcW
, &srcH
, dstStr
, &dstW
, &dstH
,
312 &flags
, &r
.crc
, &r
.ssdY
, &r
.ssdU
, &r
.ssdV
, &r
.ssdA
);
314 srcStr
[0] = dstStr
[0] = 0;
315 ret
= sscanf(buf
, "%12s -> %12s\n", srcStr
, dstStr
);
318 srcFormat
= av_get_pix_fmt(srcStr
);
319 dstFormat
= av_get_pix_fmt(dstStr
);
321 if (srcFormat
== PIX_FMT_NONE
|| dstFormat
== PIX_FMT_NONE
) {
322 fprintf(stderr
, "malformed input file\n");
325 if ((srcFormat_in
!= PIX_FMT_NONE
&& srcFormat_in
!= srcFormat
) ||
326 (dstFormat_in
!= PIX_FMT_NONE
&& dstFormat_in
!= dstFormat
))
333 doTest(ref
, refStride
, w
, h
,
334 srcFormat
, dstFormat
,
335 srcW
, srcH
, dstW
, dstH
, flags
,
345 int main(int argc
, char **argv
)
347 enum PixelFormat srcFormat
= PIX_FMT_NONE
;
348 enum PixelFormat dstFormat
= PIX_FMT_NONE
;
349 uint8_t *rgb_data
= av_malloc (W
*H
*4);
350 uint8_t *rgb_src
[3]= {rgb_data
, NULL
, NULL
};
351 int rgb_stride
[3]={4*W
, 0, 0};
352 uint8_t *data
= av_malloc (4*W
*H
);
353 uint8_t *src
[4]= {data
, data
+W
*H
, data
+W
*H
*2, data
+W
*H
*3};
354 int stride
[4]={W
, W
, W
, W
};
356 struct SwsContext
*sws
;
361 if (!rgb_data
|| !data
)
364 sws
= sws_getContext(W
/12, H
/12, PIX_FMT_RGB32
, W
, H
, PIX_FMT_YUVA420P
, SWS_BILINEAR
, NULL
, NULL
, NULL
);
366 av_lfg_init(&rand
, 1);
368 for (y
=0; y
<H
; y
++) {
369 for (x
=0; x
<W
*4; x
++) {
370 rgb_data
[ x
+ y
*4*W
]= av_lfg_get(&rand
);
373 sws_scale(sws
, rgb_src
, rgb_stride
, 0, H
, src
, stride
);
374 sws_freeContext(sws
);
377 for (i
= 1; i
< argc
; i
+= 2) {
378 if (argv
[i
][0] != '-' || i
+1 == argc
)
380 if (!strcmp(argv
[i
], "-ref")) {
381 FILE *fp
= fopen(argv
[i
+1], "r");
383 fprintf(stderr
, "could not open '%s'\n", argv
[i
+1]);
386 res
= fileTest(src
, stride
, W
, H
, fp
, srcFormat
, dstFormat
);
389 } else if (!strcmp(argv
[i
], "-src")) {
390 srcFormat
= av_get_pix_fmt(argv
[i
+1]);
391 if (srcFormat
== PIX_FMT_NONE
) {
392 fprintf(stderr
, "invalid pixel format %s\n", argv
[i
+1]);
395 } else if (!strcmp(argv
[i
], "-dst")) {
396 dstFormat
= av_get_pix_fmt(argv
[i
+1]);
397 if (dstFormat
== PIX_FMT_NONE
) {
398 fprintf(stderr
, "invalid pixel format %s\n", argv
[i
+1]);
403 fprintf(stderr
, "bad option or argument missing (%s)\n", argv
[i
]);
408 selfTest(src
, stride
, W
, H
, srcFormat
, dstFormat
);