* transcode.c
*****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN
- * $Id: transcode.c,v 1.28 2003/07/30 02:00:58 fenrir Exp $
+ * $Id: transcode.c,v 1.29 2003/08/09 14:59:24 gbazin Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
static void transcode_video_ffmpeg_close ( sout_stream_t *, sout_stream_id_t * );
static int transcode_video_ffmpeg_process( sout_stream_t *, sout_stream_id_t *, sout_buffer_t *, sout_buffer_t ** );
+static int transcode_video_ffmpeg_getframebuf( struct AVCodecContext *, AVFrame *);
+
/*****************************************************************************
* Module descriptor
*****************************************************************************/
int i_vtolerance;
int i_width;
int i_height;
+ int i_b_frames;
int i_key_int;
int i_qmin;
int i_qmax;
int i_crop_bottom;
int i_crop_right;
int i_crop_left;
+
+ mtime_t i_input_pts;
+ mtime_t i_output_pts;
+ mtime_t i_last_ref_pts;
+
+ mtime_t i_buggy_pts_detect;
};
/*****************************************************************************
p_sys->i_width = 0;
p_sys->i_height = 0;
p_sys->i_key_int = -1;
+ p_sys->i_b_frames = 0;
p_sys->i_qmin = 2;
p_sys->i_qmax = 31;
#if LIBAVCODEC_BUILD >= 4673
{
p_sys->i_key_int = atoi( val );
}
+ if( ( val = sout_cfg_find_value( p_stream->p_cfg, "bframes" ) ) )
+ {
+ p_sys->i_b_frames = atoi( val );
+ }
#if LIBAVCODEC_BUILD >= 4673
if( ( val = sout_cfg_find_value( p_stream->p_cfg, "hq" ) ) )
{
avcodec_init();
avcodec_register_all();
+ /* ffmpeg needs some padding at the end of each buffer */
+ p_stream->p_sout->i_padding += FF_INPUT_BUFFER_PADDING_SIZE;
+
return VLC_SUCCESS;
}
id->ff_dec_c->extradata = id->f_src.p_extra_data;
id->ff_dec_c->workaround_bugs = FF_BUG_AUTODETECT;
id->ff_dec_c->error_resilience= -1;
- if( id->ff_dec->capabilities & CODEC_CAP_TRUNCATED )
- {
- id->ff_dec_c->flags |= CODEC_FLAG_TRUNCATED;
- }
+ id->ff_dec_c->get_buffer = transcode_video_ffmpeg_getframebuf;
+ id->ff_dec_c->opaque = p_sys;
if( avcodec_open( id->ff_dec_c, id->ff_dec ) < 0 )
{
{
int b_gotpicture;
AVFrame frame;
-
- avcodec_decode_video( id->ff_dec_c, &frame,
- &b_gotpicture,
- id->ff_dec_c->extradata, id->ff_dec_c->extradata_size );
+ uint8_t *p_vol = malloc( id->ff_dec_c->extradata_size +
+ FF_INPUT_BUFFER_PADDING_SIZE );
+
+ memcpy( p_vol, id->ff_dec_c->extradata,
+ id->ff_dec_c->extradata_size );
+ memset( p_vol + id->ff_dec_c->extradata_size, 0,
+ FF_INPUT_BUFFER_PADDING_SIZE );
+
+ avcodec_decode_video( id->ff_dec_c, &frame, &b_gotpicture,
+ id->ff_dec_c->extradata,
+ id->ff_dec_c->extradata_size );
+ free( p_vol );
}
}
id->ff_enc_c->width = id->f_dst.i_width;
id->ff_enc_c->height = id->f_dst.i_height;
id->ff_enc_c->bit_rate = id->f_dst.i_bitrate;
+
+ if( id->ff_dec )
+ {
+ id->ff_enc_c->frame_rate = id->ff_dec_c->frame_rate;
+#if LIBAVCODEC_BUILD >= 4662
+ id->ff_enc_c->frame_rate_base= id->ff_dec_c->frame_rate_base;
+#endif
+ }
+ else
+ {
#if LIBAVCODEC_BUILD >= 4662
- id->ff_enc_c->frame_rate = 25 ; /* FIXME as it break mpeg */
- id->ff_enc_c->frame_rate_base= 1;
+ id->ff_enc_c->frame_rate = 25 ; /* FIXME as it break mpeg */
+ id->ff_enc_c->frame_rate_base= 1;
#else
- id->ff_enc_c->frame_rate = 25 * FRAME_RATE_BASE;
+ id->ff_enc_c->frame_rate = 25 * FRAME_RATE_BASE;
#endif
+ }
+
id->ff_enc_c->gop_size = p_sys->i_key_int >= 0 ? p_sys->i_key_int : 50;
+ id->ff_enc_c->max_b_frames = __MIN( p_sys->i_b_frames, FF_MAX_B_FRAMES );
+ id->ff_enc_c->b_frame_strategy = 0;
+ id->ff_enc_c->b_quant_factor = 2.0;
if( p_sys->i_vtolerance >= 0 )
{
id->p_ff_pic_tmp1 = NULL;
id->p_ff_pic_tmp2 = NULL;
id->p_vresample = NULL;
+
+ p_sys->i_last_ref_pts = 0;
+ p_sys->i_buggy_pts_detect = 0;
+
return VLC_SUCCESS;
}
free( id->p_buffer );
}
-static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_id_t *id,
- sout_buffer_t *in, sout_buffer_t **out )
+static int transcode_video_ffmpeg_process( sout_stream_t *p_stream,
+ sout_stream_id_t *id, sout_buffer_t *in, sout_buffer_t **out )
{
sout_stream_sys_t *p_sys = p_stream->p_sys;
int i_used;
{
/* decode frame */
frame = id->p_ff_pic;
+ p_sys->i_input_pts = in->i_pts;
if( id->ff_dec )
{
i_used = avcodec_decode_video( id->ff_dec_c, frame,
id->ff_dec_c->width, id->ff_dec_c->height );
i_used = i_data;
b_gotpicture = 1;
+
+ /* Set PTS */
+ frame->pts = p_sys->i_input_pts;
}
if( i_used < 0 )
return VLC_SUCCESS;
}
+ /* Get the pts of the decoded frame if any, otherwise keep the
+ * interpolated one */
+ if( frame->pts > 0 )
+ {
+ p_sys->i_output_pts = frame->pts;
+ }
+
if( !id->b_enc_inited )
{
/* XXX hack because of copy packetizer and mpeg4video that can failed
p_stream->p_sys->i_crop_right );
}
- img_resample( id->p_vresample, (AVPicture*)id->p_ff_pic_tmp2, (AVPicture*)frame );
+ img_resample( id->p_vresample, (AVPicture*)id->p_ff_pic_tmp2,
+ (AVPicture*)frame );
frame = id->p_ff_pic_tmp2;
}
- i_out = avcodec_encode_video( id->ff_enc_c, id->p_buffer, id->i_buffer, frame );
+ /* Set the pts of the frame being encoded */
+ frame->pts = p_sys->i_output_pts;
+
+ /* Interpolate the next PTS
+ * (needed by the mpeg video packetizer which can send pts <= 0 ) */
+ if( id->ff_dec_c && id->ff_dec_c->frame_rate > 0 )
+ {
+ p_sys->i_output_pts += I64C(1000000) * (2 + frame->repeat_pict) *
+ id->ff_dec_c->frame_rate_base / (2 * id->ff_dec_c->frame_rate);
+ }
+
+ /* Let ffmpeg select the frame type */
+ frame->pict_type = 0;
+
+ i_out = avcodec_encode_video( id->ff_enc_c, id->p_buffer,
+ id->i_buffer, frame );
if( i_out > 0 )
{
sout_buffer_t *p_out;
memcpy( p_out->p_buffer, id->p_buffer, i_out );
p_out->i_size = i_out;
- p_out->i_length = in->i_length;
- p_out->i_dts = in->i_dts;
- p_out->i_pts = in->i_dts; /* FIXME */
+
+ if( id->ff_enc_c->coded_frame->pts != 0 &&
+ p_sys->i_buggy_pts_detect != id->ff_enc_c->coded_frame->pts )
+ {
+ p_sys->i_buggy_pts_detect = id->ff_enc_c->coded_frame->pts;
+
+ /* FIXME, 3-2 pulldown is not handled correctly */
+ p_out->i_length = in->i_length;
+ p_out->i_pts = id->ff_enc_c->coded_frame->pts;
+
+ if( !id->ff_enc_c->delay ||
+ ( id->ff_enc_c->coded_frame->pict_type != FF_I_TYPE &&
+ id->ff_enc_c->coded_frame->pict_type != FF_P_TYPE ) )
+ {
+ p_out->i_dts = p_out->i_pts;
+ }
+ else
+ {
+ if( p_sys->i_last_ref_pts )
+ {
+ p_out->i_dts = p_sys->i_last_ref_pts;
+ }
+ else
+ {
+ /* Let's put something sensible */
+ p_out->i_dts = p_out->i_pts;
+ }
+
+ p_sys->i_last_ref_pts = p_out->i_pts;
+ }
+ }
+ else
+ {
+ /* Buggy libavcodec which doesn't update coded_frame->pts
+ * correctly */
+ p_out->i_length = in->i_length;
+ p_out->i_dts = in->i_dts;
+ p_out->i_pts = in->i_dts;
+ }
sout_BufferChain( out, p_out );
}
return VLC_SUCCESS;
}
+
+/*****************************************************************************
+ * transcode_video_ffmpeg_getframebuf:
+ *
+ * Callback used by ffmpeg to get a frame buffer.
+ * We use it to get the right PTS for each decoded picture.
+ *****************************************************************************/
+static int transcode_video_ffmpeg_getframebuf(struct AVCodecContext *p_context,
+ AVFrame *p_frame)
+{
+ sout_stream_sys_t *p_sys = (sout_stream_sys_t *)p_context->opaque;
+
+ /* Set PTS */
+ p_frame->pts = p_sys->i_input_pts;
+
+ return avcodec_default_get_buffer( p_context, p_frame );
+}
* stream_output.c : stream output module
*****************************************************************************
* Copyright (C) 2002 VideoLAN
- * $Id: stream_output.c,v 1.32 2003/08/01 18:42:56 fenrir Exp $
+ * $Id: stream_output.c,v 1.33 2003/08/09 14:59:24 gbazin Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Laurent Aimar <fenrir@via.ecp.fr>
/* *** init descriptor *** */
p_sout->psz_sout = strdup( psz_dest );
p_sout->i_preheader = 0;
+ p_sout->i_padding = 0;
p_sout->p_sys = NULL;
vlc_mutex_init( p_sout, &p_sout->lock );
return( p_fifo );
}
-void sout_FifoFree( sout_instance_t *p_sout, sout_fifo_t *p_fifo )
+void sout_FifoFree( sout_instance_t *p_sout, sout_fifo_t *p_fifo )
{
sout_buffer_t *p_buffer;
return;
}
-void sout_FifoDestroy( sout_instance_t *p_sout, sout_fifo_t *p_fifo )
+void sout_FifoDestroy( sout_instance_t *p_sout, sout_fifo_t *p_fifo )
{
sout_FifoFree( p_sout, p_fifo );
vlc_mutex_destroy( &p_fifo->lock );
free( p_fifo );
}
-void sout_FifoPut( sout_fifo_t *p_fifo, sout_buffer_t *p_buffer )
+void sout_FifoPut( sout_fifo_t *p_fifo, sout_buffer_t *p_buffer )
{
vlc_mutex_lock( &p_fifo->lock );
sout_buffer_t *sout_BufferNew( sout_instance_t *p_sout, size_t i_size )
{
sout_buffer_t *p_buffer;
- size_t i_preheader;
-
-#ifdef DEBUG_BUFFER
- msg_Dbg( p_sout, "allocating an new buffer, size:%d", (uint32_t)i_size );
-#endif
+ size_t i_preheader, i_padding;
p_buffer = malloc( sizeof( sout_buffer_t ) );
i_preheader = p_sout->i_preheader;
+ i_padding = p_sout->i_padding;
+
+#ifdef DEBUG_BUFFER
+ msg_Dbg( p_sout, "allocating an new buffer, size:%d, preheader:%d, "
+ "padding:%d", (uint32_t)i_size, i_preheader, i_padding );
+#endif
if( i_size > 0 )
{
- p_buffer->p_allocated_buffer = malloc( i_size + i_preheader );
+ p_buffer->p_allocated_buffer =
+ malloc( i_size + i_preheader + i_padding );
p_buffer->p_buffer = p_buffer->p_allocated_buffer + i_preheader;
+
+ if( p_buffer->p_allocated_buffer && i_padding )
+ memset( p_buffer->p_allocated_buffer + i_size + i_preheader, 0,
+ i_padding );
}
else
{
p_buffer->p_allocated_buffer = NULL;
p_buffer->p_buffer = NULL;
}
- p_buffer->i_allocated_size = i_size + i_preheader;
+ p_buffer->i_allocated_size = i_size + i_preheader + i_padding;
p_buffer->i_buffer_size = i_size;
p_buffer->i_size = i_size;
return( p_buffer );
}
-int sout_BufferRealloc( sout_instance_t *p_sout, sout_buffer_t *p_buffer, size_t i_size )
+
+int sout_BufferRealloc( sout_instance_t *p_sout, sout_buffer_t *p_buffer,
+ size_t i_size )
{
- size_t i_preheader;
+ size_t i_preheader, i_padding;
+
+ i_preheader = p_buffer->p_buffer - p_buffer->p_allocated_buffer;
+ i_padding = p_buffer->i_allocated_size - p_buffer->i_buffer_size
+ - i_preheader;
#ifdef DEBUG_BUFFER
- msg_Dbg( p_sout,
- "realloc buffer old size:%d new size:%d",
- (uint32_t)p_buffer->i_allocated_size,
- (uint32_t)i_size );
+ msg_Dbg( p_sout, "realloc buffer old size:%d new size:%d, preheader:%d, "
+ "padding:%d", (uint32_t)p_buffer->i_allocated_size,
+ (uint32_t)i_size, i_preheader, i_padding );
#endif
- i_preheader = p_buffer->p_buffer - p_buffer->p_allocated_buffer;
-
- if( !( p_buffer->p_allocated_buffer = realloc( p_buffer->p_allocated_buffer, i_size + i_preheader ) ) )
+ if( !( p_buffer->p_allocated_buffer =
+ realloc( p_buffer->p_allocated_buffer,
+ i_size + i_preheader + i_padding ) ) )
{
msg_Err( p_sout, "realloc failed" );
p_buffer->i_allocated_size = 0;
}
p_buffer->p_buffer = p_buffer->p_allocated_buffer + i_preheader;
- p_buffer->i_allocated_size = i_size + i_preheader;
+ p_buffer->i_allocated_size = i_size + i_preheader + i_padding;
p_buffer->i_buffer_size = i_size;
+ if( i_padding )
+ memset( p_buffer->p_allocated_buffer + i_size + i_preheader, 0,
+ i_padding );
+
return( 0 );
}
-int sout_BufferReallocFromPreHeader( sout_instance_t *p_sout, sout_buffer_t *p_buffer, size_t i_size )
+int sout_BufferReallocFromPreHeader( sout_instance_t *p_sout,
+ sout_buffer_t *p_buffer, size_t i_size )
{
- size_t i_preheader;
+ size_t i_preheader;
i_preheader = p_buffer->p_buffer - p_buffer->p_allocated_buffer;