]> git.sesse.net Git - ffmpeg/blob - libavcodec/imgconvert.c
lavc: Add per-thread surfaces in get_hw_frame_parameters()
[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 static int is_gray(const AVPixFmtDescriptor *desc)
37 {
38     return desc->nb_components - (desc->flags & AV_PIX_FMT_FLAG_ALPHA) == 1;
39 }
40
41 int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt,
42                              enum AVPixelFormat src_pix_fmt,
43                              int has_alpha)
44 {
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);
49
50     /* compute loss */
51     loss = 0;
52
53     if (dst_pix_fmt == src_pix_fmt)
54         return 0;
55
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;
59
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;
63
64     if ((src_desc->flags & AV_PIX_FMT_FLAG_RGB) != (dst_desc->flags & AV_PIX_FMT_FLAG_RGB))
65         loss |= FF_LOSS_COLORSPACE;
66
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;
70
71     if (dst_pix_fmt == AV_PIX_FMT_PAL8 && !is_gray(src_desc))
72         return loss | FF_LOSS_COLORQUANT;
73
74     if (src_desc->nb_components > dst_desc->nb_components)
75         if (is_gray(dst_desc))
76             loss |= FF_LOSS_CHROMA;
77
78     return loss;
79 }
80
81 static enum AVPixelFormat avcodec_find_best_pix_fmt1(enum AVPixelFormat *pix_fmt_list,
82                                       enum AVPixelFormat src_pix_fmt,
83                                       int has_alpha,
84                                       int loss_mask)
85 {
86     int dist, i, loss, min_dist;
87     enum AVPixelFormat dst_pix_fmt;
88
89     /* find exact color match with smallest size */
90     dst_pix_fmt = AV_PIX_FMT_NONE;
91     min_dist = 0x7fffffff;
92     i = 0;
93     while (pix_fmt_list[i] != AV_PIX_FMT_NONE) {
94         enum AVPixelFormat pix_fmt = pix_fmt_list[i];
95
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;
100         }
101
102         loss = avcodec_get_pix_fmt_loss(pix_fmt, src_pix_fmt, has_alpha) & loss_mask;
103         if (loss == 0) {
104             dist = av_get_bits_per_pixel(av_pix_fmt_desc_get(pix_fmt));
105             if (dist < min_dist) {
106                 min_dist = dist;
107                 dst_pix_fmt = pix_fmt;
108             }
109         }
110         i++;
111     }
112     return dst_pix_fmt;
113 }
114
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)
118 {
119     enum AVPixelFormat dst_pix_fmt;
120     int loss_mask, i;
121     static const int loss_mask_order[] = {
122         ~0, /* no loss first */
123         ~FF_LOSS_ALPHA,
124         ~FF_LOSS_RESOLUTION,
125         ~(FF_LOSS_COLORSPACE | FF_LOSS_RESOLUTION),
126         ~FF_LOSS_COLORQUANT,
127         ~FF_LOSS_DEPTH,
128         0,
129     };
130
131     /* try with successive loss */
132     i = 0;
133     for(;;) {
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)
138             goto found;
139         if (loss_mask == 0)
140             break;
141     }
142     return AV_PIX_FMT_NONE;
143  found:
144     if (loss_ptr)
145         *loss_ptr = avcodec_get_pix_fmt_loss(dst_pix_fmt, src_pix_fmt, has_alpha);
146     return dst_pix_fmt;
147 }
148
149 #if FF_API_AVPICTURE
150 FF_DISABLE_DEPRECATION_WARNINGS
151 /* return true if yuv planar */
152 static inline int is_yuv_planar(const AVPixFmtDescriptor *desc)
153 {
154     return (!(desc->flags & AV_PIX_FMT_FLAG_RGB) &&
155              (desc->flags & AV_PIX_FMT_FLAG_PLANAR));
156 }
157
158 int av_picture_crop(AVPicture *dst, const AVPicture *src,
159                     enum AVPixelFormat pix_fmt, int top_band, int left_band)
160 {
161     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
162     int y_shift;
163     int x_shift;
164
165     if (pix_fmt < 0 || pix_fmt >= AV_PIX_FMT_NB || !is_yuv_planar(desc))
166         return -1;
167
168     y_shift = desc->log2_chroma_h;
169     x_shift = desc->log2_chroma_w;
170
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);
174
175     dst->linesize[0] = src->linesize[0];
176     dst->linesize[1] = src->linesize[1];
177     dst->linesize[2] = src->linesize[2];
178     return 0;
179 }
180
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,
183             int *color)
184 {
185     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
186     uint8_t *optr;
187     int y_shift;
188     int x_shift;
189     int yheight;
190     int i, y;
191
192     if (pix_fmt < 0 || pix_fmt >= AV_PIX_FMT_NB ||
193         !is_yuv_planar(desc)) return -1;
194
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;
198
199         if (padtop || padleft) {
200             memset(dst->data[i], color[i],
201                 dst->linesize[i] * (padtop >> y_shift) + (padleft >> x_shift));
202         }
203
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];
211             }
212         }
213
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];
229             }
230         }
231
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));
237         }
238     }
239     return 0;
240 }
241
242 FF_ENABLE_DEPRECATION_WARNINGS
243 #endif /* FF_API_AVPICTURE */