Commit 96de7fa2 authored by Antoine Cellerier's avatar Antoine Cellerier Committed by Jean-Paul Saman

Add DaVinci video encoder support. (Untested but compiles and links fine)

Signed-off-by: Jean-Paul Saman's avatarJean-Paul Saman <jean-paul.saman@m2x.nl>
parent a16542e6
......@@ -31,31 +31,24 @@
#include <xdc/std.h>
#include <ti/sdo/ce/osal/Memory.h>
#include <ti/sdo/ce/video/viddec.h>
#include <ti/sdo/ce/video/videnc.h>
#include <ti/sdo/ce/CERuntime.h>
#define DEBUG_DAVINCI
/*****************************************************************************
*
*****************************************************************************/
struct decoder_sys_t
{
Engine_Handle e;
VIDDEC_Handle d;
XDM_BufDesc in;
XDM_BufDesc out;
};
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int OpenVideoDecoder( vlc_object_t * );
static int OpenVideoDecoder( vlc_object_t * );
static void CloseVideoDecoder( vlc_object_t * );
static picture_t *DecodeVideoBlock( decoder_t *, block_t ** );
static int AllocateBuffer( decoder_t *, XDAS_Int32, XDAS_Int32 *, XDM_BufDesc * );
static int OpenVideoEncoder( vlc_object_t * );
static void CloseVideoEncoder( vlc_object_t * );
static block_t *EncodeVideo( encoder_t *, picture_t * );
static int __AllocateBuffer( vlc_object_t *, XDAS_Int32, XDAS_Int32 *, XDM_BufDesc * );
#define AllocateBuffer( a, b, c, d ) __AllocateBuffer( VLC_OBJECT( a ), b, c, d )
static void FreeBuffer( XDM_BufDesc * );
/*****************************************************************************
......@@ -67,8 +60,16 @@ vlc_module_begin();
set_description( _("DaVinci DSP video decoder") );
set_capability( "decoder", 1337 );
set_callbacks( OpenVideoDecoder, CloseVideoDecoder );
add_submodule();
set_description( _("DaVinci DSP video encoder" ) );
set_capability( "encoder", 1337 );
set_callbacks( OpenVideoEncoder, CloseVideoEncoder );
vlc_module_end();
/*****************************************************************************
* Common stuff
*****************************************************************************/
static const char *ppsz_engine_error[] = {
[Engine_EOK] = "Ok",
[Engine_EEXIST] = "Engine name doesn't exist",
......@@ -88,6 +89,97 @@ static const char *ppsz_engine_error[] = {
//[Engine_ENOTFOUND] = "Entity was not found",
};
/* FOURCC codes copied from libavcodec module */
#define CASE_MPEG1 \
case VLC_FOURCC('m','p','e','g'): \
case VLC_FOURCC('m','p','g','1'): \
case VLC_FOURCC('P','I','M','1'):
#define CASE_MPEG2 \
case VLC_FOURCC('m','p','g','v'): \
case VLC_FOURCC('m','p','2','v'): \
case VLC_FOURCC('M','P','E','G'): \
case VLC_FOURCC('m','p','g','2'): \
case VLC_FOURCC('h','d','v','1'): \
case VLC_FOURCC('h','d','v','2'): \
case VLC_FOURCC('h','d','v','3'): \
case VLC_FOURCC('h','d','v','5'): \
case VLC_FOURCC('m','x','5','n'): \
case VLC_FOURCC('m','x','5','p'): \
case VLC_FOURCC('m','x','4','n'): \
case VLC_FOURCC('m','x','4','p'): \
case VLC_FOURCC('m','x','3','n'): \
case VLC_FOURCC('m','x','3','p'): \
case VLC_FOURCC('x','d','v','2'): \
case VLC_FOURCC('A','V','m','p'): \
case VLC_FOURCC('V','C','R','2'): \
case VLC_FOURCC('M','M','E','S'): \
case VLC_FOURCC('m','m','e','s'):
#define CASE_MPEG4 \
case VLC_FOURCC('D','I','V','X'): \
case VLC_FOURCC('d','i','v','x'): \
case VLC_FOURCC('M','P','4','S'): \
case VLC_FOURCC('M','P','4','s'): \
case VLC_FOURCC('M','4','S','2'): \
case VLC_FOURCC('m','4','s','2'): \
case VLC_FOURCC('x','v','i','d'): \
case VLC_FOURCC('X','V','I','D'): \
case VLC_FOURCC('X','v','i','D'): \
case VLC_FOURCC('X','V','I','X'): \
case VLC_FOURCC('x','v','i','x'): \
case VLC_FOURCC('D','X','5','0'): \
case VLC_FOURCC('d','x','5','0'): \
case VLC_FOURCC('B','L','Z','0'): \
case VLC_FOURCC('B','X','G','M'): \
case VLC_FOURCC('m','p','4','v'): \
case VLC_FOURCC('M','P','4','V'): \
case VLC_FOURCC( 4 , 0 , 0 , 0 ): \
case VLC_FOURCC('m','4','c','c'): \
case VLC_FOURCC('M','4','C','C'): \
case VLC_FOURCC('F','M','P','4'): \
case VLC_FOURCC('f','m','p','4'): \
case VLC_FOURCC('3','I','V','2'): \
case VLC_FOURCC('3','i','v','2'): \
case VLC_FOURCC('U','M','P','4'): \
case VLC_FOURCC('W','V','1','F'): \
case VLC_FOURCC('S','E','D','G'): \
case VLC_FOURCC('R','M','P','4'): \
case VLC_FOURCC('H','D','X','4'): \
case VLC_FOURCC('h','d','x','4'): \
case VLC_FOURCC('S','M','P','4'): \
case VLC_FOURCC('f','v','f','w'): \
case VLC_FOURCC('F','V','F','W'):
#define CASE_H264 \
case VLC_FOURCC('a','v','c','1'): \
case VLC_FOURCC('A','V','C','1'): \
case VLC_FOURCC('h','2','6','4'): \
case VLC_FOURCC('H','2','6','4'): \
case VLC_FOURCC('x','2','6','4'): \
case VLC_FOURCC('X','2','6','4'): \
case VLC_FOURCC('V','S','S','H'): \
case VLC_FOURCC('V','S','S','W'): \
case VLC_FOURCC('v','s','s','h'): \
case VLC_FOURCC('D','A','V','C'): \
case VLC_FOURCC('d','a','v','c'):
#define CASE_VC1 \
case VLC_FOURCC('W','V','C','1'): \
case VLC_FOURCC('w','v','c','1'):
/*****************************************************************************
* Video decoder
*****************************************************************************/
struct decoder_sys_t
{
Engine_Handle e;
VIDDEC_Handle d;
XDM_BufDesc in;
XDM_BufDesc out;
};
/*****************************************************************************
* OpenDecoder: probe the decoder and return score
*****************************************************************************/
......@@ -96,108 +188,31 @@ static int OpenVideoDecoder( vlc_object_t *p_this )
decoder_t *p_dec = (decoder_t*)p_this;
decoder_sys_t *p_sys;
Engine_Error err;
//IVIDEO_Format i_format;
const char *psz_codec;
VIDDEC_Params params;
switch( p_dec->fmt_in.i_codec )
{
/* FOURCC codes copied from libavcodec module */
#if 0
case VLC_FOURCC('m','p','e','g'):
case VLC_FOURCC('m','p','g','1'):
case VLC_FOURCC('P','I','M','1'):
//i_format = IVIDEO_MPEG1;
CASE_MPEG1
psz_codec = "mpegdec"; /* FIXME */
break;
#endif
case VLC_FOURCC('m','p','g','v'):
case VLC_FOURCC('m','p','2','v'):
case VLC_FOURCC('M','P','E','G'):
case VLC_FOURCC('m','p','g','2'):
case VLC_FOURCC('h','d','v','1'):
case VLC_FOURCC('h','d','v','2'):
case VLC_FOURCC('h','d','v','3'):
case VLC_FOURCC('h','d','v','5'):
case VLC_FOURCC('m','x','5','n'):
case VLC_FOURCC('m','x','5','p'):
case VLC_FOURCC('m','x','4','n'):
case VLC_FOURCC('m','x','4','p'):
case VLC_FOURCC('m','x','3','n'):
case VLC_FOURCC('m','x','3','p'):
case VLC_FOURCC('x','d','v','2'):
case VLC_FOURCC('A','V','m','p'):
case VLC_FOURCC('V','C','R','2'):
case VLC_FOURCC('M','M','E','S'):
case VLC_FOURCC('m','m','e','s'):
//i_format = IVIDEO_MPEG2SP;
//i_format = IVIDEO_MPEG2MP;
//i_format = IVIDEO_MPEG2HP;
CASE_MPEG2
psz_codec = "mpeg2dec";
break;
case VLC_FOURCC('D','I','V','X'):
case VLC_FOURCC('d','i','v','x'):
case VLC_FOURCC('M','P','4','S'):
case VLC_FOURCC('M','P','4','s'):
case VLC_FOURCC('M','4','S','2'):
case VLC_FOURCC('m','4','s','2'):
case VLC_FOURCC('x','v','i','d'):
case VLC_FOURCC('X','V','I','D'):
case VLC_FOURCC('X','v','i','D'):
case VLC_FOURCC('X','V','I','X'):
case VLC_FOURCC('x','v','i','x'):
case VLC_FOURCC('D','X','5','0'):
case VLC_FOURCC('d','x','5','0'):
case VLC_FOURCC('B','L','Z','0'):
case VLC_FOURCC('B','X','G','M'):
case VLC_FOURCC('m','p','4','v'):
case VLC_FOURCC('M','P','4','V'):
case VLC_FOURCC( 4 , 0 , 0 , 0 ):
case VLC_FOURCC('m','4','c','c'):
case VLC_FOURCC('M','4','C','C'):
case VLC_FOURCC('F','M','P','4'):
case VLC_FOURCC('f','m','p','4'):
case VLC_FOURCC('3','I','V','2'):
case VLC_FOURCC('3','i','v','2'):
case VLC_FOURCC('U','M','P','4'):
case VLC_FOURCC('W','V','1','F'):
case VLC_FOURCC('S','E','D','G'):
case VLC_FOURCC('R','M','P','4'):
case VLC_FOURCC('H','D','X','4'):
case VLC_FOURCC('h','d','x','4'):
case VLC_FOURCC('S','M','P','4'):
case VLC_FOURCC('f','v','f','w'):
case VLC_FOURCC('F','V','F','W'):
//i_format = IVIDEO_MPEG4SP;
//i_format = IVIDEO_MPEG4ASP;
CASE_MPEG4
psz_codec = "mpeg4dec";
break;
case VLC_FOURCC('a','v','c','1'):
case VLC_FOURCC('A','V','C','1'):
case VLC_FOURCC('h','2','6','4'):
case VLC_FOURCC('H','2','6','4'):
case VLC_FOURCC('x','2','6','4'):
case VLC_FOURCC('X','2','6','4'):
case VLC_FOURCC('V','S','S','H'):
case VLC_FOURCC('V','S','S','W'):
case VLC_FOURCC('v','s','s','h'):
case VLC_FOURCC('D','A','V','C'):
case VLC_FOURCC('d','a','v','c'):
//i_format = IVIDEO_H264BP;
//i_format = IVIDEO_H264MP;
//i_format = IVIDEO_H264HP;
CASE_H264
psz_codec = "h264dec";
break;
#if 0
case VLC_FOURCC('W','V','C','1'):
case VLC_FOURCC('w','v','c','1'):
//i_format = IVIDEO_VC1SP;
//i_format = IVIDEO_VC1MP;
//i_format = IVIDEO_VC1AP;
CASE_VC1
psz_codec = "vc1dec"; /* FIXME */
break;
#endif
......@@ -441,7 +456,8 @@ static picture_t *DecodeVideoBlock( decoder_t *p_dec, block_t **pp_block )
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 (Error code: %ld, Extended erorr: %lx)", i, out_args.extendedError );
msg_Err( p_dec, "Video decoding failed (Error code: %d, "
"Extended erorr: %x)", i, (int)out_args.extendedError );
goto error;
}
printf("%s %s %d\n", __FILE__, __func__, __LINE__);
......@@ -541,13 +557,343 @@ static picture_t *DecodeVideoBlock( decoder_t *p_dec, block_t **pp_block )
return NULL;
}
static int AllocateBuffer( decoder_t *p_dec, XDAS_Int32 i_num,
XDAS_Int32 *pi_sizes, XDM_BufDesc *buf )
/*****************************************************************************
* Video encoder
*****************************************************************************/
struct encoder_sys_t
{
Engine_Handle e;
VIDENC_Handle c;
XDM_BufDesc in;
XDM_BufDesc out;
};
/*****************************************************************************
*
*****************************************************************************/
static int OpenVideoEncoder( vlc_object_t *p_this )
{
encoder_t *p_enc = (encoder_t *)p_this;
encoder_sys_t *p_sys;
const char *psz_codec;
Engine_Error err;
VIDENC_Params params;
switch( p_enc->fmt_out.i_codec )
{
#if 0
CASE_MPEG1
psz_codec = "mpegenc"; /* FIXME */
break;
CASE_MPEG2
psz_codec = "mpeg2enc"; /* FIXME */
break;
#endif
CASE_MPEG4
psz_codec = "mpeg4enc";
break;
CASE_H264
psz_codec = "h264enc";
break;
#if 0
CASE_VC1
psz_codec = "vc1enc"; /* FIXME */
break;
#endif
default:
return VLC_EGENERIC;
}
/* Allocate our private structure */
p_enc->p_sys = (encoder_sys_t *)malloc( sizeof( encoder_sys_t ) );
if( !p_enc->p_sys )
{
return VLC_EGENERIC;
}
p_sys = p_enc->p_sys;
memset( p_sys, 0, sizeof( encoder_sys_t ) );
/* Initialize the codec engine */
CERuntime_init();
/* Create an engine handle */
p_sys->e = Engine_open( "encode", NULL /*&Engine_ATTRS*/, &err );
if( err != Engine_EOK )
{
msg_Err( p_enc, ppsz_engine_error[err] );
goto error;
}
/* Configure encoder */
params.size = sizeof( params );
params.encodingPreset = 0; /* Use default */
params.rateControlPreset = 0; /* Use default */
params.maxHeight = p_enc->fmt_in.video.i_height;
params.maxWidth = p_enc->fmt_in.video.i_width;
params.maxFrameRate = p_enc->fmt_out.video.i_frame_rate_base ?
p_enc->fmt_out.video.i_frame_rate * 1000 /
p_enc->fmt_out.video.i_frame_rate_base :
0; /* Frames per 1000 seconds */
params.maxBitRate = p_enc->fmt_out.i_bitrate
+ p_enc->i_tolerance; /* Bits per second. FIXME? */
params.dataEndianness = XDM_BYTE;
params.maxInterFrameInterval = p_enc->i_iframes; /* FIXME? */
switch( p_enc->fmt_in.video.i_chroma )
{
case VLC_FOURCC('I','4','2','0'):
params.inputChromaFormat = XDM_YUV_420P;
break;
case VLC_FOURCC('I','4','1','1'):
params.inputChromaFormat = XDM_YUV_411P;
break;
case VLC_FOURCC('I','4','2','2'):
params.inputChromaFormat = XDM_YUV_422P;
break;
case VLC_FOURCC('I','4','4','4'):
params.inputChromaFormat = XDM_YUV_444P;
break;
case VLC_FOURCC('Y','U','Y','V'):
params.inputChromaFormat = XDM_YUV_422IBE; /* FIXME ? */
break;
case VLC_FOURCC('U','Y','V','Y'):
params.inputChromaFormat = XDM_YUV_422ILE; /* FIXME ? */
break;
case VLC_FOURCC('G','R','E','Y'):
params.inputChromaFormat = XDM_GRAY;
break;
#if 0
/* FIXME: not sure about this one */
case VLC_FOURCC('R','V','2','4'):
case VLC_FOURCC('R','V','3','2'):
params.inputChromaFormat = XDM_RGB;
break;
#endif
default:
msg_Err( p_enc, "Unsupported input chroma (%4.4s).",
(const char *)&p_enc->fmt_in.video.i_chroma );
goto error;
}
params.inputContentType = IVIDEO_PROGRESSIVE; /* FIXME: we don't know if it's progressive or interlaced until we get the first picture (p_pic->b_progressive) */
/* Create encoder handle */
p_sys->c = VIDENC_create( p_sys->e, (String)psz_codec, &params );
if( !p_sys->c )
{
msg_Err( p_enc, "Failed to create video encoder (%s)", psz_codec );
goto error;
}
/* Initialize random stuff */
p_enc->pf_encode_video = EncodeVideo;
/* Holy bananas! We made it! */
msg_Info( p_enc, "Woohoooooooo!" );
return VLC_SUCCESS;
error:
if( p_sys->e ) Engine_close( p_sys->e );
free( p_sys );
return VLC_EGENERIC;
}
/*****************************************************************************
*
*****************************************************************************/
static void CloseVideoEncoder( vlc_object_t *p_this )
{
encoder_t *p_enc = (encoder_t *)p_this;
encoder_sys_t *p_sys = p_enc->p_sys;
/* Delete video encoder */
VIDENC_delete( p_sys->c );
/* Delete codec engine handle */
Engine_close( p_sys->e );
/* Exit the codec engine */
CERuntime_exit(); /* XXX: Should this be done only once (if we have encoder + decoder runing) */
/* Free 'DaVinci compliant' buffers */
FreeBuffer( &p_sys->in );
FreeBuffer( &p_sys->out );
free( p_sys );
}
/*****************************************************************************
*
*****************************************************************************/
static block_t *EncodeVideo( encoder_t *p_enc, picture_t *p_pic )
{
encoder_sys_t *p_sys = p_enc->p_sys;
block_t *p_block;
int i;
VIDENC_InArgs in_args;
VIDENC_OutArgs out_args;
if( p_sys->in.numBufs == 0 || p_sys->out.numBufs == 0 )
{
VIDENC_DynamicParams dparams;
VIDENC_Status status;
dparams.size = sizeof( dparams );
memset( &status, 0, sizeof( status ) );
status.size = sizeof( status );
/* Configue the encoder */
dparams.inputHeight = p_enc->fmt_in.video.i_height;
dparams.inputWidth = p_enc->fmt_in.video.i_width;
dparams.refFrameRate = p_enc->fmt_out.video.i_frame_rate_base ?
p_enc->fmt_out.video.i_frame_rate * 1000 /
p_enc->fmt_out.video.i_frame_rate_base :
30; /* Frames per 1000 seconds */
dparams.targetFrameRate = dparams.refFrameRate; /* FIXME? */
dparams.targetBitRate = p_enc->fmt_out.i_bitrate;
dparams.intraFrameInterval = p_enc->i_iframes;
dparams.generateHeader = XDM_ENCODE_AU; /* FIXME? */
dparams.captureWidth = p_pic->p->i_pitch / p_pic->p->i_pixel_pitch; /* FIXME? */
dparams.forceIFrame = 0;
if( VIDENC_control( p_sys->c, XDM_SETPARAMS, &dparams, &status )
!= VIDENC_EOK )
{
msg_Err( p_enc, "Failed to set encoder parameters" );
goto error;
}
/* Configure buffers */
if( VIDENC_control( p_sys->c, XDM_GETBUFINFO, &dparams, &status )
!= VIDENC_EOK )
{
msg_Err( p_enc, "Failed to get buffer info" );
goto error;
}
/* Allocate input buffer(s) */
if( AllocateBuffer( p_enc, status.bufInfo.minNumInBufs,
status.bufInfo.minInBufSize, &p_sys->in )
!= VLC_SUCCESS )
{
msg_Err( p_enc, "Failed to allocate input buffers" );
goto error;
}
/* Allocate output buffer */
if( AllocateBuffer( p_enc, status.bufInfo.minNumOutBufs,
status.bufInfo.minOutBufSize, &p_sys->out )
!= VLC_SUCCESS )
{
msg_Err( p_enc, "Failed to allocate input buffers" );
goto error;
}
}
/* Copy input picture */
if( p_pic->i_planes != p_sys->in.numBufs )
{
msg_Err( p_enc, "Ahem ... looks like I assumed something wrong. Please investigate." );
goto error;
}
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 );
}
/* Configure input */
in_args.size = sizeof( in_args );
/* Heh, that was useless ... */
/* Configure output */
memset( &out_args, 0, sizeof( out_args ) );
out_args.size = sizeof( out_args );
/* Encode the video */
i = VIDENC_process( p_sys->c, &p_sys->in, &p_sys->out,
&in_args, &out_args );
if( i != VIDENC_EOK )
{
msg_Err( p_enc, "Video encoding failed (Error code: %d, "
"Extended erorr: %x)", i, (int)out_args.extendedError );
goto error;
}
/* Print some info */
msg_Info( p_enc, "Encoder info:" );
msg_Info( p_enc, " Bytes generated: %d", (int)out_args.bytesGenerated );
/* Put everything in the block */
if( out_args.bytesGenerated <= 0 )
goto error;
p_block = block_New( p_enc, out_args.bytesGenerated );
if( !p_block ) goto error;
memcpy( p_block->p_buffer, p_sys->out.bufs[0], out_args.bytesGenerated );
switch( out_args.encodedFrameType )
{
case IVIDEO_I_FRAME:
case IVIDEO_II_FRAME:
p_block->i_flags |= BLOCK_FLAG_TYPE_I;
break;
case IVIDEO_P_FRAME:
case IVIDEO_PP_FRAME:
p_block->i_flags |= BLOCK_FLAG_TYPE_P;
break;
case IVIDEO_B_FRAME:
case IVIDEO_BB_FRAME:
p_block->i_flags |= BLOCK_FLAG_TYPE_B;
break;
default:
msg_Warn( p_enc, "Unknown frame type" );
p_block->i_flags |= BLOCK_FLAG_TYPE_PB; /* Wild guess */
break;
}
p_block->i_dts = p_block->i_pts = p_pic->date;
/* Shamelessly copied from ffmpeg/encoder.c */
p_block->i_length = I64C(1000000) *
p_enc->fmt_in.video.i_frame_rate_base /
p_enc->fmt_in.video.i_frame_rate;
/* Looks like we're done */
#ifdef DEBUG_DAVINCI
msg_Info( p_enc, "Yay! Frame encoded correctly" );
#endif
return p_block;
error:
return NULL;
}
/*****************************************************************************
* Misc utils
*****************************************************************************/
static int __AllocateBuffer( vlc_object_t *p_this, XDAS_Int32 i_num,
XDAS_Int32 *pi_sizes, XDM_BufDesc *buf )
{
int i;
#ifdef DEBUG_DAVINCI
msg_Info( p_dec, "Allocating buffers:" );
msg_Info( p_this, "Allocating buffers:" );
#endif
buf->numBufs = i_num;
......@@ -569,14 +915,14 @@ static int AllocateBuffer( decoder_t *p_dec, XDAS_Int32 i_num,
for( i = 0; i < i_num; i++ )
{
#ifdef DEBUG_DAVINCI
msg_Info( p_dec, " %d: size %d Bytes", i, (int)pi_sizes[i] );
msg_Info( p_this, " %d: size %d Bytes", i, (int)pi_sizes[i] );
#endif
buf->bufSizes[i] = pi_sizes[i];
buf->bufs[i] = Memory_contigAlloc( pi_sizes[i], Memory_DEFAULTALIGNMENT );
if( !buf->bufs[i] )
{
#ifdef DEBUG_DAVINCI
msg_Err( p_dec, "Failed to allocate buffer" );
msg_Err( p_this, "Failed to allocate buffer" );
#endif
for( i--; i >= 0; i-- )
{
......
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