1 /*****************************************************************
2 * gavl - a general purpose audio/video processing library
3 *
4 * Copyright (c) 2001 - 2011 Members of the Gmerlin project
5 * gmerlin-general@lists.sourceforge.net
6 * http://gmerlin.sourceforge.net
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * *****************************************************************/
21
22 #include <math.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <gavl/gavl.h>
26
gavl_rectangle_i_dump(const gavl_rectangle_i_t * r)27 void gavl_rectangle_i_dump(const gavl_rectangle_i_t * r)
28 {
29 fprintf(stderr, "%dx%d+%d+%d", r->w, r->h, r->x, r->y);
30 }
31
gavl_rectangle_f_dump(const gavl_rectangle_f_t * r)32 void gavl_rectangle_f_dump(const gavl_rectangle_f_t * r)
33 {
34 fprintf(stderr, "%fx%f+%f+%f", r->w, r->h, r->x, r->y);
35 }
36
gavl_rectangle_i_crop_to_format(gavl_rectangle_i_t * r,const gavl_video_format_t * format)37 void gavl_rectangle_i_crop_to_format(gavl_rectangle_i_t * r, const gavl_video_format_t * format)
38 {
39 if(r->x < 0)
40 {
41 r->w += r->x;
42 r->x = 0;
43 }
44 if(r->y < 0)
45 {
46 r->h += r->y;
47 r->y = 0;
48 }
49
50 /* Check if rectangle is empty */
51
52 if((r->x > format->image_width) || (r->y > format->image_height) ||
53 (r->w < 0) || (r->h < 0))
54 {
55 r->x = 0;
56 r->y = 0;
57 r->w = 0;
58 r->h = 0;
59 return;
60 }
61
62 if(r->w > format->image_width - r->x)
63 r->w = format->image_width - r->x;
64
65 if(r->h > format->image_height - r->y)
66 r->h = format->image_height - r->y;
67
68 }
69
70 #define GAVL_MIN(x, y) (x < y ? x : y);
71
gavl_rectangle_crop_to_format_noscale(gavl_rectangle_i_t * src_rect,gavl_rectangle_i_t * dst_rect,const gavl_video_format_t * src_format,const gavl_video_format_t * dst_format)72 void gavl_rectangle_crop_to_format_noscale(gavl_rectangle_i_t * src_rect,
73 gavl_rectangle_i_t * dst_rect,
74 const gavl_video_format_t * src_format,
75 const gavl_video_format_t * dst_format)
76 {
77 src_rect->w = GAVL_MIN(src_format->image_width, dst_format->image_width);
78 src_rect->h = GAVL_MIN(src_format->image_height, dst_format->image_height);
79
80 dst_rect->w = src_rect->w;
81 dst_rect->h = src_rect->h;
82
83 src_rect->x = (src_format->image_width - src_rect->w) / 2;
84 src_rect->y = (src_format->image_height - src_rect->h) / 2;
85
86 dst_rect->x = (dst_format->image_width - dst_rect->w) / 2;
87 dst_rect->y = (dst_format->image_height - dst_rect->h) / 2;
88
89 }
90
91 #undef GAVL_MIN
92
crop_dimension_scale(double * src_off,double * src_len,int src_size,int * dst_off,int * dst_len,int dst_size)93 static void crop_dimension_scale(double * src_off, double * src_len, int src_size,
94 int * dst_off, int * dst_len, int dst_size)
95 {
96 double scale_factor;
97 double dst_off_f, dst_len_f;
98 double crop;
99
100 dst_off_f = (double)(*dst_off);
101 dst_len_f = (double)(*dst_len);
102
103 scale_factor = (double)(*dst_len) / *src_len;
104
105 /* Lower limit (source) */
106 if(*src_off < 0.0)
107 {
108 crop = - (*src_off);
109 dst_off_f += (crop*scale_factor);
110 dst_len_f -= (crop*scale_factor);
111 *src_len -= (crop);
112 *src_off = 0.0;
113 }
114
115 /* Upper limit (source) */
116 if(*src_off + *src_len > (double)(src_size))
117 {
118 crop = *src_off + *src_len - (double)(src_size);
119 dst_len_f -= (crop*scale_factor);
120 *src_len -= crop;
121 }
122
123 /* Lower limit (destination) */
124 if(dst_off_f < 0.0)
125 {
126 crop = - (*dst_off);
127 *src_off += (crop/scale_factor);
128 *src_len -= (crop/scale_factor);
129 dst_len_f -= (crop);
130 dst_off_f = 0.0;
131 }
132
133 /* Upper limit (destination) */
134 if(dst_off_f + dst_len_f > (double)(dst_size))
135 {
136 crop = dst_off_f + dst_len_f - (double)(dst_size);
137 dst_len_f -= (crop);
138 *src_len -= crop/scale_factor;
139 }
140 *dst_len = (int)(dst_len_f+0.5);
141 *dst_off = (int)(dst_off_f+0.5);
142
143 }
144
145
gavl_rectangle_crop_to_format_scale(gavl_rectangle_f_t * src_rect,gavl_rectangle_i_t * dst_rect,const gavl_video_format_t * src_format,const gavl_video_format_t * dst_format)146 void gavl_rectangle_crop_to_format_scale(gavl_rectangle_f_t * src_rect,
147 gavl_rectangle_i_t * dst_rect,
148 const gavl_video_format_t * src_format,
149 const gavl_video_format_t * dst_format)
150 {
151 crop_dimension_scale(&src_rect->x, &src_rect->w, src_format->image_width,
152 &dst_rect->x, &dst_rect->w, dst_format->image_width);
153 crop_dimension_scale(&src_rect->y, &src_rect->h, src_format->image_height,
154 &dst_rect->y, &dst_rect->h, dst_format->image_height);
155 }
156
157
158 /* Let a rectangle span the whole screen for format */
159
gavl_rectangle_i_set_all(gavl_rectangle_i_t * r,const gavl_video_format_t * format)160 void gavl_rectangle_i_set_all(gavl_rectangle_i_t * r, const gavl_video_format_t * format)
161 {
162 r->x = 0;
163 r->y = 0;
164 r->w = format->image_width;
165 r->h = format->image_height;
166
167 }
168
gavl_rectangle_f_set_all(gavl_rectangle_f_t * r,const gavl_video_format_t * format)169 void gavl_rectangle_f_set_all(gavl_rectangle_f_t * r, const gavl_video_format_t * format)
170 {
171 r->x = 0;
172 r->y = 0;
173 r->w = format->image_width;
174 r->h = format->image_height;
175
176 }
177
gavl_rectangle_i_crop_left(gavl_rectangle_i_t * r,int num_pixels)178 void gavl_rectangle_i_crop_left(gavl_rectangle_i_t * r, int num_pixels)
179 {
180 r->x += num_pixels;
181 r->w -= num_pixels;
182 }
183
gavl_rectangle_i_crop_right(gavl_rectangle_i_t * r,int num_pixels)184 void gavl_rectangle_i_crop_right(gavl_rectangle_i_t * r, int num_pixels)
185 {
186 r->w -= num_pixels;
187 }
188
gavl_rectangle_i_crop_top(gavl_rectangle_i_t * r,int num_pixels)189 void gavl_rectangle_i_crop_top(gavl_rectangle_i_t * r, int num_pixels)
190 {
191 r->y += num_pixels;
192 r->h -= num_pixels;
193 }
194
gavl_rectangle_i_crop_bottom(gavl_rectangle_i_t * r,int num_pixels)195 void gavl_rectangle_i_crop_bottom(gavl_rectangle_i_t * r, int num_pixels)
196 {
197 r->h -= num_pixels;
198 }
199
gavl_rectangle_f_crop_left(gavl_rectangle_f_t * r,double num_pixels)200 void gavl_rectangle_f_crop_left(gavl_rectangle_f_t * r, double num_pixels)
201 {
202 r->x += num_pixels;
203 r->w -= num_pixels;
204 }
205
gavl_rectangle_f_crop_right(gavl_rectangle_f_t * r,double num_pixels)206 void gavl_rectangle_f_crop_right(gavl_rectangle_f_t * r, double num_pixels)
207 {
208 r->w -= num_pixels;
209 }
210
gavl_rectangle_f_crop_top(gavl_rectangle_f_t * r,double num_pixels)211 void gavl_rectangle_f_crop_top(gavl_rectangle_f_t * r, double num_pixels)
212 {
213 r->y += num_pixels;
214 r->h -= num_pixels;
215 }
216
gavl_rectangle_f_crop_bottom(gavl_rectangle_f_t * r,double num_pixels)217 void gavl_rectangle_f_crop_bottom(gavl_rectangle_f_t * r, double num_pixels)
218 {
219 r->h -= num_pixels;
220 }
221
222 #define PADD(num, multiple) num -= num % multiple
223
gavl_rectangle_i_align(gavl_rectangle_i_t * r,int h_align,int v_align)224 void gavl_rectangle_i_align(gavl_rectangle_i_t * r, int h_align, int v_align)
225 {
226 PADD(r->x, h_align);
227 PADD(r->w, h_align);
228
229 PADD(r->y, v_align);
230 PADD(r->h, v_align);
231 }
232
gavl_rectangle_i_align_to_format(gavl_rectangle_i_t * r,const gavl_video_format_t * format)233 void gavl_rectangle_i_align_to_format(gavl_rectangle_i_t * r,
234 const gavl_video_format_t * format)
235 {
236 int sub_h, sub_v;
237 gavl_pixelformat_chroma_sub(format->pixelformat, &sub_h, &sub_v);
238 gavl_rectangle_i_align(r, sub_h, sub_v);
239 }
240
241
gavl_rectangle_f_copy(gavl_rectangle_f_t * dst,const gavl_rectangle_f_t * src)242 void gavl_rectangle_f_copy(gavl_rectangle_f_t * dst, const gavl_rectangle_f_t * src)
243 {
244 memcpy(dst, src, sizeof(*dst));
245 }
246
gavl_rectangle_i_copy(gavl_rectangle_i_t * dst,const gavl_rectangle_i_t * src)247 void gavl_rectangle_i_copy(gavl_rectangle_i_t * dst, const gavl_rectangle_i_t * src)
248 {
249 memcpy(dst, src, sizeof(*dst));
250 }
251
gavl_rectangle_i_is_empty(const gavl_rectangle_i_t * r)252 int gavl_rectangle_i_is_empty(const gavl_rectangle_i_t * r)
253 {
254 return ((r->w <= 0) || (r->h <= 0)) ? 1 : 0;
255 }
256
gavl_rectangle_f_is_empty(const gavl_rectangle_f_t * r)257 int gavl_rectangle_f_is_empty(const gavl_rectangle_f_t * r)
258 {
259 return ((r->w <= 0.0) || (r->h <= 0.0)) ? 1 : 0;
260 }
261
262
263 /* Assuming we take src_rect from a frame in format src_format,
264 calculate the optimal dst_rect in dst_format. */
265
gavl_rectangle_fit_aspect(gavl_rectangle_i_t * r,const gavl_video_format_t * src_format,const gavl_rectangle_f_t * src_rect,const gavl_video_format_t * dst_format,float zoom,float squeeze)266 void gavl_rectangle_fit_aspect(gavl_rectangle_i_t * r,
267 const gavl_video_format_t * src_format,
268 const gavl_rectangle_f_t * src_rect,
269 const gavl_video_format_t * dst_format,
270 float zoom, float squeeze)
271 {
272 float dst_display_aspect;
273 float dst_pixel_aspect;
274 float src_display_aspect;
275
276 float squeeze_factor;
277
278 squeeze_factor = pow(2.0, squeeze);
279
280 src_display_aspect = squeeze_factor *
281 src_rect->w * (float)(src_format->pixel_width) /
282 (src_rect->h * (float)(src_format->pixel_height));
283
284 dst_pixel_aspect =
285 (float)(dst_format->pixel_width) /
286 (float)(dst_format->pixel_height);
287
288 dst_display_aspect =
289 dst_pixel_aspect *
290 (float)(dst_format->image_width) /
291 (float)(dst_format->image_height);
292
293 if(dst_display_aspect > src_display_aspect) /* Bars left and right */
294 {
295 // fprintf(stderr, "Bars left and right\n");
296 r->w = (int)((float)dst_format->image_height * src_display_aspect * zoom / dst_pixel_aspect + 0.5);
297 r->h = (int)((float)dst_format->image_height * zoom + 0.5);
298 // fprintf(stderr, "Bars left and right %dx%d -> %dx%d (%f, %f)\n", src_rect->w, src_rect->h, r->w, r->h,
299 // (float)(src_rect->w * src_format->pixel_width) /
300 // (float)(src_rect->h * src_format->pixel_height), dst_pixel_aspect);
301 }
302 else /* Bars top and bottom */
303 {
304 // fprintf(stderr, "Bars top and bottom\n");
305 r->w = (int)((float)(dst_format->image_width) * zoom + 0.5);
306 r->h = (int)((float)dst_format->image_width * zoom * dst_pixel_aspect / src_display_aspect + 0.5);
307 }
308 r->x = (dst_format->image_width - r->w)/2;
309 r->y = (dst_format->image_height - r->h)/2;
310 gavl_rectangle_i_align_to_format(r, dst_format);
311 }
312
gavl_rectangle_i_to_f(gavl_rectangle_f_t * dst,const gavl_rectangle_i_t * src)313 void gavl_rectangle_i_to_f(gavl_rectangle_f_t * dst, const gavl_rectangle_i_t * src)
314 {
315 dst->x = (double)(src->x);
316 dst->y = (double)(src->y);
317 dst->w = (double)(src->w);
318 dst->h = (double)(src->h);
319 }
320
gavl_rectangle_f_to_i(gavl_rectangle_i_t * dst,const gavl_rectangle_f_t * src)321 void gavl_rectangle_f_to_i(gavl_rectangle_i_t * dst, const gavl_rectangle_f_t * src)
322 {
323 dst->x = (int)(src->x+0.5);
324 dst->y = (int)(src->y+0.5);
325 dst->w = (int)(src->w+0.5);
326 dst->h = (int)(src->h+0.5);
327 }
328
329