]> git.sesse.net Git - vlc/blob - modules/packetizer/mpeg4video.c
* all: set pf_run *only* if we accept this stream.
[vlc] / modules / packetizer / mpeg4video.c
1 /*****************************************************************************
2  * mpeg4video.c
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VideoLAN
5  * $Id: mpeg4video.c,v 1.14 2003/09/24 14:59:21 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/aout.h>
30 #include <vlc/decoder.h>
31 #include <vlc/input.h>
32 #include <vlc/sout.h>
33
34 #include <stdlib.h>                                      /* malloc(), free() */
35 #include <string.h>                                              /* strdup() */
36
37 #include "codecs.h"
38
39 /*****************************************************************************
40  * Local prototypes
41  *****************************************************************************/
42 typedef struct packetizer_thread_s
43 {
44     /* Input properties */
45     decoder_fifo_t          *p_fifo;
46
47     /* Output properties */
48     sout_packetizer_input_t *p_sout_input;
49     sout_format_t           output_format;
50
51     mtime_t                 i_last_pts;
52
53     int                     i_vol;
54     uint8_t                 *p_vol;
55
56 } packetizer_thread_t;
57
58 static int  Open    ( vlc_object_t * );
59 static int  Run     ( decoder_fifo_t * );
60
61 static int  InitThread     ( packetizer_thread_t * );
62 static void PacketizeThread   ( packetizer_thread_t * );
63 static void EndThread      ( packetizer_thread_t * );
64
65
66 static void input_ShowPES( decoder_fifo_t *p_fifo, pes_packet_t **pp_pes );
67
68 /*****************************************************************************
69  * Module descriptor
70  *****************************************************************************/
71
72 vlc_module_begin();
73     set_description( _("MPEG4 Video packetizer") );
74     set_capability( "packetizer", 50 );
75     set_callbacks( Open, NULL );
76 vlc_module_end();
77
78 #define VIDEO_OBJECT_MASK                       0x01f
79 #define VIDEO_OBJECT_LAYER_MASK                 0x00f
80
81 #define VIDEO_OBJECT_START_CODE                 0x100
82 #define VIDEO_OBJECT_LAYER_START_CODE           0x120
83 #define VISUAL_OBJECT_SEQUENCE_START_CODE       0x1b0
84 #define VISUAL_OBJECT_SEQUENCE_END_CODE         0x1b1
85 #define USER_DATA_START_CODE                    0x1b2
86 #define GROUP_OF_VOP_START_CODE                 0x1b3
87 #define VIDEO_SESSION_ERROR_CODE                0x1b4
88 #define VISUAL_OBJECT_START_CODE                0x1b5
89 #define VOP_START_CODE                          0x1b6
90 #define FACE_OBJECT_START_CODE                  0x1ba
91 #define FACE_OBJECT_PLANE_START_CODE            0x1bb
92 #define MESH_OBJECT_START_CODE                  0x1bc
93 #define MESH_OBJECT_PLANE_START_CODE            0x1bd
94 #define STILL_TEXTURE_OBJECT_START_CODE         0x1be
95 #define TEXTURE_SPATIAL_LAYER_START_CODE        0x1bf
96 #define TEXTURE_SNR_LAYER_START_CODE            0x1c0
97
98
99 /*****************************************************************************
100  * OpenDecoder: probe the packetizer and return score
101  *****************************************************************************
102  * Tries to launch a decoder and return score so that the interface is able
103  * to choose.
104  *****************************************************************************/
105 static int Open( vlc_object_t *p_this )
106 {
107     decoder_t *p_dec = (decoder_t*)p_this;
108
109     switch( p_dec->p_fifo->i_fourcc )
110     {
111         case VLC_FOURCC( 'm', '4', 's', '2'):
112         case VLC_FOURCC( 'M', '4', 'S', '2'):
113         case VLC_FOURCC( 'm', 'p', '4', 's'):
114         case VLC_FOURCC( 'M', 'P', '4', 'S'):
115         case VLC_FOURCC( 'm', 'p', '4', 'v'):
116         case VLC_FOURCC( 'D', 'I', 'V', 'X'):
117         case VLC_FOURCC( 'd', 'i', 'v', 'x'):
118         case VLC_FOURCC( 'X', 'V', 'I', 'D'):
119         case VLC_FOURCC( 'X', 'v', 'i', 'D'):
120         case VLC_FOURCC( 'x', 'v', 'i', 'd'):
121         case VLC_FOURCC( 'D', 'X', '5', '0'):
122         case VLC_FOURCC( 0x04, 0,   0,   0):
123         case VLC_FOURCC( '3', 'I', 'V', '2'):
124             p_dec->pf_run = Run;
125             return VLC_SUCCESS;
126         default:
127             return VLC_EGENERIC;
128     }
129 }
130
131 /*****************************************************************************
132  * RunDecoder: this function is called just after the thread is created
133  *****************************************************************************/
134 static int Run( decoder_fifo_t *p_fifo )
135 {
136     packetizer_thread_t *p_pack;
137     int b_error;
138
139     msg_Info( p_fifo, "Running MPEG4 Video packetizer" );
140     if( !( p_pack = malloc( sizeof( packetizer_thread_t ) ) ) )
141     {
142         msg_Err( p_fifo, "out of memory" );
143         DecoderError( p_fifo );
144         return( -1 );
145     }
146     memset( p_pack, 0, sizeof( packetizer_thread_t ) );
147
148     p_pack->p_fifo = p_fifo;
149
150     if( InitThread( p_pack ) != 0 )
151     {
152         DecoderError( p_fifo );
153         return( -1 );
154     }
155
156     while( ( !p_pack->p_fifo->b_die )&&( !p_pack->p_fifo->b_error ) )
157     {
158         PacketizeThread( p_pack );
159     }
160
161
162     if( ( b_error = p_pack->p_fifo->b_error ) )
163     {
164         DecoderError( p_pack->p_fifo );
165     }
166
167     EndThread( p_pack );
168     if( b_error )
169     {
170         return( -1 );
171     }
172
173     return( 0 );
174 }
175
176
177 #define FREE( p ) if( p ) free( p ); p = NULL
178
179 /*****************************************************************************
180  * InitThread: initialize data before entering main loop
181  *****************************************************************************/
182
183 static int InitThread( packetizer_thread_t *p_pack )
184 {
185     BITMAPINFOHEADER *p_bih;
186
187     p_bih = (BITMAPINFOHEADER*)p_pack->p_fifo->p_bitmapinfoheader;
188
189     if( p_bih && p_bih->biSize > sizeof( BITMAPINFOHEADER ) )
190     {
191         /* We have a vol */
192         p_pack->i_vol = p_bih->biSize - sizeof( BITMAPINFOHEADER );
193         p_pack->p_vol = malloc( p_pack->i_vol );
194         memcpy( p_pack->p_vol, &p_bih[1], p_pack->i_vol );
195
196         /* create stream input output */
197         p_pack->output_format.i_cat = VIDEO_ES;
198         p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', '4', 'v' );
199         p_pack->output_format.i_width  = p_bih->biWidth;
200         p_pack->output_format.i_height = p_bih->biHeight;
201         p_pack->output_format.i_bitrate= 0;
202
203         p_pack->output_format.i_extra_data = p_pack->i_vol;
204         p_pack->output_format.p_extra_data = malloc( p_pack->i_vol );
205         memcpy( p_pack->output_format.p_extra_data,
206                 p_pack->p_vol,
207                 p_pack->i_vol );
208
209         msg_Warn( p_pack->p_fifo, "opening with vol size:%d", p_pack->i_vol );
210         p_pack->p_sout_input =
211             sout_InputNew( p_pack->p_fifo,
212                            &p_pack->output_format );
213     }
214     else
215     {
216         p_pack->i_vol = 0;
217         p_pack->p_vol = 0;
218         p_pack->output_format.i_cat = UNKNOWN_ES;
219         p_pack->output_format.i_fourcc = VLC_FOURCC( 'n', 'u', 'l', 'l' );
220         p_pack->output_format.i_width  = 0;
221         p_pack->output_format.i_height = 0;
222         p_pack->output_format.i_bitrate= 0;
223         p_pack->output_format.i_extra_data = 0;
224         p_pack->output_format.p_extra_data = NULL;
225
226         p_pack->p_sout_input =
227             sout_InputNew( p_pack->p_fifo,
228                            &p_pack->output_format );
229     }
230
231     if( !p_pack->p_sout_input )
232     {
233         msg_Err( p_pack->p_fifo, "cannot add a new stream" );
234         return( -1 );
235     }
236     p_pack->i_last_pts = 0;
237
238     return VLC_SUCCESS;
239 }
240
241 static int m4v_FindStartCode( uint8_t **pp_data, uint8_t *p_end )
242 {
243     for( ; *pp_data < p_end - 4; (*pp_data)++ )
244     {
245         if( (*pp_data)[0] == 0 && (*pp_data)[1] == 0 && (*pp_data)[2] == 1 )
246         {
247             return( 0 );
248         }
249     }
250     fprintf( stderr, "\n********* cannot find startcode\n" );
251     return( -1 );
252 }
253 /*****************************************************************************
254  * PacketizeThread: packetize an unit (here copy a complete pes)
255  *****************************************************************************/
256 static void PacketizeThread( packetizer_thread_t *p_pack )
257 {
258     sout_buffer_t   *p_sout_buffer;
259     pes_packet_t    *p_pes;
260     ssize_t         i_size;
261     mtime_t         i_pts;
262
263     /* **** get samples count **** */
264     input_ExtractPES( p_pack->p_fifo, &p_pes );
265     if( !p_pes )
266     {
267         p_pack->p_fifo->b_error = 1;
268         return;
269     }
270
271     i_pts = p_pes->i_pts;
272 #if 0
273     if( i_pts <= 0 && p_pack->i_last_pts <= 0 )
274     {
275         msg_Dbg( p_pack->p_fifo, "need a starting pts" );
276         input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes );
277         return;
278     }
279 #endif
280
281     i_size = p_pes->i_pes_size;
282     if( i_size > 0 )
283     {
284         pes_packet_t    *p_pes_next;
285         data_packet_t   *p_data;
286         ssize_t          i_buffer;
287
288         p_sout_buffer =
289             sout_BufferNew( p_pack->p_sout_input->p_sout, i_size );
290         if( !p_sout_buffer )
291         {
292             p_pack->p_fifo->b_error = 1;
293             return;
294         }
295         /* TODO: memcpy of the pes packet */
296         for( i_buffer = 0, p_data = p_pes->p_first;
297              p_data != NULL && i_buffer < i_size;
298              p_data = p_data->p_next)
299         {
300             ssize_t i_copy;
301
302             i_copy = __MIN( p_data->p_payload_end - p_data->p_payload_start, 
303                             i_size - i_buffer );
304             if( i_copy > 0 )
305             {
306                 p_pack->p_fifo->p_vlc->pf_memcpy( p_sout_buffer->p_buffer + i_buffer,
307                                                   p_data->p_payload_start,
308                                                   i_copy );
309             }
310             i_buffer += i_copy;
311         }
312
313         input_ShowPES( p_pack->p_fifo, &p_pes_next );
314         if( p_pes_next && p_pes_next->i_pts > 0 )
315         {
316             mtime_t i_gap;
317
318             i_gap = p_pes_next->i_pts - p_pes->i_pts;
319             p_sout_buffer->i_length = i_gap;
320         }
321         else
322         {
323             p_sout_buffer->i_length = 0;
324         }
325         p_sout_buffer->i_dts = i_pts;
326         p_sout_buffer->i_pts = i_pts;
327         p_sout_buffer->i_bitrate = 0;
328
329         if( p_pack->p_vol == NULL )
330         {
331             uint8_t *p_vol_begin, *p_vol_end, *p_end;
332             /* search if p_sout_buffer contains with a vol */
333             p_vol_begin = p_sout_buffer->p_buffer;
334             p_vol_end   = NULL;
335             p_end       = p_sout_buffer->p_buffer + p_sout_buffer->i_size;
336
337             for( ;; )
338             {
339                 if( m4v_FindStartCode( &p_vol_begin, p_end ) )
340                 {
341                     break;
342                 }
343                 msg_Dbg( p_pack->p_fifo,
344                           "starcode 0x%2.2x%2.2x%2.2x%2.2x",
345                           p_vol_begin[0], p_vol_begin[1], p_vol_begin[2], p_vol_begin[3] );
346
347                 if( ( p_vol_begin[3] & ~VIDEO_OBJECT_MASK ) == ( VIDEO_OBJECT_START_CODE&0xff ) )
348                 {
349                     p_vol_end = p_vol_begin + 4;
350                     if( m4v_FindStartCode( &p_vol_end, p_end ) )
351                     {
352                         break;
353                     }
354                     if( ( p_vol_end[3] & ~VIDEO_OBJECT_LAYER_MASK ) == ( VIDEO_OBJECT_LAYER_START_CODE&0xff ) )
355                     {
356                         p_vol_end += 4;
357                         if( m4v_FindStartCode( &p_vol_end, p_end ) )
358                         {
359                             p_vol_end = p_end;
360                         }
361                     }
362                     else
363                     {
364                         p_vol_end = NULL;
365                     }
366                 }
367                 else if( ( p_vol_begin[3] & ~VIDEO_OBJECT_LAYER_MASK ) == ( VIDEO_OBJECT_LAYER_START_CODE&0xff) )
368                 {
369                     p_vol_end = p_vol_begin + 4;
370                     if( m4v_FindStartCode( &p_vol_end, p_end ) )
371                     {
372                         p_vol_end = p_end;
373                     }
374                 }
375
376                 if( p_vol_end != NULL && p_vol_begin < p_vol_end )
377                 {
378                     BITMAPINFOHEADER *p_bih =
379                         (BITMAPINFOHEADER*)p_pack->p_fifo->p_bitmapinfoheader;
380                     p_pack->i_vol = p_vol_end - p_vol_begin;
381                     msg_Dbg( p_pack->p_fifo, "Reopening output" );
382
383                     p_pack->p_vol = malloc( p_pack->i_vol );
384                     memcpy( p_pack->p_vol, p_vol_begin, p_pack->i_vol );
385
386                     sout_InputDelete( p_pack->p_sout_input );
387
388                     p_pack->output_format.i_cat = VIDEO_ES;
389                     p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', '4', 'v' );
390
391                     if( p_bih )
392                     {
393                         p_pack->output_format.i_width  = p_bih->biWidth;
394                         p_pack->output_format.i_height = p_bih->biHeight;
395                     }
396                     else
397                     {
398                         p_pack->output_format.i_width  = 0;
399                         p_pack->output_format.i_height = 0;
400                     }
401                     p_pack->output_format.i_bitrate= 0;
402
403                     p_pack->output_format.i_extra_data = p_pack->i_vol;
404                     p_pack->output_format.p_extra_data = malloc( p_pack->i_vol );
405                     memcpy( p_pack->output_format.p_extra_data,
406                             p_pack->p_vol,
407                             p_pack->i_vol );
408
409                     p_pack->p_sout_input =
410                         sout_InputNew( p_pack->p_fifo,
411                                        &p_pack->output_format );
412                     if( !p_pack->p_sout_input )
413                     {
414                         p_pack->p_fifo->b_error = 1;
415                         return;
416                     }
417
418                     break;
419                 }
420                 else
421                 {
422                     p_vol_begin += 4;
423                 }
424             }
425         }
426
427         if( i_pts > 0 )
428         {
429             sout_InputSendBuffer( p_pack->p_sout_input,
430                                   p_sout_buffer );
431         }
432         else
433         {
434             sout_BufferDelete( p_pack->p_sout_input->p_sout,
435                                p_sout_buffer );
436         }
437     }
438
439     input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes );
440 }
441
442
443 /*****************************************************************************
444  * EndThread : packetizer thread destruction
445  *****************************************************************************/
446 static void EndThread ( packetizer_thread_t *p_pack)
447 {
448     if( p_pack->p_sout_input )
449     {
450         sout_InputDelete( p_pack->p_sout_input );
451     }
452     free( p_pack );
453 }
454
455 static void input_ShowPES( decoder_fifo_t *p_fifo, pes_packet_t **pp_pes )
456 {
457     pes_packet_t *p_pes;
458
459     vlc_mutex_lock( &p_fifo->data_lock );
460
461     if( p_fifo->p_first == NULL )
462     {
463         if( p_fifo->b_die )
464         {
465             vlc_mutex_unlock( &p_fifo->data_lock );
466             if( pp_pes ) *pp_pes = NULL;
467             return;
468         }
469
470         /* Signal the input thread we're waiting. This is only
471          * needed in case of slave clock (ES plug-in) but it won't
472          * harm. */
473         vlc_cond_signal( &p_fifo->data_wait );
474
475         /* Wait for the input to tell us when we received a packet. */
476         vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
477     }
478     p_pes = p_fifo->p_first;
479     vlc_mutex_unlock( &p_fifo->data_lock );
480
481     if( pp_pes )
482     {
483         *pp_pes = p_pes;
484     }
485 }