]> git.sesse.net Git - ffmpeg/blob - libavcodec/imgconvert.c
ppc: Centralize compiler-specific altivec.h #include handling in one place
[ffmpeg] / libavcodec / imgconvert.c
1 /*
2  * Misc image conversion routines
3  * Copyright (c) 2001, 2002, 2003 Fabrice Bellard
4  *
5  * This file is part of Libav.
6  *
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.
11  *
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.
16  *
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
20  */
21
22 /**
23  * @file
24  * misc image conversion routines
25  */
26
27 #include "avcodec.h"
28 #include "internal.h"
29 #include "mathops.h"
30 #include "libavutil/colorspace.h"
31 #include "libavutil/common.h"
32 #include "libavutil/pixdesc.h"
33 #include "libavutil/internal.h"
34 #include "libavutil/imgutils.h"
35
36 #if FF_API_GETCHROMA
37 void avcodec_get_chroma_sub_sample(enum AVPixelFormat pix_fmt, int *h_shift, int *v_shift)
38 {
39     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
40     *h_shift = desc->log2_chroma_w;
41     *v_shift = desc->log2_chroma_h;
42 }
43 #endif
44
45 static int is_gray(const AVPixFmtDescriptor *desc)
46 {
47     return desc->nb_components - (desc->flags & AV_PIX_FMT_FLAG_ALPHA) == 1;
48 }
49
50 int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt,
51                              enum AVPixelFormat src_pix_fmt,
52                              int has_alpha)
53 {
54     const AVPixFmtDescriptor *src_desc = av_pix_fmt_desc_get(src_pix_fmt);
55     const AVPixFmtDescriptor *dst_desc = av_pix_fmt_desc_get(dst_pix_fmt);
56     int loss, i, nb_components = FFMIN(src_desc->nb_components,
57                                        dst_desc->nb_components);
58
59     /* compute loss */
60     loss = 0;
61
62     if (dst_pix_fmt == src_pix_fmt)
63         return 0;
64
65     for (i = 0; i < nb_components; i++)
66         if (src_desc->comp[i].depth > dst_desc->comp[i].depth)
67             loss |= FF_LOSS_DEPTH;
68
69     if (dst_desc->log2_chroma_w > src_desc->log2_chroma_w ||
70         dst_desc->log2_chroma_h > src_desc->log2_chroma_h)
71         loss |= FF_LOSS_RESOLUTION;
72
73     if ((src_desc->flags & AV_PIX_FMT_FLAG_RGB) != (dst_desc->flags & AV_PIX_FMT_FLAG_RGB))
74         loss |= FF_LOSS_COLORSPACE;
75
76     if (has_alpha && !(dst_desc->flags & AV_PIX_FMT_FLAG_ALPHA) &&
77          (src_desc->flags & AV_PIX_FMT_FLAG_ALPHA))
78         loss |= FF_LOSS_ALPHA;
79
80     if (dst_pix_fmt == AV_PIX_FMT_PAL8 && !is_gray(src_desc))
81         return loss | FF_LOSS_COLORQUANT;
82
83     if (src_desc->nb_components > dst_desc->nb_components)
84         if (is_gray(dst_desc))
85             loss |= FF_LOSS_CHROMA;
86
87     return loss;
88 }
89
90 static enum AVPixelFormat avcodec_find_best_pix_fmt1(enum AVPixelFormat *pix_fmt_list,
91                                       enum AVPixelFormat src_pix_fmt,
92                                       int has_alpha,
93                                       int loss_mask)
94 {
95     int dist, i, loss, min_dist;
96     enum AVPixelFormat dst_pix_fmt;
97
98     /* find exact color match with smallest size */
99     dst_pix_fmt = AV_PIX_FMT_NONE;
100     min_dist = 0x7fffffff;
101     i = 0;
102     while (pix_fmt_list[i] != AV_PIX_FMT_NONE) {
103         enum AVPixelFormat pix_fmt = pix_fmt_list[i];
104
105         if (i > AV_PIX_FMT_NB) {
106             av_log(NULL, AV_LOG_ERROR, "Pixel format list longer than expected, "
107                    "it is either not properly terminated or contains duplicates\n");
108             return AV_PIX_FMT_NONE;
109         }
110
111         loss = avcodec_get_pix_fmt_loss(pix_fmt, src_pix_fmt, has_alpha) & loss_mask;
112         if (loss == 0) {
113             dist = av_get_bits_per_pixel(av_pix_fmt_desc_get(pix_fmt));
114             if (dist < min_dist) {
115                 min_dist = dist;
116                 dst_pix_fmt = pix_fmt;
117             }
118         }
119         i++;
120     }
121     return dst_pix_fmt;
122 }
123
124 enum AVPixelFormat avcodec_find_best_pix_fmt2(enum AVPixelFormat *pix_fmt_list,
125                                             enum AVPixelFormat src_pix_fmt,
126                                             int has_alpha, int *loss_ptr)
127 {
128     enum AVPixelFormat dst_pix_fmt;
129     int loss_mask, i;
130     static const int loss_mask_order[] = {
131         ~0, /* no loss first */
132         ~FF_LOSS_ALPHA,
133         ~FF_LOSS_RESOLUTION,
134         ~(FF_LOSS_COLORSPACE | FF_LOSS_RESOLUTION),
135         ~FF_LOSS_COLORQUANT,
136         ~FF_LOSS_DEPTH,
137         0,
138     };
139
140     /* try with successive loss */
141     i = 0;
142     for(;;) {
143         loss_mask = loss_mask_order[i++];
144         dst_pix_fmt = avcodec_find_best_pix_fmt1(pix_fmt_list, src_pix_fmt,
145                                                  has_alpha, loss_mask);
146         if (dst_pix_fmt >= 0)
147             goto found;
148         if (loss_mask == 0)
149             break;
150     }
151     return AV_PIX_FMT_NONE;
152  found:
153     if (loss_ptr)
154         *loss_ptr = avcodec_get_pix_fmt_loss(dst_pix_fmt, src_pix_fmt, has_alpha);
155     return dst_pix_fmt;
156 }
157
158 #if FF_API_AVPICTURE
159 FF_DISABLE_DEPRECATION_WARNINGS
160 /* return true if yuv planar */
161 static inline int is_yuv_planar(const AVPixFmtDescriptor *desc)
162 {
163     return (!(desc->flags & AV_PIX_FMT_FLAG_RGB) &&
164              (desc->flags & AV_PIX_FMT_FLAG_PLANAR));
165 }
166
167 int av_picture_crop(AVPicture *dst, const AVPicture *src,
168                     enum AVPixelFormat pix_fmt, int top_band, int left_band)
169 {
170     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
171     int y_shift;
172     int x_shift;
173
174     if (pix_fmt < 0 || pix_fmt >= AV_PIX_FMT_NB || !is_yuv_planar(desc))
175         return -1;
176
177     y_shift = desc->log2_chroma_h;
178     x_shift = desc->log2_chroma_w;
179
180     dst->data[0] = src->data[0] + (top_band * src->linesize[0]) + left_band;
181     dst->data[1] = src->data[1] + ((top_band >> y_shift) * src->linesize[1]) + (left_band >> x_shift);
182     dst->data[2] = src->data[2] + ((top_band >> y_shift) * src->linesize[2]) + (left_band >> x_shift);
183
184     dst->linesize[0] = src->linesize[0];
185     dst->linesize[1] = src->linesize[1];
186     dst->linesize[2] = src->linesize[2];
187     return 0;
188 }
189
190 int av_picture_pad(AVPicture *dst, const AVPicture *src, int height, int width,
191                    enum AVPixelFormat pix_fmt, int padtop, int padbottom, int padleft, int padright,
192             int *color)
193 {
194     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
195     uint8_t *optr;
196     int y_shift;
197     int x_shift;
198     int yheight;
199     int i, y;
200
201     if (pix_fmt < 0 || pix_fmt >= AV_PIX_FMT_NB ||
202         !is_yuv_planar(desc)) return -1;
203
204     for (i = 0; i < 3; i++) {
205         x_shift = i ? desc->log2_chroma_w : 0;
206         y_shift = i ? desc->log2_chroma_h : 0;
207
208         if (padtop || padleft) {
209             memset(dst->data[i], color[i],
210                 dst->linesize[i] * (padtop >> y_shift) + (padleft >> x_shift));
211         }
212
213         if (padleft || padright) {
214             optr = dst->data[i] + dst->linesize[i] * (padtop >> y_shift) +
215                 (dst->linesize[i] - (padright >> x_shift));
216             yheight = (height - 1 - (padtop + padbottom)) >> y_shift;
217             for (y = 0; y < yheight; y++) {
218                 memset(optr, color[i], (padleft + padright) >> x_shift);
219                 optr += dst->linesize[i];
220             }
221         }
222
223         if (src) { /* first line */
224             uint8_t *iptr = src->data[i];
225             optr = dst->data[i] + dst->linesize[i] * (padtop >> y_shift) +
226                     (padleft >> x_shift);
227             memcpy(optr, iptr, (width - padleft - padright) >> x_shift);
228             iptr += src->linesize[i];
229             optr = dst->data[i] + dst->linesize[i] * (padtop >> y_shift) +
230                 (dst->linesize[i] - (padright >> x_shift));
231             yheight = (height - 1 - (padtop + padbottom)) >> y_shift;
232             for (y = 0; y < yheight; y++) {
233                 memset(optr, color[i], (padleft + padright) >> x_shift);
234                 memcpy(optr + ((padleft + padright) >> x_shift), iptr,
235                        (width - padleft - padright) >> x_shift);
236                 iptr += src->linesize[i];
237                 optr += dst->linesize[i];
238             }
239         }
240
241         if (padbottom || padright) {
242             optr = dst->data[i] + dst->linesize[i] *
243                 ((height - padbottom) >> y_shift) - (padright >> x_shift);
244             memset(optr, color[i],dst->linesize[i] *
245                 (padbottom >> y_shift) + (padright >> x_shift));
246         }
247     }
248     return 0;
249 }
250
251 FF_ENABLE_DEPRECATION_WARNINGS
252 #endif /* FF_API_AVPICTURE */