2 * Misc image conversion routines
3 * Copyright (c) 2001, 2002, 2003 Fabrice Bellard
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 * misc image conversion routines
28 * - write 'ffimg' program to test all the image related stuff
29 * - move all api to slice based system
30 * - integrate deinterlacing, postprocessing and scaling in the conversion process
34 #include "imgconvert.h"
37 #include "libavutil/avassert.h"
38 #include "libavutil/colorspace.h"
39 #include "libavutil/common.h"
40 #include "libavutil/pixdesc.h"
41 #include "libavutil/imgutils.h"
43 void avcodec_get_chroma_sub_sample(enum AVPixelFormat pix_fmt
, int *h_shift
, int *v_shift
)
45 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(pix_fmt
);
47 *h_shift
= desc
->log2_chroma_w
;
48 *v_shift
= desc
->log2_chroma_h
;
51 int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt
,
52 enum AVPixelFormat src_pix_fmt
,
55 return av_get_pix_fmt_loss(dst_pix_fmt
, src_pix_fmt
, has_alpha
);
58 enum AVPixelFormat
avcodec_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1
, enum AVPixelFormat dst_pix_fmt2
,
59 enum AVPixelFormat src_pix_fmt
, int has_alpha
, int *loss_ptr
)
61 return av_find_best_pix_fmt_of_2(dst_pix_fmt1
, dst_pix_fmt2
, src_pix_fmt
, has_alpha
, loss_ptr
);
64 #if AV_HAVE_INCOMPATIBLE_LIBAV_ABI
65 enum AVPixelFormat
avcodec_find_best_pix_fmt2(const enum AVPixelFormat
*pix_fmt_list
,
66 enum AVPixelFormat src_pix_fmt
,
67 int has_alpha
, int *loss_ptr
){
68 return avcodec_find_best_pix_fmt_of_list(pix_fmt_list
, src_pix_fmt
, has_alpha
, loss_ptr
);
71 enum AVPixelFormat
avcodec_find_best_pix_fmt2(enum AVPixelFormat dst_pix_fmt1
, enum AVPixelFormat dst_pix_fmt2
,
72 enum AVPixelFormat src_pix_fmt
, int has_alpha
, int *loss_ptr
)
74 return avcodec_find_best_pix_fmt_of_2(dst_pix_fmt1
, dst_pix_fmt2
, src_pix_fmt
, has_alpha
, loss_ptr
);
78 enum AVPixelFormat
avcodec_find_best_pix_fmt_of_list(const enum AVPixelFormat
*pix_fmt_list
,
79 enum AVPixelFormat src_pix_fmt
,
80 int has_alpha
, int *loss_ptr
){
83 enum AVPixelFormat best
= AV_PIX_FMT_NONE
;
85 for(i
=0; pix_fmt_list
[i
] != AV_PIX_FMT_NONE
; i
++)
86 best
= avcodec_find_best_pix_fmt_of_2(best
, pix_fmt_list
[i
], src_pix_fmt
, has_alpha
, loss_ptr
);
92 void ff_shrink22(uint8_t *dst
, int dst_wrap
,
93 const uint8_t *src
, int src_wrap
,
94 int width
, int height
)
97 const uint8_t *s1
, *s2
;
100 for(;height
> 0; height
--) {
104 for(w
= width
;w
>= 4; w
-=4) {
105 d
[0] = (s1
[0] + s1
[1] + s2
[0] + s2
[1] + 2) >> 2;
106 d
[1] = (s1
[2] + s1
[3] + s2
[2] + s2
[3] + 2) >> 2;
107 d
[2] = (s1
[4] + s1
[5] + s2
[4] + s2
[5] + 2) >> 2;
108 d
[3] = (s1
[6] + s1
[7] + s2
[6] + s2
[7] + 2) >> 2;
114 d
[0] = (s1
[0] + s1
[1] + s2
[0] + s2
[1] + 2) >> 2;
125 void ff_shrink44(uint8_t *dst
, int dst_wrap
,
126 const uint8_t *src
, int src_wrap
,
127 int width
, int height
)
130 const uint8_t *s1
, *s2
, *s3
, *s4
;
133 for(;height
> 0; height
--) {
139 for(w
= width
;w
> 0; w
--) {
140 d
[0] = (s1
[0] + s1
[1] + s1
[2] + s1
[3] +
141 s2
[0] + s2
[1] + s2
[2] + s2
[3] +
142 s3
[0] + s3
[1] + s3
[2] + s3
[3] +
143 s4
[0] + s4
[1] + s4
[2] + s4
[3] + 8) >> 4;
156 void ff_shrink88(uint8_t *dst
, int dst_wrap
,
157 const uint8_t *src
, int src_wrap
,
158 int width
, int height
)
162 for(;height
> 0; height
--) {
163 for(w
= width
;w
> 0; w
--) {
166 tmp
+= src
[0] + src
[1] + src
[2] + src
[3] + src
[4] + src
[5] + src
[6] + src
[7];
169 *(dst
++) = (tmp
+ 32)>>6;
170 src
+= 8 - 8*src_wrap
;
172 src
+= 8*src_wrap
- 8*width
;
173 dst
+= dst_wrap
- width
;
177 /* return true if yuv planar */
178 static inline int is_yuv_planar(const AVPixFmtDescriptor
*desc
)
181 int planes
[4] = { 0 };
183 if ( desc
->flags
& AV_PIX_FMT_FLAG_RGB
184 || !(desc
->flags
& AV_PIX_FMT_FLAG_PLANAR
))
187 /* set the used planes */
188 for (i
= 0; i
< desc
->nb_components
; i
++)
189 planes
[desc
->comp
[i
].plane
] = 1;
191 /* if there is an unused plane, the format is not planar */
192 for (i
= 0; i
< desc
->nb_components
; i
++)
198 int av_picture_crop(AVPicture
*dst
, const AVPicture
*src
,
199 enum AVPixelFormat pix_fmt
, int top_band
, int left_band
)
201 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(pix_fmt
);
205 if (pix_fmt
< 0 || pix_fmt
>= AV_PIX_FMT_NB
)
208 y_shift
= desc
->log2_chroma_h
;
209 x_shift
= desc
->log2_chroma_w
;
211 if (is_yuv_planar(desc
)) {
212 dst
->data
[0] = src
->data
[0] + (top_band
* src
->linesize
[0]) + left_band
;
213 dst
->data
[1] = src
->data
[1] + ((top_band
>> y_shift
) * src
->linesize
[1]) + (left_band
>> x_shift
);
214 dst
->data
[2] = src
->data
[2] + ((top_band
>> y_shift
) * src
->linesize
[2]) + (left_band
>> x_shift
);
216 if(top_band
% (1<<y_shift
) || left_band
% (1<<x_shift
))
218 if(left_band
) //FIXME add support for this too
220 dst
->data
[0] = src
->data
[0] + (top_band
* src
->linesize
[0]) + left_band
;
223 dst
->linesize
[0] = src
->linesize
[0];
224 dst
->linesize
[1] = src
->linesize
[1];
225 dst
->linesize
[2] = src
->linesize
[2];
229 int av_picture_pad(AVPicture
*dst
, const AVPicture
*src
, int height
, int width
,
230 enum AVPixelFormat pix_fmt
, int padtop
, int padbottom
, int padleft
, int padright
,
233 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(pix_fmt
);
240 if (pix_fmt
< 0 || pix_fmt
>= AV_PIX_FMT_NB
||
241 !is_yuv_planar(desc
)) return -1;
243 for (i
= 0; i
< 3; i
++) {
244 x_shift
= i
? desc
->log2_chroma_w
: 0;
245 y_shift
= i
? desc
->log2_chroma_h
: 0;
247 if (padtop
|| padleft
) {
248 memset(dst
->data
[i
], color
[i
],
249 dst
->linesize
[i
] * (padtop
>> y_shift
) + (padleft
>> x_shift
));
252 if (padleft
|| padright
) {
253 optr
= dst
->data
[i
] + dst
->linesize
[i
] * (padtop
>> y_shift
) +
254 (dst
->linesize
[i
] - (padright
>> x_shift
));
255 yheight
= (height
- 1 - (padtop
+ padbottom
)) >> y_shift
;
256 for (y
= 0; y
< yheight
; y
++) {
257 memset(optr
, color
[i
], (padleft
+ padright
) >> x_shift
);
258 optr
+= dst
->linesize
[i
];
262 if (src
) { /* first line */
263 uint8_t *iptr
= src
->data
[i
];
264 optr
= dst
->data
[i
] + dst
->linesize
[i
] * (padtop
>> y_shift
) +
265 (padleft
>> x_shift
);
266 memcpy(optr
, iptr
, (width
- padleft
- padright
) >> x_shift
);
267 iptr
+= src
->linesize
[i
];
268 optr
= dst
->data
[i
] + dst
->linesize
[i
] * (padtop
>> y_shift
) +
269 (dst
->linesize
[i
] - (padright
>> x_shift
));
270 yheight
= (height
- 1 - (padtop
+ padbottom
)) >> y_shift
;
271 for (y
= 0; y
< yheight
; y
++) {
272 memset(optr
, color
[i
], (padleft
+ padright
) >> x_shift
);
273 memcpy(optr
+ ((padleft
+ padright
) >> x_shift
), iptr
,
274 (width
- padleft
- padright
) >> x_shift
);
275 iptr
+= src
->linesize
[i
];
276 optr
+= dst
->linesize
[i
];
280 if (padbottom
|| padright
) {
281 optr
= dst
->data
[i
] + dst
->linesize
[i
] *
282 ((height
- padbottom
) >> y_shift
) - (padright
>> x_shift
);
283 memset(optr
, color
[i
],dst
->linesize
[i
] *
284 (padbottom
>> y_shift
) + (padright
>> x_shift
));
290 #if FF_API_DEINTERLACE
292 #if HAVE_MMX_EXTERNAL
293 #define deinterlace_line_inplace ff_deinterlace_line_inplace_mmx
294 #define deinterlace_line ff_deinterlace_line_mmx
296 #define deinterlace_line_inplace deinterlace_line_inplace_c
297 #define deinterlace_line deinterlace_line_c
299 /* filter parameters: [-1 4 2 4 -1] // 8 */
300 static void deinterlace_line_c(uint8_t *dst
,
301 const uint8_t *lum_m4
, const uint8_t *lum_m3
,
302 const uint8_t *lum_m2
, const uint8_t *lum_m1
,
306 const uint8_t *cm
= ff_crop_tab
+ MAX_NEG_CROP
;
309 for(;size
> 0;size
--) {
311 sum
+= lum_m3
[0] << 2;
312 sum
+= lum_m2
[0] << 1;
313 sum
+= lum_m1
[0] << 2;
315 dst
[0] = cm
[(sum
+ 4) >> 3];
325 static void deinterlace_line_inplace_c(uint8_t *lum_m4
, uint8_t *lum_m3
,
326 uint8_t *lum_m2
, uint8_t *lum_m1
,
327 uint8_t *lum
, int size
)
329 const uint8_t *cm
= ff_crop_tab
+ MAX_NEG_CROP
;
332 for(;size
> 0;size
--) {
334 sum
+= lum_m3
[0] << 2;
335 sum
+= lum_m2
[0] << 1;
337 sum
+= lum_m1
[0] << 2;
339 lum_m2
[0] = cm
[(sum
+ 4) >> 3];
347 #endif /* !HAVE_MMX_EXTERNAL */
349 /* deinterlacing : 2 temporal taps, 3 spatial taps linear filter. The
350 top field is copied as is, but the bottom field is deinterlaced
351 against the top field. */
352 static void deinterlace_bottom_field(uint8_t *dst
, int dst_wrap
,
353 const uint8_t *src1
, int src_wrap
,
354 int width
, int height
)
356 const uint8_t *src_m2
, *src_m1
, *src_0
, *src_p1
, *src_p2
;
361 src_0
=&src_m1
[src_wrap
];
362 src_p1
=&src_0
[src_wrap
];
363 src_p2
=&src_p1
[src_wrap
];
364 for(y
=0;y
<(height
-2);y
+=2) {
365 memcpy(dst
,src_m1
,width
);
367 deinterlace_line(dst
,src_m2
,src_m1
,src_0
,src_p1
,src_p2
,width
);
371 src_p1
+= 2*src_wrap
;
372 src_p2
+= 2*src_wrap
;
375 memcpy(dst
,src_m1
,width
);
378 deinterlace_line(dst
,src_m2
,src_m1
,src_0
,src_0
,src_0
,width
);
381 static void deinterlace_bottom_field_inplace(uint8_t *src1
, int src_wrap
,
382 int width
, int height
)
384 uint8_t *src_m1
, *src_0
, *src_p1
, *src_p2
;
387 buf
= av_malloc(width
);
390 memcpy(buf
,src_m1
,width
);
391 src_0
=&src_m1
[src_wrap
];
392 src_p1
=&src_0
[src_wrap
];
393 src_p2
=&src_p1
[src_wrap
];
394 for(y
=0;y
<(height
-2);y
+=2) {
395 deinterlace_line_inplace(buf
,src_m1
,src_0
,src_p1
,src_p2
,width
);
398 src_p1
+= 2*src_wrap
;
399 src_p2
+= 2*src_wrap
;
402 deinterlace_line_inplace(buf
,src_m1
,src_0
,src_0
,src_0
,width
);
406 int avpicture_deinterlace(AVPicture
*dst
, const AVPicture
*src
,
407 enum AVPixelFormat pix_fmt
, int width
, int height
)
411 if (pix_fmt
!= AV_PIX_FMT_YUV420P
&&
412 pix_fmt
!= AV_PIX_FMT_YUVJ420P
&&
413 pix_fmt
!= AV_PIX_FMT_YUV422P
&&
414 pix_fmt
!= AV_PIX_FMT_YUVJ422P
&&
415 pix_fmt
!= AV_PIX_FMT_YUV444P
&&
416 pix_fmt
!= AV_PIX_FMT_YUV411P
&&
417 pix_fmt
!= AV_PIX_FMT_GRAY8
)
419 if ((width
& 3) != 0 || (height
& 3) != 0)
425 case AV_PIX_FMT_YUVJ420P
:
426 case AV_PIX_FMT_YUV420P
:
430 case AV_PIX_FMT_YUV422P
:
431 case AV_PIX_FMT_YUVJ422P
:
434 case AV_PIX_FMT_YUV411P
:
440 if (pix_fmt
== AV_PIX_FMT_GRAY8
) {
445 deinterlace_bottom_field_inplace(dst
->data
[i
], dst
->linesize
[i
],
448 deinterlace_bottom_field(dst
->data
[i
],dst
->linesize
[i
],
449 src
->data
[i
], src
->linesize
[i
],
457 #endif /* FF_API_DEINTERLACE */
466 for (i
=0; i
<AV_PIX_FMT_NB
*2; i
++) {
467 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(i
);
468 if(!desc
|| !desc
->name
) {
473 av_log(NULL
, AV_LOG_INFO
, "%3d unused pixel format values\n", skip
);
476 av_log(NULL
, AV_LOG_INFO
, "pix fmt %s yuv_plan:%d avg_bpp:%d\n", desc
->name
, is_yuv_planar(desc
), av_get_padded_bits_per_pixel(desc
));
477 if ((!(desc
->flags
& AV_PIX_FMT_FLAG_ALPHA
)) != (desc
->nb_components
!= 2 && desc
->nb_components
!= 4)) {
478 av_log(NULL
, AV_LOG_ERROR
, "Alpha flag mismatch\n");