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