Commit 5c808483 authored by Jean-Paul Saman's avatar Jean-Paul Saman

davinci: Partially backport 788db410392dea2bd5c390efff8da3246cfd66d1

Needs more cleaning and rewritting.
parent fd963914
......@@ -4,4 +4,6 @@ SOURCES_davinci = \
auddec.c \
viddec.c \
videnc.c \
resizer.c \
reziser.h \
$(NULL)
/*****************************************************************************
* resizer.c: Resize pictures directly into framebuffer (DaVinci specific)
*****************************************************************************
* Copyright (C) 2008 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.
*****************************************************************************/
#undef _FILE_OFFSET_BITS /* mmap() fails on 64 bits offsets */
#include "davinci.h" /* DAVINCI_HACK defined here */
#ifdef DAVINCI_HACK
#include "resizer.h"
#include <assert.h>
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;
msg_Dbg( p_dec, "Destination fixed to %dx%d", *i_width, *i_height );
}
/* open() a framebuffer by its name (NOT device path) */
int OpenFB( const char *psz_name )
{
int i_fd = -1;
int i_tries = 0; /* begin with /dev/fb0 */
char *psz_device;
struct fb_fix_screeninfo info;
do {
if( asprintf( &psz_device, "/dev/fb%d", i_tries++ ) == -1 )
return -1;
i_fd = open( psz_device, O_RDWR);
free( psz_device );
if( i_fd == -1 )
return -1; /* check errno */
if( ioctl( i_fd, FBIOGET_FSCREENINFO, &info ) == -1 )
{
close( i_fd );
continue;
}
if( !strcmp( info.id, psz_name ) )
return i_fd;
close( i_fd );
} while(1);
}
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.;
}
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 * PI * i / i_winlen ) +
.08 * cos( 4 * PI * i / i_winlen );
i_nphases = 8;
i_ntaps = 4;
i_phase_offset = 4;
/* 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( decoder_t *p_dec, vlc_bool_t b_scale, davinci_resizer_t *rsz,
davinci_fb_t *fb, XDM_BufDesc out )
{
if( !rsz->i_yuyv )
{
/* use screen resolution for the buffer, we may be off by a few */
rsz->i_yuyv = fb->var_info.xres * fb->var_info.yres_virtual;
assert(rsz->i_yuyv);
rsz_reqbufs_t reqbufs;
rsz_buffer_t buffer;
memset( &reqbufs, 0, sizeof( reqbufs ) );
memset( &buffer, 0, sizeof( buffer ) );
reqbufs.buf_type = RSZ_BUF_OUT;
reqbufs.size = rsz->i_yuyv;
reqbufs.count = 1;
if( ioctl( rsz->i_fd, RSZ_REQBUF, &reqbufs ) )
{
msg_Err( p_dec, "RSZ_REQBUF failed (%m)" );
return;
}
buffer.buf_type = RSZ_BUF_OUT;
buffer.index = 0;
if( ioctl( rsz->i_fd, RSZ_QUERYBUF, &buffer ) )
{
msg_Err( p_dec, "RSZ_QUERYBUF failed (%m)" );
return;
}
rsz->offset = buffer.offset;
rsz->p_yuyv = mmap( NULL, reqbufs.size, PROT_READ|PROT_WRITE,
MAP_SHARED, rsz->i_fd, buffer.offset );
if( rsz->p_yuyv == MAP_FAILED )
{
rsz->i_yuyv = 0;
msg_Err( p_dec, "mmap resizer to buffer failed (%m)" );
return;
}
}
/* 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 = fb->var_info.xres;
rsz_params.out_vsize = fb->var_info.yres;
}
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
* 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)fb->var_info.xres;
rsz->i_out_width = rsz_params.out_hsize;
rsz->i_out_height = rsz_params.out_vsize;
short hcoefs[32], vcoefs[32];
get_coeffs( hcoefs , rsz_params.in_hsize, rsz_params.out_hsize );
get_coeffs( vcoefs , rsz_params.in_vsize, rsz_params.out_vsize );
int i;
for( i = 0; i < 32; i++ )
{
rsz_params.hfilt_coeffs[i] = hcoefs[i];
rsz_params.vfilt_coeffs[i] = vcoefs[i];
}
rsz_params.yenh_params.type = RSZ_YENH_DISABLE;
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;
return;
}
}
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 );
rszh.out_buf.index = -1;
rszh.out_buf.buf_type = RSZ_BUF_OUT;
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];
rszh.out_buf.size = fb->var_info.xres * fb->var_info.yres_virtual;
}
else
{
rszh.out_buf.offset = rsz->offset;
rszh.out_buf.size = rsz->i_yuyv;
}
do
{
if( ioctl( rsz->i_fd, RSZ_RESIZE, &rszh ) == -1 )
{
if( errno == EAGAIN )
continue;
msg_Err( p_dec, "Resizing failed (%m)" );
return;
}
} while(0);
}
int DavinciInit( decoder_t *p_dec, davinci_fb_t *fb, davinci_resizer_t *rsz )
{
fb->i_fd = rsz->i_fd = -1;
/* Open framebuffer */
if( ( fb->i_fd = OpenFB( "dm_vid0_fb" ) ) == -1 )
{
msg_Err( p_dec, "Failed to open framebuffer (%m)" );
goto error;
}
if( ioctl( fb->i_fd, FBIOGET_VSCREENINFO, &fb->var_info ) == -1 )
{
msg_Err( p_dec, "Failed to get framebuffer info (%m)" );
goto error;
}
fb->var_info.yres_virtual = fb->var_info.yres * NUM_BUFFERS;
fb->var_info.bits_per_pixel = BPP;
if( ioctl( fb->i_fd, FBIOPUT_VSCREENINFO, &fb->var_info ) == -1 )
{
msg_Err( p_dec, "Can not set fb info (%m)" );
goto error;
}
if( fb->var_info.bits_per_pixel != BPP )
{
msg_Err( p_dec, "Can not use requested size (%dx%d at %d bpp)",
fb->var_info.xres, fb->var_info.yres,
fb->var_info.bits_per_pixel );
goto error;
}
if( ioctl( fb->i_fd, FBIOGET_FSCREENINFO, &fb->fix_info ) == -1 )
{
msg_Err( p_dec, "Failed to get framebuffer fixed info (%m)" );
goto error;
}
/* Yes, 32bits * 32bits fills 64 bits.
* * Oh and if you find a screen with 16 billions of billions of pixels ...
* * Keep it for yourself. */
uint64_t i_display_sz = fb->fix_info.line_length * fb->var_info.yres;
uint64_t i_display_total_sz =
fb->fix_info.line_length * fb->var_info.yres_virtual;
fb->p_map = mmap( NULL, i_display_total_sz,
PROT_READ | PROT_WRITE, MAP_SHARED, fb->i_fd, 0 );
if( fb->p_map == MAP_FAILED )
{
fb->p_map = NULL; /* set to NULL for error handling */
msg_Err( p_dec, "Memory mapping of framebuffer failed (%m)" );
goto error;
}
/* Clears fb */
unsigned int i;
for( i = 0 ; i < i_display_total_sz / 4 ; i++ )
((uint32_t*)fb->p_map)[i] = 0x10801080;
for( i = 0 ; i < NUM_BUFFERS ; i++ )
if( ( fb->p_physbufs[i] = Memory_getBufferPhysicalAddress(
fb->p_map + i * i_display_sz, i_display_sz, NULL ) ) == 0 )
{
msg_Err( p_dec, "Unable to get physical address of buffer "
"%d/%d (%"PRId64" bytes)", i, NUM_BUFFERS, i_display_sz );
goto error;
}
/* Open and setup resizer */
if( ( rsz->i_fd = open( "/dev/davinci_resizer", O_RDWR ) ) == -1 )
{
msg_Err( p_dec, "Failed to open resizer (%m)" );
goto error;
}
rsz->p_yuyv = NULL;
rsz->i_yuyv = 0;
rsz->i_height = rsz->i_width = 0;
return VLC_SUCCESS;
error:
DavinciClose( fb, rsz );
return VLC_EGENERIC;
}
void DavinciClose( davinci_fb_t *fb, davinci_resizer_t *rsz )
{
if( fb->p_map )
{
/* Clears fb */
unsigned int i;
uint64_t i_display_size =
fb->fix_info.line_length * fb->var_info.yres_virtual / 4;
for( i = 0 ; i < i_display_size ; i++ )
((uint32_t*)fb->p_map)[i] = 0x10801080;
munmap( fb->p_map, i_display_size );
}
if( fb->i_fd != -1 ) close( fb->i_fd );
if( rsz->i_fd != -1 ) close( rsz->i_fd );
rsz->i_fd = fb->i_fd = -1;
fb->p_map = NULL;
}
#endif /* DAVINCI_HACK */
#ifndef RESIZER_H
#define RESIZER_H
#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>
#define NUM_BUFFERS 1 /* XXX: mesure performance with 3 buffers if needed */
#define BPP 16
#define PI 3.1415926535897932384626
typedef struct
{
int i_fd;
struct fb_var_screeninfo var_info;
struct fb_fix_screeninfo fix_info;
uint8_t *p_map;
UInt32 p_physbufs[NUM_BUFFERS];
} davinci_fb_t;
typedef struct
{
int i_fd;
unsigned int i_height;
unsigned int i_width;
uint8_t *p_yuyv;
int offset;
int i_yuyv;
unsigned int i_out_width;
unsigned int i_out_height;
vlc_bool_t b_direct;
} davinci_resizer_t;
void Resize_coeff( decoder_t *, unsigned int *, unsigned int * );
int OpenFB( const char *psz_name );
void get_coeffs( short [32], unsigned int, unsigned int );
void Resize( decoder_t *, vlc_bool_t, davinci_resizer_t *, davinci_fb_t *,
XDM_BufDesc );
int DavinciInit( decoder_t *, davinci_fb_t *, davinci_resizer_t * );
void DavinciClose( davinci_fb_t *, davinci_resizer_t * );
#endif /* RESIZER_H */
......@@ -25,31 +25,13 @@
/*****************************************************************************
* Preamble
*****************************************************************************/
#undef _FILE_OFFSET_BITS /* mmap() fails on 64 bits offsets */
#include "davinci.h"
#include <assert.h>
#include <ti/sdo/ce/video/viddec.h>
#ifdef DAVINCI_HACK
#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>
#define NUM_BUFFERS 1 /* XXX: mesure performance with 3 buffers if needed */
#define BPP 16
#define PI 3.1415926535897932384626
#include "resizer.h"
#endif
/*****************************************************************************
......@@ -69,29 +51,17 @@ struct decoder_sys_t
XDM_BufDesc in;
XDM_BufDesc out;
decoder_t *p_packetizer; /* for avc1 -> h264 */
#ifdef DAVINCI_HACK
/* framebuffer */
int i_fd_fb;
struct fb_var_screeninfo var_info;
struct fb_fix_screeninfo fix_info;
uint8_t *p_fb_map;
UInt32 p_physbufs[NUM_BUFFERS];
davinci_fb_t fb;
/* resizer */
int i_fd_resizer;
unsigned int i_height;
unsigned int i_width;
davinci_resizer_t rsz;
vlc_bool_t b_resize;
vlc_mutex_t cb_lock;
uint8_t *p_yuyv;
int offset;
int i_yuyv;
vlc_bool_t b_direct; /* resize directly in the fb */
unsigned int i_out_width;
unsigned int i_out_height;
#endif
};
......@@ -108,210 +78,6 @@ int fullscreen_cb( vlc_object_t *p_this, const char *psz_var,
return VLC_SUCCESS;
}
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;
msg_Dbg( p_dec, "Destination fixed to %dx%d", *i_width, *i_height );
}
/* open() a framebuffer by its name (NOT device path) */
static int OpenFB( const char *psz_name )
{
int i_fd = -1;
int i_tries = 0; /* begin with /dev/fb0 */
char *psz_device;
struct fb_fix_screeninfo info;
do {
if( asprintf( &psz_device, "/dev/fb%d", i_tries++ ) == -1 )
return -1;
i_fd = open( psz_device, O_RDWR);
free( psz_device );
if( i_fd == -1 )
return -1; /* check errno */
if( ioctl( i_fd, FBIOGET_FSCREENINFO, &info ) == -1 )
{
close( i_fd );
continue;
}
if( !strcmp( info.id, psz_name ) )
return i_fd;
close( i_fd );
} while(1);
}
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 * PI * i / i_winlen ) +
.08 * cos( 4 * PI * i / i_winlen );
i_nphases = 8;
i_ntaps = 4;
i_phase_offset = 4;
/* 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;
}
}
}
#endif
/*****************************************************************************
......@@ -431,87 +197,12 @@ int OpenVideoDecoder( vlc_object_t *p_this )
p_dec->fmt_out.video.i_aspect = p_dec->fmt_in.video.i_aspect;
#ifdef DAVINCI_HACK
p_sys->i_fd_fb = p_sys->i_fd_resizer = -1;
/* Open framebuffer */
if( ( p_sys->i_fd_fb = OpenFB( "dm_vid0_fb" ) ) == -1 )
{
msg_Err( p_dec, "Failed to open framebuffer (%m)" );
goto error;
}
if( ioctl( p_sys->i_fd_fb, FBIOGET_VSCREENINFO, &p_sys->var_info ) == -1 )
{
msg_Err( p_dec, "Failed to get framebuffer info (%m)" );
goto error;
}
p_sys->var_info.yres_virtual = p_sys->var_info.yres * NUM_BUFFERS;
p_sys->var_info.bits_per_pixel = BPP;
if( ioctl( p_sys->i_fd_fb, FBIOPUT_VSCREENINFO, &p_sys->var_info ) == -1 )
{
msg_Err( p_dec, "Can not set fb info (%m)" );
goto error;
}
if( p_sys->var_info.bits_per_pixel != BPP )
{
msg_Err( p_dec, "Can not use requested size (%dx%d at %d bpp)",
p_sys->var_info.xres, p_sys->var_info.yres,
p_sys->var_info.bits_per_pixel );
goto error;
}
if( ioctl( p_sys->i_fd_fb, FBIOGET_FSCREENINFO, &p_sys->fix_info ) == -1 )
{
msg_Err( p_dec, "Failed to get framebuffer fixed info (%m)" );
goto error;
}
/* Yes, 32bits * 32bits fills 64 bits.
* Oh and if you find a screen with 16 billions of billions of pixels ...
* Keep it for yourself. */
uint64_t i_display_sz = p_sys->fix_info.line_length * p_sys->var_info.yres;
uint64_t i_display_total_sz =
p_sys->fix_info.line_length * p_sys->var_info.yres_virtual;
p_sys->p_fb_map = mmap( NULL, i_display_total_sz,
PROT_READ | PROT_WRITE, MAP_SHARED, p_sys->i_fd_fb, 0 );
if( p_sys->p_fb_map == MAP_FAILED )
{
p_sys->p_fb_map = NULL; /* set to NULL for error handling */
msg_Err( p_dec, "Memory mapping of framebuffer failed (%m)" );
goto error;
}
/* Clears fb */
unsigned int i;
for( i = 0 ; i < i_display_total_sz / 4 ; i++ )
((uint32_t*)p_sys->p_fb_map)[i] = 0x10801080;
for( i = 0 ; i < NUM_BUFFERS ; i++ )
if( ( p_sys->p_physbufs[i] = Memory_getBufferPhysicalAddress(
p_sys->p_fb_map + i * i_display_sz, i_display_sz, NULL ) ) == 0 )
{
msg_Err( p_dec, "Unable to get physical address of buffer "
"%d/%d (%"PRId64" bytes)", i, NUM_BUFFERS, i_display_sz );
goto error;
}
/* Open and setup resizer */
if( ( p_sys->i_fd_resizer = open( "/dev/davinci_resizer", O_RDWR ) ) == -1 )
if( DavinciInit( p_dec, &p_sys->fb, &p_sys->rsz ) != VLC_SUCCESS )
{
msg_Err( p_dec, "Failed to open resizer (%m)" );
msg_Err( p_dec, "Initialization of Davinci devices failed" );
goto error;
}
p_sys->p_yuyv = NULL;
p_sys->i_yuyv = 0;
p_sys->i_height = p_sys->i_width = 0;
p_sys->b_resize = var_CreateGetBool( p_dec, "davinci-viddec-fullscreen" );
var_AddCallback( p_dec, "davinci-viddec-fullscreen", fullscreen_cb, p_sys );
vlc_mutex_init( p_this, &p_sys->cb_lock );
......@@ -528,11 +219,6 @@ int OpenVideoDecoder( vlc_object_t *p_this )
error:
if( p_sys->e ) Engine_close( p_sys->e );
#ifdef DAVINCI_HACK
if( p_sys->p_fb_map ) munmap( p_sys->p_fb_map, i_display_total_sz );
if( p_sys->i_fd_fb != -1 ) close( p_sys->i_fd_fb );
if( p_sys->i_fd_resizer != -1 ) close( p_sys->i_fd_resizer );
#endif
free( p_sys );
free( psz_codec );
return VLC_EGENERIC;
......@@ -546,6 +232,12 @@ void CloseVideoDecoder( vlc_object_t *p_this )
decoder_t *p_dec = (decoder_t *)p_this;
decoder_sys_t *p_sys = p_dec->p_sys;
if( p_sys->p_packetizer )
{
module_Unneed( p_sys->p_packetizer, p_sys->p_packetizer->p_module );
vlc_object_destroy( p_sys->p_packetizer );
}
/* Close our codec handle */
VIDDEC_delete( p_sys->d );
......@@ -556,19 +248,7 @@ void CloseVideoDecoder( vlc_object_t *p_this )
CERuntime_exit();
#ifdef DAVINCI_HACK
/* Clears fb */
unsigned int i;
uint64_t i_display_size =
p_sys->fix_info.line_length * p_sys->var_info.yres_virtual / 4;
for( i = 0 ; i < i_display_size ; i++ )
((uint32_t*)p_sys->p_fb_map)[i] = 0x10801080;
if( p_sys->p_fb_map ) munmap( p_sys->p_fb_map, i_display_size );
/* Close file descriptors */
close( p_sys->i_fd_resizer );
close( p_sys->i_fd_fb );
DavinciClose( &p_sys->fb, &p_sys->rsz );
vlc_mutex_destroy( &p_sys->cb_lock );
#endif
......@@ -579,185 +259,6 @@ void CloseVideoDecoder( vlc_object_t *p_this )
free( p_sys );
}
#ifdef DAVINCI_HACK
static void Resize( decoder_t *p_dec, vlc_bool_t b_scale )
{
decoder_sys_t *p_sys = p_dec->p_sys;
if( !p_sys->i_yuyv )
{
/* use screen resolution for the buffer, we may be off by a few */
p_sys->i_yuyv = p_sys->var_info.xres * p_sys->var_info.yres_virtual;
assert(p_sys->i_yuyv);
rsz_reqbufs_t reqbufs;
rsz_buffer_t buffer;
memset( &reqbufs, 0, sizeof( reqbufs ) );
memset( &buffer, 0, sizeof( buffer ) );
reqbufs.buf_type = RSZ_BUF_OUT;
reqbufs.size = p_sys->i_yuyv;
reqbufs.count = 1;
if( ioctl( p_sys->i_fd_resizer, RSZ_REQBUF, &reqbufs ) )
{
msg_Err( p_dec, "RSZ_REQBUF failed (%m)" );
return;
}
buffer.buf_type = RSZ_BUF_OUT;
buffer.index = 0;
if( ioctl( p_sys->i_fd_resizer, RSZ_QUERYBUF, &buffer ) )
{
msg_Err( p_dec, "RSZ_QUERYBUF failed (%m)" );
return;
}
p_sys->offset = buffer.offset;
p_sys->p_yuyv = mmap( NULL, reqbufs.size, PROT_READ|PROT_WRITE,
MAP_SHARED, p_sys->i_fd_resizer, buffer.offset );
if( p_sys->p_yuyv == MAP_FAILED )
{
p_sys->i_yuyv = 0;
msg_Err( p_dec, "mmap to buffer failed (%m)" );
return;
}
}
/* Sets resizer parameters when video starts or when resolution changes */
if( p_sys->i_width != p_dec->fmt_out.video.i_width ||
p_sys->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 = p_sys->i_width = p_dec->fmt_out.video.i_width;
rsz_params.in_vsize = p_sys->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 = p_sys->var_info.xres;
rsz_params.out_vsize = p_sys->var_info.yres;
}
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
* 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;
p_sys->b_direct =
(unsigned)rsz_params.out_hsize == (unsigned)p_sys->var_info.xres;
p_sys->i_out_width = rsz_params.out_hsize;
p_sys->i_out_height = rsz_params.out_vsize;
short hcoefs[32] = {
0, 256, 0, 0,
-11, 245, 23, -1,
-17, 220, 58, -5,
-18, 184, 100, -10,
-15, 143, 143, -15,
-10, 100, 184, -18,
-5, 58, 220, -17,
-1, 23, 245, -11
};
short vcoefs[32] = {
0, 256, 0, 0,
-11, 245, 23, -1,
-17, 220, 58, -5,
-18, 184, 100, -10,
-15, 143, 143, -15,
-10, 100, 184, -18,
-5, 58, 220, -17,
-1, 23, 245, -11
};
/* HACK HACK HACK : use --davinci-viddec-chroma resize
* to not compute coefficients */
char *psz_chroma= var_CreateGetString( p_dec, "davinci-viddec-chroma" );
if( psz_chroma && strcmp( psz_chroma, "resize" ) )
{
get_coeffs( hcoefs , rsz_params.in_hsize, rsz_params.out_hsize );
get_coeffs( vcoefs , rsz_params.in_vsize, rsz_params.out_vsize );
}
free( psz_chroma );
int i;
for( i = 0; i < 32; i++ )
{
rsz_params.hfilt_coeffs[i] = hcoefs[i];
rsz_params.vfilt_coeffs[i] = vcoefs[i];
}
rsz_params.yenh_params.type = RSZ_YENH_DISABLE;
if( ioctl( p_sys->i_fd_resizer, 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
);
p_sys->i_width = p_sys->i_height = 0;
return;
}
}
rsz_resize_t rsz;
rsz.in_buf.index = -1;
rsz.in_buf.buf_type = RSZ_BUF_IN;
rsz.in_buf.size =
p_dec->fmt_out.video.i_height *
((p_dec->fmt_out.video.i_width * BPP / 8 + 31) & ~31);
rsz.in_buf.offset = Memory_getBufferPhysicalAddress(
p_sys->out.bufs[0], rsz.in_buf.size, NULL );
assert( rsz.in_buf.offset );
rsz.out_buf.index = -1;
rsz.out_buf.buf_type = RSZ_BUF_OUT;
if( b_scale && p_sys->b_direct /* output video res is screen res */ )
{
/* FIXME: use NUM_BUFFERS if needed */
rsz.out_buf.offset = p_sys->p_physbufs[0];
rsz.out_buf.size = p_sys->var_info.xres * p_sys->var_info.yres_virtual;
}
else
{
rsz.out_buf.offset = p_sys->offset;
rsz.out_buf.size = p_sys->i_yuyv;
}
do
{
if( ioctl( p_sys->i_fd_resizer, RSZ_RESIZE, &rsz ) == -1 )
{
if( errno == EAGAIN )
continue;
msg_Err( p_dec, "Resizing failed (%m)" );
return;
}
} while(0);
}
#endif
/****************************************************************************
* DecodeBlock: the whole thing
****************************************************************************/
......@@ -776,6 +277,28 @@ static picture_t *DecodeVideoBlockInner( decoder_t *p_dec, block_t **pp_block, i
VIDDEC_Status status;
int i;
if( !p_sys->p_packetizer &&
p_dec->fmt_in.i_codec == VLC_FOURCC( 'a', 'v', 'c', '1' ) )
{
p_sys->p_packetizer = vlc_object_create( p_dec, VLC_OBJECT_PACKETIZER );
if( p_sys->p_packetizer )
{
p_sys->p_packetizer->pf_decode_audio = NULL;
p_sys->p_packetizer->pf_decode_video = NULL;
p_sys->p_packetizer->pf_decode_sub = NULL;
p_sys->p_packetizer->pf_packetize = NULL;
es_format_Copy( &p_sys->p_packetizer->fmt_in, &p_dec->fmt_in );
p_sys->p_packetizer->fmt_in = p_dec->fmt_in;
p_sys->p_packetizer->p_module = module_Need( p_sys->p_packetizer,
"packetizer", NULL, 0 );
if( !p_sys->p_packetizer->p_module )
{
vlc_object_destroy( p_sys->p_packetizer );
p_sys->p_packetizer = NULL;
}
}
}
if( !pp_block || !*pp_block ) return NULL;
p_block = *pp_block;
......@@ -785,6 +308,15 @@ static picture_t *DecodeVideoBlockInner( decoder_t *p_dec, block_t **pp_block, i
return NULL;
}
if( p_sys->p_packetizer && !i_extra )
{
block_t *p_new_block = p_sys->p_packetizer->pf_packetize(
p_sys->p_packetizer, &p_block );
p_block = p_new_block;
if( !p_block )
return NULL;
}
memset( &in_args, 0, sizeof( in_args ) );
memset( &out_args, 0, sizeof( out_args ) );
......@@ -877,7 +409,7 @@ static picture_t *DecodeVideoBlockInner( decoder_t *p_dec, block_t **pp_block, i
abort();
}
#endif
if( i_extra == 0 && p_dec->fmt_in.i_extra > 0 )
if( !p_sys->p_packetizer && i_extra == 0 && p_dec->fmt_in.i_extra > 0 )
{ /* FIXME : doesn't decode, for example, avc1 (avcC) */
msg_Dbg( p_dec, "Trying again with p_extra" );
return DecodeVideoBlockInner( p_dec, pp_block, p_dec->fmt_in.i_extra );
......@@ -966,24 +498,24 @@ static picture_t *DecodeVideoBlockInner( decoder_t *p_dec, block_t **pp_block, i
vlc_bool_t b_resize = p_sys->b_resize;
vlc_mutex_unlock( &p_sys->cb_lock );
Resize( p_dec, b_resize );
Resize( p_dec, b_resize, &p_sys->rsz, &p_sys->fb, p_sys->out );
if( !b_resize || !p_sys->b_direct )
if( !b_resize )
{
uint32_t black = 0x88888888; /* for vout YUYV */
/* fb */
/* output top & bottom black */
int i_line_len = p_sys->var_info.xres * BPP/8; /* in bytes */
int i_nlines = p_sys->var_info.yres; /* in lines */
int i_line_len = p_sys->fb.var_info.xres * BPP/8; /* in bytes */
int i_nlines = p_sys->fb.var_info.yres; /* in lines */
/* bytes per input line */
int i_vidw = p_sys->i_out_width * (BPP/8);
int i_vidw = p_sys->rsz.i_out_width * (BPP/8);
/* borders */
int i_sideborder = (i_line_len - i_vidw) / 2; /* in bytes */
int i_edgeborder = /* in lines */
(i_nlines - p_sys->i_out_height) / 2;
(i_nlines - p_sys->rsz.i_out_height) / 2;
int i,j;
......@@ -994,7 +526,7 @@ static picture_t *DecodeVideoBlockInner( decoder_t *p_dec, block_t **pp_block, i
{
int lim = i_line_len / 4;
for( j=0; j < lim; j++ )
((uint32_t*)p_sys->p_fb_map)[i*lim+j] = black;
((uint32_t*)p_sys->fb.p_map)[i*lim+j] = black;
}
else /* draw video */
{
......@@ -1003,23 +535,23 @@ static picture_t *DecodeVideoBlockInner( decoder_t *p_dec, block_t **pp_block, i
/* draw a line */
int i_vidw_pad = (i_vidw + 15) & ~15;
memcpy( &p_sys->p_fb_map[i*i_line_len + i_sideborder],
&p_sys->p_yuyv[(i-i_edgeborder)*i_vidw_pad],
memcpy( &p_sys->fb.p_map[i*i_line_len + i_sideborder],
&p_sys->rsz.p_yuyv[(i-i_edgeborder)*i_vidw_pad],
i_vidw_pad
);
/* and black borders */
int p;
for( p=0; p < i_sideborder / 4 ;p++ )
((uint32_t*)p_sys->p_fb_map)[i * i_line_len / 4 + p]= black;
((uint32_t*)p_sys->fb.p_map)[i * i_line_len / 4 + p]= black;
for( p=(i_line_len - i_sideborder)/4; p < i_line_len / 4; p++ )
((uint32_t*)p_sys->p_fb_map)[i * i_line_len / 4 + p]= black;
((uint32_t*)p_sys->fb.p_map)[i * i_line_len / 4 + p]= black;
}
}
}
int i_dummy;
ioctl( p_sys->i_fd_fb, FBIO_WAITFORVSYNC, &i_dummy ); /* ignore return */
ioctl( p_sys->fb.i_fd, FBIO_WAITFORVSYNC, &i_dummy ); /* ignore return */
#endif
#ifndef DAVINCI_HACK
......@@ -1038,4 +570,3 @@ error:
block_Release( p_block );
return NULL;
}
......@@ -5,6 +5,7 @@
* $Id$
*
* Authors: Antoine Cellerier <dionoea at videolan dot org>
* 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
......@@ -49,6 +50,58 @@ struct encoder_sys_t
/*****************************************************************************
*
*****************************************************************************/
static void picfree( picture_t *p_pic )
{
if( p_pic->i_type == MEMORY_PICTURE )
free( p_pic->p_data_orig );
free( p_pic );
}
static picture_t * NewEncoderBuffer( encoder_t *p_enc, decoder_t *p_dec )
{
p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
picture_t *p_pic = malloc(sizeof(picture_t));
if( !p_pic ) return NULL;
if( !p_enc->p_sys->in.numBufs )
{
vout_AllocatePicture( p_dec, p_pic,
p_dec->fmt_out.video.i_chroma,
p_dec->fmt_out.video.i_width,
p_dec->fmt_out.video.i_height,
p_dec->fmt_out.video.i_aspect );
if( !p_pic->i_planes )
{
free( p_pic );
return NULL;
}
p_pic->i_type = MEMORY_PICTURE;
}
else
{
p_pic->i_planes = 1;
vout_InitPicture( p_dec, p_pic,
p_dec->fmt_out.video.i_chroma,
p_dec->fmt_out.video.i_width,
p_dec->fmt_out.video.i_height,
p_dec->fmt_out.video.i_aspect );
p_pic->p_data = p_enc->p_sys->in.bufs[0];
p_pic->p_data_orig = NULL;
p_pic->p[0].p_pixels = p_pic->p_data;
p_pic->i_type = DIRECT_PICTURE;
}
p_pic->pf_release = picfree;
p_pic->i_status = RESERVED_PICTURE;
p_pic->p_sys = NULL;
return p_pic;
}
int OpenVideoEncoder( vlc_object_t *p_this )
{
encoder_t *p_enc = (encoder_t *)p_this;
......@@ -147,6 +200,7 @@ int OpenVideoEncoder( vlc_object_t *p_this )
/* Initialize random stuff */
p_enc->pf_encode_video = EncodeVideo;
p_enc->pf_enc_buffer_new = NewEncoderBuffer;
free( psz_codec );
return VLC_SUCCESS;
......@@ -257,11 +311,16 @@ static block_t *EncodeVideo( encoder_t *p_enc, picture_t *p_pic )
/* Copy input picture */
assert( p_pic->i_planes == p_sys->in.numBufs );
assert( p_pic->i_planes == 1 );
for( i = 0; i < p_pic->i_planes; i++ )
{
plane_t *p = p_pic->p+i;
memcpy( p_sys->in.bufs[i], p->p_pixels, p->i_pitch * p->i_visible_lines );
if( p_pic->i_type == MEMORY_PICTURE )
{
plane_t *p = p_pic->p+i;
memcpy( p_sys->in.bufs[i], p->p_pixels, p->i_pitch * p->i_visible_lines );
}
/* if it's our direct buffer, we have nothing to do */
}
/* Configure input */
......
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