]> git.sesse.net Git - vlc/blob - modules/packetizer/mpeg4video.c
* all: new sout scheme. Now a chain of module are created that can
[vlc] / modules / packetizer / mpeg4video.c
1 /*****************************************************************************
2  * mpeg4video.c
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VideoLAN
5  * $Id: mpeg4video.c,v 1.10 2003/04/13 20:00: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_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
108
109     p_fifo->pf_run = Run;
110
111     switch(  p_fifo->i_fourcc )
112     {
113         case VLC_FOURCC( 'm', '4', 's', '2'):
114         case VLC_FOURCC( 'M', '4', 'S', '2'):
115         case VLC_FOURCC( 'm', 'p', '4', 's'):
116         case VLC_FOURCC( 'M', 'P', '4', 'S'):
117         case VLC_FOURCC( 'm', 'p', '4', 'v'):
118         case VLC_FOURCC( 'D', 'I', 'V', 'X'):
119         case VLC_FOURCC( 'd', 'i', 'v', 'x'):
120         case VLC_FOURCC( 'X', 'V', 'I', 'D'):
121         case VLC_FOURCC( 'X', 'v', 'i', 'D'):
122         case VLC_FOURCC( 'x', 'v', 'i', 'd'):
123         case VLC_FOURCC( 'D', 'X', '5', '0'):
124         case VLC_FOURCC( 0x04, 0,   0,   0):
125         case VLC_FOURCC( '3', 'I', 'V', '2'):
126
127             return VLC_SUCCESS;
128         default:
129             return VLC_EGENERIC;
130     }
131 }
132
133 /*****************************************************************************
134  * RunDecoder: this function is called just after the thread is created
135  *****************************************************************************/
136 static int Run( decoder_fifo_t *p_fifo )
137 {
138     packetizer_thread_t *p_pack;
139     int b_error;
140
141     msg_Info( p_fifo, "Running MPEG4 Video packetizer" );
142     if( !( p_pack = malloc( sizeof( packetizer_thread_t ) ) ) )
143     {
144         msg_Err( p_fifo, "out of memory" );
145         DecoderError( p_fifo );
146         return( -1 );
147     }
148     memset( p_pack, 0, sizeof( packetizer_thread_t ) );
149
150     p_pack->p_fifo = p_fifo;
151
152     if( InitThread( p_pack ) != 0 )
153     {
154         DecoderError( p_fifo );
155         return( -1 );
156     }
157
158     while( ( !p_pack->p_fifo->b_die )&&( !p_pack->p_fifo->b_error ) )
159     {
160         PacketizeThread( p_pack );
161     }
162
163
164     if( ( b_error = p_pack->p_fifo->b_error ) )
165     {
166         DecoderError( p_pack->p_fifo );
167     }
168
169     EndThread( p_pack );
170     if( b_error )
171     {
172         return( -1 );
173     }
174
175     return( 0 );
176 }
177
178
179 #define FREE( p ) if( p ) free( p ); p = NULL
180
181 /*****************************************************************************
182  * InitThread: initialize data before entering main loop
183  *****************************************************************************/
184
185 static int InitThread( packetizer_thread_t *p_pack )
186 {
187     BITMAPINFOHEADER *p_bih;
188
189     p_bih = (BITMAPINFOHEADER*)p_pack->p_fifo->p_bitmapinfoheader;
190
191     if( p_bih && p_bih->biSize > sizeof( BITMAPINFOHEADER ) )
192     {
193         /* We have a vol */
194         p_pack->i_vol = p_bih->biSize - sizeof( BITMAPINFOHEADER );
195         p_pack->p_vol = malloc( p_pack->i_vol );
196         memcpy( p_pack->p_vol, &p_bih[1], p_pack->i_vol );
197
198         /* create stream input output */
199         p_pack->output_format.i_cat = VIDEO_ES;
200         p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', '4', 'v' );
201         p_pack->output_format.i_width  = p_bih->biWidth;
202         p_pack->output_format.i_height = p_bih->biHeight;
203         p_pack->output_format.i_bitrate= 0;
204
205         p_pack->output_format.i_extra_data = p_pack->i_vol;
206         p_pack->output_format.p_extra_data = malloc( p_pack->i_vol );
207         memcpy( p_pack->output_format.p_extra_data,
208                 p_pack->p_vol,
209                 p_pack->i_vol );
210
211         msg_Warn( p_pack->p_fifo, "opening with vol size:%d", p_pack->i_vol );
212         p_pack->p_sout_input =
213             sout_InputNew( p_pack->p_fifo,
214                            &p_pack->output_format );
215     }
216     else
217     {
218         p_pack->i_vol = 0;
219         p_pack->p_vol = 0;
220         p_pack->output_format.i_cat = UNKNOWN_ES;
221         p_pack->output_format.i_fourcc = VLC_FOURCC( 'n', 'u', 'l', 'l' );
222         p_pack->output_format.i_width  = 0;
223         p_pack->output_format.i_height = 0;
224         p_pack->output_format.i_bitrate= 0;
225         p_pack->output_format.i_extra_data = 0;
226         p_pack->output_format.p_extra_data = NULL;
227
228         p_pack->p_sout_input =
229             sout_InputNew( p_pack->p_fifo,
230                            &p_pack->output_format );
231     }
232
233     if( !p_pack->p_sout_input )
234     {
235         msg_Err( p_pack->p_fifo, "cannot add a new stream" );
236         return( -1 );
237     }
238     p_pack->i_last_pts = 0;
239
240     return VLC_SUCCESS;
241 }
242
243 static int m4v_FindStartCode( uint8_t **pp_data, uint8_t *p_end )
244 {
245     for( ; *pp_data < p_end - 4; (*pp_data)++ )
246     {
247         if( (*pp_data)[0] == 0 && (*pp_data)[1] == 0 && (*pp_data)[2] == 1 )
248         {
249             return( 0 );
250         }
251     }
252     fprintf( stderr, "\n********* cannot find startcode\n" );
253     return( -1 );
254 }
255 /*****************************************************************************
256  * PacketizeThread: packetize an unit (here copy a complete pes)
257  *****************************************************************************/
258 static void PacketizeThread( packetizer_thread_t *p_pack )
259 {
260     sout_buffer_t   *p_sout_buffer;
261     pes_packet_t    *p_pes;
262     ssize_t         i_size;
263     mtime_t         i_pts;
264
265     /* **** get samples count **** */
266     input_ExtractPES( p_pack->p_fifo, &p_pes );
267     if( !p_pes )
268     {
269         p_pack->p_fifo->b_error = 1;
270         return;
271     }
272
273     i_pts = p_pes->i_pts;
274 #if 0
275     if( i_pts <= 0 && p_pack->i_last_pts <= 0 )
276     {
277         msg_Dbg( p_pack->p_fifo, "need a starting pts" );
278         input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes );
279         return;
280     }
281 #endif
282
283     i_size = p_pes->i_pes_size;
284     if( i_size > 0 )
285     {
286         pes_packet_t    *p_pes_next;
287         data_packet_t   *p_data;
288         ssize_t          i_buffer;
289
290         p_sout_buffer =
291             sout_BufferNew( p_pack->p_sout_input->p_sout, i_size );
292         if( !p_sout_buffer )
293         {
294             p_pack->p_fifo->b_error = 1;
295             return;
296         }
297         /* TODO: memcpy of the pes packet */
298         for( i_buffer = 0, p_data = p_pes->p_first;
299              p_data != NULL && i_buffer < i_size;
300              p_data = p_data->p_next)
301         {
302             ssize_t i_copy;
303
304             i_copy = __MIN( p_data->p_payload_end - p_data->p_payload_start, 
305                             i_size - i_buffer );
306             if( i_copy > 0 )
307             {
308                 p_pack->p_fifo->p_vlc->pf_memcpy( p_sout_buffer->p_buffer + i_buffer,
309                                                   p_data->p_payload_start,
310                                                   i_copy );
311             }
312             i_buffer += i_copy;
313         }
314
315         input_ShowPES( p_pack->p_fifo, &p_pes_next );
316         if( p_pes_next && p_pes_next->i_pts > 0 )
317         {
318             mtime_t i_gap;
319
320             i_gap = p_pes_next->i_pts - p_pes->i_pts;
321             p_sout_buffer->i_length = i_gap;
322         }
323         else
324         {
325             p_sout_buffer->i_length = 0;
326         }
327         p_sout_buffer->i_dts = i_pts;
328         p_sout_buffer->i_pts = i_pts;
329         p_sout_buffer->i_bitrate = 0;
330
331         if( p_pack->p_vol == NULL )
332         {
333             uint8_t *p_vol_begin, *p_vol_end, *p_end;
334             /* search if p_sout_buffer contains with a vol */
335             p_vol_begin = p_sout_buffer->p_buffer;
336             p_vol_end   = NULL;
337             p_end       = p_sout_buffer->p_buffer + p_sout_buffer->i_size;
338
339             for( ;; )
340             {
341                 if( m4v_FindStartCode( &p_vol_begin, p_end ) )
342                 {
343                     break;
344                 }
345                 msg_Dbg( p_pack->p_fifo,
346                           "starcode 0x%2.2x%2.2x%2.2x%2.2x",
347                           p_vol_begin[0], p_vol_begin[1], p_vol_begin[2], p_vol_begin[3] );
348
349                 if( ( p_vol_begin[3] & ~VIDEO_OBJECT_MASK ) == ( VIDEO_OBJECT_START_CODE&0xff ) )
350                 {
351                     p_vol_end = p_vol_begin + 4;
352                     if( m4v_FindStartCode( &p_vol_end, p_end ) )
353                     {
354                         break;
355                     }
356                     if( ( p_vol_end[3] & ~VIDEO_OBJECT_LAYER_MASK ) == ( VIDEO_OBJECT_LAYER_START_CODE&0xff ) )
357                     {
358                         p_vol_end += 4;
359                         if( m4v_FindStartCode( &p_vol_end, p_end ) )
360                         {
361                             p_vol_end = p_end;
362                         }
363                     }
364                     else
365                     {
366                         p_vol_end = NULL;
367                     }
368                 }
369                 else if( ( p_vol_begin[3] & ~VIDEO_OBJECT_LAYER_MASK ) == ( VIDEO_OBJECT_LAYER_START_CODE&0xff) )
370                 {
371                     p_vol_end = p_vol_begin + 4;
372                     if( m4v_FindStartCode( &p_vol_end, p_end ) )
373                     {
374                         p_vol_end = p_end;
375                     }
376                 }
377
378                 if( p_vol_end != NULL && p_vol_begin < p_vol_end )
379                 {
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                     p_pack->output_format.i_width  = 0;
392                     p_pack->output_format.i_height = 0;
393                     p_pack->output_format.i_bitrate= 0;
394
395                     p_pack->output_format.i_extra_data = p_pack->i_vol;
396                     p_pack->output_format.p_extra_data = malloc( p_pack->i_vol );
397                     memcpy( p_pack->output_format.p_extra_data,
398                             p_pack->p_vol,
399                             p_pack->i_vol );
400
401                     p_pack->p_sout_input =
402                         sout_InputNew( p_pack->p_fifo,
403                                        &p_pack->output_format );
404                     if( !p_pack->p_sout_input )
405                     {
406                         p_pack->p_fifo->b_error = 1;
407                         return;
408                     }
409
410                     break;
411                 }
412                 else
413                 {
414                     p_vol_begin += 4;
415                 }
416             }
417         }
418
419         if( i_pts > 0 )
420         {
421             sout_InputSendBuffer( p_pack->p_sout_input,
422                                   p_sout_buffer );
423         }
424         else
425         {
426             sout_BufferDelete( p_pack->p_sout_input->p_sout,
427                                p_sout_buffer );
428         }
429     }
430
431     input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes );
432 }
433
434
435 /*****************************************************************************
436  * EndThread : packetizer thread destruction
437  *****************************************************************************/
438 static void EndThread ( packetizer_thread_t *p_pack)
439 {
440     if( p_pack->p_sout_input )
441     {
442         sout_InputDelete( p_pack->p_sout_input );
443     }
444 }
445
446 static void input_ShowPES( decoder_fifo_t *p_fifo, pes_packet_t **pp_pes )
447 {
448     pes_packet_t *p_pes;
449
450     vlc_mutex_lock( &p_fifo->data_lock );
451
452     if( p_fifo->p_first == NULL )
453     {
454         if( p_fifo->b_die )
455         {
456             vlc_mutex_unlock( &p_fifo->data_lock );
457             if( pp_pes ) *pp_pes = NULL;
458             return;
459         }
460
461         /* Signal the input thread we're waiting. This is only
462          * needed in case of slave clock (ES plug-in) but it won't
463          * harm. */
464         vlc_cond_signal( &p_fifo->data_wait );
465
466         /* Wait for the input to tell us when we received a packet. */
467         vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
468     }
469     p_pes = p_fifo->p_first;
470     vlc_mutex_unlock( &p_fifo->data_lock );
471
472     if( pp_pes )
473     {
474         *pp_pes = p_pes;
475     }
476 }
477