]> git.sesse.net Git - vlc/blob - modules/packetizer/mpegvideo.c
* mpegvideo.c : raah, removed a debug message...
[vlc] / modules / packetizer / mpegvideo.c
1 /*****************************************************************************
2  * mpegvideo.c
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VideoLAN
5  * $Id: mpegvideo.c,v 1.6 2003/01/20 02:19:56 fenrir Exp $
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *          Eric Petit <titer@videolan.org>
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 <vlc/vlc.h>
29 #include <vlc/decoder.h>
30 #include <vlc/input.h>
31 #include <vlc/sout.h>
32 #include "codecs.h"                         /* WAVEFORMATEX BITMAPINFOHEADER */
33
34 #include <stdlib.h>                                      /* malloc(), free() */
35 #include <string.h>                                              /* strdup() */
36
37 /*****************************************************************************
38  * Local prototypes
39  *****************************************************************************/
40 typedef struct packetizer_s
41 {
42     /* Input properties */
43     decoder_fifo_t          *p_fifo;
44     bit_stream_t            bit_stream;
45
46     /* Output properties */
47     sout_input_t            *p_sout_input;
48     sout_packet_format_t    output_format;
49
50     mtime_t                 i_last_dts;
51     mtime_t                 i_last_ref_pts;
52     double                  d_frame_rate;
53     int                     i_progressive_sequence;
54     uint8_t                 p_sequence_header[150];
55     int                     i_sequence_header_length;
56     int                     i_last_sequence_header;
57
58 } packetizer_t;
59
60 static int  Open    ( vlc_object_t * );
61 static int  Run     ( decoder_fifo_t * );
62
63 static int  InitThread     ( packetizer_t * );
64 static void PacketizeThread   ( packetizer_t * );
65 static void EndThread      ( packetizer_t * );
66
67 /*****************************************************************************
68  * Module descriptor
69  *****************************************************************************/
70
71 vlc_module_begin();
72     set_description( _("MPEG-I/II video packetizer") );
73     set_capability( "packetizer", 50 );
74     set_callbacks( Open, NULL );
75 vlc_module_end();
76
77 /*****************************************************************************
78  * OpenDecoder: probe the packetizer and return score
79  *****************************************************************************
80  * Tries to launch a decoder and return score so that the interface is able
81  * to choose.
82  *****************************************************************************/
83 static int Open( vlc_object_t *p_this )
84 {
85     decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
86
87     if( p_fifo->i_fourcc != VLC_FOURCC( 'm', 'p', 'g', 'v') &&
88         p_fifo->i_fourcc != VLC_FOURCC( 'm', 'p', 'g', '1') &&
89         p_fifo->i_fourcc != VLC_FOURCC( 'm', 'p', 'g', '2') )
90     {
91         return VLC_EGENERIC;
92     }
93
94     p_fifo->pf_run = Run;
95     return VLC_SUCCESS;
96 }
97
98 /*****************************************************************************
99  * RunDecoder: this function is called just after the thread is created
100  *****************************************************************************/
101 static int Run( decoder_fifo_t *p_fifo )
102 {
103     packetizer_t *p_pack;
104     int b_error;
105
106     msg_Info( p_fifo, "Running mpegvideo packetizer" );
107     if( !( p_pack = malloc( sizeof( packetizer_t ) ) ) )
108     {
109         msg_Err( p_fifo, "out of memory" );
110         DecoderError( p_fifo );
111         return( -1 );
112     }
113     memset( p_pack, 0, sizeof( packetizer_t ) );
114
115     p_pack->p_fifo = p_fifo;
116
117     if( InitThread( p_pack ) != 0 )
118     {
119         DecoderError( p_fifo );
120         return( -1 );
121     }
122
123     while( ( !p_pack->p_fifo->b_die )&&( !p_pack->p_fifo->b_error ) )
124     {
125         PacketizeThread( p_pack );
126     }
127
128
129     if( ( b_error = p_pack->p_fifo->b_error ) )
130     {
131         DecoderError( p_pack->p_fifo );
132     }
133
134     EndThread( p_pack );
135
136     if( p_pack )
137     {
138         free( p_pack );
139     }
140
141     if( b_error )
142     {
143         return( -1 );
144     }
145
146     return( 0 );
147 }
148
149
150 /*****************************************************************************
151  * InitThread: initialize data before entering main loop
152  *****************************************************************************/
153
154 static int InitThread( packetizer_t *p_pack )
155 {
156
157     p_pack->output_format.i_cat = VIDEO_ES;
158     p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', 'g', 'v');
159
160     p_pack->p_sout_input = NULL;
161
162     if( InitBitstream( &p_pack->bit_stream, p_pack->p_fifo,
163                        NULL, NULL ) != VLC_SUCCESS )
164     {
165         msg_Err( p_pack->p_fifo, "cannot initialize bitstream" );
166         return -1;
167     }
168
169     return( 0 );
170 }
171
172 /* from ISO 13818-2 */
173 /* converting frame_rate_code to frame_rate */
174 static const double pd_frame_rates[16] =
175 {
176     0, 24000/1001, 24, 25, 30000/1001, 30, 50, 60000/1001, 60,
177     0, 0, 0, 0, 0, 0, 0
178 };
179
180 static int CopyUntilNextStartCode( packetizer_t   *p_pack,
181                                    sout_buffer_t  *p_sout_buffer,
182                                    int            *pi_pos )
183 {
184     int i_copy = 0;
185
186     do
187     {
188         p_sout_buffer->p_buffer[(*pi_pos)++] =
189                 GetBits( &p_pack->bit_stream, 8 );
190         i_copy++;
191
192         if( *pi_pos + 2048 > p_sout_buffer->i_buffer_size )
193         {
194             sout_BufferRealloc( p_pack->p_sout_input->p_sout,
195                                 p_sout_buffer,
196                                 p_sout_buffer->i_buffer_size + 50 * 1024);
197         }
198
199     } while( ShowBits( &p_pack->bit_stream, 24 ) != 0x01 &&
200              !p_pack->p_fifo->b_die && !p_pack->p_fifo->b_error );
201
202     return( i_copy );
203 }
204
205 /*****************************************************************************
206  * PacketizeThread: packetize an unit (here copy a complete pes)
207  *****************************************************************************/
208 static void PacketizeThread( packetizer_t *p_pack )
209 {
210     sout_buffer_t *p_sout_buffer = NULL;
211     int32_t i_pos;
212     int i_temporal_ref = 0;
213     int i_skipped;
214
215     if( !p_pack->p_sout_input )
216     {
217         byte_t p_temp[512];/* 150 bytes is the maximal size
218                                of a sequence_header + sequence_extension */
219         int i_frame_rate_code;
220         BITMAPINFOHEADER *p_bih;
221
222         p_bih = malloc( sizeof( BITMAPINFOHEADER ) );
223         p_pack->output_format.p_format = (void*)p_bih;
224
225         /* skip data until we find a sequence_header_code */
226         /* TODO: store skipped somewhere so can send it to the mux
227          * after the input is created */
228         i_skipped = 0;
229         while( ShowBits( &p_pack->bit_stream, 32 ) != 0x1B3 )
230         {
231             RemoveBits( &p_pack->bit_stream, 8 );
232             i_skipped++;
233         }
234         msg_Warn( p_pack->p_fifo, "sequence_header_code found (%d skipped)",
235                  i_skipped );
236
237         /* copy the start_code */
238         i_pos = 0;
239         GetChunk( &p_pack->bit_stream, p_temp, 4 ); i_pos += 4;
240
241         p_bih->biSize = sizeof( BITMAPINFOHEADER );
242         /* horizontal_size_value */
243         p_bih->biWidth = ShowBits( &p_pack->bit_stream, 12 );
244         /* vertical_size_value */
245         p_bih->biHeight = ShowBits( &p_pack->bit_stream, 24 ) & 0xFFF;
246         /* frame_rate_code */
247         i_frame_rate_code = ShowBits( &p_pack->bit_stream, 32 ) & 0xF;
248         p_bih->biPlanes = 1;
249         p_bih->biBitCount = 0;
250         p_bih->biCompression = VLC_FOURCC( 'm', 'p', 'g', '2' );
251         p_bih->biSizeImage = 0;
252         p_bih->biXPelsPerMeter = 0;
253         p_bih->biYPelsPerMeter = 0;
254         p_bih->biClrUsed = 0;
255         p_bih->biClrImportant = 0;
256
257         /* copy headers */
258         GetChunk( &p_pack->bit_stream, p_temp + i_pos, 7 ); i_pos += 7;
259
260         /* intra_quantiser_matrix [non_intra_quantiser_matrix] */
261         if( ShowBits( &p_pack->bit_stream, 7 ) & 0x1 )
262         {
263
264             GetChunk( &p_pack->bit_stream, p_temp + i_pos, 64 ); i_pos += 64;
265
266             if( ShowBits( &p_pack->bit_stream, 8 ) & 0x1 )
267             {
268                 GetChunk( &p_pack->bit_stream, p_temp + i_pos, 65); i_pos += 65;
269             }
270         }
271         /* non_intra_quantiser_matrix */
272         else if( ShowBits( &p_pack->bit_stream, 8 ) & 0x1 )
273         {
274             GetChunk( &p_pack->bit_stream, p_temp + i_pos, 65); i_pos += 65;
275         }
276         /* nothing */
277         else
278         {
279             GetChunk( &p_pack->bit_stream, p_temp + i_pos, 1 ); i_pos += 1;
280         }
281
282         /* sequence_extension (10 bytes) */
283         if( ShowBits( &p_pack->bit_stream, 32 ) != 0x1B5 )
284         {
285             msg_Dbg( p_pack->p_fifo, "ARRGG no extension_start_code" );
286             p_pack->i_progressive_sequence = 1;
287         }
288         else
289         {
290             GetChunk( &p_pack->bit_stream, p_temp + i_pos, 10 );
291             p_pack->i_progressive_sequence = ( p_temp[i_pos+5]&0x08 ) ? 1 : 0;
292
293             i_pos += 10;
294         }
295
296         /* remember sequence_header and sequence_extention */
297         memcpy( p_pack->p_sequence_header, p_temp, i_pos );
298         p_pack->i_sequence_header_length = i_pos;
299
300         p_pack->d_frame_rate =  pd_frame_rates[i_frame_rate_code];
301
302         msg_Warn( p_pack->p_fifo,
303                   "creating input (image size %dx%d, frame rate %.2f)",
304                   p_bih->biWidth, p_bih->biHeight, p_pack->d_frame_rate );
305
306         /* now we have informations to create the input */
307         p_pack->p_sout_input = sout_InputNew( p_pack->p_fifo,
308                                               &p_pack->output_format );
309
310         if( !p_pack->p_sout_input )
311         {
312             msg_Err( p_pack->p_fifo, "cannot add a new stream" );
313             return;
314         }
315
316         p_sout_buffer = sout_BufferNew( p_pack->p_sout_input->p_sout,
317                                         100 * 1024 );
318         p_sout_buffer->i_size = i_pos;
319         memcpy( p_sout_buffer->p_buffer, p_temp, i_pos );
320
321     }
322     else
323     {
324         p_sout_buffer =
325                 sout_BufferNew( p_pack->p_sout_input->p_sout, 100 * 1024 );
326         i_pos = 0;
327     }
328
329     p_pack->i_last_sequence_header++;
330
331     for( ;; )
332     {
333         uint32_t i_code;
334         if( p_pack->p_fifo->b_die || p_pack->p_fifo->b_error )
335         {
336             break;
337         }
338
339         i_code = ShowBits( &p_pack->bit_stream, 32 );
340
341         if( i_code == 0x1B8 ) /* GOP */
342         {
343             /* usefull for bad MPEG-1 : repeat the sequence_header
344                every second */
345             if( p_pack->i_last_sequence_header > (int) p_pack->d_frame_rate )
346             {
347                memcpy( p_sout_buffer->p_buffer + i_pos,
348                        p_pack->p_sequence_header,
349                        p_pack->i_sequence_header_length );
350                i_pos += p_pack->i_sequence_header_length;
351                p_pack->i_last_sequence_header = 0;
352             }
353
354             p_pack->i_last_ref_pts =
355                    p_pack->i_last_dts + 40000; /* FIXME */
356             CopyUntilNextStartCode( p_pack, p_sout_buffer, &i_pos );
357         }
358         else if( i_code == 0x100 ) /* Picture */
359         {
360             /* picture_start_code */
361             GetChunk( &p_pack->bit_stream,
362                       p_sout_buffer->p_buffer + i_pos, 4 ); i_pos += 4;
363             i_temporal_ref = ShowBits( &p_pack->bit_stream, 10 );
364
365             CopyUntilNextStartCode( p_pack, p_sout_buffer, &i_pos );
366             break;
367         }
368         else
369         {
370             if( i_code == 0x1B3 )
371             {
372                 p_pack->i_last_sequence_header = 0;
373             }
374             CopyUntilNextStartCode( p_pack, p_sout_buffer, &i_pos );
375         }
376     }
377
378     sout_BufferRealloc( p_pack->p_sout_input->p_sout,
379                         p_sout_buffer, i_pos );
380     p_sout_buffer->i_size = i_pos;
381
382     p_sout_buffer->i_dts = p_pack->i_last_dts;
383     p_sout_buffer->i_pts = p_pack->i_last_ref_pts +
384         i_temporal_ref * (mtime_t)( 1000000 / p_pack->d_frame_rate );
385
386
387     p_sout_buffer->i_length = (uint64_t)1000000 / p_pack->d_frame_rate;
388     p_sout_buffer->i_bitrate = (int)( 8 * i_pos * p_pack->d_frame_rate );
389
390 //    msg_Dbg( p_pack->p_fifo, "frame length %d b", i_pos );
391
392     sout_InputSendBuffer( p_pack->p_sout_input, p_sout_buffer );
393
394     if( p_pack->i_progressive_sequence )
395     {
396         p_pack->i_last_dts += (mtime_t)( 1000000 / p_pack->d_frame_rate );
397     }
398     else
399     {
400         p_pack->i_last_dts += (mtime_t)( 1000000 / p_pack->d_frame_rate / 2 );
401     }
402 }
403
404
405 /*****************************************************************************
406  * EndThread : packetizer thread destruction
407  *****************************************************************************/
408 static void EndThread ( packetizer_t *p_pack)
409 {
410     if( p_pack->p_sout_input )
411     {
412         sout_InputDelete( p_pack->p_sout_input );
413     }
414 }