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