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"
37 void avcodec_get_chroma_sub_sample(enum AVPixelFormat pix_fmt, int *h_shift, int *v_shift)
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;
45 static int is_gray(const AVPixFmtDescriptor *desc)
47 return desc->nb_components - (desc->flags & AV_PIX_FMT_FLAG_ALPHA) == 1;
50 int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt,
51 enum AVPixelFormat src_pix_fmt,
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);
62 if (dst_pix_fmt == src_pix_fmt)
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;
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;
73 if ((src_desc->flags & AV_PIX_FMT_FLAG_RGB) != (dst_desc->flags & AV_PIX_FMT_FLAG_RGB))
74 loss |= FF_LOSS_COLORSPACE;
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;
80 if (dst_pix_fmt == AV_PIX_FMT_PAL8 && !is_gray(src_desc))
81 return loss | FF_LOSS_COLORQUANT;
83 if (src_desc->nb_components > dst_desc->nb_components)
84 if (is_gray(dst_desc))
85 loss |= FF_LOSS_CHROMA;
90 static enum AVPixelFormat avcodec_find_best_pix_fmt1(enum AVPixelFormat *pix_fmt_list,
91 enum AVPixelFormat src_pix_fmt,
95 int dist, i, loss, min_dist;
96 enum AVPixelFormat dst_pix_fmt;
98 /* find exact color match with smallest size */
99 dst_pix_fmt = AV_PIX_FMT_NONE;
100 min_dist = 0x7fffffff;
102 while (pix_fmt_list[i] != AV_PIX_FMT_NONE) {
103 enum AVPixelFormat pix_fmt = pix_fmt_list[i];
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;
111 loss = avcodec_get_pix_fmt_loss(pix_fmt, src_pix_fmt, has_alpha) & loss_mask;
113 dist = av_get_bits_per_pixel(av_pix_fmt_desc_get(pix_fmt));
114 if (dist < min_dist) {
116 dst_pix_fmt = pix_fmt;
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)
128 enum AVPixelFormat dst_pix_fmt;
130 static const int loss_mask_order[] = {
131 ~0, /* no loss first */
134 ~(FF_LOSS_COLORSPACE | FF_LOSS_RESOLUTION),
140 /* try with successive loss */
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)
151 return AV_PIX_FMT_NONE;
154 *loss_ptr = avcodec_get_pix_fmt_loss(dst_pix_fmt, src_pix_fmt, has_alpha);
159 FF_DISABLE_DEPRECATION_WARNINGS
160 /* return true if yuv planar */
161 static inline int is_yuv_planar(const AVPixFmtDescriptor *desc)
163 return (!(desc->flags & AV_PIX_FMT_FLAG_RGB) &&
164 (desc->flags & AV_PIX_FMT_FLAG_PLANAR));
167 int av_picture_crop(AVPicture *dst, const AVPicture *src,
168 enum AVPixelFormat pix_fmt, int top_band, int left_band)
170 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
174 if (pix_fmt < 0 || pix_fmt >= AV_PIX_FMT_NB || !is_yuv_planar(desc))
177 y_shift = desc->log2_chroma_h;
178 x_shift = desc->log2_chroma_w;
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);
184 dst->linesize[0] = src->linesize[0];
185 dst->linesize[1] = src->linesize[1];
186 dst->linesize[2] = src->linesize[2];
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,
194 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
201 if (pix_fmt < 0 || pix_fmt >= AV_PIX_FMT_NB ||
202 !is_yuv_planar(desc)) return -1;
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;
208 if (padtop || padleft) {
209 memset(dst->data[i], color[i],
210 dst->linesize[i] * (padtop >> y_shift) + (padleft >> x_shift));
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];
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];
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));
251 FF_ENABLE_DEPRECATION_WARNINGS
252 #endif /* FF_API_AVPICTURE */