2 * Misc image conversion routines
3 * Copyright (c) 2001, 2002, 2003 Fabrice Bellard
5 * This file is part of Libav.
7 * Libav 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 * Libav 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 Libav; 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
35 #include "imgconvert.h"
37 #include "libavutil/colorspace.h"
38 #include "libavutil/common.h"
39 #include "libavutil/pixdesc.h"
40 #include "libavutil/imgutils.h"
43 #include "x86/dsputil_mmx.h"
47 #define deinterlace_line_inplace ff_deinterlace_line_inplace_mmx
48 #define deinterlace_line ff_deinterlace_line_mmx
50 #define deinterlace_line_inplace deinterlace_line_inplace_c
51 #define deinterlace_line deinterlace_line_c
54 void avcodec_get_chroma_sub_sample(enum AVPixelFormat pix_fmt
, int *h_shift
, int *v_shift
)
56 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(pix_fmt
);
57 *h_shift
= desc
->log2_chroma_w
;
58 *v_shift
= desc
->log2_chroma_h
;
61 static int is_gray(const AVPixFmtDescriptor
*desc
)
63 return desc
->nb_components
- (desc
->flags
& PIX_FMT_ALPHA
) == 1;
66 int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt
,
67 enum AVPixelFormat src_pix_fmt
,
70 const AVPixFmtDescriptor
*src_desc
= av_pix_fmt_desc_get(src_pix_fmt
);
71 const AVPixFmtDescriptor
*dst_desc
= av_pix_fmt_desc_get(dst_pix_fmt
);
72 int loss
, i
, nb_components
= FFMIN(src_desc
->nb_components
,
73 dst_desc
->nb_components
);
78 if (dst_pix_fmt
== src_pix_fmt
)
81 for (i
= 0; i
< nb_components
; i
++)
82 if (src_desc
->comp
[i
].depth_minus1
> dst_desc
->comp
[i
].depth_minus1
)
83 loss
|= FF_LOSS_DEPTH
;
85 if (dst_desc
->log2_chroma_w
> src_desc
->log2_chroma_w
||
86 dst_desc
->log2_chroma_h
> src_desc
->log2_chroma_h
)
87 loss
|= FF_LOSS_RESOLUTION
;
89 if ((src_desc
->flags
& PIX_FMT_RGB
) != (dst_desc
->flags
& PIX_FMT_RGB
))
90 loss
|= FF_LOSS_COLORSPACE
;
92 if (has_alpha
&& !(dst_desc
->flags
& PIX_FMT_ALPHA
) &&
93 (dst_desc
->flags
& PIX_FMT_ALPHA
))
94 loss
|= FF_LOSS_ALPHA
;
96 if (dst_pix_fmt
== AV_PIX_FMT_PAL8
&& !is_gray(src_desc
))
97 return loss
| FF_LOSS_COLORQUANT
;
99 if (src_desc
->nb_components
> dst_desc
->nb_components
)
100 if (is_gray(dst_desc
))
101 loss
|= FF_LOSS_CHROMA
;
106 static enum AVPixelFormat
avcodec_find_best_pix_fmt1(enum AVPixelFormat
*pix_fmt_list
,
107 enum AVPixelFormat src_pix_fmt
,
111 int dist
, i
, loss
, min_dist
;
112 enum AVPixelFormat dst_pix_fmt
;
114 /* find exact color match with smallest size */
115 dst_pix_fmt
= AV_PIX_FMT_NONE
;
116 min_dist
= 0x7fffffff;
118 while (pix_fmt_list
[i
] != AV_PIX_FMT_NONE
) {
119 enum AVPixelFormat pix_fmt
= pix_fmt_list
[i
];
121 if (i
> AV_PIX_FMT_NB
) {
122 av_log(NULL
, AV_LOG_ERROR
, "Pixel format list longer than expected, "
123 "it is either not properly terminated or contains duplicates\n");
124 return AV_PIX_FMT_NONE
;
127 loss
= avcodec_get_pix_fmt_loss(pix_fmt
, src_pix_fmt
, has_alpha
) & loss_mask
;
129 dist
= av_get_bits_per_pixel(av_pix_fmt_desc_get(pix_fmt
));
130 if (dist
< min_dist
) {
132 dst_pix_fmt
= pix_fmt
;
140 #if FF_API_FIND_BEST_PIX_FMT
141 enum AVPixelFormat
avcodec_find_best_pix_fmt(int64_t pix_fmt_mask
, enum AVPixelFormat src_pix_fmt
,
142 int has_alpha
, int *loss_ptr
)
144 enum AVPixelFormat list
[64];
147 // test only the first 64 pixel formats to avoid undefined behaviour
148 for (i
= 0; i
< 64; i
++) {
149 if (pix_fmt_mask
& (1ULL << i
))
152 list
[j
] = AV_PIX_FMT_NONE
;
154 return avcodec_find_best_pix_fmt2(list
, src_pix_fmt
, has_alpha
, loss_ptr
);
156 #endif /* FF_API_FIND_BEST_PIX_FMT */
158 enum AVPixelFormat
avcodec_find_best_pix_fmt2(enum AVPixelFormat
*pix_fmt_list
,
159 enum AVPixelFormat src_pix_fmt
,
160 int has_alpha
, int *loss_ptr
)
162 enum AVPixelFormat dst_pix_fmt
;
164 static const int loss_mask_order
[] = {
165 ~0, /* no loss first */
168 ~(FF_LOSS_COLORSPACE
| FF_LOSS_RESOLUTION
),
174 /* try with successive loss */
177 loss_mask
= loss_mask_order
[i
++];
178 dst_pix_fmt
= avcodec_find_best_pix_fmt1(pix_fmt_list
, src_pix_fmt
,
179 has_alpha
, loss_mask
);
180 if (dst_pix_fmt
>= 0)
185 return AV_PIX_FMT_NONE
;
188 *loss_ptr
= avcodec_get_pix_fmt_loss(dst_pix_fmt
, src_pix_fmt
, has_alpha
);
193 void ff_shrink22(uint8_t *dst
, int dst_wrap
,
194 const uint8_t *src
, int src_wrap
,
195 int width
, int height
)
198 const uint8_t *s1
, *s2
;
201 for(;height
> 0; height
--) {
205 for(w
= width
;w
>= 4; w
-=4) {
206 d
[0] = (s1
[0] + s1
[1] + s2
[0] + s2
[1] + 2) >> 2;
207 d
[1] = (s1
[2] + s1
[3] + s2
[2] + s2
[3] + 2) >> 2;
208 d
[2] = (s1
[4] + s1
[5] + s2
[4] + s2
[5] + 2) >> 2;
209 d
[3] = (s1
[6] + s1
[7] + s2
[6] + s2
[7] + 2) >> 2;
215 d
[0] = (s1
[0] + s1
[1] + s2
[0] + s2
[1] + 2) >> 2;
226 void ff_shrink44(uint8_t *dst
, int dst_wrap
,
227 const uint8_t *src
, int src_wrap
,
228 int width
, int height
)
231 const uint8_t *s1
, *s2
, *s3
, *s4
;
234 for(;height
> 0; height
--) {
240 for(w
= width
;w
> 0; w
--) {
241 d
[0] = (s1
[0] + s1
[1] + s1
[2] + s1
[3] +
242 s2
[0] + s2
[1] + s2
[2] + s2
[3] +
243 s3
[0] + s3
[1] + s3
[2] + s3
[3] +
244 s4
[0] + s4
[1] + s4
[2] + s4
[3] + 8) >> 4;
257 void ff_shrink88(uint8_t *dst
, int dst_wrap
,
258 const uint8_t *src
, int src_wrap
,
259 int width
, int height
)
263 for(;height
> 0; height
--) {
264 for(w
= width
;w
> 0; w
--) {
267 tmp
+= src
[0] + src
[1] + src
[2] + src
[3] + src
[4] + src
[5] + src
[6] + src
[7];
270 *(dst
++) = (tmp
+ 32)>>6;
271 src
+= 8 - 8*src_wrap
;
273 src
+= 8*src_wrap
- 8*width
;
274 dst
+= dst_wrap
- width
;
278 /* return true if yuv planar */
279 static inline int is_yuv_planar(const AVPixFmtDescriptor
*desc
)
281 return (!(desc
->flags
& PIX_FMT_RGB
) &&
282 (desc
->flags
& PIX_FMT_PLANAR
));
285 int av_picture_crop(AVPicture
*dst
, const AVPicture
*src
,
286 enum AVPixelFormat pix_fmt
, int top_band
, int left_band
)
288 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(pix_fmt
);
292 if (pix_fmt
< 0 || pix_fmt
>= AV_PIX_FMT_NB
|| !is_yuv_planar(desc
))
295 y_shift
= desc
->log2_chroma_h
;
296 x_shift
= desc
->log2_chroma_w
;
298 dst
->data
[0] = src
->data
[0] + (top_band
* src
->linesize
[0]) + left_band
;
299 dst
->data
[1] = src
->data
[1] + ((top_band
>> y_shift
) * src
->linesize
[1]) + (left_band
>> x_shift
);
300 dst
->data
[2] = src
->data
[2] + ((top_band
>> y_shift
) * src
->linesize
[2]) + (left_band
>> x_shift
);
302 dst
->linesize
[0] = src
->linesize
[0];
303 dst
->linesize
[1] = src
->linesize
[1];
304 dst
->linesize
[2] = src
->linesize
[2];
308 int av_picture_pad(AVPicture
*dst
, const AVPicture
*src
, int height
, int width
,
309 enum AVPixelFormat pix_fmt
, int padtop
, int padbottom
, int padleft
, int padright
,
312 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(pix_fmt
);
319 if (pix_fmt
< 0 || pix_fmt
>= AV_PIX_FMT_NB
||
320 !is_yuv_planar(desc
)) return -1;
322 for (i
= 0; i
< 3; i
++) {
323 x_shift
= i
? desc
->log2_chroma_w
: 0;
324 y_shift
= i
? desc
->log2_chroma_h
: 0;
326 if (padtop
|| padleft
) {
327 memset(dst
->data
[i
], color
[i
],
328 dst
->linesize
[i
] * (padtop
>> y_shift
) + (padleft
>> x_shift
));
331 if (padleft
|| padright
) {
332 optr
= dst
->data
[i
] + dst
->linesize
[i
] * (padtop
>> y_shift
) +
333 (dst
->linesize
[i
] - (padright
>> x_shift
));
334 yheight
= (height
- 1 - (padtop
+ padbottom
)) >> y_shift
;
335 for (y
= 0; y
< yheight
; y
++) {
336 memset(optr
, color
[i
], (padleft
+ padright
) >> x_shift
);
337 optr
+= dst
->linesize
[i
];
341 if (src
) { /* first line */
342 uint8_t *iptr
= src
->data
[i
];
343 optr
= dst
->data
[i
] + dst
->linesize
[i
] * (padtop
>> y_shift
) +
344 (padleft
>> x_shift
);
345 memcpy(optr
, iptr
, (width
- padleft
- padright
) >> x_shift
);
346 iptr
+= src
->linesize
[i
];
347 optr
= dst
->data
[i
] + dst
->linesize
[i
] * (padtop
>> y_shift
) +
348 (dst
->linesize
[i
] - (padright
>> x_shift
));
349 yheight
= (height
- 1 - (padtop
+ padbottom
)) >> y_shift
;
350 for (y
= 0; y
< yheight
; y
++) {
351 memset(optr
, color
[i
], (padleft
+ padright
) >> x_shift
);
352 memcpy(optr
+ ((padleft
+ padright
) >> x_shift
), iptr
,
353 (width
- padleft
- padright
) >> x_shift
);
354 iptr
+= src
->linesize
[i
];
355 optr
+= dst
->linesize
[i
];
359 if (padbottom
|| padright
) {
360 optr
= dst
->data
[i
] + dst
->linesize
[i
] *
361 ((height
- padbottom
) >> y_shift
) - (padright
>> x_shift
);
362 memset(optr
, color
[i
],dst
->linesize
[i
] *
363 (padbottom
>> y_shift
) + (padright
>> x_shift
));
369 #if FF_API_DEINTERLACE
371 #if !HAVE_MMX_EXTERNAL
372 /* filter parameters: [-1 4 2 4 -1] // 8 */
373 static void deinterlace_line_c(uint8_t *dst
,
374 const uint8_t *lum_m4
, const uint8_t *lum_m3
,
375 const uint8_t *lum_m2
, const uint8_t *lum_m1
,
379 uint8_t *cm
= ff_cropTbl
+ MAX_NEG_CROP
;
382 for(;size
> 0;size
--) {
384 sum
+= lum_m3
[0] << 2;
385 sum
+= lum_m2
[0] << 1;
386 sum
+= lum_m1
[0] << 2;
388 dst
[0] = cm
[(sum
+ 4) >> 3];
398 static void deinterlace_line_inplace_c(uint8_t *lum_m4
, uint8_t *lum_m3
,
399 uint8_t *lum_m2
, uint8_t *lum_m1
,
400 uint8_t *lum
, int size
)
402 uint8_t *cm
= ff_cropTbl
+ MAX_NEG_CROP
;
405 for(;size
> 0;size
--) {
407 sum
+= lum_m3
[0] << 2;
408 sum
+= lum_m2
[0] << 1;
410 sum
+= lum_m1
[0] << 2;
412 lum_m2
[0] = cm
[(sum
+ 4) >> 3];
420 #endif /* !HAVE_MMX_EXTERNAL */
422 /* deinterlacing : 2 temporal taps, 3 spatial taps linear filter. The
423 top field is copied as is, but the bottom field is deinterlaced
424 against the top field. */
425 static void deinterlace_bottom_field(uint8_t *dst
, int dst_wrap
,
426 const uint8_t *src1
, int src_wrap
,
427 int width
, int height
)
429 const uint8_t *src_m2
, *src_m1
, *src_0
, *src_p1
, *src_p2
;
434 src_0
=&src_m1
[src_wrap
];
435 src_p1
=&src_0
[src_wrap
];
436 src_p2
=&src_p1
[src_wrap
];
437 for(y
=0;y
<(height
-2);y
+=2) {
438 memcpy(dst
,src_m1
,width
);
440 deinterlace_line(dst
,src_m2
,src_m1
,src_0
,src_p1
,src_p2
,width
);
444 src_p1
+= 2*src_wrap
;
445 src_p2
+= 2*src_wrap
;
448 memcpy(dst
,src_m1
,width
);
451 deinterlace_line(dst
,src_m2
,src_m1
,src_0
,src_0
,src_0
,width
);
454 static void deinterlace_bottom_field_inplace(uint8_t *src1
, int src_wrap
,
455 int width
, int height
)
457 uint8_t *src_m1
, *src_0
, *src_p1
, *src_p2
;
460 buf
= av_malloc(width
);
463 memcpy(buf
,src_m1
,width
);
464 src_0
=&src_m1
[src_wrap
];
465 src_p1
=&src_0
[src_wrap
];
466 src_p2
=&src_p1
[src_wrap
];
467 for(y
=0;y
<(height
-2);y
+=2) {
468 deinterlace_line_inplace(buf
,src_m1
,src_0
,src_p1
,src_p2
,width
);
471 src_p1
+= 2*src_wrap
;
472 src_p2
+= 2*src_wrap
;
475 deinterlace_line_inplace(buf
,src_m1
,src_0
,src_0
,src_0
,width
);
479 int avpicture_deinterlace(AVPicture
*dst
, const AVPicture
*src
,
480 enum AVPixelFormat pix_fmt
, int width
, int height
)
484 if (pix_fmt
!= AV_PIX_FMT_YUV420P
&&
485 pix_fmt
!= AV_PIX_FMT_YUVJ420P
&&
486 pix_fmt
!= AV_PIX_FMT_YUV422P
&&
487 pix_fmt
!= AV_PIX_FMT_YUVJ422P
&&
488 pix_fmt
!= AV_PIX_FMT_YUV444P
&&
489 pix_fmt
!= AV_PIX_FMT_YUV411P
&&
490 pix_fmt
!= AV_PIX_FMT_GRAY8
)
492 if ((width
& 3) != 0 || (height
& 3) != 0)
498 case AV_PIX_FMT_YUVJ420P
:
499 case AV_PIX_FMT_YUV420P
:
503 case AV_PIX_FMT_YUV422P
:
504 case AV_PIX_FMT_YUVJ422P
:
507 case AV_PIX_FMT_YUV411P
:
513 if (pix_fmt
== AV_PIX_FMT_GRAY8
) {
518 deinterlace_bottom_field_inplace(dst
->data
[i
], dst
->linesize
[i
],
521 deinterlace_bottom_field(dst
->data
[i
],dst
->linesize
[i
],
522 src
->data
[i
], src
->linesize
[i
],
530 #endif /* FF_API_DEINTERLACE */