00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #define NDEBUG 1
00031 #include <assert.h>
00032 #include <math.h>
00033
00034 #include <vlc/vlc.h>
00035 #include <vlc/sout.h>
00036 #include <vlc/input.h>
00037
00038 #include "transrate.h"
00039
00040
00041
00042
00043 static int Open ( vlc_object_t * );
00044 static void Close ( vlc_object_t * );
00045
00046 static sout_stream_id_t *Add ( sout_stream_t *, es_format_t * );
00047 static int Del ( sout_stream_t *, sout_stream_id_t * );
00048 static int Send( sout_stream_t *, sout_stream_id_t *, block_t * );
00049
00050 static int transrate_video_process( sout_stream_t *, sout_stream_id_t *, block_t *, block_t ** );
00051
00052
00053
00054
00055 vlc_module_begin();
00056 set_category( CAT_SOUT );
00057 set_subcategory( SUBCAT_SOUT_STREAM );
00058 set_description( _("MPEG2 video transrating stream output") );
00059 set_capability( "sout stream", 50 );
00060 add_shortcut( "transrate" );
00061 set_callbacks( Open, Close );
00062 vlc_module_end();
00063
00064 struct sout_stream_sys_t
00065 {
00066 sout_stream_t *p_out;
00067
00068 int i_vbitrate;
00069 mtime_t i_shaping_delay;
00070 int b_mpeg4_matrix;
00071
00072 mtime_t i_dts, i_pts;
00073 };
00074
00075
00076
00077
00078 static int Open( vlc_object_t *p_this )
00079 {
00080 sout_stream_t *p_stream = (sout_stream_t*)p_this;
00081 sout_stream_sys_t *p_sys;
00082 char *val;
00083
00084 p_sys = malloc( sizeof( sout_stream_sys_t ) );
00085 p_sys->p_out = sout_StreamNew( p_stream->p_sout, p_stream->psz_next );
00086
00087 p_sys->i_vbitrate = 0;
00088
00089 if( ( val = sout_cfg_find_value( p_stream->p_cfg, "vb" ) ) )
00090 {
00091 p_sys->i_vbitrate = atoi( val );
00092 if( p_sys->i_vbitrate < 16000 )
00093 {
00094 p_sys->i_vbitrate *= 1000;
00095 }
00096 }
00097 else
00098 {
00099 p_sys->i_vbitrate = 3000000;
00100 }
00101
00102 p_sys->i_shaping_delay = 500000;
00103 if( ( val = sout_cfg_find_value( p_stream->p_cfg, "shaping" ) ) )
00104 {
00105 p_sys->i_shaping_delay = (int64_t)atoi( val ) * 1000;
00106 if( p_sys->i_shaping_delay <= 0 )
00107 {
00108 msg_Err( p_stream,
00109 "invalid shaping ("I64Fd"ms) reseting to 500ms",
00110 p_sys->i_shaping_delay / 1000 );
00111 p_sys->i_shaping_delay = 500000;
00112 }
00113 }
00114
00115 p_sys->b_mpeg4_matrix = 0;
00116 if( sout_cfg_find( p_stream->p_cfg, "mpeg4-matrix" ) )
00117 {
00118 p_sys->b_mpeg4_matrix = 1;
00119 }
00120
00121 msg_Dbg( p_stream, "codec video %dkb/s max gop="I64Fd"us",
00122 p_sys->i_vbitrate / 1024, p_sys->i_shaping_delay );
00123
00124 if( !p_sys->p_out )
00125 {
00126 msg_Err( p_stream, "cannot create chain" );
00127 free( p_sys );
00128 return VLC_EGENERIC;
00129 }
00130 p_stream->pf_add = Add;
00131 p_stream->pf_del = Del;
00132 p_stream->pf_send = Send;
00133
00134 p_stream->p_sys = p_sys;
00135
00136 return VLC_SUCCESS;
00137 }
00138
00139
00140
00141
00142 static void Close( vlc_object_t * p_this )
00143 {
00144 sout_stream_t *p_stream = (sout_stream_t *)p_this;
00145 sout_stream_sys_t *p_sys = p_stream->p_sys;
00146
00147 sout_StreamDelete( p_sys->p_out );
00148 free( p_sys );
00149 }
00150
00151
00152 static sout_stream_id_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt )
00153 {
00154 sout_stream_sys_t *p_sys = p_stream->p_sys;
00155 sout_stream_id_t *id;
00156
00157 id = malloc( sizeof( sout_stream_id_t ) );
00158 id->id = NULL;
00159
00160 if( p_fmt->i_cat == VIDEO_ES
00161 && p_fmt->i_codec == VLC_FOURCC('m', 'p', 'g', 'v') )
00162 {
00163 msg_Dbg( p_stream,
00164 "creating video transrating for fcc=`%4.4s'",
00165 (char*)&p_fmt->i_codec );
00166
00167 id->p_current_buffer = NULL;
00168 id->p_next_gop = NULL;
00169 id->i_next_gop_duration = 0;
00170 id->i_next_gop_size = 0;
00171 memset( &id->tr, 0, sizeof( transrate_t ) );
00172 id->tr.bs.i_byte_in = id->tr.bs.i_byte_out = 0;
00173 id->tr.mpeg4_matrix = p_sys->b_mpeg4_matrix;
00174
00175
00176 id->id = p_sys->p_out->pf_add( p_sys->p_out, p_fmt );
00177 id->b_transrate = VLC_TRUE;
00178 }
00179 else
00180 {
00181 msg_Dbg( p_stream, "not transrating a stream (fcc=`%4.4s')", (char*)&p_fmt->i_codec );
00182 id->id = p_sys->p_out->pf_add( p_sys->p_out, p_fmt );
00183 id->b_transrate = VLC_FALSE;
00184
00185 if( id->id == NULL )
00186 {
00187 free( id );
00188 return NULL;
00189 }
00190 }
00191
00192 return id;
00193 }
00194
00195 static int Del ( sout_stream_t *p_stream, sout_stream_id_t *id )
00196 {
00197 sout_stream_sys_t *p_sys = p_stream->p_sys;
00198
00199 if( id->id )
00200 {
00201 p_sys->p_out->pf_del( p_sys->p_out, id->id );
00202 }
00203 free( id );
00204
00205 return VLC_SUCCESS;
00206 }
00207
00208 static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
00209 block_t *p_buffer )
00210 {
00211 sout_stream_sys_t *p_sys = p_stream->p_sys;
00212
00213 if( id->b_transrate )
00214 {
00215 block_t *p_buffer_out;
00216
00217 p_buffer = block_Realloc( p_buffer, 0, p_buffer->i_buffer + 8 );
00218 p_buffer->i_buffer -= 8;
00219 memset( &p_buffer->p_buffer[p_buffer->i_buffer], 0, 8 );
00220
00221 transrate_video_process( p_stream, id, p_buffer, &p_buffer_out );
00222
00223 if( p_buffer_out )
00224 {
00225 return p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer_out );
00226 }
00227 return VLC_SUCCESS;
00228 }
00229 else if( id->id != NULL )
00230 {
00231 return p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer );
00232 }
00233 else
00234 {
00235 block_Release( p_buffer );
00236 return VLC_EGENERIC;
00237 }
00238 }
00239
00240 static int transrate_video_process( sout_stream_t *p_stream,
00241 sout_stream_id_t *id, block_t *in, block_t **out )
00242 {
00243 transrate_t *tr = &id->tr;
00244 bs_transrate_t *bs = &tr->bs;
00245
00246 *out = NULL;
00247
00248 while ( in != NULL )
00249 {
00250 block_t * p_next = in->p_next;
00251 int i_flags = in->i_flags;
00252
00253 in->p_next = NULL;
00254 block_ChainAppend( &id->p_next_gop, in );
00255 id->i_next_gop_duration += in->i_length;
00256 id->i_next_gop_size += in->i_buffer;
00257 in = p_next;
00258
00259 if( ((i_flags & BLOCK_FLAG_TYPE_I )
00260 && id->i_next_gop_duration >= 300000)
00261 || (id->i_next_gop_duration > p_stream->p_sys->i_shaping_delay) )
00262 {
00263 mtime_t i_bitrate = (mtime_t)id->i_next_gop_size * 8000
00264 / (id->i_next_gop_duration / 1000);
00265 mtime_t i_new_bitrate;
00266
00267 id->tr.i_total_input = id->i_next_gop_size;
00268 id->tr.i_remaining_input = id->i_next_gop_size;
00269 id->tr.i_wanted_output = (p_stream->p_sys->i_vbitrate)
00270 * (id->i_next_gop_duration / 1000) / 8000;
00271 id->tr.i_current_output = 0;
00272
00273 id->p_current_buffer = id->p_next_gop;
00274
00275 while ( id->p_current_buffer != NULL )
00276 {
00277 block_t * p_next = id->p_current_buffer->p_next;
00278 if ( !p_stream->p_sys->b_mpeg4_matrix
00279 && id->tr.i_wanted_output >= id->tr.i_total_input )
00280 {
00281 bs->i_byte_out += id->p_current_buffer->i_buffer;
00282 id->p_current_buffer->p_next = NULL;
00283 block_ChainAppend( out, id->p_current_buffer );
00284 }
00285 else
00286 {
00287 if ( process_frame( p_stream, id, id->p_current_buffer,
00288 out, 0 ) < 0 )
00289 {
00290 id->p_current_buffer->p_next = NULL;
00291 block_ChainAppend( out, id->p_current_buffer );
00292 if ( p_stream->p_sys->b_mpeg4_matrix )
00293 id->tr.i_wanted_output = id->tr.i_total_input;
00294 }
00295 else
00296 {
00297 block_Release( id->p_current_buffer );
00298 }
00299 }
00300 id->p_current_buffer = p_next;
00301 }
00302
00303 if ( id->tr.i_wanted_output < id->tr.i_total_input )
00304 {
00305 i_new_bitrate = (mtime_t)tr->i_current_output * 8000
00306 / (id->i_next_gop_duration / 1000);
00307 if (i_new_bitrate > p_stream->p_sys->i_vbitrate + 300000)
00308 msg_Err(p_stream, "%lld -> %lld d=%lld",
00309 i_bitrate, i_new_bitrate,
00310 id->i_next_gop_duration);
00311 else
00312 msg_Dbg(p_stream, "%lld -> %lld d=%lld",
00313 i_bitrate, i_new_bitrate,
00314 id->i_next_gop_duration);
00315 }
00316
00317 id->p_next_gop = NULL;
00318 id->i_next_gop_duration = 0;
00319 id->i_next_gop_size = 0;
00320 }
00321 }
00322
00323 return VLC_SUCCESS;
00324 }
00325