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 = \ ...@@ -6,9 +6,13 @@ SOURCES_davinci = \
fourcc.c \ fourcc.c \
$(NULL) $(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 \ # resizer.c \
# reziser.h # resizer.h \
# $(NULL)
if ENABLE_SOUT if ENABLE_SOUT
SOURCES_davinci += encoder.c audio_encoder.c video_encoder.c audio1_encoder.c 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> * Authors: Antoine Cellerier <dionoea at videolan dot org>
* Jean-Paul Saman <jean-paul.saman at m2x dot nl>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -21,379 +22,307 @@ ...@@ -21,379 +22,307 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/ *****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include <config.h> # include "config.h"
#endif #endif
#include <vlc_common.h> #undef _FILE_OFFSET_BITS /* mmap() will fail if we use 64bits offsets */
#include <vlc_codec.h>
#undef _FILE_OFFSET_BITS /* mmap() fails on 64 bits offsets */ #include <vlc_common.h>
#include "davinci.h"
#include "resizer.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> #include <assert.h>
static void Resize_coeff( decoder_t *p_dec, #include <sys/mman.h>
unsigned int *i_width, unsigned int *i_height ) #include <sys/ioctl.h>
{
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;
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 ) #include "resizer.h"
{
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 ) *
*****************************************************************************/
typedef struct resizer_t
{ {
assert( i_out > 1 ); int fd; /* /dev/davincresizer */
assert( i_in > 7 );
float f_deinterleave_coef[ 32 ]; rsz_resize_t resize;
float f_windows[ 32+1 ];
unsigned int i_rsz; int in_size;
uint8_t *p_out;
int out_size;
if( i_in == i_out ) int in_height;
i_rsz = 256; int in_width;
else int out_height;
{ int out_width;
i_rsz = ((i_in - 7) * 256) / (i_out - 1); } davinci_resizer_t;
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; /* resizer_coefs.c */
float f_fc; 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 ) /*****************************************************************************
{ * Local functions
i_nphases = 4; *****************************************************************************/
i_ntaps = 7; static uint8_t *GetBuffer(struct resizer_t *rsz, int type, int size, int *offset)
i_phase_offset = 8; {
} uint8_t *p_buf;
else struct rsz_reqbufs reqbufs;
{ struct rsz_buffer buffer;
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 */ memset(&reqbufs, 0, sizeof(reqbufs));
f_fc = ( i_rsz < 256) ? (1. / i_nphases) : 256. / (i_rsz * i_nphases); memset(&buffer, 0, sizeof(buffer));
for( i = 0 ; i <= i_winlen ; i++ ) reqbufs.buf_type = type;
f_windows[i] = .42 - .5 * cos( 2 * PI * i / i_winlen ) + reqbufs.size = size;
.08 * cos( 4 * PI * i / i_winlen ); reqbufs.count = 1;
i_nphases = 8; if (ioctl(rsz->fd, RSZ_REQBUF, &reqbufs))
i_ntaps = 4; return NULL;
i_phase_offset = 4;
/* calculating the bi-cubic coefficients */ buffer.buf_type = type;
for( i = 0 ; i < i_nphases ; i++ ) buffer.index = 0;
{
float f_alpha = ((float)i) / i_nphases;
f_deinterleave_coef[i_phase_offset*i] = bicubic_core( f_alpha + 1. ); if (ioctl(rsz->fd, RSZ_QUERYBUF, &buffer))
f_deinterleave_coef[i_phase_offset*i+1] = bicubic_core( f_alpha ); return NULL;
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 */ if (offset) *offset = buffer.offset;
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 */ p_buf = mmap(NULL, reqbufs.size, PROT_READ|PROT_WRITE, MAP_SHARED,
for( i = 0 ; i < i_nphases ; i++ ) rsz->fd, buffer.offset);
{ if(p_buf == MAP_FAILED)
int max = coefs[i_phase_offset*i]; return NULL;
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) 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); msg_Err(p_this, "Failed setting resizer params (look at dmesg)\n");
coefs[i_phase_offset*i+index] += (delta-(delta>>1)); return -1;
}
else
coefs[i_phase_offset*i+index] += delta;
} }
if( i_rsz == 256 ) /* Set resizer speed to fastest */
{ /* no resizing, all pass filtering */ int speed = 0;
for( i = 0 ; i < i_nphases * i_ntaps ; i+= 4 ) if (ioctl(rsz->fd, RSZ_S_EXP, &speed))
{ {
coefs[i] = 256; msg_Err(p_this, "Failed setting resizer speed\n");
coefs[i+1] = coefs[i+2] = coefs[i+3] = 0; return -2;
}
} }
}
/* rsz->in_size = (OUT_WIDTH << 1) * in_height;
* Resizer functions rsz->resize.in_buf.index = -1;
*/
int Resize( decoder_t *p_dec, davinci_resizer_t *rsz, bool b_scale, rsz->out_size = (OUT_WIDTH << 1) * *out_height;
XDM_BufDesc in, XDM_BufDesc out ) #ifdef DIRECT_OUTPUT
{ rsz->resize.out_buf.index = -1;
assert( rsz ); #else
assert( p_dec ); rsz->resize.out_buf.index = 0;
rsz->p_out = GetBuffer(rsz, RSZ_BUF_OUT, rsz->out_size,
if( rsz->i_yuyv == 0) &rsz->resize.out_buf.offset); /* FIXME: offset width + height */
{ if (!rsz->p_out)
/* use screen resolution for the buffer, we may be off by a few */ return -4;
rsz->i_yuyv = rsz->i_out_width * rsz->i_out_height; #endif
assert(rsz->i_yuyv);
rsz_reqbufs_t reqbufs; /* Initialize resize structure */
rsz_buffer_t buffer; rsz->resize.in_buf.size = rsz->in_size;
memset( &reqbufs, 0, sizeof( reqbufs ) ); rsz->resize.out_buf.size = rsz->out_size;
memset( &buffer, 0, sizeof( buffer ) );
reqbufs.buf_type = RSZ_BUF_OUT; return 0;
reqbufs.size = rsz->i_yuyv; }
reqbufs.count = 1;
if( ioctl( rsz->i_fd, RSZ_REQBUF, &reqbufs ) ) /*****************************************************************************
{ * Exported functions
msg_Err( p_dec, "RSZ_REQBUF failed (%m)" ); *****************************************************************************/
return VLC_EGENERIC; void resizer_close(struct resizer_t *rsz)
} {
close(rsz->fd);
free(rsz);
}
buffer.buf_type = RSZ_BUF_OUT; struct resizer_t *resizer_open(vlc_object_t *p_this,
buffer.index = 0; 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)" ); msg_Err(p_this, "Couldn't open device (%m)");
return VLC_EGENERIC; free(rsz);
return NULL;
} }
rsz->p_yuyv = mmap( NULL, reqbufs.size, PROT_READ|PROT_WRITE, int ret = Init(p_this, rsz, in_width, in_height, out_width, out_height);
MAP_SHARED, rsz->i_fd, buffer.offset ); if (ret != 0)
if( rsz->p_yuyv == MAP_FAILED )
{ {
rsz->i_yuyv = 0; msg_Err(p_this, "Resizer init failed (%d)\n", ret);
msg_Err( p_dec, "mmap resizer to buffer failed (%m)" ); resizer_close(rsz);
return VLC_EGENERIC; 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 */ rsz->out_height = *out_height;
if( rsz->i_width != p_dec->fmt_out.video.i_width || rsz->out_width = *out_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;
}
/* And then modify it to keep the same aspect ratio, and make sure return rsz;
* 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;
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; #else /* C */
rsz->i_out_height = rsz_params.out_vsize; 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 ); int resizer_resize(struct resizer_t *rsz, uint8_t *in, uint8_t *out)
get_coeffs( vcoefs , rsz_params.in_vsize, rsz_params.out_vsize ); {
/* We can use the decoder output buffer as is */
rsz->resize.in_buf.offset =
Memory_getBufferPhysicalAddress(in, rsz->in_size, NULL);
int i; #ifdef DIRECT_OUTPUT
for( i = 0; i < 32; i++ ) rsz->resize.out_buf.offset =
{ Memory_getBufferPhysicalAddress(out, rsz->out_size, NULL);
rsz_params.hfilt_coeffs[i] = hcoefs[i]; assert(rsz->resize.out_buf.offset);
rsz_params.vfilt_coeffs[i] = vcoefs[i];
}
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 ) ) rsz->resize.out_buf.offset += (lines >> 1) * pitch + (cols & ~31);
{ #endif
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;
return VLC_EGENERIC; int error;
} do
} { /* resize */
error = ioctl(rsz->fd, RSZ_RESIZE, &rsz->resize);
} while(error == -1 && errno == EAGAIN);
rsz_resize_t rszh; if (error == -1)
rszh.in_buf.index = -1; return errno;
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 );
rszh.out_buf.index = -1; #ifdef DIRECT_OUTPUT
rszh.out_buf.buf_type = RSZ_BUF_OUT; 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 */ ) assert((pitch_pic & 3) == 0);
{
/* 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;
}
do out = fill_black(out, lines_top * pitch);
{ for (int i = 0; i < rsz->out_height; i++)
if( ioctl( rsz->i_fd, RSZ_RESIZE, &rszh ) == -1 )
{ {
if( errno == EAGAIN ) out = fill_black(out, cols_left) + pitch_pic;
continue; out = fill_black(out, cols_right);
msg_Err( p_dec, "Resizing failed (%m)" );
return VLC_EGENERIC;
} }
} 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 */ const unsigned pitch = (width << 1) & ~3;
if( ( rsz->i_fd = open( "/dev/davinci_resizer", O_RDWR ) ) == -1 )
{
msg_Err( p_this, "Failed to open resizer (%m)" );
goto error;
}
rsz->p_yuyv = MAP_FAILED; const unsigned v_black_left = (OUT_WIDTH - width) & ~3;
rsz->i_yuyv = 0; const unsigned v_black_right = (OUT_WIDTH << 1) - pitch - v_black_left;
rsz->offset = 0;
rsz->i_height = 0;
rsz->i_width = 0;
rsz->i_out_height = 0;
rsz->i_out_width = 0;
return VLC_SUCCESS; out = fill_black(out, h_black_top);
error: for (int i = 0; i < height; i++)
ResizerClose( rsz ); {
return VLC_EGENERIC; out = fill_black(out, v_black_left);
}
void ResizerClose( davinci_resizer_t *rsz ) memcpy(out, in, pitch);
{ in += (OUT_WIDTH << 1);
if( rsz->i_fd != -1 ) out += pitch;
close( rsz->i_fd );
if( rsz->p_yuyv != MAP_FAILED ) out = fill_black(out, v_black_right);
munmap( rsz->p_yuyv, rsz->offset ); }
rsz->i_fd = -1;
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 * 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 * it under the terms of the GNU General Public License as published by
...@@ -20,56 +20,31 @@ ...@@ -20,56 +20,31 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/ *****************************************************************************/
#ifndef RESIZER_H #ifndef VLC_DAVINCI_RESIZER_H
#define 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 <inttypes.h>
#include <asm-arm/arch-davinci/davinci_resizer.h> #include <assert.h>
#include <math.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 resizer_resize(vlc_object_t *p_this,
{ struct resizer_t *rsz, uint8_t *in, uint8_t *out);
int i_fd;
unsigned int i_height;
unsigned int i_width;
uint8_t *p_yuyv; void resizer_copy_picture(vlc_object_t *p_this,
int offset; uint8_t *out, uint8_t *in, int width, int height);
int i_yuyv;
unsigned int i_out_width; /** FIXME: arbritary values make them more configurable */
unsigned int i_out_height; #define OUT_WIDTH 720
#define OUT_HEIGHT 480
bool b_direct; /* define if VLC picture buffers are allocated with Memorycontig_Alloc() */
} davinci_resizer_t; #define DIRECT_OUTPUT
/* Resize: resize and/or enhance input picture #endif /* VLC_DAVINCI_RESIZER_H */
* \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 */
/*****************************************************************************
* 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