Commit af806199 authored by Jean-Paul Saman's avatar Jean-Paul Saman

davinci: video1_encoder.c: XDM 1.0 video encoder (not tested)

Add an XDM 1.0 video encoder to modules/codec/davinci.c. This code
is simply copied from XDM 0.9 video_encoder.c and needs to be further
adapted for use with an XDM 1.0 video encoder.
parent 7b740bd1
/*****************************************************************************
* encoder.c: video encoder module using the DaVinci DSP.
*****************************************************************************
* Copyright (C) 2010 M2X BV
* $Id$
*
* Authors: 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_vout.h>
#include <vlc_aout.h>
#include <vlc_sout.h>
#include <vlc_codec.h>
#include "davinci.h"
/* XDM 1.0 */
#include <ti/sdo/ce/video1/videnc1.h>
#include <assert.h>
/*****************************************************************************
* Local prototypes
*****************************************************************************/
/* XDM 1.0 */
static block_t *EncodeVideo1( encoder_t *, aout_buffer_t * );
static int GetVideo1EncoderSettings( encoder_t *p_enc, const char *psz_codec );
/*****************************************************************************
* Encoder
*****************************************************************************/
struct xdm_sys_t
{
/* XDM 1.0 */
VIDENC1_Handle handle;
AUDENC1_Params params;
AUDENC1_DynamicParams dparams;
XDM1_BufDesc in;
XDM1_BufDesc out;
VIDENC_InArgs in_args;
VIDENC_OutArgs out_args;
};
/*****************************************************************************
*
*****************************************************************************/
int OpenEncoderVideo( encoder_t *p_enc )
{
encoder_sys_t *p_sys = p_enc->p_sys;
xdm_sys_t *xdm;
p_sys->xdm = xdm = (xdm_sys_t *) calloc( 1, sizeof( xdm_sys_t ) );
if( !p_sys->xdm )
return VLC_ENOMEM;
/* */
xdm->dparams.size = sizeof( xdm->dparams );
memset( &xdm->in_args, 0, sizeof( xdm->in_args ) );
xdm->in_args.size = sizeof( xdm->in_args );
memset( &xdm->out_args, 0, sizeof( xdm->out_args ) );
xdm->out_args.size = sizeof( xdm->out_args );
/* */
if( GetVideoEncoderSettings( p_enc, p_sys->psz_codec ) != VLC_SUCCESS )
goto error;
p_sys->pf_encode_video = EncodeVideo;
return VLC_SUCCESS;
error:
free( p_sys->xdm );
p_sys->xdm = NULL;
return VLC_EGENERIC;
}
void CloseEncoderVideo( encoder_t *p_enc )
{
encoder_sys_t *p_sys = p_enc->p_sys;
xdm_sys_t *xdm = p_sys->xdm;
if( !xdm ) return;
/* Delete video encoder */
if( p_enc->fmt_out.i_cat == VIDEO_ES )
VIDENC1_delete( xdm->handle );
/* Free 'DaVinci compliant' buffers */
davinci_FreeBuffer1( &xdm->in );
davinci_FreeBuffer1( &xdm->out );
free( xdm );
xdm = NULL;
}
/*****************************************************************************
* Video Encoder: XDM 1.0 API
*****************************************************************************/
static int GetVideoEncoderSettings( encoder_t *p_enc, const char *psz_codec )
{
encoder_sys_t *p_sys = p_enc->p_sys;
xdm_sys_t *xdm = p_sys->xdm;
VIDENC1_Params params;
p_enc->i_iframes = var_CreateGetInteger( p_enc, ENC_CFG_PREFIX "keyint" );
p_enc->i_tolerance = var_CreateGetInteger( p_enc, ENC_CFG_PREFIX "tolerance" );
p_enc->i_tolerance *= 1024; /* bits per second */
#ifdef DEBUG_FPS
p_sys->i_fps = p_enc->i_iframes;
#endif
/* Configure encoder */
params.size = sizeof( params );
switch( var_CreateGetInteger( p_enc, ENC_CFG_PREFIX "quality" ) )
{
case 1: params.encodingPreset = XDM_HIGH_QUALITY; break;
case 2: params.encodingPreset = XDM_HIGH_SPEED; break;
case 3: params.encodingPreset = XDM_USER_DEFINED; break;
default:
params.encodingPreset = XDM_DEFAULT;
break;
}
switch( var_CreateGetInteger( p_enc, ENC_CFG_PREFIX "rc" ) )
{
case 1: params.rateControlPreset = IVIDEO_LOW_DELAY; break;
case 2: params.rateControlPreset = IVIDEO_STORAGE; break;
case 3: params.rateControlPreset = IVIDEO_TWOPASS; break;
case 4: params.rateControlPreset = IVIDEO_NONE; break;
case 5: params.rateControlPreset = IVIDEO_USER_DEFINED; break;
default:
params.rateControlPreset = IVIDEO_RATECONTROLPRESET_DEFAULT;
break;
}
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 :
50000; /* Frames per 1000 seconds */
params.maxBitRate = p_enc->fmt_out.i_bitrate
+ p_enc->i_tolerance;
params.dataEndianness = XDM_BYTE;
params.maxInterFrameInterval = 0; /* NOTE: should be null */
params.inputChromaFormat = VlcChromaToXdm( p_enc->fmt_in.i_codec );
msg_Info( p_enc, "max %dx%d at %.3f fps (max bitrate %d kBps, I-Frame interval %d)\n",
(int)params.maxWidth, (int)params.maxHeight,
((float)params.maxFrameRate)/1000.,
((int)params.maxBitRate) / (8*1024),
(int)p_enc->i_iframes );
if( params.inputChromaFormat == XDM_CHROMA_NA )
{
msg_Warn( p_enc, "Unsupported input chroma (%4.4s), forcing I420.",
(const char *)&p_enc->fmt_in.i_codec );
params.inputChromaFormat = VlcChromaToXdm( VLC_FOURCC('I','4','2','0' ) );
}
/* NOTE: we don't know if it's progressive or interlaced
* until we get the first picture (p_pic->b_progressive).
* Thus let a knowledgeable user override this setting. */
if( var_CreateGetBool( p_enc, ENC_CFG_PREFIX "interlace" ) )
params.inputContentType = IVIDEO_INTERLACED;
else
params.inputContentType = IVIDEO_PROGRESSIVE;
/* Create encoder handle */
xdm->handle = VIDENC1_create( p_sys->engine, (String)psz_codec, &params );
if( !xdm->handle )
return VLC_EGENERIC;
return VLC_SUCCESS;
}
static inline void davinci_CopyPictureToXDM1(XDM1_BufDesc *p_buf, picture_t *p_pic )
{
/* Copy input picture */
assert( p_pic->i_planes == p_buf->numBufs );
assert( p_pic->i_planes == 1 );
for( int i = 0; i < p_pic->i_planes; i++ )
{
plane_t *p = p_pic->p + i;
memcpy( p_buf->bufs[i], p->p_pixels, p->i_pitch * p->i_visible_lines );
}
}
static int davinci_SetDynamicParams( encoder_t *p_enc )
{
encoder_sys_t *p_sys = p_enc->p_sys;
xdm_sys_t *xdm = p_sys->xdm;
VIDENC1_Status status;
memset( &status, 0, sizeof( status ) );
status.size = sizeof( status );
/* Configue the encoder */
xdm->dparams.inputHeight = p_enc->fmt_in.video.i_height;
xdm->dparams.inputWidth = p_enc->fmt_in.video.i_width;
xdm->dparams.refFrameRate = (p_enc->fmt_out.video.i_frame_rate_base != 0) ?
(p_enc->fmt_out.video.i_frame_rate * 1000) /
p_enc->fmt_out.video.i_frame_rate_base :
p_enc->i_iframes * 1000; /* Frames per 1000 seconds */
xdm->dparams.targetFrameRate = xdm->dparams.refFrameRate; /* input fps = output fps */
xdm->dparams.targetBitRate = p_enc->fmt_out.i_bitrate;
xdm->dparams.intraFrameInterval = p_enc->i_iframes;
xdm->dparams.generateHeader = XDM_ENCODE_AU; /* don't encode only the header */
xdm->dparams.captureWidth = 0;
xdm->dparams.forceIFrame = 1;
msg_Dbg( p_enc, "using %dx%d at %.3f fps (bitrate %d kBps, I-Frame interval %d)\n",
(int)xdm->dparams.inputWidth, (int)xdm->dparams.inputHeight,
((float)xdm->dparams.targetFrameRate)/1000.,
((int)xdm->dparams.targetBitRate) >> 13 /* / (8*1024)*/,
(int)xdm->dparams.intraFrameInterval );
if( VIDENC1_control( xdm->handle, XDM_SETPARAMS, &xdm->dparams, &status )
!= VIDENC_EOK )
{
msg_Err( p_enc, "Failed to set encoder parameters." );
return VLC_EGENERIC;
}
return VLC_SUCCESS;
}
static int davinci_InitVideoBuffers( encoder_t *p_enc )
{
encoder_sys_t *p_sys = p_enc->p_sys;
xdm_sys_t *xdm = p_sys->xdm;
int i_ret = VLC_SUCCESS;
VIDENC1_Status status;
memset( &status, 0, sizeof( status ) );
status.size = sizeof( status );
/* Configure buffers */
if( VIDENC1_control( xdm->handle, XDM_GETBUFINFO, &xdm->dparams, &status )
!= VIDENC_EOK )
{
msg_Err( p_enc, "Failed to get buffer info" );
return VLC_EGENERIC;
}
/* Allocate input buffer(s) */
if( (i_ret = davinci_AllocateBuffer1( status.bufInfo.minNumInBufs,
status.bufInfo.minInBufSize, &xdm->in ))
!= VLC_SUCCESS )
{
msg_Err( p_enc, "Failed to allocate input buffers" );
return i_ret;
}
/* Allocate output buffer */
if( (i_ret = davinci_AllocateBuffer1( status.bufInfo.minNumOutBufs,
status.bufInfo.minOutBufSize, &xdm->out ))
!= VLC_SUCCESS )
{
msg_Err( p_enc, "Failed to allocate output buffers" );
return i_ret;
}
return i_ret;
}
static block_t *EncodeVideo( encoder_t *p_enc, picture_t *p_pic )
{
encoder_sys_t *p_sys = p_enc->p_sys;
xdm_sys_t *xdm = p_sys->xdm;
block_t *p_block;
int i_ret;
if( xdm->in.numBufs == 0 || xdm->out.numBufs == 0 )
{
if( davinci_SetDynamicParams( p_enc ) != VLC_SUCCESS )
msg_Err( p_enc, "Encoding continues with previous settings" );
if( davinci_InitVideoBuffers( p_enc ) != VLC_SUCCESS )
return NULL;
}
else if( p_sys->i_pics >= p_enc->i_iframes )
{
if( davinci_SetDynamicParams( p_enc ) != VLC_SUCCESS )
msg_Err( p_enc, "Encoding continues with previous settings" );
p_sys->i_pics = 0;
}
p_sys->i_pics++;
davinci_CopyPictureToXDM1( &xdm->in, p_pic );
/* Encode the video */
i_ret = VIDENC1_process( xdm->handle, &xdm->in, &xdm->out,
&xdm->in_args, &xdm->out_args );
if( i_ret != VIDENC_EOK )
{
msg_Err( p_enc, "Video encoding failed (%d): %s", i_ret,
davinci_GetExtendedError( xdm->out_args.extendedError ) );
return NULL;
}
/* Print some info */
//msg_Dbg( p_enc, "Bytes generated: %d", (int)out_args.bytesGenerated );
#ifdef DEBUG_FPS
calculate_fps( p_enc );
#endif
/* Put everything in the block */
if( xdm->out_args.bytesGenerated <= 0 )
return NULL;
p_block = block_New( p_enc, xdm->out_args.bytesGenerated );
if( !p_block )
return NULL;
memcpy( p_block->p_buffer, xdm->out.bufs[0], xdm->out_args.bytesGenerated );
switch( xdm->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 = INT64_C(1000000) *
p_enc->fmt_in.video.i_frame_rate_base /
p_enc->fmt_in.video.i_frame_rate;
return p_block;
}
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