/*****************************************************************
* gavl - a general purpose audio/video processing library
*
* Copyright (c) 2001 - 2011 Members of the Gmerlin project
* gmerlin-general@lists.sourceforge.net
* http://gmerlin.sourceforge.net
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* *****************************************************************/
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <gavl/gavl.h>
void gavl_rectangle_i_dump(const gavl_rectangle_i_t * r)
{
fprintf(stderr, "%dx%d+%d+%d", r->w, r->h, r->x, r->y);
}
void gavl_rectangle_f_dump(const gavl_rectangle_f_t * r)
{
fprintf(stderr, "%fx%f+%f+%f", r->w, r->h, r->x, r->y);
}
void gavl_rectangle_i_crop_to_format(gavl_rectangle_i_t * r, const gavl_video_format_t * format)
{
if(r->x < 0)
{
r->w += r->x;
r->x = 0;
}
if(r->y < 0)
{
r->h += r->y;
r->y = 0;
}
/* Check if rectangle is empty */
if((r->x > format->image_width) || (r->y > format->image_height) ||
(r->w < 0) || (r->h < 0))
{
r->x = 0;
r->y = 0;
r->w = 0;
r->h = 0;
return;
}
if(r->w > format->image_width - r->x)
r->w = format->image_width - r->x;
if(r->h > format->image_height - r->y)
r->h = format->image_height - r->y;
}
#define GAVL_MIN(x, y) (x < y ? x : y);
void 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)
{
src_rect->w = GAVL_MIN(src_format->image_width, dst_format->image_width);
src_rect->h = GAVL_MIN(src_format->image_height, dst_format->image_height);
dst_rect->w = src_rect->w;
dst_rect->h = src_rect->h;
src_rect->x = (src_format->image_width - src_rect->w) / 2;
src_rect->y = (src_format->image_height - src_rect->h) / 2;
dst_rect->x = (dst_format->image_width - dst_rect->w) / 2;
dst_rect->y = (dst_format->image_height - dst_rect->h) / 2;
}
#undef GAVL_MIN
static void crop_dimension_scale(double * src_off, double * src_len, int src_size,
int * dst_off, int * dst_len, int dst_size)
{
double scale_factor;
double dst_off_f, dst_len_f;
double crop;
dst_off_f = (double)(*dst_off);
dst_len_f = (double)(*dst_len);
scale_factor = (double)(*dst_len) / *src_len;
/* Lower limit (source) */
if(*src_off < 0.0)
{
crop = - (*src_off);
dst_off_f += (crop*scale_factor);
dst_len_f -= (crop*scale_factor);
*src_len -= (crop);
*src_off = 0.0;
}
/* Upper limit (source) */
if(*src_off + *src_len > (double)(src_size))
{
crop = *src_off + *src_len - (double)(src_size);
dst_len_f -= (crop*scale_factor);
*src_len -= crop;
}
/* Lower limit (destination) */
if(dst_off_f < 0.0)
{
crop = - (*dst_off);
*src_off += (crop/scale_factor);
*src_len -= (crop/scale_factor);
dst_len_f -= (crop);
dst_off_f = 0.0;
}
/* Upper limit (destination) */
if(dst_off_f + dst_len_f > (double)(dst_size))
{
crop = dst_off_f + dst_len_f - (double)(dst_size);
dst_len_f -= (crop);
*src_len -= crop/scale_factor;
}
*dst_len = (int)(dst_len_f+0.5);
*dst_off = (int)(dst_off_f+0.5);
}
void 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)
{
crop_dimension_scale(&src_rect->x, &src_rect->w, src_format->image_width,
&dst_rect->x, &dst_rect->w, dst_format->image_width);
crop_dimension_scale(&src_rect->y, &src_rect->h, src_format->image_height,
&dst_rect->y, &dst_rect->h, dst_format->image_height);
}
/* Let a rectangle span the whole screen for format */
void gavl_rectangle_i_set_all(gavl_rectangle_i_t * r, const gavl_video_format_t * format)
{
r->x = 0;
r->y = 0;
r->w = format->image_width;
r->h = format->image_height;
}
void gavl_rectangle_f_set_all(gavl_rectangle_f_t * r, const gavl_video_format_t * format)
{
r->x = 0;
r->y = 0;
r->w = format->image_width;
r->h = format->image_height;
}
void gavl_rectangle_i_crop_left(gavl_rectangle_i_t * r, int num_pixels)
{
r->x += num_pixels;
r->w -= num_pixels;
}
void gavl_rectangle_i_crop_right(gavl_rectangle_i_t * r, int num_pixels)
{
r->w -= num_pixels;
}
void gavl_rectangle_i_crop_top(gavl_rectangle_i_t * r, int num_pixels)
{
r->y += num_pixels;
r->h -= num_pixels;
}
void gavl_rectangle_i_crop_bottom(gavl_rectangle_i_t * r, int num_pixels)
{
r->h -= num_pixels;
}
void gavl_rectangle_f_crop_left(gavl_rectangle_f_t * r, double num_pixels)
{
r->x += num_pixels;
r->w -= num_pixels;
}
void gavl_rectangle_f_crop_right(gavl_rectangle_f_t * r, double num_pixels)
{
r->w -= num_pixels;
}
void gavl_rectangle_f_crop_top(gavl_rectangle_f_t * r, double num_pixels)
{
r->y += num_pixels;
r->h -= num_pixels;
}
void gavl_rectangle_f_crop_bottom(gavl_rectangle_f_t * r, double num_pixels)
{
r->h -= num_pixels;
}
#define PADD(num, multiple) num -= num % multiple
void gavl_rectangle_i_align(gavl_rectangle_i_t * r, int h_align, int v_align)
{
PADD(r->x, h_align);
PADD(r->w, h_align);
PADD(r->y, v_align);
PADD(r->h, v_align);
}
void gavl_rectangle_i_align_to_format(gavl_rectangle_i_t * r,
const gavl_video_format_t * format)
{
int sub_h, sub_v;
gavl_pixelformat_chroma_sub(format->pixelformat, &sub_h, &sub_v);
gavl_rectangle_i_align(r, sub_h, sub_v);
}
void gavl_rectangle_f_copy(gavl_rectangle_f_t * dst, const gavl_rectangle_f_t * src)
{
memcpy(dst, src, sizeof(*dst));
}
void gavl_rectangle_i_copy(gavl_rectangle_i_t * dst, const gavl_rectangle_i_t * src)
{
memcpy(dst, src, sizeof(*dst));
}
int gavl_rectangle_i_is_empty(const gavl_rectangle_i_t * r)
{
return ((r->w <= 0) || (r->h <= 0)) ? 1 : 0;
}
int gavl_rectangle_f_is_empty(const gavl_rectangle_f_t * r)
{
return ((r->w <= 0.0) || (r->h <= 0.0)) ? 1 : 0;
}
/* Assuming we take src_rect from a frame in format src_format,
calculate the optimal dst_rect in dst_format. */
void 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)
{
float dst_display_aspect;
float dst_pixel_aspect;
float src_display_aspect;
float squeeze_factor;
squeeze_factor = pow(2.0, squeeze);
src_display_aspect = squeeze_factor *
src_rect->w * (float)(src_format->pixel_width) /
(src_rect->h * (float)(src_format->pixel_height));
dst_pixel_aspect =
(float)(dst_format->pixel_width) /
(float)(dst_format->pixel_height);
dst_display_aspect =
dst_pixel_aspect *
(float)(dst_format->image_width) /
(float)(dst_format->image_height);
if(dst_display_aspect > src_display_aspect) /* Bars left and right */
{
// fprintf(stderr, "Bars left and right\n");
r->w = (int)((float)dst_format->image_height * src_display_aspect * zoom / dst_pixel_aspect + 0.5);
r->h = (int)((float)dst_format->image_height * zoom + 0.5);
// fprintf(stderr, "Bars left and right %dx%d -> %dx%d (%f, %f)\n", src_rect->w, src_rect->h, r->w, r->h,
// (float)(src_rect->w * src_format->pixel_width) /
// (float)(src_rect->h * src_format->pixel_height), dst_pixel_aspect);
}
else /* Bars top and bottom */
{
// fprintf(stderr, "Bars top and bottom\n");
r->w = (int)((float)(dst_format->image_width) * zoom + 0.5);
r->h = (int)((float)dst_format->image_width * zoom * dst_pixel_aspect / src_display_aspect + 0.5);
}
r->x = (dst_format->image_width - r->w)/2;
r->y = (dst_format->image_height - r->h)/2;
gavl_rectangle_i_align_to_format(r, dst_format);
}
void gavl_rectangle_i_to_f(gavl_rectangle_f_t * dst, const gavl_rectangle_i_t * src)
{
dst->x = (double)(src->x);
dst->y = (double)(src->y);
dst->w = (double)(src->w);
dst->h = (double)(src->h);
}
void gavl_rectangle_f_to_i(gavl_rectangle_i_t * dst, const gavl_rectangle_f_t * src)
{
dst->x = (int)(src->x+0.5);
dst->y = (int)(src->y+0.5);
dst->w = (int)(src->w+0.5);
dst->h = (int)(src->h+0.5);
}