* stream_out: sout_buffer_t -> block_t.
[vlc.git] / modules / stream_out / transrate / transrate.c
1 /*****************************************************************************
2  * transrate.c: MPEG2 video transrating module
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id$
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 *, block_t * );
49
50 static int  transrate_video_process( sout_stream_t *, sout_stream_id_t *, block_t *, block_t ** );
51
52 void E_(process_frame)( sout_stream_t *p_stream,
53                sout_stream_id_t *id, block_t *in, block_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     return VLC_SUCCESS;
134 }
135
136 /*****************************************************************************
137  * Close:
138  *****************************************************************************/
139 static void Close( vlc_object_t * p_this )
140 {
141     sout_stream_t       *p_stream = (sout_stream_t *)p_this;
142     sout_stream_sys_t   *p_sys = p_stream->p_sys;
143
144     sout_stream_delete( p_sys->p_out );
145     free( p_sys );
146 }
147
148
149 static sout_stream_id_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt )
150 {
151     sout_stream_sys_t   *p_sys = p_stream->p_sys;
152     sout_stream_id_t    *id;
153
154     id = malloc( sizeof( sout_stream_id_t ) );
155     id->id = NULL;
156
157     if( p_fmt->i_cat == VIDEO_ES
158             && p_fmt->i_codec == VLC_FOURCC('m', 'p', 'g', 'v') )
159     {
160         msg_Dbg( p_stream,
161                  "creating video transrating for fcc=`%4.4s'",
162                  (char*)&p_fmt->i_codec );
163
164         id->p_current_buffer = NULL;
165         id->p_next_gop = NULL;
166         id->i_next_gop_duration = 0;
167         id->i_next_gop_size = 0;
168         memset( &id->tr, 0, sizeof( transrate_t ) );
169         id->tr.bs.i_byte_in = id->tr.bs.i_byte_out = 0;
170         id->tr.fact_x = 1.0;
171
172         /* open output stream */
173         id->id = p_sys->p_out->pf_add( p_sys->p_out, p_fmt );
174         id->b_transrate = VLC_TRUE;
175     }
176     else
177     {
178         msg_Dbg( p_stream, "not transrating a stream (fcc=`%4.4s')", (char*)&p_fmt->i_codec );
179         id->id = p_sys->p_out->pf_add( p_sys->p_out, p_fmt );
180         id->b_transrate = VLC_FALSE;
181
182         if( id->id == NULL )
183         {
184             free( id );
185             return NULL;
186         }
187     }
188
189     return id;
190 }
191
192 static int     Del      ( sout_stream_t *p_stream, sout_stream_id_t *id )
193 {
194     sout_stream_sys_t   *p_sys = p_stream->p_sys;
195
196     if( id->id )
197     {
198         p_sys->p_out->pf_del( p_sys->p_out, id->id );
199     }
200     free( id );
201
202     return VLC_SUCCESS;
203 }
204
205 static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
206                  block_t *p_buffer )
207 {
208     sout_stream_sys_t   *p_sys = p_stream->p_sys;
209
210     if( id->b_transrate )
211     {
212         block_t *p_buffer_out;
213         /* be sure to have at least 8 bytes of padding (maybe only 4) */
214         p_buffer = block_Realloc( p_buffer, 0, p_buffer->i_buffer + 8 );
215         p_buffer->i_buffer -= 8;
216         memset( &p_buffer->p_buffer[p_buffer->i_buffer], 0, 8 );
217
218         transrate_video_process( p_stream, id, p_buffer, &p_buffer_out );
219
220         if( p_buffer_out )
221         {
222             return p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer_out );
223         }
224         return VLC_SUCCESS;
225     }
226     else if( id->id != NULL )
227     {
228         return p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer );
229     }
230     else
231     {
232         block_Release( p_buffer );
233         return VLC_EGENERIC;
234     }
235 }
236
237 static int transrate_video_process( sout_stream_t *p_stream,
238                sout_stream_id_t *id, block_t *in, block_t **out )
239 {
240     transrate_t    *tr = &id->tr;
241     bs_transrate_t *bs = &tr->bs;
242
243     *out = NULL;
244
245     while ( in != NULL )
246     {
247         block_t * p_next = in->p_next;
248         int i_flags = in->i_flags;
249
250         in->p_next = NULL;
251         block_ChainAppend( &id->p_next_gop, in );
252         id->i_next_gop_duration += in->i_length;
253         id->i_next_gop_size += in->i_buffer;
254         in = p_next;
255
256         if( ((i_flags & BLOCK_FLAG_TYPE_I )
257                 && id->i_next_gop_duration >= 300000)
258               || (id->i_next_gop_duration > p_stream->p_sys->i_shaping_delay) )
259         {
260             mtime_t i_bitrate = (mtime_t)id->i_next_gop_size * 8000
261                                     / (id->i_next_gop_duration / 1000);
262             mtime_t i_new_bitrate;
263
264             if ( i_bitrate > p_stream->p_sys->i_vbitrate )
265             {
266                 tr->fact_x = (double)i_bitrate / p_stream->p_sys->i_vbitrate;
267             }
268             else
269             {
270                 tr->fact_x = 1.0;
271             }
272             id->tr.i_current_gop_size = id->i_next_gop_size;
273             id->tr.i_wanted_gop_size = (p_stream->p_sys->i_vbitrate)
274                                     * (id->i_next_gop_duration / 1000) / 8000;
275             id->tr.i_new_gop_size = 0;
276
277             id->p_current_buffer = id->p_next_gop;
278
279             while ( id->p_current_buffer != NULL )
280             {
281                 block_t * p_next = id->p_current_buffer->p_next;
282                 if ( tr->fact_x == 1.0 )
283                 {
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 );
287                 }
288                 else
289                 {
290                     E_(process_frame)( p_stream, id, id->p_current_buffer, out );
291                     block_Release( id->p_current_buffer);
292                 }
293                 id->p_current_buffer = p_next;
294             }
295
296             if ( tr->fact_x != 1.0 )
297             {
298                 i_new_bitrate = (mtime_t)tr->i_new_gop_size * 8000
299                                     / (id->i_next_gop_duration / 1001);
300                 if (i_new_bitrate > p_stream->p_sys->i_vbitrate + 300000)
301                     msg_Err(p_stream, "%lld -> %lld (%f, r:%f) d=%lld",
302                             i_bitrate, i_new_bitrate, tr->fact_x,
303                             (float)i_bitrate / i_new_bitrate,
304                             id->i_next_gop_duration);
305                     else
306                         msg_Dbg(p_stream, "%lld -> %lld (%f, r:%f) d=%lld",
307                             i_bitrate, i_new_bitrate, tr->fact_x,
308                             (float)i_bitrate / i_new_bitrate,
309                             id->i_next_gop_duration);
310             }
311
312             id->p_next_gop = NULL;
313             id->i_next_gop_duration = 0;
314             id->i_next_gop_size = 0;
315         }
316     }
317
318     return VLC_SUCCESS;
319 }
320