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

davinci: fb.c: Remove hack that bypasses VLC video output chain.

The file modules/codec/davinci/fb.c used a hack to bypass VLC video
output chain in order to improve playback speed. By doing so it was
able to eliminate a lot of memory copies from and to different buffer
types.
parent c53866c7
/*****************************************************************************
* fb.c: video decoder module using the DaVinci DSP.
*****************************************************************************
* Copyright (C) 2008-2009 M2X BV
* $Id$
*
* Authors: Antoine Cellerier <dionoea at videolan dot org>
* Rafaël Carré <rcarre@m2x.nl>
* Jean-Paul Saman <jean-paul.saman at m2x dot 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.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_codec.h>
#include <vlc_vout.h>
#include <vlc_codecs.h>
#include "davinci.h"
#include <assert.h>
#include <ti/sdo/ce/video/viddec.h>
#define DAVINCI_HACK /* directly resize and output the decoded video */
#ifdef DAVINCI_HACK
#include "resizer.h"
#endif
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static picture_t *DecodeVideoBlock( decoder_t *, block_t ** );
static picture_t *DecodeVideoBlockInner( decoder_t *, block_t **, int );
/*****************************************************************************
* Video decoder
*****************************************************************************/
struct decoder_sys_t
{
char *psz_ti_engine;
Engine_Handle e;
VIDDEC_Handle d;
XDM_BufDesc in;
XDM_BufDesc out;
decoder_t *p_packetizer; /* for avc1 -> h264 */
#ifdef DAVINCI_HACK
/* framebuffer */
davinci_fb_t fb;
/* resizer */
davinci_resizer_t rsz;
bool b_resize;
vlc_mutex_t cb_lock;
#endif
};
#ifdef DAVINCI_HACK
int fullscreen_cb( vlc_object_t *p_this, const char *psz_var,
vlc_value_t old, vlc_value_t new, void * p_data )
{
decoder_sys_t *p_sys = (decoder_sys_t*)p_data;
vlc_mutex_lock( &p_sys->cb_lock );
p_sys->b_resize = new.b_bool;
vlc_mutex_unlock( &p_sys->cb_lock );
return VLC_SUCCESS;
}
#endif
/*****************************************************************************
* OpenDecoder: probe the decoder and return score
*****************************************************************************/
int OpenVideoDecoder( vlc_object_t *p_this )
{
decoder_t *p_dec = (decoder_t*)p_this;
decoder_sys_t *p_sys;
Engine_Error err;
char *psz_chroma = NULL;
char *psz_codec = NULL;
vlc_fourcc_t i_chroma = VLC_FOURCC('U','Y','V','Y');
VIDDEC_Params params;
switch( p_dec->fmt_in.i_codec )
{
CASE_VC1
psz_codec = strdup( "vc1dec" );
break;
CASE_MPEG1
psz_codec = strdup( "mpegdec" );
break;
CASE_MPEG2
psz_codec = strdup( "mpeg2dec" );
break;
CASE_MPEG4
psz_codec = strdup( "mpeg4dec" );
break;
CASE_H264
psz_codec = strdup( "h264dec" );
break;
default:
return VLC_EGENERIC;
}
/* Allocate our private structure */
p_dec->p_sys = (decoder_sys_t *)calloc( 1, sizeof( decoder_sys_t ) );
if( !p_dec->p_sys )
{
free( psz_codec );
return VLC_ENOMEM;
}
p_sys = p_dec->p_sys;
p_sys->psz_ti_engine = var_CreateGetString( DEC_CFG_PREFIX "engine" );
if( !p_sys->psz_ti_engine )
{
free( psz_codec );
free( p_sys );
return VLC_ENOMEM;
}
/* Initialize the codec engine */
CERuntime_init();
/* Create an engine handle */
p_sys->e = Engine_open( p_sys->psz_ti_engine, NULL /*&Engine_ATTRS*/, &err );
if( err != Engine_EOK )
{
msg_Err( p_dec, "Error while opening engine `%s': %s",
p_sys->psz_ti_engine, ppsz_engine_error[err] );
goto error;
}
davinci_PrintAvailableAlgorithms( p_this, p_sys->psz_ti_engine );
/* Get user supplied chroma setting */
psz_chroma = config_GetPsz( p_dec, DEC_CFG_PREFIX "chroma" );
if( psz_chroma && strlen( psz_chroma ) == 4 )
{
i_chroma = VLC_FOURCC( psz_chroma[0], psz_chroma[1],
psz_chroma[2], psz_chroma[3] );
msg_Dbg( p_dec, "Forcing output chroma to `%s'", psz_chroma );
}
free( psz_chroma );
/* Create video decoder */
params.size = sizeof( VIDDEC_Params );
/* TODO change the params when HD codecs are available */
params.maxHeight = p_dec->fmt_in.video.i_height ?: 576 /*720*/;
params.maxWidth = p_dec->fmt_in.video.i_width ?: 720 /*1280*/;
/* The application should set the parameters to 0 to use the algorithm's default values. */
params.maxFrameRate = 0;
params.maxBitRate = 0;
msg_Dbg( p_dec, "Creating decoder for %dx%d codec %4s in chroma %4s",
(int)params.maxWidth, (int)params.maxHeight,
(const char *)&p_dec->fmt_in.i_codec,
(char*)&i_chroma
);
params.dataEndianness = XDM_BYTE;
params.forceChromaFormat = VlcChromaToXdm( i_chroma );
if( params.forceChromaFormat == XDM_CHROMA_NA )
{
msg_Err( p_dec, "Unsupported output chroma (%4.4s).",
(const char *)&i_chroma );
goto error;
}
p_sys->d = VIDDEC_create( p_sys->e, (String)psz_codec, &params );
if( !p_sys->d )
{
msg_Err( p_dec, "Failed to create video decoder (%s)", psz_codec );
goto error;
}
/* Set output properties */
p_dec->fmt_out.i_cat = VIDEO_ES;
p_dec->fmt_out.i_codec =
p_dec->fmt_out.video.i_chroma = i_chroma;
p_dec->fmt_out.video.i_width = p_dec->fmt_in.video.i_width;
p_dec->fmt_out.video.i_height = p_dec->fmt_in.video.i_height;
p_dec->fmt_out.video.i_aspect = p_dec->fmt_in.video.i_aspect;
#ifdef DAVINCI_HACK
if( DavinciInit( p_dec, &p_sys->fb, &p_sys->rsz ) != VLC_SUCCESS )
{
msg_Err( p_dec, "Initialization of Davinci devices failed" );
goto error;
}
p_sys->b_resize = var_GetBool( p_dec->p_libvlc, "fullscreen" );
var_AddCallback( p_dec->p_libvlc, "fullscreen", fullscreen_cb, p_sys );
vlc_mutex_init( p_this, &p_sys->cb_lock );
#endif
/* Set callbacks */
p_dec->pf_decode_video = DecodeVideoBlock;
/* DaVinci decoder needs complete frames */
p_dec->b_need_packetized = true;
free( psz_codec );
return VLC_SUCCESS;
error:
if( p_sys->e ) Engine_close( p_sys->e );
free( p_sys->psz_ti_engine );
free( p_sys );
free( psz_codec );
return VLC_EGENERIC;
}
/*****************************************************************************
* CloseDecoder: png decoder destruction
*****************************************************************************/
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 );
/* Close our engine handle */
Engine_close( p_sys->e );
/* Exit the codec engine */
CERuntime_exit();
#ifdef DAVINCI_HACK
DavinciClose( &p_sys->fb, &p_sys->rsz );
vlc_mutex_destroy( &p_sys->cb_lock );
#endif
/* Free 'DaVinci compliant' buffers */
davinci_FreeBuffer( &p_sys->in );
davinci_FreeBuffer( &p_sys->out );
free( p_sys->psz_ti_engine );
free( p_sys );
}
/****************************************************************************
* DecodeBlock: the whole thing
****************************************************************************/
static picture_t *DecodeVideoBlock( decoder_t *p_dec, block_t **pp_block )
{
return DecodeVideoBlockInner( p_dec, pp_block, 0 );
}
static picture_t *DecodeVideoBlockInner( decoder_t *p_dec, block_t **pp_block, int i_extra )
{
decoder_sys_t *p_sys = p_dec->p_sys;
block_t *p_block;
VIDDEC_InArgs in_args;
VIDDEC_OutArgs out_args;
VIDDEC_DynamicParams dparams;
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->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;
}
es_format_Copy( &p_dec->fmt_in, &p_sys->p_packetizer->fmt_out );
}
}
if( !pp_block || !*pp_block ) return NULL;
p_block = *pp_block;
if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
{
block_Release( p_block );
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 );
*pp_block = p_block = p_new_block; /* keep refernce to packetized blk */
if( !p_block )
return NULL;
}
memset( &in_args, 0, sizeof( in_args ) );
memset( &out_args, 0, sizeof( out_args ) );
/* Configure video decoder */
dparams.size = sizeof( VIDDEC_DynamicParams );
memset( &status, 0, sizeof( VIDDEC_Status ) );
status.size = sizeof( VIDDEC_Status );
if( p_sys->in.numBufs == 0 || p_sys->out.numBufs == 0 )
{
if( VIDDEC_control( p_sys->d, XDM_GETBUFINFO, &dparams, &status )
!= VIDDEC_EOK )
{
msg_Err( p_dec, "Failed to get buffer info" );
goto error;
}
/* Allocate input buffer */
if( davinci_AllocateBuffer( status.bufInfo.minNumInBufs,
status.bufInfo.minInBufSize, &p_sys->in )
!= VLC_SUCCESS )
{
msg_Err( p_dec, "Failed to allocate input buffers" );
goto error;
}
/* Allocate output buffer(s) */
if( davinci_AllocateBuffer( status.bufInfo.minNumOutBufs,
status.bufInfo.minOutBufSize, &p_sys->out )
!= VLC_SUCCESS )
{
davinci_FreeBuffer( &p_sys->in );
msg_Err( p_dec, "Failed to allocate output buffers" );
goto error;
}
}
if( VIDDEC_control( p_sys->d, XDM_GETSTATUS, &dparams, &status )
!= VIDDEC_EOK )
{
msg_Err( p_dec, "Failed to get decoder status" );
goto error;
}
/* Setup input arguments */
in_args.size = sizeof( in_args );
in_args.numBytes = __MIN( i_extra + p_block->i_buffer,
p_sys->in.bufSizes[0] );
in_args.inputID = 1;
/* Setup input buffer */
assert( p_block->i_buffer <= p_sys->in.bufSizes[0] );
if( i_extra > 0 )
{
memcpy( p_sys->in.bufs[0], p_dec->fmt_in.p_extra, i_extra );
}
memcpy( p_sys->in.bufs[0] + i_extra, p_block->p_buffer,
in_args.numBytes - i_extra );
#ifdef DEBUG_DAVINCI
msg_Dbg( p_dec, "Frame is %d bytes (%d extra), %dx%d, type %s",
(int)in_args.numBytes, i_extra, (int)status.outputWidth,
(int)status.outputHeight,
status.contentType == IVIDEO_PROGRESSIVE ? "progressive" :
status.contentType == IVIDEO_INTERLACED ? "interlaced" :
"unknown" );
#endif
/* Setup output arguemnts */
out_args.size = sizeof( out_args );
/* Decode the video */
if( ( i = VIDDEC_process( p_sys->d, &p_sys->in, &p_sys->out, &in_args, &out_args ) )
!= VIDDEC_EOK )
{
msg_Err( p_dec, "Video decoding failed: %s",
davinci_GetExtendedError(out_args.extendedError ) );
#if 0
if( (unsigned int)out_args.extendedError == 0x402 )
{
printf("frame was %d bytes\n",(unsigned int)in_args.numBytes);
unsigned int j;
for(j=0;j<(unsigned int)in_args.numBytes;j++)
printf("%.2x ",p_sys->in.bufs[0][j]&0xff);
printf("\n");
CERuntime_exit();
abort();
}
#endif
if( i_extra == 0 && p_dec->fmt_in.i_extra > 0 )
{
msg_Dbg( p_dec, "Trying again with p_extra" );
return DecodeVideoBlockInner( p_dec, pp_block, p_dec->fmt_in.i_extra );
}
goto error;
}
if( VIDDEC_control( p_sys->d, XDM_GETSTATUS, &dparams, &status ) != VIDDEC_EOK )
{
msg_Err( p_dec, "Failed to get decoder status" );
goto error;
}
if( in_args.numBytes > out_args.bytesConsumed )
msg_Err( p_dec, "%d bytes were not consumed", (int)(out_args.bytesConsumed - in_args.numBytes) );
p_block->p_buffer += out_args.bytesConsumed - i_extra;
p_block->i_buffer -= out_args.bytesConsumed - i_extra;
p_dec->fmt_out.video.i_width = status.outputWidth;
p_dec->fmt_out.video.i_height = status.outputHeight;
p_dec->fmt_out.video.i_aspect = VOUT_ASPECT_FACTOR * status.outputWidth
/ status.outputHeight; /* FIXME */
#ifndef DAVINCI_HACK
/* Get a new picture */
picture_t *p_pic = p_dec->pf_vout_buffer_new( p_dec );
if( !p_pic )
{
msg_Err( p_dec, "Could not get picture" );
goto error;
}
p_pic->b_progressive = status.contentType == IVIDEO_INTERLACED ? false
: true;
#endif
#ifdef DEBUG_DAVINCI
switch( out_args.decodedFrameType )
{
case IVIDEO_NA_FRAME:
msg_Dbg( p_dec, "Unknown frame type" );
break;
case IVIDEO_I_FRAME:
msg_Dbg( p_dec, "I frame" );
break;
case IVIDEO_P_FRAME:
msg_Dbg( p_dec, "P frame" );
break;
case IVIDEO_B_FRAME:
msg_Dbg( p_dec, "B frame" );
break;
case IVIDEO_II_FRAME:
msg_Dbg( p_dec, "Interlaced I frame" );
break;
case IVIDEO_PP_FRAME:
msg_Dbg( p_dec, "Interlaced P frame" );
break;
case IVIDEO_BB_FRAME:
msg_Dbg( p_dec, "Interlaced B frame" );
break;
default:
msg_Dbg( p_dec, "Other frame type: %d", (int)out_args.decodedFrameType );
break;
}
#endif
#ifndef DAVINCI_HACK
/* Copy stuff to picture here */
assert( p_pic->i_planes == p_sys->out.numBufs );
for( i = 0; i < p_pic->i_planes; i++ )
{
plane_t *p = p_pic->p+i;
memcpy( p->p_pixels, p_sys->out.bufs[i], p->i_pitch * p->i_visible_lines );
}
p_pic->date = p_block->i_pts > 0 ? p_block->i_pts : p_block->i_dts;
if( p_block->i_buffer == 0 )
{
block_Release( p_block );
*pp_block = NULL;
}
#else
vlc_mutex_lock( &p_sys->cb_lock );
bool b_resize = p_sys->b_resize;
vlc_mutex_unlock( &p_sys->cb_lock );
Resize( p_dec, b_resize, &p_sys->rsz, &p_sys->fb, p_sys->out );
if( !b_resize || p_sys->fb.var_info.xres != p_sys->rsz.i_out_width )
{
uint32_t black = 0x88888888; /* for vout YUYV */
/* fb */
/* output top & bottom black */
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->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->rsz.i_out_height) / 2;
int i,j;
for( i=0; i < i_nlines ; i++ )
{
/* draw black lines */
if( i >= i_nlines - i_edgeborder || i < i_edgeborder )
{
int lim = i_line_len / 4;
for( j=0; j < lim; j++ )
((uint32_t*)p_sys->fb.p_map)[i*lim+j] = black;
}
else /* draw video */
{
assert(p_sys->out.numBufs == 1);
/* draw a line */
int i_vidw_pad = (i_vidw + 15) & ~15;
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->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->fb.p_map)[i * i_line_len / 4 + p]= black;
}
}
}
#endif
#ifndef DAVINCI_HACK
return p_pic;
#else
block_Release( p_block );
*pp_block = NULL;
return NULL; /* Do not feed the video output */
#endif
error:
#ifndef DAVINCI_HACK
if( p_pic && p_pic->pf_release )
p_pic->pf_release( p_pic );
#endif
block_Release( p_block );
return NULL;
}
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