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
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"
36 static int is_gray(const AVPixFmtDescriptor *desc)
38 return desc->nb_components - (desc->flags & AV_PIX_FMT_FLAG_ALPHA) == 1;
41 int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt,
42 enum AVPixelFormat src_pix_fmt,
45 const AVPixFmtDescriptor *src_desc = av_pix_fmt_desc_get(src_pix_fmt);
46 const AVPixFmtDescriptor *dst_desc = av_pix_fmt_desc_get(dst_pix_fmt);
47 int loss, i, nb_components = FFMIN(src_desc->nb_components,
48 dst_desc->nb_components);
53 if (dst_pix_fmt == src_pix_fmt)
56 for (i = 0; i < nb_components; i++)
57 if (src_desc->comp[i].depth > dst_desc->comp[i].depth)
58 loss |= FF_LOSS_DEPTH;
60 if (dst_desc->log2_chroma_w > src_desc->log2_chroma_w ||
61 dst_desc->log2_chroma_h > src_desc->log2_chroma_h)
62 loss |= FF_LOSS_RESOLUTION;
64 if ((src_desc->flags & AV_PIX_FMT_FLAG_RGB) != (dst_desc->flags & AV_PIX_FMT_FLAG_RGB))
65 loss |= FF_LOSS_COLORSPACE;
67 if (has_alpha && !(dst_desc->flags & AV_PIX_FMT_FLAG_ALPHA) &&
68 (src_desc->flags & AV_PIX_FMT_FLAG_ALPHA))
69 loss |= FF_LOSS_ALPHA;
71 if (dst_pix_fmt == AV_PIX_FMT_PAL8 && !is_gray(src_desc))
72 return loss | FF_LOSS_COLORQUANT;
74 if (src_desc->nb_components > dst_desc->nb_components)
75 if (is_gray(dst_desc))
76 loss |= FF_LOSS_CHROMA;
81 static enum AVPixelFormat avcodec_find_best_pix_fmt1(enum AVPixelFormat *pix_fmt_list,
82 enum AVPixelFormat src_pix_fmt,
86 int dist, i, loss, min_dist;
87 enum AVPixelFormat dst_pix_fmt;
89 /* find exact color match with smallest size */
90 dst_pix_fmt = AV_PIX_FMT_NONE;
91 min_dist = 0x7fffffff;
93 while (pix_fmt_list[i] != AV_PIX_FMT_NONE) {
94 enum AVPixelFormat pix_fmt = pix_fmt_list[i];
96 if (i > AV_PIX_FMT_NB) {
97 av_log(NULL, AV_LOG_ERROR, "Pixel format list longer than expected, "
98 "it is either not properly terminated or contains duplicates\n");
99 return AV_PIX_FMT_NONE;
102 loss = avcodec_get_pix_fmt_loss(pix_fmt, src_pix_fmt, has_alpha) & loss_mask;
104 dist = av_get_bits_per_pixel(av_pix_fmt_desc_get(pix_fmt));
105 if (dist < min_dist) {
107 dst_pix_fmt = pix_fmt;
115 enum AVPixelFormat avcodec_find_best_pix_fmt2(enum AVPixelFormat *pix_fmt_list,
116 enum AVPixelFormat src_pix_fmt,
117 int has_alpha, int *loss_ptr)
119 enum AVPixelFormat dst_pix_fmt;
121 static const int loss_mask_order[] = {
122 ~0, /* no loss first */
125 ~(FF_LOSS_COLORSPACE | FF_LOSS_RESOLUTION),
131 /* try with successive loss */
134 loss_mask = loss_mask_order[i++];
135 dst_pix_fmt = avcodec_find_best_pix_fmt1(pix_fmt_list, src_pix_fmt,
136 has_alpha, loss_mask);
137 if (dst_pix_fmt >= 0)
142 return AV_PIX_FMT_NONE;
145 *loss_ptr = avcodec_get_pix_fmt_loss(dst_pix_fmt, src_pix_fmt, has_alpha);
150 FF_DISABLE_DEPRECATION_WARNINGS
151 /* return true if yuv planar */
152 static inline int is_yuv_planar(const AVPixFmtDescriptor *desc)
154 return (!(desc->flags & AV_PIX_FMT_FLAG_RGB) &&
155 (desc->flags & AV_PIX_FMT_FLAG_PLANAR));
158 int av_picture_crop(AVPicture *dst, const AVPicture *src,
159 enum AVPixelFormat pix_fmt, int top_band, int left_band)
161 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
165 if (pix_fmt < 0 || pix_fmt >= AV_PIX_FMT_NB || !is_yuv_planar(desc))
168 y_shift = desc->log2_chroma_h;
169 x_shift = desc->log2_chroma_w;
171 dst->data[0] = src->data[0] + (top_band * src->linesize[0]) + left_band;
172 dst->data[1] = src->data[1] + ((top_band >> y_shift) * src->linesize[1]) + (left_band >> x_shift);
173 dst->data[2] = src->data[2] + ((top_band >> y_shift) * src->linesize[2]) + (left_band >> x_shift);
175 dst->linesize[0] = src->linesize[0];
176 dst->linesize[1] = src->linesize[1];
177 dst->linesize[2] = src->linesize[2];
181 int av_picture_pad(AVPicture *dst, const AVPicture *src, int height, int width,
182 enum AVPixelFormat pix_fmt, int padtop, int padbottom, int padleft, int padright,
185 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
192 if (pix_fmt < 0 || pix_fmt >= AV_PIX_FMT_NB ||
193 !is_yuv_planar(desc)) return -1;
195 for (i = 0; i < 3; i++) {
196 x_shift = i ? desc->log2_chroma_w : 0;
197 y_shift = i ? desc->log2_chroma_h : 0;
199 if (padtop || padleft) {
200 memset(dst->data[i], color[i],
201 dst->linesize[i] * (padtop >> y_shift) + (padleft >> x_shift));
204 if (padleft || padright) {
205 optr = dst->data[i] + dst->linesize[i] * (padtop >> y_shift) +
206 (dst->linesize[i] - (padright >> x_shift));
207 yheight = (height - 1 - (padtop + padbottom)) >> y_shift;
208 for (y = 0; y < yheight; y++) {
209 memset(optr, color[i], (padleft + padright) >> x_shift);
210 optr += dst->linesize[i];
214 if (src) { /* first line */
215 uint8_t *iptr = src->data[i];
216 optr = dst->data[i] + dst->linesize[i] * (padtop >> y_shift) +
217 (padleft >> x_shift);
218 memcpy(optr, iptr, (width - padleft - padright) >> x_shift);
219 iptr += src->linesize[i];
220 optr = dst->data[i] + dst->linesize[i] * (padtop >> y_shift) +
221 (dst->linesize[i] - (padright >> x_shift));
222 yheight = (height - 1 - (padtop + padbottom)) >> y_shift;
223 for (y = 0; y < yheight; y++) {
224 memset(optr, color[i], (padleft + padright) >> x_shift);
225 memcpy(optr + ((padleft + padright) >> x_shift), iptr,
226 (width - padleft - padright) >> x_shift);
227 iptr += src->linesize[i];
228 optr += dst->linesize[i];
232 if (padbottom || padright) {
233 optr = dst->data[i] + dst->linesize[i] *
234 ((height - padbottom) >> y_shift) - (padright >> x_shift);
235 memset(optr, color[i],dst->linesize[i] *
236 (padbottom >> y_shift) + (padright >> x_shift));
242 FF_ENABLE_DEPRECATION_WARNINGS
243 #endif /* FF_API_AVPICTURE */