]> git.sesse.net Git - vlc/blob - modules/packetizer/mpeg4video.c
Added stream output. (common work with titer).
[vlc] / modules / packetizer / mpeg4video.c
1 /*****************************************************************************
2  * mpeg4video.c:
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VideoLAN
5  * $Id: mpeg4video.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/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 /*****************************************************************************
38  * Local prototypes
39  *****************************************************************************/
40 typedef struct packetizer_thread_s
41 {
42     /* Input properties */
43     decoder_fifo_t          *p_fifo;
44     bit_stream_t            bit_stream;
45
46     mtime_t                 i_dts;
47
48     /* Output properties */
49     sout_input_t            *p_sout_input;
50     sout_packet_format_t    output_format;
51
52
53     sout_buffer_t           *p_vol;
54     int                     i_vop_since_vol;
55 } packetizer_thread_t;
56
57 static int  Open    ( vlc_object_t * );
58 static int  Run     ( decoder_fifo_t * );
59
60 static int  InitThread     ( packetizer_thread_t * );
61 static void PacketizeThread   ( packetizer_thread_t * );
62 static void EndThread      ( packetizer_thread_t * );
63
64 /*****************************************************************************
65  * Module descriptor
66  *****************************************************************************/
67
68 vlc_module_begin();
69     set_description( _("MPEG-4 packetizer") );
70     set_capability( "packetizer", 50 );
71     set_callbacks( Open, NULL );
72 vlc_module_end();
73
74 #define VIDEO_OBJECT_MASK                       0x01f
75 #define VIDEO_OBJECT_LAYER_MASK                 0x00f
76
77 #define VIDEO_OBJECT_START_CODE                 0x100
78 #define VIDEO_OBJECT_LAYER_START_CODE           0x120
79 #define VISUAL_OBJECT_SEQUENCE_START_CODE       0x1b0
80 #define VISUAL_OBJECT_SEQUENCE_END_CODE         0x1b1
81 #define USER_DATA_START_CODE                    0x1b2
82 #define GROUP_OF_VOP_START_CODE                 0x1b3
83 #define VIDEO_SESSION_ERROR_CODE                0x1b4
84 #define VISUAL_OBJECT_START_CODE                0x1b5
85 #define VOP_START_CODE                          0x1b6
86 #define FACE_OBJECT_START_CODE                  0x1ba
87 #define FACE_OBJECT_PLANE_START_CODE            0x1bb
88 #define MESH_OBJECT_START_CODE                  0x1bc
89 #define MESH_OBJECT_PLANE_START_CODE            0x1bd
90 #define STILL_TEXTURE_OBJECT_START_CODE         0x1be
91 #define TEXTURE_SPATIAL_LAYER_START_CODE        0x1bf
92 #define TEXTURE_SNR_LAYER_START_CODE            0x1c0
93
94 /*****************************************************************************
95  * OpenDecoder: probe the packetizer and return score
96  *****************************************************************************
97  * Tries to launch a decoder and return score so that the interface is able
98  * to choose.
99  *****************************************************************************/
100 static int Open( vlc_object_t *p_this )
101 {
102     decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
103
104     p_fifo->pf_run = Run;
105
106     switch(  p_fifo->i_fourcc )
107     {
108         case VLC_FOURCC( 'm', 'p', '4', 'v'):
109         case VLC_FOURCC( 'D', 'I', 'V', 'X'):
110         case VLC_FOURCC( 'd', 'i', 'v', 'x'):
111         case VLC_FOURCC( 'X', 'V', 'I', 'D'):
112         case VLC_FOURCC( 'X', 'v', 'i', 'D'):
113         case VLC_FOURCC( 'x', 'v', 'i', 'd'):
114         case VLC_FOURCC( 'D', 'X', '5', '0'):
115             return VLC_SUCCESS;
116         default:
117             return VLC_EGENERIC;
118     }
119 }
120
121 /*****************************************************************************
122  * RunDecoder: this function is called just after the thread is created
123  *****************************************************************************/
124 static int Run( decoder_fifo_t *p_fifo )
125 {
126     packetizer_thread_t *p_pack;
127     int b_error;
128
129     msg_Info( p_fifo, "Running MPEG-4 packetizer" );
130     if( !( p_pack = malloc( sizeof( packetizer_thread_t ) ) ) )
131     {
132         msg_Err( p_fifo, "out of memory" );
133         DecoderError( p_fifo );
134         return( -1 );
135     }
136     memset( p_pack, 0, sizeof( packetizer_thread_t ) );
137
138     p_pack->p_fifo = p_fifo;
139
140     if( InitThread( p_pack ) != 0 )
141     {
142         DecoderError( p_fifo );
143         return( -1 );
144     }
145
146     while( ( !p_pack->p_fifo->b_die )&&( !p_pack->p_fifo->b_error ) )
147     {
148         PacketizeThread( p_pack );
149     }
150
151
152     if( ( b_error = p_pack->p_fifo->b_error ) )
153     {
154         DecoderError( p_pack->p_fifo );
155     }
156
157     EndThread( p_pack );
158     if( b_error )
159     {
160         return( -1 );
161     }
162
163     return( 0 );
164 }
165
166
167 #define FREE( p ) if( p ) free( p ); p = NULL
168
169 static int CopyUntilNextStartCode( packetizer_thread_t   *p_pack,
170                                    sout_buffer_t  *p_sout_buffer,
171                                    int            *pi_pos )
172 {
173     int i_copy = 0;
174
175     do
176     {
177         p_sout_buffer->p_buffer[(*pi_pos)++] =
178         GetBits( &p_pack->bit_stream, 8 );
179         i_copy++;
180
181         if( *pi_pos + 2048 > p_sout_buffer->i_allocated_size )
182         {
183             sout_BufferRealloc( p_pack->p_sout_input->p_sout,
184                                 p_sout_buffer,
185                                 p_sout_buffer->i_allocated_size + 50 * 1024);
186         }
187
188     } while( ShowBits( &p_pack->bit_stream, 24 ) != 0x01 &&
189              !p_pack->p_fifo->b_die && !p_pack->p_fifo->b_error );
190
191     return( i_copy );
192 }
193
194 static int sout_BufferAddMem( sout_instance_t *p_sout,
195                               sout_buffer_t   *p_buffer,
196                               int             i_mem,
197                               uint8_t         *p_mem )
198 {
199     if( p_buffer->i_size + i_mem >= p_buffer->i_allocated_size )
200     {
201         sout_BufferRealloc( p_sout,
202                             p_buffer,
203                             p_buffer->i_size + i_mem + 1024 );
204     }
205     memcpy( p_buffer->p_buffer + p_buffer->i_size, p_mem, i_mem );
206     p_buffer->i_size += i_mem;
207
208     return( i_mem );
209 }
210
211 /*****************************************************************************
212  * InitThread: initialize data before entering main loop
213  *****************************************************************************/
214
215 static int InitThread( packetizer_thread_t *p_pack )
216 {
217     p_pack->i_dts = 0;
218     p_pack->p_vol = NULL;
219     p_pack->i_vop_since_vol = 0;
220     p_pack->output_format.i_cat = VIDEO_ES;
221     p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', '4', 'v' );
222
223     if( InitBitstream( &p_pack->bit_stream, p_pack->p_fifo,
224                        NULL, NULL ) != VLC_SUCCESS )
225     {
226         msg_Err( p_pack->p_fifo, "cannot initialize bitstream" );
227         return -1;
228     }
229
230     p_pack->p_sout_input =
231         sout_InputNew( p_pack->p_fifo,
232                        &p_pack->output_format );
233
234     if( !p_pack->p_sout_input )
235     {
236         msg_Err( p_pack->p_fifo,
237                  "cannot add a new stream" );
238         return( -1 );
239     }
240
241     return( 0 );
242 }
243
244 /*****************************************************************************
245  * PacketizeThread: packetize an unit (here copy a complete pes)
246  *****************************************************************************/
247 static void PacketizeThread( packetizer_thread_t *p_pack )
248 {
249     sout_instance_t *p_sout = p_pack->p_sout_input->p_sout;
250     sout_buffer_t   *p_frame;
251
252     uint32_t        i_startcode;
253
254     /* Idea: Copy until a vop has been found
255      *       Once a videoobject & videoobjectlayer has been found we save it
256      */
257
258     p_frame = sout_BufferNew( p_sout, 20*1024 );    // FIXME
259     p_frame->i_size = 0;
260
261     for( ;; )
262     {
263         while( ( ( i_startcode = ShowBits( &p_pack->bit_stream, 32 ) )&0xffffff00 ) != 0x00000100 )
264         {
265             RemoveBits( &p_pack->bit_stream, 8 );
266         }
267
268         if( i_startcode == VISUAL_OBJECT_SEQUENCE_START_CODE )
269         {
270             msg_Dbg( p_pack->p_fifo, "<visuel_object_sequence>" );
271             RemoveBits32( &p_pack->bit_stream );
272         }
273         else if( i_startcode == VISUAL_OBJECT_SEQUENCE_END_CODE )
274         {
275             msg_Dbg( p_pack->p_fifo, "</visuel_object_sequence>" );
276             RemoveBits32( &p_pack->bit_stream );
277         }
278         else
279         {
280             msg_Dbg( p_pack->p_fifo, "start code:0x%8.8x", i_startcode );
281
282             if( ( i_startcode & ~VIDEO_OBJECT_MASK ) == VIDEO_OBJECT_START_CODE )
283             {
284                 msg_Dbg( p_pack->p_fifo, "<video_object>" );
285                 CopyUntilNextStartCode( p_pack, p_frame, &p_frame->i_size );
286             }
287             else if( ( i_startcode & ~VIDEO_OBJECT_LAYER_MASK ) == VIDEO_OBJECT_LAYER_START_CODE )
288             {
289                 /* first: save it */
290                 if( p_pack->p_vol == NULL )
291                 {
292                     p_pack->p_vol = sout_BufferNew( p_sout, 1024 );
293                 }
294                 p_pack->p_vol->i_size = 0;
295                 CopyUntilNextStartCode( p_pack, p_pack->p_vol, &p_pack->p_vol->i_size );
296                 p_pack->i_vop_since_vol = 0;
297
298                 /* then: add it to p_frame */
299                 sout_BufferAddMem( p_sout, p_frame,
300                                    p_pack->p_vol->i_size,
301                                    p_pack->p_vol->p_buffer );
302             }
303             else if( i_startcode == GROUP_OF_VOP_START_CODE )
304             {
305                 msg_Dbg( p_pack->p_fifo, "<group_of_vop>" );
306                 if( p_pack->p_vol && p_pack->i_vop_since_vol > 100 ) // FIXME
307                 {
308                     sout_BufferAddMem( p_sout, p_frame,
309                                        p_pack->p_vol->i_size,
310                                        p_pack->p_vol->p_buffer );
311                     p_pack->i_vop_since_vol = 0;
312                 }
313                 CopyUntilNextStartCode( p_pack, p_frame, &p_frame->i_size );
314             }
315             else if( i_startcode == VOP_START_CODE )
316             {
317                 msg_Dbg( p_pack->p_fifo, "<vop>" );
318                 if( p_pack->p_vol && p_pack->i_vop_since_vol > 100 ) // FIXME
319                 {
320                     sout_BufferAddMem( p_sout, p_frame,
321                                        p_pack->p_vol->i_size,
322                                        p_pack->p_vol->p_buffer );
323                     p_pack->i_vop_since_vol = 0;
324                 }
325                 CopyUntilNextStartCode( p_pack, p_frame, &p_frame->i_size );
326                 p_pack->i_vop_since_vol++;
327                 break;
328             }
329             else
330             {
331                 msg_Dbg( p_pack->p_fifo, "unknown start code" );
332                 CopyUntilNextStartCode( p_pack, p_frame, &p_frame->i_size );
333             }
334
335         }
336     }
337
338     p_frame->i_length = 1000000 / 25;
339     p_frame->i_bitrate= 0;
340     p_frame->i_dts = p_pack->i_dts;
341     p_frame->i_pts = p_pack->i_dts;
342
343     p_pack->i_dts += 1000000 / 25;
344     sout_InputSendBuffer( p_pack->p_sout_input, p_frame );
345 }
346
347
348 /*****************************************************************************
349  * EndThread : packetizer thread destruction
350  *****************************************************************************/
351 static void EndThread ( packetizer_thread_t *p_pack)
352 {
353     if( p_pack->p_sout_input )
354     {
355         sout_InputDelete( p_pack->p_sout_input );
356     }
357 }
358