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 @@ ...@@ -2,7 +2,7 @@
* stream_output.h : stream output module * stream_output.h : stream output module
***************************************************************************** *****************************************************************************
* Copyright (C) 2002 VideoLAN * 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> * Authors: Christophe Massiot <massiot@via.ecp.fr>
* Laurent Aimar <fenrir@via.ecp.fr> * Laurent Aimar <fenrir@via.ecp.fr>
...@@ -243,6 +243,8 @@ struct sout_instance_t ...@@ -243,6 +243,8 @@ struct sout_instance_t
/* muxer data */ /* muxer data */
int i_preheader; /* max over all muxer */ int i_preheader; /* max over all muxer */
int i_padding; /* needed by some decoders */
vlc_mutex_t lock; vlc_mutex_t lock;
sout_stream_t *p_stream; sout_stream_t *p_stream;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* transcode.c * transcode.c
***************************************************************************** *****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN * 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> * Authors: Laurent Aimar <fenrir@via.ecp.fr>
* *
...@@ -64,6 +64,8 @@ static int transcode_video_ffmpeg_new ( sout_stream_t *, sout_stream_id_t * ...@@ -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 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_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 * Module descriptor
*****************************************************************************/ *****************************************************************************/
...@@ -88,6 +90,7 @@ struct sout_stream_sys_t ...@@ -88,6 +90,7 @@ struct sout_stream_sys_t
int i_vtolerance; int i_vtolerance;
int i_width; int i_width;
int i_height; int i_height;
int i_b_frames;
int i_key_int; int i_key_int;
int i_qmin; int i_qmin;
int i_qmax; int i_qmax;
...@@ -98,6 +101,12 @@ struct sout_stream_sys_t ...@@ -98,6 +101,12 @@ struct sout_stream_sys_t
int i_crop_bottom; int i_crop_bottom;
int i_crop_right; int i_crop_right;
int i_crop_left; 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 ) ...@@ -123,6 +132,7 @@ static int Open( vlc_object_t *p_this )
p_sys->i_width = 0; p_sys->i_width = 0;
p_sys->i_height = 0; p_sys->i_height = 0;
p_sys->i_key_int = -1; p_sys->i_key_int = -1;
p_sys->i_b_frames = 0;
p_sys->i_qmin = 2; p_sys->i_qmin = 2;
p_sys->i_qmax = 31; p_sys->i_qmax = 31;
#if LIBAVCODEC_BUILD >= 4673 #if LIBAVCODEC_BUILD >= 4673
...@@ -222,6 +232,10 @@ static int Open( vlc_object_t *p_this ) ...@@ -222,6 +232,10 @@ static int Open( vlc_object_t *p_this )
{ {
p_sys->i_key_int = atoi( val ); 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 LIBAVCODEC_BUILD >= 4673
if( ( val = sout_cfg_find_value( p_stream->p_cfg, "hq" ) ) ) if( ( val = sout_cfg_find_value( p_stream->p_cfg, "hq" ) ) )
{ {
...@@ -278,6 +292,9 @@ static int Open( vlc_object_t *p_this ) ...@@ -278,6 +292,9 @@ static int Open( vlc_object_t *p_this )
avcodec_init(); avcodec_init();
avcodec_register_all(); 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; return VLC_SUCCESS;
} }
...@@ -1154,10 +1171,8 @@ static int transcode_video_ffmpeg_new( sout_stream_t *p_stream, ...@@ -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->extradata = id->f_src.p_extra_data;
id->ff_dec_c->workaround_bugs = FF_BUG_AUTODETECT; id->ff_dec_c->workaround_bugs = FF_BUG_AUTODETECT;
id->ff_dec_c->error_resilience= -1; id->ff_dec_c->error_resilience= -1;
if( id->ff_dec->capabilities & CODEC_CAP_TRUNCATED ) id->ff_dec_c->get_buffer = transcode_video_ffmpeg_getframebuf;
{ id->ff_dec_c->opaque = p_sys;
id->ff_dec_c->flags |= CODEC_FLAG_TRUNCATED;
}
if( avcodec_open( id->ff_dec_c, id->ff_dec ) < 0 ) 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, ...@@ -1169,10 +1184,18 @@ static int transcode_video_ffmpeg_new( sout_stream_t *p_stream,
{ {
int b_gotpicture; int b_gotpicture;
AVFrame frame; AVFrame frame;
uint8_t *p_vol = malloc( id->ff_dec_c->extradata_size +
FF_INPUT_BUFFER_PADDING_SIZE );
avcodec_decode_video( id->ff_dec_c, &frame, memcpy( p_vol, id->ff_dec_c->extradata,
&b_gotpicture, id->ff_dec_c->extradata_size );
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, ...@@ -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->width = id->f_dst.i_width;
id->ff_enc_c->height = id->f_dst.i_height; id->ff_enc_c->height = id->f_dst.i_height;
id->ff_enc_c->bit_rate = id->f_dst.i_bitrate; 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 #if LIBAVCODEC_BUILD >= 4662
id->ff_enc_c->frame_rate = 25 ; /* FIXME as it break mpeg */ 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_base= 1;
#else #else
id->ff_enc_c->frame_rate = 25 * FRAME_RATE_BASE; id->ff_enc_c->frame_rate = 25 * FRAME_RATE_BASE;
#endif #endif
}
id->ff_enc_c->gop_size = p_sys->i_key_int >= 0 ? p_sys->i_key_int : 50; 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 ) if( p_sys->i_vtolerance >= 0 )
{ {
...@@ -1243,6 +1281,10 @@ static int transcode_video_ffmpeg_new( sout_stream_t *p_stream, ...@@ -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_tmp1 = NULL;
id->p_ff_pic_tmp2 = NULL; id->p_ff_pic_tmp2 = NULL;
id->p_vresample = NULL; id->p_vresample = NULL;
p_sys->i_last_ref_pts = 0;
p_sys->i_buggy_pts_detect = 0;
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -1288,8 +1330,8 @@ static void transcode_video_ffmpeg_close ( sout_stream_t *p_stream, sout_stream_ ...@@ -1288,8 +1330,8 @@ static void transcode_video_ffmpeg_close ( sout_stream_t *p_stream, sout_stream_
free( id->p_buffer ); free( id->p_buffer );
} }
static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_id_t *id, static int transcode_video_ffmpeg_process( sout_stream_t *p_stream,
sout_buffer_t *in, sout_buffer_t **out ) sout_stream_id_t *id, sout_buffer_t *in, sout_buffer_t **out )
{ {
sout_stream_sys_t *p_sys = p_stream->p_sys; sout_stream_sys_t *p_sys = p_stream->p_sys;
int i_used; int i_used;
...@@ -1309,6 +1351,7 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_ ...@@ -1309,6 +1351,7 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_
{ {
/* decode frame */ /* decode frame */
frame = id->p_ff_pic; frame = id->p_ff_pic;
p_sys->i_input_pts = in->i_pts;
if( id->ff_dec ) if( id->ff_dec )
{ {
i_used = avcodec_decode_video( id->ff_dec_c, frame, 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_ ...@@ -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 ); id->ff_dec_c->width, id->ff_dec_c->height );
i_used = i_data; i_used = i_data;
b_gotpicture = 1; b_gotpicture = 1;
/* Set PTS */
frame->pts = p_sys->i_input_pts;
} }
if( i_used < 0 ) if( i_used < 0 )
...@@ -1339,6 +1385,13 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_ ...@@ -1339,6 +1385,13 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_
return VLC_SUCCESS; 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 ) if( !id->b_enc_inited )
{ {
/* XXX hack because of copy packetizer and mpeg4video that can failed /* 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_ ...@@ -1450,12 +1503,28 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_
p_stream->p_sys->i_crop_right ); 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; 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 ) if( i_out > 0 )
{ {
sout_buffer_t *p_out; sout_buffer_t *p_out;
...@@ -1464,9 +1533,45 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_ ...@@ -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 ); memcpy( p_out->p_buffer, id->p_buffer, i_out );
p_out->i_size = i_out; p_out->i_size = i_out;
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_length = in->i_length;
p_out->i_dts = in->i_dts; p_out->i_dts = in->i_dts;
p_out->i_pts = in->i_dts; /* FIXME */ p_out->i_pts = in->i_dts;
}
sout_BufferChain( out, p_out ); sout_BufferChain( out, p_out );
} }
...@@ -1479,3 +1584,20 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_ ...@@ -1479,3 +1584,20 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_
return VLC_SUCCESS; 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 @@ ...@@ -2,7 +2,7 @@
* stream_output.c : stream output module * stream_output.c : stream output module
***************************************************************************** *****************************************************************************
* Copyright (C) 2002 VideoLAN * 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> * Authors: Christophe Massiot <massiot@via.ecp.fr>
* Laurent Aimar <fenrir@via.ecp.fr> * Laurent Aimar <fenrir@via.ecp.fr>
...@@ -85,6 +85,7 @@ sout_instance_t * __sout_NewInstance ( vlc_object_t *p_parent, ...@@ -85,6 +85,7 @@ sout_instance_t * __sout_NewInstance ( vlc_object_t *p_parent,
/* *** init descriptor *** */ /* *** init descriptor *** */
p_sout->psz_sout = strdup( psz_dest ); p_sout->psz_sout = strdup( psz_dest );
p_sout->i_preheader = 0; p_sout->i_preheader = 0;
p_sout->i_padding = 0;
p_sout->p_sys = NULL; p_sout->p_sys = NULL;
vlc_mutex_init( p_sout, &p_sout->lock ); vlc_mutex_init( p_sout, &p_sout->lock );
...@@ -597,26 +598,33 @@ sout_buffer_t *sout_FifoShow( sout_fifo_t *p_fifo ) ...@@ -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 *sout_BufferNew( sout_instance_t *p_sout, size_t i_size )
{ {
sout_buffer_t *p_buffer; sout_buffer_t *p_buffer;
size_t i_preheader; size_t i_preheader, i_padding;
#ifdef DEBUG_BUFFER
msg_Dbg( p_sout, "allocating an new buffer, size:%d", (uint32_t)i_size );
#endif
p_buffer = malloc( sizeof( sout_buffer_t ) ); p_buffer = malloc( sizeof( sout_buffer_t ) );
i_preheader = p_sout->i_preheader; 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 ) 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; 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 else
{ {
p_buffer->p_allocated_buffer = NULL; p_buffer->p_allocated_buffer = NULL;
p_buffer->p_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_buffer_size = i_size;
p_buffer->i_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 ) ...@@ -629,20 +637,25 @@ sout_buffer_t *sout_BufferNew( sout_instance_t *p_sout, size_t i_size )
return( p_buffer ); 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 #ifdef DEBUG_BUFFER
msg_Dbg( p_sout, msg_Dbg( p_sout, "realloc buffer old size:%d new size:%d, preheader:%d, "
"realloc buffer old size:%d new size:%d", "padding:%d", (uint32_t)p_buffer->i_allocated_size,
(uint32_t)p_buffer->i_allocated_size, (uint32_t)i_size, i_preheader, i_padding );
(uint32_t)i_size );
#endif #endif
i_preheader = p_buffer->p_buffer - p_buffer->p_allocated_buffer; if( !( p_buffer->p_allocated_buffer =
realloc( p_buffer->p_allocated_buffer,
if( !( p_buffer->p_allocated_buffer = realloc( p_buffer->p_allocated_buffer, i_size + i_preheader ) ) ) i_size + i_preheader + i_padding ) ) )
{ {
msg_Err( p_sout, "realloc failed" ); msg_Err( p_sout, "realloc failed" );
p_buffer->i_allocated_size = 0; p_buffer->i_allocated_size = 0;
...@@ -653,13 +666,18 @@ int sout_BufferRealloc( sout_instance_t *p_sout, sout_buffer_t *p_buffer, size_t ...@@ -653,13 +666,18 @@ 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->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; 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 ); 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;
......
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