Commit d9069191 authored by Gildas Bazin's avatar Gildas Bazin

* src/stream_output/stream_output.c, include/stream_output.h: added an i_padding field to sout_instance_t so we can allocate sout_buffers with a bit more space than asked for (needed for ffmpeg decoding).
* modules/stream_out/transcode.c: proper pts/dts generation. This allows the transcoder module to finally generate proper streams.
   Added support for b frames (bframe=x option) + couple of bug fixes.
parent b3b99a16
......@@ -2,7 +2,7 @@
* stream_output.h : stream output module
*****************************************************************************
* Copyright (C) 2002 VideoLAN
* $Id: stream_output.h,v 1.11 2003/07/31 19:14:59 fenrir Exp $
* $Id: stream_output.h,v 1.12 2003/08/09 14:59:24 gbazin Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Laurent Aimar <fenrir@via.ecp.fr>
......@@ -243,6 +243,8 @@ struct sout_instance_t
/* muxer data */
int i_preheader; /* max over all muxer */
int i_padding; /* needed by some decoders */
vlc_mutex_t lock;
sout_stream_t *p_stream;
......
......@@ -2,7 +2,7 @@
* 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>
*
......@@ -64,6 +64,8 @@ static int transcode_video_ffmpeg_new ( sout_stream_t *, sout_stream_id_t *
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
*****************************************************************************/
......@@ -88,6 +90,7 @@ struct sout_stream_sys_t
int i_vtolerance;
int i_width;
int i_height;
int i_b_frames;
int i_key_int;
int i_qmin;
int i_qmax;
......@@ -98,6 +101,12 @@ struct sout_stream_sys_t
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;
};
/*****************************************************************************
......@@ -123,6 +132,7 @@ static int Open( vlc_object_t *p_this )
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
......@@ -222,6 +232,10 @@ static int Open( vlc_object_t *p_this )
{
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" ) ) )
{
......@@ -278,6 +292,9 @@ static int Open( vlc_object_t *p_this )
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;
}
......@@ -1154,10 +1171,8 @@ static int transcode_video_ffmpeg_new( sout_stream_t *p_stream,
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 )
{
......@@ -1169,10 +1184,18 @@ static int transcode_video_ffmpeg_new( sout_stream_t *p_stream,
{
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 );
}
}
......@@ -1196,13 +1219,28 @@ static int transcode_video_ffmpeg_new( sout_stream_t *p_stream,
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 )
{
......@@ -1243,6 +1281,10 @@ static int transcode_video_ffmpeg_new( sout_stream_t *p_stream,
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;
}
......@@ -1288,8 +1330,8 @@ static void transcode_video_ffmpeg_close ( sout_stream_t *p_stream, sout_stream_
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;
......@@ -1309,6 +1351,7 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_
{
/* 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,
......@@ -1324,6 +1367,9 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_
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 )
......@@ -1339,6 +1385,13 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_
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
......@@ -1450,12 +1503,28 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_
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;
......@@ -1464,9 +1533,45 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_
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 );
}
......@@ -1479,3 +1584,20 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_
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 );
}
......@@ -2,7 +2,7 @@
* 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>
......@@ -85,6 +85,7 @@ sout_instance_t * __sout_NewInstance ( vlc_object_t *p_parent,
/* *** 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 );
......@@ -504,7 +505,7 @@ sout_fifo_t *sout_FifoCreate( sout_instance_t *p_sout )
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;
......@@ -521,7 +522,7 @@ void sout_FifoFree( sout_instance_t *p_sout, sout_fifo_t *p_fifo )
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 );
......@@ -530,7 +531,7 @@ void sout_FifoDestroy( sout_instance_t *p_sout, sout_fifo_t *p_fifo )
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 );
......@@ -597,26 +598,33 @@ sout_buffer_t *sout_FifoShow( sout_fifo_t *p_fifo )
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;
......@@ -629,20 +637,25 @@ sout_buffer_t *sout_BufferNew( sout_instance_t *p_sout, size_t 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;
......@@ -653,15 +666,20 @@ int sout_BufferRealloc( sout_instance_t *p_sout, sout_buffer_t *p_buffer, size_t
}
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;
......
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