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