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
34 #include "imgconvert.h"
37 #include "libavutil/colorspace.h"
38 #include "libavutil/common.h"
39 #include "libavutil/pixdesc.h"
40 #include "libavutil/internal.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
);
46 *h_shift
= desc
->log2_chroma_w
;
47 *v_shift
= desc
->log2_chroma_h
;
50 static int is_gray(const AVPixFmtDescriptor
*desc
)
52 return desc
->nb_components
- (desc
->flags
& AV_PIX_FMT_FLAG_ALPHA
) == 1;
55 int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt
,
56 enum AVPixelFormat src_pix_fmt
,
59 const AVPixFmtDescriptor
*src_desc
= av_pix_fmt_desc_get(src_pix_fmt
);
60 const AVPixFmtDescriptor
*dst_desc
= av_pix_fmt_desc_get(dst_pix_fmt
);
61 int loss
, i
, nb_components
= FFMIN(src_desc
->nb_components
,
62 dst_desc
->nb_components
);
67 if (dst_pix_fmt
== src_pix_fmt
)
70 for (i
= 0; i
< nb_components
; i
++)
71 if (src_desc
->comp
[i
].depth
> dst_desc
->comp
[i
].depth
)
72 loss
|= FF_LOSS_DEPTH
;
74 if (dst_desc
->log2_chroma_w
> src_desc
->log2_chroma_w
||
75 dst_desc
->log2_chroma_h
> src_desc
->log2_chroma_h
)
76 loss
|= FF_LOSS_RESOLUTION
;
78 if ((src_desc
->flags
& AV_PIX_FMT_FLAG_RGB
) != (dst_desc
->flags
& AV_PIX_FMT_FLAG_RGB
))
79 loss
|= FF_LOSS_COLORSPACE
;
81 if (has_alpha
&& !(dst_desc
->flags
& AV_PIX_FMT_FLAG_ALPHA
) &&
82 (src_desc
->flags
& AV_PIX_FMT_FLAG_ALPHA
))
83 loss
|= FF_LOSS_ALPHA
;
85 if (dst_pix_fmt
== AV_PIX_FMT_PAL8
&& !is_gray(src_desc
))
86 return loss
| FF_LOSS_COLORQUANT
;
88 if (src_desc
->nb_components
> dst_desc
->nb_components
)
89 if (is_gray(dst_desc
))
90 loss
|= FF_LOSS_CHROMA
;
95 static enum AVPixelFormat
avcodec_find_best_pix_fmt1(enum AVPixelFormat
*pix_fmt_list
,
96 enum AVPixelFormat src_pix_fmt
,
100 int dist
, i
, loss
, min_dist
;
101 enum AVPixelFormat dst_pix_fmt
;
103 /* find exact color match with smallest size */
104 dst_pix_fmt
= AV_PIX_FMT_NONE
;
105 min_dist
= 0x7fffffff;
107 while (pix_fmt_list
[i
] != AV_PIX_FMT_NONE
) {
108 enum AVPixelFormat pix_fmt
= pix_fmt_list
[i
];
110 if (i
> AV_PIX_FMT_NB
) {
111 av_log(NULL
, AV_LOG_ERROR
, "Pixel format list longer than expected, "
112 "it is either not properly terminated or contains duplicates\n");
113 return AV_PIX_FMT_NONE
;
116 loss
= avcodec_get_pix_fmt_loss(pix_fmt
, src_pix_fmt
, has_alpha
) & loss_mask
;
118 dist
= av_get_bits_per_pixel(av_pix_fmt_desc_get(pix_fmt
));
119 if (dist
< min_dist
) {
121 dst_pix_fmt
= pix_fmt
;
129 enum AVPixelFormat
avcodec_find_best_pix_fmt2(enum AVPixelFormat
*pix_fmt_list
,
130 enum AVPixelFormat src_pix_fmt
,
131 int has_alpha
, int *loss_ptr
)
133 enum AVPixelFormat dst_pix_fmt
;
135 static const int loss_mask_order
[] = {
136 ~0, /* no loss first */
139 ~(FF_LOSS_COLORSPACE
| FF_LOSS_RESOLUTION
),
145 /* try with successive loss */
148 loss_mask
= loss_mask_order
[i
++];
149 dst_pix_fmt
= avcodec_find_best_pix_fmt1(pix_fmt_list
, src_pix_fmt
,
150 has_alpha
, loss_mask
);
151 if (dst_pix_fmt
>= 0)
156 return AV_PIX_FMT_NONE
;
159 *loss_ptr
= avcodec_get_pix_fmt_loss(dst_pix_fmt
, src_pix_fmt
, has_alpha
);
164 void ff_shrink22(uint8_t *dst
, int dst_wrap
,
165 const uint8_t *src
, int src_wrap
,
166 int width
, int height
)
169 const uint8_t *s1
, *s2
;
172 for(;height
> 0; height
--) {
176 for(w
= width
;w
>= 4; w
-=4) {
177 d
[0] = (s1
[0] + s1
[1] + s2
[0] + s2
[1] + 2) >> 2;
178 d
[1] = (s1
[2] + s1
[3] + s2
[2] + s2
[3] + 2) >> 2;
179 d
[2] = (s1
[4] + s1
[5] + s2
[4] + s2
[5] + 2) >> 2;
180 d
[3] = (s1
[6] + s1
[7] + s2
[6] + s2
[7] + 2) >> 2;
186 d
[0] = (s1
[0] + s1
[1] + s2
[0] + s2
[1] + 2) >> 2;
197 void ff_shrink44(uint8_t *dst
, int dst_wrap
,
198 const uint8_t *src
, int src_wrap
,
199 int width
, int height
)
202 const uint8_t *s1
, *s2
, *s3
, *s4
;
205 for(;height
> 0; height
--) {
211 for(w
= width
;w
> 0; w
--) {
212 d
[0] = (s1
[0] + s1
[1] + s1
[2] + s1
[3] +
213 s2
[0] + s2
[1] + s2
[2] + s2
[3] +
214 s3
[0] + s3
[1] + s3
[2] + s3
[3] +
215 s4
[0] + s4
[1] + s4
[2] + s4
[3] + 8) >> 4;
228 void ff_shrink88(uint8_t *dst
, int dst_wrap
,
229 const uint8_t *src
, int src_wrap
,
230 int width
, int height
)
234 for(;height
> 0; height
--) {
235 for(w
= width
;w
> 0; w
--) {
238 tmp
+= src
[0] + src
[1] + src
[2] + src
[3] + src
[4] + src
[5] + src
[6] + src
[7];
241 *(dst
++) = (tmp
+ 32)>>6;
242 src
+= 8 - 8*src_wrap
;
244 src
+= 8*src_wrap
- 8*width
;
245 dst
+= dst_wrap
- width
;
249 /* return true if yuv planar */
250 static inline int is_yuv_planar(const AVPixFmtDescriptor
*desc
)
252 return (!(desc
->flags
& AV_PIX_FMT_FLAG_RGB
) &&
253 (desc
->flags
& AV_PIX_FMT_FLAG_PLANAR
));
257 FF_DISABLE_DEPRECATION_WARNINGS
259 int av_picture_crop(AVPicture
*dst
, const AVPicture
*src
,
260 enum AVPixelFormat pix_fmt
, int top_band
, int left_band
)
262 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(pix_fmt
);
266 if (pix_fmt
< 0 || pix_fmt
>= AV_PIX_FMT_NB
|| !is_yuv_planar(desc
))
269 y_shift
= desc
->log2_chroma_h
;
270 x_shift
= desc
->log2_chroma_w
;
272 dst
->data
[0] = src
->data
[0] + (top_band
* src
->linesize
[0]) + left_band
;
273 dst
->data
[1] = src
->data
[1] + ((top_band
>> y_shift
) * src
->linesize
[1]) + (left_band
>> x_shift
);
274 dst
->data
[2] = src
->data
[2] + ((top_band
>> y_shift
) * src
->linesize
[2]) + (left_band
>> x_shift
);
276 dst
->linesize
[0] = src
->linesize
[0];
277 dst
->linesize
[1] = src
->linesize
[1];
278 dst
->linesize
[2] = src
->linesize
[2];
282 int av_picture_pad(AVPicture
*dst
, const AVPicture
*src
, int height
, int width
,
283 enum AVPixelFormat pix_fmt
, int padtop
, int padbottom
, int padleft
, int padright
,
286 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(pix_fmt
);
293 if (pix_fmt
< 0 || pix_fmt
>= AV_PIX_FMT_NB
||
294 !is_yuv_planar(desc
)) return -1;
296 for (i
= 0; i
< 3; i
++) {
297 x_shift
= i ? desc
->log2_chroma_w
: 0;
298 y_shift
= i ? desc
->log2_chroma_h
: 0;
300 if (padtop
|| padleft
) {
301 memset(dst
->data
[i
], color
[i
],
302 dst
->linesize
[i
] * (padtop
>> y_shift
) + (padleft
>> x_shift
));
305 if (padleft
|| padright
) {
306 optr
= dst
->data
[i
] + dst
->linesize
[i
] * (padtop
>> y_shift
) +
307 (dst
->linesize
[i
] - (padright
>> x_shift
));
308 yheight
= (height
- 1 - (padtop
+ padbottom
)) >> y_shift
;
309 for (y
= 0; y
< yheight
; y
++) {
310 memset(optr
, color
[i
], (padleft
+ padright
) >> x_shift
);
311 optr
+= dst
->linesize
[i
];
315 if (src
) { /* first line */
316 uint8_t *iptr
= src
->data
[i
];
317 optr
= dst
->data
[i
] + dst
->linesize
[i
] * (padtop
>> y_shift
) +
318 (padleft
>> x_shift
);
319 memcpy(optr
, iptr
, (width
- padleft
- padright
) >> x_shift
);
320 iptr
+= src
->linesize
[i
];
321 optr
= dst
->data
[i
] + dst
->linesize
[i
] * (padtop
>> y_shift
) +
322 (dst
->linesize
[i
] - (padright
>> x_shift
));
323 yheight
= (height
- 1 - (padtop
+ padbottom
)) >> y_shift
;
324 for (y
= 0; y
< yheight
; y
++) {
325 memset(optr
, color
[i
], (padleft
+ padright
) >> x_shift
);
326 memcpy(optr
+ ((padleft
+ padright
) >> x_shift
), iptr
,
327 (width
- padleft
- padright
) >> x_shift
);
328 iptr
+= src
->linesize
[i
];
329 optr
+= dst
->linesize
[i
];
333 if (padbottom
|| padright
) {
334 optr
= dst
->data
[i
] + dst
->linesize
[i
] *
335 ((height
- padbottom
) >> y_shift
) - (padright
>> x_shift
);
336 memset(optr
, color
[i
],dst
->linesize
[i
] *
337 (padbottom
>> y_shift
) + (padright
>> x_shift
));
343 FF_DISABLE_DEPRECATION_WARNINGS
344 #endif /* FF_API_AVPICTURE */