1 /*****************************************************************************
2 * transrate.c: MPEG2 video transrating module
3 *****************************************************************************
4 * Copyright (C) 2003 the VideoLAN team
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
8 * Laurent Aimar <fenrir@via.ecp.fr>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
36 #include <vlc_common.h>
37 #include <vlc_plugin.h>
39 #include <vlc_input.h>
41 #include "transrate.h"
43 /*****************************************************************************
45 *****************************************************************************/
46 static int Open ( vlc_object_t * );
47 static void Close ( vlc_object_t * );
49 static sout_stream_id_t *Add ( sout_stream_t *, es_format_t * );
50 static int Del ( sout_stream_t *, sout_stream_id_t * );
51 static int Send( sout_stream_t *, sout_stream_id_t *, block_t * );
53 static int transrate_video_process( sout_stream_t *, sout_stream_id_t *, block_t *, block_t ** );
55 /*****************************************************************************
57 *****************************************************************************/
59 set_category( CAT_SOUT );
60 set_subcategory( SUBCAT_SOUT_STREAM );
61 set_description( N_("MPEG2 video transrating stream output") );
62 set_capability( "sout stream", 50 );
63 add_shortcut( "transrate" );
64 set_callbacks( Open, Close );
67 struct sout_stream_sys_t
72 mtime_t i_shaping_delay;
78 /*****************************************************************************
80 *****************************************************************************/
81 static int Open( vlc_object_t *p_this )
83 sout_stream_t *p_stream = (sout_stream_t*)p_this;
84 sout_stream_sys_t *p_sys;
87 p_sys = malloc( sizeof( sout_stream_sys_t ) );
88 p_sys->p_out = sout_StreamNew( p_stream->p_sout, p_stream->psz_next );
90 p_sys->i_vbitrate = 0;
92 if( ( val = sout_cfg_find_value( p_stream->p_cfg, "vb" ) ) )
94 p_sys->i_vbitrate = atoi( val );
95 if( p_sys->i_vbitrate < 16000 )
97 p_sys->i_vbitrate *= 1000;
102 p_sys->i_vbitrate = 3000000;
105 p_sys->i_shaping_delay = 500000;
106 if( ( val = sout_cfg_find_value( p_stream->p_cfg, "shaping" ) ) )
108 p_sys->i_shaping_delay = (int64_t)atoi( val ) * 1000;
109 if( p_sys->i_shaping_delay <= 0 )
112 "invalid shaping (%"PRId64"ms) reseting to 500ms",
113 p_sys->i_shaping_delay / 1000 );
114 p_sys->i_shaping_delay = 500000;
118 p_sys->b_mpeg4_matrix = 0;
119 if( sout_cfg_find( p_stream->p_cfg, "mpeg4-matrix" ) )
121 p_sys->b_mpeg4_matrix = 1;
124 msg_Dbg( p_stream, "codec video %dkb/s max gop=%"PRId64"us",
125 p_sys->i_vbitrate / 1024, p_sys->i_shaping_delay );
129 msg_Err( p_stream, "cannot create chain" );
133 p_stream->pf_add = Add;
134 p_stream->pf_del = Del;
135 p_stream->pf_send = Send;
137 p_stream->p_sys = p_sys;
142 /*****************************************************************************
144 *****************************************************************************/
145 static void Close( vlc_object_t * p_this )
147 sout_stream_t *p_stream = (sout_stream_t *)p_this;
148 sout_stream_sys_t *p_sys = p_stream->p_sys;
150 sout_StreamDelete( p_sys->p_out );
155 static sout_stream_id_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt )
157 sout_stream_sys_t *p_sys = p_stream->p_sys;
158 sout_stream_id_t *id;
160 id = malloc( sizeof( sout_stream_id_t ) );
163 if( p_fmt->i_cat == VIDEO_ES
164 && p_fmt->i_codec == VLC_FOURCC('m', 'p', 'g', 'v') )
167 "creating video transrating for fcc=`%4.4s'",
168 (char*)&p_fmt->i_codec );
170 id->p_current_buffer = NULL;
171 id->p_next_gop = NULL;
172 id->i_next_gop_duration = 0;
173 id->i_next_gop_size = 0;
174 memset( &id->tr, 0, sizeof( transrate_t ) );
175 id->tr.bs.i_byte_in = id->tr.bs.i_byte_out = 0;
176 id->tr.mpeg4_matrix = p_sys->b_mpeg4_matrix;
178 /* open output stream */
179 id->id = p_sys->p_out->pf_add( p_sys->p_out, p_fmt );
180 id->b_transrate = true;
184 msg_Dbg( p_stream, "not transrating a stream (fcc=`%4.4s')", (char*)&p_fmt->i_codec );
185 id->id = p_sys->p_out->pf_add( p_sys->p_out, p_fmt );
186 id->b_transrate = false;
198 static int Del ( sout_stream_t *p_stream, sout_stream_id_t *id )
200 sout_stream_sys_t *p_sys = p_stream->p_sys;
204 p_sys->p_out->pf_del( p_sys->p_out, id->id );
211 static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
214 sout_stream_sys_t *p_sys = p_stream->p_sys;
216 if( id->b_transrate )
218 block_t *p_buffer_out;
219 /* be sure to have at least 8 bytes of padding (maybe only 4) */
220 p_buffer = block_Realloc( p_buffer, 0, p_buffer->i_buffer + 8 );
221 p_buffer->i_buffer -= 8;
222 memset( &p_buffer->p_buffer[p_buffer->i_buffer], 0, 8 );
224 transrate_video_process( p_stream, id, p_buffer, &p_buffer_out );
228 return p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer_out );
232 else if( id->id != NULL )
234 return p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer );
238 block_Release( p_buffer );
243 static int transrate_video_process( sout_stream_t *p_stream,
244 sout_stream_id_t *id, block_t *in, block_t **out )
246 transrate_t *tr = &id->tr;
247 bs_transrate_t *bs = &tr->bs;
253 block_t * p_next = in->p_next;
254 int i_flags = in->i_flags;
257 block_ChainAppend( &id->p_next_gop, in );
258 id->i_next_gop_duration += in->i_length;
259 id->i_next_gop_size += in->i_buffer;
262 if( ((i_flags & BLOCK_FLAG_TYPE_I )
263 && id->i_next_gop_duration >= 300000)
264 || (id->i_next_gop_duration > p_stream->p_sys->i_shaping_delay) )
266 mtime_t i_bitrate = (mtime_t)id->i_next_gop_size * 8000
267 / (id->i_next_gop_duration / 1000);
268 mtime_t i_new_bitrate;
270 id->tr.i_total_input = id->i_next_gop_size;
271 id->tr.i_remaining_input = id->i_next_gop_size;
272 id->tr.i_wanted_output = (p_stream->p_sys->i_vbitrate)
273 * (id->i_next_gop_duration / 1000) / 8000;
274 id->tr.i_current_output = 0;
276 id->p_current_buffer = id->p_next_gop;
278 while ( id->p_current_buffer != NULL )
280 block_t * p_next = id->p_current_buffer->p_next;
281 if ( !p_stream->p_sys->b_mpeg4_matrix
282 && id->tr.i_wanted_output >= id->tr.i_total_input )
284 bs->i_byte_out += id->p_current_buffer->i_buffer;
285 id->p_current_buffer->p_next = NULL;
286 block_ChainAppend( out, id->p_current_buffer );
290 if ( process_frame( p_stream, id, id->p_current_buffer,
293 id->p_current_buffer->p_next = NULL;
294 block_ChainAppend( out, id->p_current_buffer );
295 if ( p_stream->p_sys->b_mpeg4_matrix )
296 id->tr.i_wanted_output = id->tr.i_total_input;
300 block_Release( id->p_current_buffer );
303 id->p_current_buffer = p_next;
306 if ( id->tr.i_wanted_output < id->tr.i_total_input )
308 i_new_bitrate = (mtime_t)tr->i_current_output * 8000
309 / (id->i_next_gop_duration / 1000);
310 if (i_new_bitrate > p_stream->p_sys->i_vbitrate + 300000)
311 msg_Err(p_stream, "%lld -> %lld d=%lld",
312 i_bitrate, i_new_bitrate,
313 id->i_next_gop_duration);
315 msg_Dbg(p_stream, "%lld -> %lld d=%lld",
316 i_bitrate, i_new_bitrate,
317 id->i_next_gop_duration);
320 id->p_next_gop = NULL;
321 id->i_next_gop_duration = 0;
322 id->i_next_gop_size = 0;