1e0a09133f5db3ec649a1b6d0790fa0a46752845
[vlc.git] / modules / stream_out / transrate / transrate.c
1 /*****************************************************************************
2  * transrate.c: MPEG2 video transrating module
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id: transrate.c,v 1.7 2004/03/03 11:20:52 massiot Exp $
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *          Laurent Aimar <fenrir@via.ecp.fr>
9  *
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.
14  *
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.
19  *
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdio.h>
29 #include <stdlib.h>
30 #define NDEBUG 1
31 #include <assert.h>
32 #include <math.h>
33
34 #include <vlc/vlc.h>
35 #include <vlc/sout.h>
36 #include <vlc/input.h>
37
38 #include "transrate.h"
39
40 /*****************************************************************************
41  * Exported prototypes
42  *****************************************************************************/
43 static int      Open    ( vlc_object_t * );
44 static void     Close   ( vlc_object_t * );
45
46 static sout_stream_id_t *Add ( sout_stream_t *, es_format_t * );
47 static int               Del ( sout_stream_t *, sout_stream_id_t * );
48 static int               Send( sout_stream_t *, sout_stream_id_t *, sout_buffer_t * );
49
50 static int  transrate_video_process( sout_stream_t *, sout_stream_id_t *, sout_buffer_t *, sout_buffer_t ** );
51
52 void E_(process_frame)( sout_stream_t *p_stream,
53                sout_stream_id_t *id, sout_buffer_t *in, sout_buffer_t **out );
54
55 /*****************************************************************************
56  * Module descriptor
57  *****************************************************************************/
58 vlc_module_begin();
59     set_description( _("MPEG2 video transrating stream output") );
60     set_capability( "sout stream", 50 );
61     add_shortcut( "transrate" );
62     set_callbacks( Open, Close );
63 vlc_module_end();
64
65 struct sout_stream_sys_t
66 {
67     sout_stream_t   *p_out;
68
69     int             i_vbitrate;
70     mtime_t         i_shaping_delay;
71
72     mtime_t         i_first_frame;
73     mtime_t         i_dts, i_pts;
74 };
75
76 /*****************************************************************************
77  * Open:
78  *****************************************************************************/
79 static int Open( vlc_object_t *p_this )
80 {
81     sout_stream_t     *p_stream = (sout_stream_t*)p_this;
82     sout_stream_sys_t *p_sys;
83     char *val;
84
85     p_sys = malloc( sizeof( sout_stream_sys_t ) );
86     p_sys->p_out = sout_stream_new( p_stream->p_sout, p_stream->psz_next );
87
88     p_sys->i_vbitrate   = 0;
89
90     if( ( val = sout_cfg_find_value( p_stream->p_cfg, "vb" ) ) )
91     {
92         p_sys->i_vbitrate = atoi( val );
93         if( p_sys->i_vbitrate < 16000 )
94         {
95             p_sys->i_vbitrate *= 1000;
96         }
97     }
98     else
99     {
100         p_sys->i_vbitrate = 3000000;
101     }
102
103     p_sys->i_shaping_delay = 500000;
104     if( ( val = sout_cfg_find_value( p_stream->p_cfg, "shaping" ) ) )
105     {
106         p_sys->i_shaping_delay = (int64_t)atoi( val ) * 1000;
107         if( p_sys->i_shaping_delay <= 0 )
108         {
109             msg_Err( p_stream,
110                      "invalid shaping ("I64Fd"ms) reseting to 500ms",
111                      p_sys->i_shaping_delay / 1000 );
112             p_sys->i_shaping_delay = 500000;
113         }
114     }
115
116     p_sys->i_first_frame = 0;
117
118     msg_Dbg( p_stream, "codec video %dkb/s max gop="I64Fd"us",
119              p_sys->i_vbitrate / 1024, p_sys->i_shaping_delay );
120
121     if( !p_sys->p_out )
122     {
123         msg_Err( p_stream, "cannot create chain" );
124         free( p_sys );
125         return VLC_EGENERIC;
126     }
127     p_stream->pf_add    = Add;
128     p_stream->pf_del    = Del;
129     p_stream->pf_send   = Send;
130
131     p_stream->p_sys     = p_sys;
132
133     p_stream->p_sout->i_padding += 200;
134
135     return VLC_SUCCESS;
136 }
137
138 /*****************************************************************************
139  * Close:
140  *****************************************************************************/
141 static void Close( vlc_object_t * p_this )
142 {
143     sout_stream_t       *p_stream = (sout_stream_t *)p_this;
144     sout_stream_sys_t   *p_sys = p_stream->p_sys;
145
146     sout_stream_delete( p_sys->p_out );
147     free( p_sys );
148 }
149
150
151 static sout_stream_id_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt )
152 {
153     sout_stream_sys_t   *p_sys = p_stream->p_sys;
154     sout_stream_id_t    *id;
155
156     id = malloc( sizeof( sout_stream_id_t ) );
157     id->id = NULL;
158
159     if( p_fmt->i_cat == VIDEO_ES
160             && p_fmt->i_codec == VLC_FOURCC('m', 'p', 'g', 'v') )
161     {
162         msg_Dbg( p_stream,
163                  "creating video transrating for fcc=`%4.4s'",
164                  (char*)&p_fmt->i_codec );
165
166         id->p_current_buffer = NULL;
167         id->p_next_gop = NULL;
168         id->i_next_gop_duration = 0;
169         id->i_next_gop_size = 0;
170         memset( &id->tr, 0, sizeof( transrate_t ) );
171         id->tr.bs.i_byte_in = id->tr.bs.i_byte_out = 0;
172         id->tr.fact_x = 1.0;
173
174         /* open output stream */
175         id->id = p_sys->p_out->pf_add( p_sys->p_out, p_fmt );
176         id->b_transrate = VLC_TRUE;
177     }
178     else
179     {
180         msg_Dbg( p_stream, "not transrating a stream (fcc=`%4.4s')", (char*)&p_fmt->i_codec );
181         id->id = p_sys->p_out->pf_add( p_sys->p_out, p_fmt );
182         id->b_transrate = VLC_FALSE;
183
184         if( id->id == NULL )
185         {
186             free( id );
187             return NULL;
188         }
189     }
190
191     return id;
192 }
193
194 static int     Del      ( sout_stream_t *p_stream, sout_stream_id_t *id )
195 {
196     sout_stream_sys_t   *p_sys = p_stream->p_sys;
197
198     if( id->id )
199     {
200         p_sys->p_out->pf_del( p_sys->p_out, id->id );
201     }
202     free( id );
203
204     return VLC_SUCCESS;
205 }
206
207 static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
208                  sout_buffer_t *p_buffer )
209 {
210     sout_stream_sys_t   *p_sys = p_stream->p_sys;
211
212     if( id->b_transrate )
213     {
214         sout_buffer_t *p_buffer_out;
215         transrate_video_process( p_stream, id, p_buffer, &p_buffer_out );
216
217         if( p_buffer_out )
218         {
219             return p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer_out );
220         }
221         return VLC_SUCCESS;
222     }
223     else if( id->id != NULL )
224     {
225         return p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer );
226     }
227     else
228     {
229         sout_BufferDelete( p_stream->p_sout, p_buffer );
230         return VLC_EGENERIC;
231     }
232 }
233
234 static int transrate_video_process( sout_stream_t *p_stream,
235                sout_stream_id_t *id, sout_buffer_t *in, sout_buffer_t **out )
236 {
237     transrate_t    *tr = &id->tr;
238     bs_transrate_t *bs = &tr->bs;
239
240     *out = NULL;
241
242     while ( in != NULL )
243     {
244         sout_buffer_t * p_next = in->p_next;
245         int i_flags = in->i_flags;
246
247         in->p_next = NULL;
248         sout_BufferChain( &id->p_next_gop, in );
249         id->i_next_gop_duration += in->i_length;
250         id->i_next_gop_size += in->i_size;
251         in = p_next;
252
253         if( ((i_flags & (BLOCK_FLAG_TYPE_I << SOUT_BUFFER_FLAGS_BLOCK_SHIFT))
254                 && id->i_next_gop_duration >= 300000)
255               || (id->i_next_gop_duration > p_stream->p_sys->i_shaping_delay) )
256         {
257             mtime_t i_bitrate = (mtime_t)id->i_next_gop_size * 8000
258                                     / (id->i_next_gop_duration / 1000);
259             mtime_t i_new_bitrate;
260
261             if ( i_bitrate > p_stream->p_sys->i_vbitrate )
262             {
263                 tr->fact_x = (double)i_bitrate / p_stream->p_sys->i_vbitrate;
264             }
265             else
266             {
267                 tr->fact_x = 1.0;
268             }
269             id->tr.i_current_gop_size = id->i_next_gop_size;
270             id->tr.i_wanted_gop_size = (p_stream->p_sys->i_vbitrate)
271                                     * (id->i_next_gop_duration / 1000) / 8000;
272             id->tr.i_new_gop_size = 0;
273
274             id->p_current_buffer = id->p_next_gop;
275
276             while ( id->p_current_buffer != NULL )
277             {
278                 sout_buffer_t * p_next = id->p_current_buffer->p_next;
279                 if ( tr->fact_x == 1.0 )
280                 {
281                     bs->i_byte_out += id->p_current_buffer->i_size;
282                     id->p_current_buffer->p_next = NULL;
283                     sout_BufferChain( out, id->p_current_buffer );
284                 }
285                 else
286                 {
287                     E_(process_frame)( p_stream, id, id->p_current_buffer, out );
288                     sout_BufferDelete(p_stream->p_sout, id->p_current_buffer);
289                 }
290                 id->p_current_buffer = p_next;
291             }
292
293             if ( tr->fact_x != 1.0 )
294             {
295                 i_new_bitrate = (mtime_t)tr->i_new_gop_size * 8000
296                                     / (id->i_next_gop_duration / 1001);
297                 if (i_new_bitrate > p_stream->p_sys->i_vbitrate + 300000)
298                     msg_Err(p_stream, "%lld -> %lld (%f, r:%f) d=%lld",
299                             i_bitrate, i_new_bitrate, tr->fact_x,
300                             (float)i_bitrate / i_new_bitrate,
301                             id->i_next_gop_duration);
302                     else
303                         msg_Dbg(p_stream, "%lld -> %lld (%f, r:%f) d=%lld",
304                             i_bitrate, i_new_bitrate, tr->fact_x,
305                             (float)i_bitrate / i_new_bitrate,
306                             id->i_next_gop_duration);
307             }
308
309             id->p_next_gop = NULL;
310             id->i_next_gop_duration = 0;
311             id->i_next_gop_size = 0;
312         }
313     }
314
315     return VLC_SUCCESS;
316 }
317