Commit 612836aa authored by Jean-Paul Saman's avatar Jean-Paul Saman

davinci: resizer.c: resizer.h: resizer_coefs.c: Update DaVinci resizer implementation

Update the DaVinci resizer implementation modules/codec/davinci to latest
state of Rafael Carre his work. This introduces one new file 'resizer_coefs.c'.
parent 5bb9468d
......@@ -6,9 +6,13 @@ SOURCES_davinci = \
fourcc.c \
$(NULL)
# Davinci resizer/scaling hack
# The decoder does not know the eventual screen size
# so optimizing by resizing to screen size is not
# feasible here
# resizer_coefs.c \
# resizer.c \
# reziser.h
# resizer.h \
# $(NULL)
if ENABLE_SOUT
SOURCES_davinci += encoder.c audio_encoder.c video_encoder.c audio1_encoder.c
......
/*****************************************************************************
* resizer.c: Resize pictures directly into framebuffer (DaVinci specific)
* resizer.c : DaVinci resizer
*****************************************************************************
* Copyright (C) 2008-2009 M2X BV
* Copyright (C) 2008-2010 M2X BV
* Copyright © 2010 Rafaël Carré
* $Id$
*
* Authors: Rafaël Carré <rcarre@m2x.nl>
* Jean-Paul Saman <jean-paul.saman at m2x dot nl>
* Authors: Antoine Cellerier <dionoea at videolan dot org>
*
* 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
......@@ -21,379 +22,307 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_codec.h>
#undef _FILE_OFFSET_BITS /* mmap() will fail if we use 64bits offsets */
#undef _FILE_OFFSET_BITS /* mmap() fails on 64 bits offsets */
#include "davinci.h"
#include "resizer.h"
#include <vlc_common.h>
#include <stdio.h>
#include <string.h> /* strerror() */
#include <stdlib.h> /* malloc(), free() */
#include <stdbool.h>
#include <inttypes.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
static void Resize_coeff( decoder_t *p_dec,
unsigned int *i_width, unsigned int *i_height )
{
unsigned int i_vidw = p_dec->fmt_out.video.i_width;
unsigned int i_vidh = p_dec->fmt_out.video.i_height;
unsigned int i_hratio = VOUT_ASPECT_FACTOR * *i_height / i_vidh;
unsigned int i_wratio = VOUT_ASPECT_FACTOR * *i_width / i_vidw;
msg_Dbg( p_dec, "Original Video %dx%d, Output destination %dx%d",
i_vidw, i_vidh, *i_width, *i_height );
/* Davinci Resizer can only do from x0.25 to x4 */
if( i_hratio > VOUT_ASPECT_FACTOR * 4 )
i_hratio = VOUT_ASPECT_FACTOR * 4;
else if( i_hratio < VOUT_ASPECT_FACTOR / 4 )
i_hratio = VOUT_ASPECT_FACTOR / 4;
/* do that also for the width */
if( i_wratio > VOUT_ASPECT_FACTOR * 4 )
i_wratio = VOUT_ASPECT_FACTOR * 4;
else if( i_wratio < VOUT_ASPECT_FACTOR / 4 )
i_wratio = VOUT_ASPECT_FACTOR / 4;
/* choose the minimum for both axes */
i_hratio = i_wratio = i_hratio < i_wratio ? i_hratio : i_wratio;
/* Now calculate hrsz and vrsz */
int i_hrsz = 256 * VOUT_ASPECT_FACTOR / i_wratio;
int i_vrsz = 256 * VOUT_ASPECT_FACTOR / i_hratio;
/* Then recalculate final resolution */
int i_htap = i_hrsz > 512 ? 7 : 4;
int i_vtap = i_vrsz > 512 ? 7 : 4;
*i_width = ((i_vidw - 7) * 256 - (i_htap == 7 ? 32 : 16)) / i_hrsz + 1;
*i_height = ((i_vidh - i_vtap) * 256 - (i_vtap == 7 ? 32 : 16)) / i_vrsz + 1;
/* width must be a factor of 16 : davinci resizer limitation when doing
* vertical upscaling, 16 bytes per output line
* the bpp is 2 so a factor of 8 should be good but not in practice
*/
*i_width = ( *i_width + 15 ) & ~15;
#include <sys/mman.h>
#include <sys/ioctl.h>
msg_Dbg( p_dec, "Destination fixed to %dx%d", *i_width, *i_height );
}
#include <gnu/targets/std.h>
#include <xdc/std.h>
#include <ti/sdo/ce/osal/Memory.h>
#include <davinci_resizer.h>
static float bicubic_core( float s )
{
if( s < 0 ) s = -s;
if( 0. <= s && s <= 1. )
return 1.5 * s * s * s - 2.5 * s * s + 1.;
else if( s <= 2. )
return -.5 * s * s * s + 2.5 * s * s - 4. *s + 2.;
else
return 0.;
}
#include "resizer.h"
static void get_coeffs( short coefs[32], unsigned int i_in,
unsigned int i_out )
/*****************************************************************************
*
*****************************************************************************/
typedef struct resizer_t
{
assert( i_out > 1 );
assert( i_in > 7 );
int fd; /* /dev/davincresizer */
float f_deinterleave_coef[ 32 ];
float f_windows[ 32+1 ];
rsz_resize_t resize;
unsigned int i_rsz;
int in_size;
uint8_t *p_out;
int out_size;
if( i_in == i_out )
i_rsz = 256;
else
{
i_rsz = ((i_in - 7) * 256) / (i_out - 1);
if( i_rsz <= 512 )
{
i_rsz = ((i_in - 4) * 256) / (i_out - 1);
if( i_rsz > 512 ) i_rsz = 512;
}
}
int in_height;
int in_width;
int out_height;
int out_width;
} davinci_resizer_t;
int i_nphases, i_ntaps, i_winlen, i_phase_offset, i, j;
float f_fc;
/* resizer_coefs.c */
extern void resize_coefs(unsigned int vidw, unsigned int vidh,
unsigned int *width, unsigned int *height,
short hcoefs[32], short vcoefs[32]);
if( i_rsz > 512 )
{
i_nphases = 4;
i_ntaps = 7;
i_phase_offset = 8;
}
else
{
i_nphases = 8;
i_ntaps = 4;
i_phase_offset = 4;
}
i_winlen = i_nphases * i_ntaps;
/*****************************************************************************
* Local functions
*****************************************************************************/
static uint8_t *GetBuffer(struct resizer_t *rsz, int type, int size, int *offset)
{
uint8_t *p_buf;
struct rsz_reqbufs reqbufs;
struct rsz_buffer buffer;
/* calculating the cut-off frequency, normalized by fs/2 */
f_fc = ( i_rsz < 256) ? (1. / i_nphases) : 256. / (i_rsz * i_nphases);
memset(&reqbufs, 0, sizeof(reqbufs));
memset(&buffer, 0, sizeof(buffer));
for( i = 0 ; i <= i_winlen ; i++ )
f_windows[i] = .42 - .5 * cos( 2 * PI * i / i_winlen ) +
.08 * cos( 4 * PI * i / i_winlen );
reqbufs.buf_type = type;
reqbufs.size = size;
reqbufs.count = 1;
i_nphases = 8;
i_ntaps = 4;
i_phase_offset = 4;
if (ioctl(rsz->fd, RSZ_REQBUF, &reqbufs))
return NULL;
/* calculating the bi-cubic coefficients */
for( i = 0 ; i < i_nphases ; i++ )
{
float f_alpha = ((float)i) / i_nphases;
buffer.buf_type = type;
buffer.index = 0;
f_deinterleave_coef[i_phase_offset*i] = bicubic_core( f_alpha + 1. );
f_deinterleave_coef[i_phase_offset*i+1] = bicubic_core( f_alpha );
f_deinterleave_coef[i_phase_offset*i+2] = bicubic_core( 1. - f_alpha );
f_deinterleave_coef[i_phase_offset*i+3] = bicubic_core( 2. - f_alpha );
}
if (ioctl(rsz->fd, RSZ_QUERYBUF, &buffer))
return NULL;
/* de-interleave into phases */
for( i = 0 ; i < i_nphases ; i++ )
{ /* i=phase */
float f_gain = 0;
for( j = 0 ; j < i_ntaps ; j++ ) /* j=tap */
f_gain += f_deinterleave_coef[i_phase_offset * i + j];
for( j = 0 ; j < i_ntaps ; j ++)
coefs[i_phase_offset * i + j] = (short)
(f_deinterleave_coef[i_phase_offset*i+j] * 256 / f_gain + 0.5 );
if( i_ntaps == 7 )
coefs[i_phase_offset * i + 7] = 0.;
}
if (offset) *offset = buffer.offset;
/* adjust the gain to make it exactly one */
for( i = 0 ; i < i_nphases ; i++ )
{
int max = coefs[i_phase_offset*i];
int max2 = 0;
int index = 0;
int index2 = 0;
int total_gain = max;
int delta;
for( j = 1 ; j < i_ntaps ; j++ )
{
total_gain += coefs[i_phase_offset*i+j];
if( abs( coefs[i_phase_offset*i+j] ) >= max )
{
max2 = max;
index2 = index;
index = j;
max = abs( coefs[i_phase_offset*i+j] );
}
}
delta = 256 - total_gain;
p_buf = mmap(NULL, reqbufs.size, PROT_READ|PROT_WRITE, MAP_SHARED,
rsz->fd, buffer.offset);
if(p_buf == MAP_FAILED)
return NULL;
if(max - max2 < 10)
return p_buf;
}
static int Init(vlc_object_t *p_this, struct resizer_t *rsz, int in_width, int in_height,
int *out_width, int *out_height)
{
/* Set the parameters */
rsz_params_t params;
memset(&params, 0, sizeof(params));
params.in_hsize = in_width;
params.in_vsize = in_height;
params.in_pitch = OUT_WIDTH << 1;
params.inptyp = RSZ_INTYPE_YCBCR422_16BIT;
params.pix_fmt = RSZ_PIX_FMT_YUYV;
/* will modify output dimensions to something sensible */
resize_coefs(params.in_hsize, params.in_vsize, out_width, out_height,
params.hfilt_coeffs, params.vfilt_coeffs);
params.out_hsize = *out_width;
params.out_vsize = *out_height;
params.out_pitch = OUT_WIDTH << 1;
params.yenh_params.type = RSZ_YENH_DISABLE;
if (ioctl(rsz->fd, RSZ_S_PARAM, &params))
{
coefs[i_phase_offset*i+index2] += (delta>>1);
coefs[i_phase_offset*i+index] += (delta-(delta>>1));
}
else
coefs[i_phase_offset*i+index] += delta;
msg_Err(p_this, "Failed setting resizer params (look at dmesg)\n");
return -1;
}
if( i_rsz == 256 )
{ /* no resizing, all pass filtering */
for( i = 0 ; i < i_nphases * i_ntaps ; i+= 4 )
/* Set resizer speed to fastest */
int speed = 0;
if (ioctl(rsz->fd, RSZ_S_EXP, &speed))
{
coefs[i] = 256;
coefs[i+1] = coefs[i+2] = coefs[i+3] = 0;
}
msg_Err(p_this, "Failed setting resizer speed\n");
return -2;
}
}
/*
* Resizer functions
*/
int Resize( decoder_t *p_dec, davinci_resizer_t *rsz, bool b_scale,
XDM_BufDesc in, XDM_BufDesc out )
{
assert( rsz );
assert( p_dec );
if( rsz->i_yuyv == 0)
{
/* use screen resolution for the buffer, we may be off by a few */
rsz->i_yuyv = rsz->i_out_width * rsz->i_out_height;
assert(rsz->i_yuyv);
rsz->in_size = (OUT_WIDTH << 1) * in_height;
rsz->resize.in_buf.index = -1;
rsz->out_size = (OUT_WIDTH << 1) * *out_height;
#ifdef DIRECT_OUTPUT
rsz->resize.out_buf.index = -1;
#else
rsz->resize.out_buf.index = 0;
rsz->p_out = GetBuffer(rsz, RSZ_BUF_OUT, rsz->out_size,
&rsz->resize.out_buf.offset); /* FIXME: offset width + height */
if (!rsz->p_out)
return -4;
#endif
rsz_reqbufs_t reqbufs;
rsz_buffer_t buffer;
memset( &reqbufs, 0, sizeof( reqbufs ) );
memset( &buffer, 0, sizeof( buffer ) );
/* Initialize resize structure */
rsz->resize.in_buf.size = rsz->in_size;
rsz->resize.out_buf.size = rsz->out_size;
reqbufs.buf_type = RSZ_BUF_OUT;
reqbufs.size = rsz->i_yuyv;
reqbufs.count = 1;
return 0;
}
if( ioctl( rsz->i_fd, RSZ_REQBUF, &reqbufs ) )
{
msg_Err( p_dec, "RSZ_REQBUF failed (%m)" );
return VLC_EGENERIC;
}
/*****************************************************************************
* Exported functions
*****************************************************************************/
void resizer_close(struct resizer_t *rsz)
{
close(rsz->fd);
free(rsz);
}
buffer.buf_type = RSZ_BUF_OUT;
buffer.index = 0;
struct resizer_t *resizer_open(vlc_object_t *p_this,
int in_width, int in_height, int *out_width, int *out_height)
{
struct resizer_t *rsz = calloc(1, sizeof(*rsz));
if (!rsz)
return NULL;
if( ioctl( rsz->i_fd, RSZ_QUERYBUF, &buffer ) )
rsz->fd = open("/dev/davinci_resizer", O_RDWR);
if (rsz->fd == -1)
{
msg_Err( p_dec, "RSZ_QUERYBUF failed (%m)" );
return VLC_EGENERIC;
msg_Err(p_this, "Couldn't open device (%m)");
free(rsz);
return NULL;
}
rsz->p_yuyv = mmap( NULL, reqbufs.size, PROT_READ|PROT_WRITE,
MAP_SHARED, rsz->i_fd, buffer.offset );
if( rsz->p_yuyv == MAP_FAILED )
int ret = Init(p_this, rsz, in_width, in_height, out_width, out_height);
if (ret != 0)
{
rsz->i_yuyv = 0;
msg_Err( p_dec, "mmap resizer to buffer failed (%m)" );
return VLC_EGENERIC;
msg_Err(p_this, "Resizer init failed (%d)\n", ret);
resizer_close(rsz);
return NULL;
}
rsz->offset = buffer.offset;
}
rsz->in_height = in_height;
rsz->in_width = in_width;
/* Sets resizer parameters when video starts or when resolution changes */
if( rsz->i_width != p_dec->fmt_out.video.i_width ||
rsz->i_height != p_dec->fmt_out.video.i_height )
{
rsz_params_t rsz_params;
memset( &rsz_params, 0, sizeof( rsz_params ) );
rsz_params.in_hsize = rsz->i_width = p_dec->fmt_out.video.i_width;
rsz_params.in_vsize = rsz->i_height = p_dec->fmt_out.video.i_height;
rsz_params.in_pitch =
(p_dec->fmt_out.video.i_width * BPP / 8 + 31) & ~31;
rsz_params.inptyp = RSZ_INTYPE_YCBCR422_16BIT;
rsz_params.pix_fmt = RSZ_PIX_FMT_YUYV;
/* Sets the desired maximum destination resolution */
if( b_scale )
{
rsz_params.out_hsize = rsz->i_out_width;
rsz_params.out_vsize = rsz->i_out_height;
}
else
{
rsz_params.out_hsize = rsz_params.in_hsize;
rsz_params.out_vsize = rsz_params.in_vsize;
}
rsz->out_height = *out_height;
rsz->out_width = *out_width;
/* And then modify it to keep the same aspect ratio, and make sure
* that the hardware is able to handle it */
Resize_coeff( p_dec, &rsz_params.out_hsize, &rsz_params.out_vsize );
/* RSZ_PIX_FMT_YUYV is 2 bytes per pixel */
rsz_params.out_pitch = ( rsz_params.out_hsize * 2 + 15 ) & ~15;
return rsz;
}
rsz->b_direct = ((unsigned)rsz_params.out_hsize == (unsigned)width);
/* fill pointer with size bytes of black (== size/2 pixels!)
* and increment pointer */
static inline uint8_t *fill_black(uint8_t *out, const size_t size)
{
assert((size & 3) == 0);
if(!size)
return out;
register int loops = size >> 2;
register const int black = 0x10801080;
#if 1 /* ASM */
asm volatile (
"1:\tstr %[b], [%[out]], #4 \n" /* do { *p++ = black; */
"\tsubs %[s], %[s], #1 \n" /* } while(--size); */
"\tbne 1b \n"
/* output */ : [out]"+r"(out), [s]"+r"(loops) /* both are modified */
/* input */ : [b]"r"(black)
/* clobber */ : "memory"
);
rsz->i_out_width = rsz_params.out_hsize;
rsz->i_out_height = rsz_params.out_vsize;
#else /* C */
int *out32 = (int*) out;
do {
*out32++ = black;
} while(--loops);
out = (uint8_t*)out32;
#endif /* C / ASM */
short hcoefs[32], vcoefs[32];
return out;
}
get_coeffs( hcoefs , rsz_params.in_hsize, rsz_params.out_hsize );
get_coeffs( vcoefs , rsz_params.in_vsize, rsz_params.out_vsize );
int resizer_resize(struct resizer_t *rsz, uint8_t *in, uint8_t *out)
{
/* We can use the decoder output buffer as is */
rsz->resize.in_buf.offset =
Memory_getBufferPhysicalAddress(in, rsz->in_size, NULL);
int i;
for( i = 0; i < 32; i++ )
{
rsz_params.hfilt_coeffs[i] = hcoefs[i];
rsz_params.vfilt_coeffs[i] = vcoefs[i];
}
#ifdef DIRECT_OUTPUT
rsz->resize.out_buf.offset =
Memory_getBufferPhysicalAddress(out, rsz->out_size, NULL);
assert(rsz->resize.out_buf.offset);
rsz_params.yenh_params.type = RSZ_YENH_DISABLE;
const unsigned lines = (OUT_HEIGHT - rsz->out_height);
const unsigned pitch = OUT_WIDTH << 1;
const unsigned cols = (OUT_WIDTH - rsz->out_width); /* in bytes */
if( ioctl( rsz->i_fd, RSZ_S_PARAM, &rsz_params ) )
{
msg_Err( p_dec, "Failed setting resizer parameters: "
"%dx%d (pitch %d) -> %dx%d (pitch %d) : %m",
rsz_params.in_hsize, rsz_params.in_vsize, rsz_params.in_pitch,
rsz_params.out_hsize, rsz_params.out_vsize, rsz_params.out_pitch
);
rsz->i_width = rsz->i_height = 0;
rsz->resize.out_buf.offset += (lines >> 1) * pitch + (cols & ~31);
#endif
return VLC_EGENERIC;
}
}
int error;
do
{ /* resize */
error = ioctl(rsz->fd, RSZ_RESIZE, &rsz->resize);
} while(error == -1 && errno == EAGAIN);
rsz_resize_t rszh;
rszh.in_buf.index = -1;
rszh.in_buf.buf_type = RSZ_BUF_IN;
rszh.in_buf.size = p_dec->fmt_out.video.i_height *
((p_dec->fmt_out.video.i_width * BPP / 8 + 31) & ~31);
rszh.in_buf.offset = Memory_getBufferPhysicalAddress(
out.bufs[0], rszh.in_buf.size, NULL );
assert( rszh.in_buf.offset );
if (error == -1)
return errno;
rszh.out_buf.index = -1;
rszh.out_buf.buf_type = RSZ_BUF_OUT;
#ifdef DIRECT_OUTPUT
const unsigned cols_left = (cols & ~31);
const unsigned cols_right = ((OUT_WIDTH - rsz->out_width) << 1) - cols_left;
const unsigned lines_top = lines >> 1;
const unsigned lines_bottom = (lines + 1) >> 1;
const unsigned pitch_pic = rsz->out_width << 1;
if( b_scale && rsz->b_direct /* output video res is screen res */ )
{
/* FIXME: use NUM_BUFFERS if needed */
rszh.out_buf.offset = fb->p_physbufs[0]; //FIXME:
rszh.out_buf.size = rsz->i_out_width * rsz->i_out_height;
}
else
{
rszh.out_buf.offset = rsz->offset;
rszh.out_buf.size = rsz->i_yuyv;
}
assert((pitch_pic & 3) == 0);
do
{
if( ioctl( rsz->i_fd, RSZ_RESIZE, &rszh ) == -1 )
out = fill_black(out, lines_top * pitch);
for (int i = 0; i < rsz->out_height; i++)
{
if( errno == EAGAIN )
continue;
msg_Err( p_dec, "Resizing failed (%m)" );
return VLC_EGENERIC;
out = fill_black(out, cols_left) + pitch_pic;
out = fill_black(out, cols_right);
}
} while(0);
fill_black(out, lines_bottom * pitch);
#else
resizer_copy_picture(out, rsz->p_out, rsz->out_width, rsz->out_height);
#endif
return VLC_SUCCESS;
return 0;
}
int ResizerOpen( vlc_object_t *p_this, davinci_resizer_t *rsz )
/*
* copy input picture (width x height)
* into output picture (OUT_WIDTH x OUT_HEIGHT)
*
* fill borders with black
*/
void resizer_copy_picture(uint8_t *out, uint8_t *in, int width, int height)
{
rsz->i_fd = -1;
const unsigned h_offset = OUT_HEIGHT - height;
const unsigned h_black_top = (OUT_WIDTH << 1) * (h_offset >> 1);
const unsigned h_black_bottom = (OUT_WIDTH << 1) * ((h_offset + 1) >> 1);
/* Open and setup resizer */
if( ( rsz->i_fd = open( "/dev/davinci_resizer", O_RDWR ) ) == -1 )
{
msg_Err( p_this, "Failed to open resizer (%m)" );
goto error;
}
const unsigned pitch = (width << 1) & ~3;
rsz->p_yuyv = MAP_FAILED;
rsz->i_yuyv = 0;
rsz->offset = 0;
rsz->i_height = 0;
rsz->i_width = 0;
rsz->i_out_height = 0;
rsz->i_out_width = 0;
const unsigned v_black_left = (OUT_WIDTH - width) & ~3;
const unsigned v_black_right = (OUT_WIDTH << 1) - pitch - v_black_left;
return VLC_SUCCESS;
out = fill_black(out, h_black_top);
error:
ResizerClose( rsz );
return VLC_EGENERIC;
}
for (int i = 0; i < height; i++)
{
out = fill_black(out, v_black_left);
void ResizerClose( davinci_resizer_t *rsz )
{
if( rsz->i_fd != -1 )
close( rsz->i_fd );
if( rsz->p_yuyv != MAP_FAILED )
munmap( rsz->p_yuyv, rsz->offset );
rsz->i_fd = -1;
memcpy(out, in, pitch);
in += (OUT_WIDTH << 1);
out += pitch;
out = fill_black(out, v_black_right);
}
fill_black(out, h_black_bottom);
}
/*****************************************************************************
* resizer.c: Resize pictures directly into framebuffer (DaVinci specific)
* resizer.c : DaVinci resizer
*****************************************************************************
* Copyright (C) 2008-2009 M2X BV
* Copyright © 2010 Rafaël Carré
*
* Authors: Rafaël Carré <rcarre@m2x.nl>
* Authors: Rafaël Carré <rafael at gmail>
*
* 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
......@@ -20,56 +20,31 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifndef RESIZER_H
#define RESIZER_H
#ifndef VLC_DAVINCI_RESIZER_H
#define VLC_DAVINCI_RESIZER_H 1
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/fb.h>
#include <video/davincifb.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <ti/sdo/ce/osal/Memory.h>
#include <inttypes.h>
#include <asm-arm/arch-davinci/davinci_resizer.h>
#include <math.h>
#include <assert.h>
#define NUM_BUFFERS 1 /* XXX: mesure performance with 3 buffers if needed */
typedef struct resizer_t davinci_resizer_t;
#define BPP 16
void resizer_close(struct resizer_t *rsz);
#define PI 3.1415926535897932384626
struct resizer_t *resizer_open(vlc_object_t *p_this,
int in_width, int in_height,
int *out_width, int *out_height);
typedef struct
{
int i_fd;
unsigned int i_height;
unsigned int i_width;
int resizer_resize(vlc_object_t *p_this,
struct resizer_t *rsz, uint8_t *in, uint8_t *out);
uint8_t *p_yuyv;
int offset;
int i_yuyv;
void resizer_copy_picture(vlc_object_t *p_this,
uint8_t *out, uint8_t *in, int width, int height);
unsigned int i_out_width;
unsigned int i_out_height;
/** FIXME: arbritary values make them more configurable */
#define OUT_WIDTH 720
#define OUT_HEIGHT 480
bool b_direct;
} davinci_resizer_t;
/* define if VLC picture buffers are allocated with Memorycontig_Alloc() */
#define DIRECT_OUTPUT
/* Resize: resize and/or enhance input picture
* \param p_dec : pointer to decoder_t structure
* \param rsz : pointer to davinci_resizer_t structure
* \param b_scale : rescale to output size
* \param in : input buffer as XDM_BufDesc
* \param out : output buffer as XDM_BufDesc
* \return VLC_SUCCESS on success and VLC_EGENERIC on failure
*/
int Resize( decoder_t *p_dec, davinci_resizer_t *rsz, bool b_scale,
XDM_BufDesc in, XDM_BufDesc out );
int ResizerOpen( vlc_object_t *p_this, davinci_resizer_t *rsz );
void ResizerClose( davinci_resizer_t *rsz );
#endif /* RESIZER_H */
#endif /* VLC_DAVINCI_RESIZER_H */
/*****************************************************************************
* resizer_coefs.c: Resize coefs (DaVinci specific)
*****************************************************************************
* Copyright (C) 2008-2010 M2X BV
*
* Authors: Rafaël Carré <rcarre@m2x.nl>
*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*
* Resizer parameters calculation
* Based on SPRAAI7B documentation from TI
*
*/
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#define VOUT_ASPECT_FACTOR 432000
static float bicubic_core( float s )
{
if( s < 0 ) s = -s;
if( 0. <= s && s <= 1. )
return 1.5 * s * s * s - 2.5 * s * s + 1.;
else if( s <= 2. )
return -.5 * s * s * s + 2.5 * s * s - 4. *s + 2.;
else
return 0.;
}
static void get_coeffs( short coefs[32], unsigned int i_in, unsigned int i_out )
{
assert( i_out > 1 );
assert( i_in > 7 );
float f_deinterleave_coef[ 32 ];
float f_windows[ 32+1 ];
unsigned int i_rsz;
if( i_in == i_out )
i_rsz = 256;
else
{
i_rsz = ((i_in - 7) * 256) / (i_out - 1);
if( i_rsz <= 512 )
{
i_rsz = ((i_in - 4) * 256) / (i_out - 1);
if( i_rsz > 512 ) i_rsz = 512;
}
}
int i_nphases, i_ntaps, i_winlen, i_phase_offset, i, j;
float f_fc;
if( i_rsz > 512 )
{
i_nphases = 4;
i_ntaps = 7;
i_phase_offset = 8;
}
else
{
i_nphases = 8;
i_ntaps = 4;
i_phase_offset = 4;
}
i_winlen = i_nphases * i_ntaps;
/* calculating the cut-off frequency, normalized by fs/2 */
f_fc = ( i_rsz < 256) ? (1. / i_nphases) : 256. / (i_rsz * i_nphases);
for( i = 0 ; i <= i_winlen ; i++ )
f_windows[i] = .42 - .5 * cos( 2 * M_PI * i / i_winlen ) +
.08 * cos( 4 * M_PI * i / i_winlen );
/* calculating the bi-cubic coefficients */
for( i = 0 ; i < i_nphases ; i++ )
{
float f_alpha = ((float)i) / i_nphases;
f_deinterleave_coef[i_phase_offset*i] = bicubic_core( f_alpha + 1. );
f_deinterleave_coef[i_phase_offset*i+1] = bicubic_core( f_alpha );
f_deinterleave_coef[i_phase_offset*i+2] = bicubic_core( 1. - f_alpha );
f_deinterleave_coef[i_phase_offset*i+3] = bicubic_core( 2. - f_alpha );
}
/* de-interleave into phases */
for( i = 0 ; i < i_nphases ; i++ )
{ /* i=phase */
float f_gain = 0;
for( j = 0 ; j < i_ntaps ; j++ ) /* j=tap */
f_gain += f_deinterleave_coef[i_phase_offset * i + j];
for( j = 0 ; j < i_ntaps ; j ++)
coefs[i_phase_offset * i + j] = (short)
(f_deinterleave_coef[i_phase_offset*i+j] * 256 / f_gain + 0.5 );
if( i_ntaps == 7 )
coefs[i_phase_offset * i + 7] = 0.;
}
/* adjust the gain to make it exactly one */
for( i = 0 ; i < i_nphases ; i++ )
{
int max = coefs[i_phase_offset*i];
int max2 = 0;
int index = 0;
int index2 = 0;
int total_gain = max;
int delta;
for( j = 1 ; j < i_ntaps ; j++ )
{
total_gain += coefs[i_phase_offset*i+j];
if( abs( coefs[i_phase_offset*i+j] ) >= max )
{
max2 = max;
index2 = index;
index = j;
max = abs( coefs[i_phase_offset*i+j] );
}
}
delta = 256 - total_gain;
if(max - max2 < 10)
{
coefs[i_phase_offset*i+index2] += (delta>>1);
coefs[i_phase_offset*i+index] += (delta-(delta>>1));
}
else
coefs[i_phase_offset*i+index] += delta;
}
if( i_rsz == 256 )
{ /* no resizing, all pass filtering */
for( i = 0 ; i < i_nphases * i_ntaps ; i+= 4 )
{
coefs[i] = 256;
coefs[i+1] = coefs[i+2] = coefs[i+3] = 0;
}
}
}
void resize_coefs(unsigned int i_vidw, unsigned int i_vidh,
unsigned int *i_width, unsigned int *i_height,
short hcoefs[32], short vcoefs[32])
{
unsigned int i_hratio = VOUT_ASPECT_FACTOR * *i_height / i_vidh;
unsigned int i_wratio = VOUT_ASPECT_FACTOR * *i_width / i_vidw;
/* Davinci Resizer can only do from x0.25 to x4 */
if( i_hratio > VOUT_ASPECT_FACTOR * 4 )
i_hratio = VOUT_ASPECT_FACTOR * 4;
else if( i_hratio < VOUT_ASPECT_FACTOR / 4 )
i_hratio = VOUT_ASPECT_FACTOR / 4;
/* do that also for the width */
if( i_wratio > VOUT_ASPECT_FACTOR * 4 )
i_wratio = VOUT_ASPECT_FACTOR * 4;
else if( i_wratio < VOUT_ASPECT_FACTOR / 4 )
i_wratio = VOUT_ASPECT_FACTOR / 4;
/* choose the minimum for both axes */
i_hratio = i_wratio = i_hratio < i_wratio ? i_hratio : i_wratio;
/* Now calculate hrsz and vrsz */
int i_hrsz = 256 * VOUT_ASPECT_FACTOR / i_wratio;
int i_vrsz = 256 * VOUT_ASPECT_FACTOR / i_hratio;
/* Then recalculate final resolution */
int i_htap = i_hrsz > 512 ? 7 : 4;
int i_vtap = i_vrsz > 512 ? 7 : 4;
*i_width = ((i_vidw - 7) * 256 - (i_htap == 7 ? 32 : 16)) / i_hrsz + 1;
*i_height = ((i_vidh - i_vtap) * 256 - (i_vtap == 7 ? 32 : 16)) / i_vrsz + 1;
/* width must be a factor of 16 : davinci resizer limitation when doing
* vertical upscaling, 16 bytes per output line
*/
*i_width = ( *i_width + 15 ) & ~15;
get_coeffs( hcoefs, i_vidw, *i_width );
get_coeffs( vcoefs, i_vidh, *i_height );
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment