* asf : asf muxer, not well tested yet.
[vlc.git] / modules / mux / asf.c
1 /*****************************************************************************
2  * asf.c
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id: asf.c,v 1.1 2003/08/24 16:38:38 fenrir Exp $
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>
28
29 #include <vlc/vlc.h>
30 #include <vlc/input.h>
31 #include <vlc/sout.h>
32
33 #include "codecs.h"
34
35 /*****************************************************************************
36  * Module descriptor
37  *****************************************************************************/
38 static int  Open   ( vlc_object_t * );
39 static void Close  ( vlc_object_t * );
40
41 vlc_module_begin();
42     set_description( _("Asf muxer") );
43     set_capability( "sout mux", 5 );
44     add_shortcut( "asf" );
45     set_callbacks( Open, Close );
46 vlc_module_end();
47
48 /*****************************************************************************
49  * Locales prototypes
50  *****************************************************************************/
51 static int  Capability(sout_mux_t *, int, void *, void * );
52 static int  AddStream( sout_mux_t *, sout_input_t * );
53 static int  DelStream( sout_mux_t *, sout_input_t * );
54 static int  Mux      ( sout_mux_t * );
55
56 typedef struct
57 {
58     uint32_t v1; /* le */
59     uint16_t v2; /* le */
60     uint16_t v3; /* le */
61     uint8_t  v4[8];
62 } guid_t;
63
64 typedef struct
65 {
66     int     i_id;
67     int     i_cat;
68     int     i_sequence;
69
70     int     i_extra;
71     uint8_t *p_extra;
72 } asf_track_t;
73
74 struct sout_mux_sys_t
75 {
76     guid_t          fid;    /* file id */
77     int             i_packet_size;
78     int64_t         i_packet_count;
79     mtime_t         i_dts_first;
80
81     int             i_track;
82     asf_track_t     track[128];
83
84     vlc_bool_t      b_write_header;
85
86     sout_buffer_t   *pk;
87     int             i_pk_used;
88     int             i_pk_frame;
89     mtime_t         i_pk_dts;
90 };
91
92 static int MuxGetStream( sout_mux_t *, int *pi_stream, mtime_t *pi_dts );
93
94 static sout_buffer_t *asf_header_create( sout_mux_t *, vlc_bool_t b_broadcast );
95 static sout_buffer_t *asf_packet_create( sout_mux_t *,
96                                          asf_track_t *, sout_buffer_t * );
97
98 typedef struct
99 {
100     int      i_buffer_size;
101     int      i_buffer;
102     uint8_t  *p_buffer;
103 } bo_t;
104
105 static void bo_init     ( bo_t *, uint8_t *, int  );
106 static void bo_add_u8   ( bo_t *, uint8_t  );
107 static void bo_addle_u16( bo_t *, uint16_t );
108 static void bo_addle_u32( bo_t *, uint32_t );
109 static void bo_addle_u64( bo_t *, uint64_t );
110 static void bo_add_mem  ( bo_t *, uint8_t *, int );
111
112
113 /*****************************************************************************
114  * Open:
115  *****************************************************************************/
116 static int Open( vlc_object_t *p_this )
117 {
118     sout_mux_t     *p_mux = (sout_mux_t*)p_this;
119     sout_mux_sys_t *p_sys;
120     int i;
121
122     msg_Dbg( p_mux, "Asf muxer opened" );
123
124     p_mux->pf_capacity  = Capability;
125     p_mux->pf_addstream = AddStream;
126     p_mux->pf_delstream = DelStream;
127     p_mux->pf_mux       = Mux;
128
129     p_mux->p_sys = p_sys = malloc( sizeof( sout_mux_sys_t ) );
130     p_sys->pk = NULL;
131     p_sys->i_pk_used = 0;
132     p_sys->i_pk_frame = 0;
133     p_sys->i_dts_first = -1;
134
135     p_sys->b_write_header = VLC_TRUE;
136     p_sys->i_track = 1;
137     p_sys->i_packet_size = 4096;
138     p_sys->i_packet_count= 0;
139     /* generate a random fid */
140     srand( mdate() & 0xffffffff );
141     p_sys->fid.v1 = 0xbabac001;
142     p_sys->fid.v2 = ( (uint64_t)rand() << 16 ) / RAND_MAX;
143     p_sys->fid.v3 = ( (uint64_t)rand() << 16 ) / RAND_MAX;
144     for( i = 0; i < 8; i++ )
145     {
146         p_sys->fid.v4[i] = ( (uint64_t)rand() << 8 ) / RAND_MAX;
147     }
148
149     return VLC_SUCCESS;
150 }
151
152 /*****************************************************************************
153  * Close:
154  *****************************************************************************/
155 static void Close( vlc_object_t * p_this )
156 {
157     sout_mux_t     *p_mux = (sout_mux_t*)p_this;
158     sout_mux_sys_t *p_sys = p_mux->p_sys;
159     int i;
160
161     msg_Dbg( p_mux, "Asf muxer closed" );
162
163     /* rewrite header */
164     if( !sout_AccessOutSeek( p_mux->p_access, 0 ) )
165     {
166         sout_buffer_t *h = asf_header_create( p_mux, VLC_FALSE );
167         sout_AccessOutWrite( p_mux->p_access, h );
168     }
169
170     for( i = 1; i < p_sys->i_track; i++ )
171     {
172         free( p_sys->track[i].p_extra );
173     }
174     free( p_sys );
175 }
176
177 /*****************************************************************************
178  * Capability:
179  *****************************************************************************/
180 static int Capability( sout_mux_t *p_mux, int i_query,
181                        void *p_args, void *p_answer )
182 {
183    switch( i_query )
184    {
185         case SOUT_MUX_CAP_GET_ADD_STREAM_ANY_TIME:
186             *(vlc_bool_t*)p_answer = VLC_FALSE;
187             return( SOUT_MUX_CAP_ERR_OK );
188         default:
189             return( SOUT_MUX_CAP_ERR_UNIMPLEMENTED );
190    }
191 }
192
193 /*****************************************************************************
194  * AddStream:
195  *****************************************************************************/
196 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
197 {
198     sout_mux_sys_t   *p_sys = p_mux->p_sys;
199     asf_track_t      *tk;
200     bo_t             bo;
201
202     msg_Dbg( p_mux, "adding input" );
203     if( p_sys->i_track > 127 )
204     {
205         msg_Dbg( p_mux, "cannot add this track (too much track)" );
206         return VLC_EGENERIC;
207     }
208
209     tk = p_input->p_sys = &p_sys->track[p_sys->i_track];
210     tk->i_id  = p_sys->i_track;
211     tk->i_cat = p_input->p_fmt->i_cat;
212     tk->i_sequence = 0;
213
214     switch( tk->i_cat )
215     {
216         case AUDIO_ES:
217         {
218             uint16_t i_tag;
219             int      i_blockalign = p_input->p_fmt->i_block_align;
220             int      i_bitspersample = 0;
221
222             switch( p_input->p_fmt->i_fourcc )
223             {
224                 case VLC_FOURCC( 'a', '5', '2', ' ' ):
225                     i_tag = WAVE_FORMAT_A52;
226                     break;
227                 case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
228                     i_tag = WAVE_FORMAT_MPEGLAYER3;
229                     break;
230                 case VLC_FOURCC( 'w', 'm', 'a', '1' ):
231                     i_tag = WAVE_FORMAT_WMA1;
232                     break;
233                 case VLC_FOURCC( 'w', 'm', 'a', '2' ):
234                     i_tag = WAVE_FORMAT_WMA2;
235                     break;
236                 case VLC_FOURCC( 'w', 'm', 'a', '3' ):
237                     i_tag = WAVE_FORMAT_WMA3;
238                     break;
239                     /* raw codec */
240                 case VLC_FOURCC( 'u', '8', ' ', ' ' ):
241                     i_tag = WAVE_FORMAT_PCM;
242                     i_blockalign= p_input->p_fmt->i_channels;
243                     i_bitspersample = 8;
244                     break;
245                 case VLC_FOURCC( 's', '1', '6', 'l' ):
246                     i_tag = WAVE_FORMAT_PCM;
247                     i_blockalign= 2 * p_input->p_fmt->i_channels;
248                     i_bitspersample = 16;
249                     break;
250                 case VLC_FOURCC( 's', '2', '4', 'l' ):
251                     i_tag = WAVE_FORMAT_PCM;
252                     i_blockalign= 3 * p_input->p_fmt->i_channels;
253                     i_bitspersample = 24;
254                     break;
255                 case VLC_FOURCC( 's', '3', '2', 'l' ):
256                     i_tag = WAVE_FORMAT_PCM;
257                     i_blockalign= 4 * p_input->p_fmt->i_channels;
258                     i_bitspersample = 32;
259                     break;
260                 default:
261                     return VLC_EGENERIC;
262             }
263
264             tk->i_extra = sizeof( WAVEFORMATEX ) + p_input->p_fmt->i_extra_data;
265             tk->p_extra = malloc( tk->i_extra );
266             bo_init( &bo, tk->p_extra, tk->i_extra );
267             bo_addle_u16( &bo, i_tag );
268             bo_addle_u16( &bo, p_input->p_fmt->i_channels );
269             bo_addle_u32( &bo, p_input->p_fmt->i_sample_rate );
270             bo_addle_u32( &bo, p_input->p_fmt->i_bitrate / 8 );
271             bo_addle_u16( &bo, i_blockalign );
272             bo_addle_u16( &bo, i_bitspersample );
273             bo_addle_u16( &bo, p_input->p_fmt->i_extra_data );
274             bo_add_mem  ( &bo, p_input->p_fmt->p_extra_data,
275                           p_input->p_fmt->i_extra_data );
276             break;
277         }
278         case VIDEO_ES:
279         {
280             tk->i_extra = 11 + sizeof( BITMAPINFOHEADER ) +
281                           p_input->p_fmt->i_extra_data;
282             tk->p_extra = malloc( tk->i_extra );
283             bo_init( &bo, tk->p_extra, tk->i_extra );
284             bo_addle_u32( &bo, p_input->p_fmt->i_width );
285             bo_addle_u32( &bo, p_input->p_fmt->i_height );
286             bo_add_u8   ( &bo, 0x02 );  /* flags */
287             bo_addle_u16( &bo, sizeof( BITMAPINFOHEADER ) +
288                                p_input->p_fmt->i_extra_data );
289             bo_addle_u32( &bo, sizeof( BITMAPINFOHEADER ) +
290                                p_input->p_fmt->i_extra_data );
291             bo_addle_u32( &bo, p_input->p_fmt->i_width );
292             bo_addle_u32( &bo, p_input->p_fmt->i_height );
293             bo_addle_u16( &bo, 1 );
294             bo_addle_u16( &bo, 24 );
295             if( p_input->p_fmt->i_fourcc == VLC_FOURCC('m','p','4','v') )
296             {
297                 bo_add_mem( &bo, "MP4S", 4 );
298             }
299             else if( p_input->p_fmt->i_fourcc == VLC_FOURCC('D','I','V','3') )
300             {
301                 bo_add_mem( &bo, "MP43", 4 );
302             }
303             else
304             {
305                 bo_add_mem( &bo, (uint8_t*)&p_input->p_fmt->i_fourcc, 4 );
306             }
307             bo_addle_u32( &bo, 0 );
308             bo_addle_u32( &bo, 0 );
309             bo_addle_u32( &bo, 0 );
310             bo_addle_u32( &bo, 0 );
311             bo_addle_u32( &bo, 0 );
312             bo_add_mem  ( &bo, p_input->p_fmt->p_extra_data,
313                           p_input->p_fmt->i_extra_data );
314             break;
315         }
316         default:
317             msg_Err(p_mux, "unhandled track type" );
318             return VLC_EGENERIC;
319     }
320
321     p_sys->i_track++;
322     return VLC_SUCCESS;
323 }
324
325 /*****************************************************************************
326  * DelStream:
327  *****************************************************************************/
328 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
329 {
330     msg_Dbg( p_mux, "removing input" );
331     return VLC_SUCCESS;
332 }
333
334 /*****************************************************************************
335  * Mux:
336  *****************************************************************************/
337 static int Mux      ( sout_mux_t *p_mux )
338 {
339     sout_mux_sys_t *p_sys = p_mux->p_sys;
340
341     if( p_sys->b_write_header )
342     {
343         sout_buffer_t *out = asf_header_create( p_mux, VLC_TRUE );
344
345         out->i_flags |= SOUT_BUFFER_FLAGS_HEADER;
346         sout_AccessOutWrite( p_mux->p_access, out );
347
348         p_sys->b_write_header = VLC_FALSE;
349     }
350
351     for( ;; )
352     {
353         sout_input_t  *p_input;
354         asf_track_t   *tk;
355         int           i_stream;
356         mtime_t       i_dts;
357         sout_buffer_t *data;
358         sout_buffer_t *pk;
359
360         if( MuxGetStream( p_mux, &i_stream, &i_dts ) )
361         {
362             /* not enough data */
363             return VLC_SUCCESS;
364         }
365
366         if( p_sys->i_dts_first < 0 )
367         {
368             p_sys->i_dts_first = i_dts;
369         }
370
371         p_input = p_mux->pp_inputs[i_stream];
372         tk      = (asf_track_t*)p_input->p_sys;
373
374         data = sout_FifoGet( p_input->p_fifo );
375
376         if( ( pk = asf_packet_create( p_mux, tk, data ) ) )
377         {
378             sout_AccessOutWrite( p_mux->p_access, pk );
379         }
380     }
381
382     return VLC_SUCCESS;
383 }
384
385
386 static int MuxGetStream( sout_mux_t *p_mux,
387                          int        *pi_stream,
388                          mtime_t    *pi_dts )
389 {
390     mtime_t i_dts;
391     int     i_stream;
392     int     i;
393
394     for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ )
395     {
396         sout_input_t  *p_input = p_mux->pp_inputs[i];
397         sout_buffer_t *p_data;
398
399         if( p_input->p_fifo->i_depth <= 0 )
400         {
401             if( p_input->p_fmt->i_cat == AUDIO_ES ||
402                 p_input->p_fmt->i_cat == VIDEO_ES )
403             {
404                 /* We need that audio+video fifo contain at least 1 packet */
405                 return VLC_EGENERIC;
406             }
407             /* SPU */
408             continue;
409         }
410
411         p_data = sout_FifoShow( p_input->p_fifo );
412         if( i_stream == -1 ||
413             p_data->i_dts < i_dts )
414         {
415             i_stream = i;
416             i_dts    = p_data->i_dts;
417         }
418     }
419
420     *pi_stream = i_stream;
421     *pi_dts = i_dts;
422
423     return VLC_SUCCESS;
424 }
425
426 /****************************************************************************
427  * Asf header construction
428  ****************************************************************************/
429
430 /****************************************************************************
431  * Buffer out
432  ****************************************************************************/
433 static void bo_init( bo_t *p_bo, uint8_t *p_buffer, int i_size )
434 {
435     p_bo->i_buffer_size = i_size;
436     p_bo->i_buffer = 0;
437     p_bo->p_buffer = p_buffer;
438 }
439 static void bo_add_u8( bo_t *p_bo, uint8_t i )
440 {
441     if( p_bo->i_buffer < p_bo->i_buffer_size )
442     {
443         p_bo->p_buffer[p_bo->i_buffer] = i;
444     }
445     p_bo->i_buffer++;
446 }
447 static void bo_addle_u16( bo_t *p_bo, uint16_t i )
448 {
449     bo_add_u8( p_bo, i &0xff );
450     bo_add_u8( p_bo, ( ( i >> 8) &0xff ) );
451 }
452 static void bo_addle_u32( bo_t *p_bo, uint32_t i )
453 {
454     bo_addle_u16( p_bo, i &0xffff );
455     bo_addle_u16( p_bo, ( ( i >> 16) &0xffff ) );
456 }
457 static void bo_addle_u64( bo_t *p_bo, uint64_t i )
458 {
459     bo_addle_u32( p_bo, i &0xffffffff );
460     bo_addle_u32( p_bo, ( ( i >> 32) &0xffffffff ) );
461 }
462
463 static void bo_add_mem( bo_t *p_bo, uint8_t *p_mem, int i_size )
464 {
465     int i_copy = __MIN( i_size, p_bo->i_buffer_size - p_bo->i_buffer );
466
467     if( i_copy > 0 )
468     {
469         memcpy( &p_bo->p_buffer[p_bo->i_buffer],
470                 p_mem,
471                 i_copy );
472     }
473     p_bo->i_buffer += i_size;
474 }
475
476 /****************************************************************************
477  * guid
478  ****************************************************************************/
479 static void bo_add_guid( bo_t *p_bo, const guid_t *id )
480 {
481     int i;
482     bo_addle_u32( p_bo, id->v1 );
483     bo_addle_u16( p_bo, id->v2 );
484     bo_addle_u16( p_bo, id->v3 );
485     for( i = 0; i < 8; i++ )
486     {
487         bo_add_u8( p_bo, id->v4[i] );
488     }
489 }
490
491 static const guid_t asf_object_header_guid =
492 {
493     0x75B22630,
494     0x668E,
495     0x11CF,
496     { 0xA6,0xD9, 0x00,0xAA,0x00,0x62,0xCE,0x6C }
497 };
498 static const guid_t asf_object_data_guid =
499 {
500     0x75B22636,
501     0x668E,
502     0x11CF,
503     { 0xA6,0xD9, 0x00,0xAA,0x00,0x62,0xCE,0x6C }
504 };
505
506 static const guid_t asf_object_file_properties_guid =
507 {
508     0x8cabdca1,
509     0xa947,
510     0x11cf,
511     { 0x8e,0xe4, 0x00,0xC0,0x0C,0x20,0x53,0x65 }
512
513 };
514 static const guid_t asf_object_stream_properties_guid =
515 {
516     0xB7DC0791,
517     0xA9B7,
518     0x11CF,
519     { 0x8E,0xE6, 0x00,0xC0,0x0C,0x20,0x53,0x65 }
520
521 };
522 static const guid_t asf_object_header_extention_guid =
523 {
524    0x5FBF03B5,
525    0xA92E,
526    0x11CF,
527    { 0x8E,0xE3, 0x00,0xC0,0x0C,0x20,0x53,0x65 }
528 };
529
530 static const guid_t asf_object_stream_type_audio =
531 {
532     0xF8699E40,
533     0x5B4D,
534     0x11CF,
535     { 0xA8,0xFD, 0x00,0x80,0x5F,0x5C,0x44,0x2B }
536 };
537
538 static const guid_t asf_object_stream_type_video =
539 {
540     0xbc19efc0,
541     0x5B4D,
542     0x11CF,
543     { 0xA8,0xFD, 0x00,0x80,0x5F,0x5C,0x44,0x2B }
544 };
545
546 static const guid_t asf_guid_audio_conceal_none =
547 {
548     0x20FB5700,
549     0x5B55,
550     0x11CF,
551     { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B }
552 };
553 static const guid_t asf_guid_video_conceal_none =
554 {
555     0x20FB5700,
556     0x5B55,
557     0x11CF,
558     { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B }
559 };
560 static const guid_t asf_guid_reserved_1 =
561 {
562     0xABD3D211,
563     0xA9BA,
564     0x11cf,
565     { 0x8E, 0xE6,0x00, 0xC0, 0x0C ,0x20, 0x53, 0x65 }
566 };
567
568 static sout_buffer_t *asf_header_create( sout_mux_t *p_mux,
569                                          vlc_bool_t b_broadcast )
570 {
571     sout_mux_sys_t *p_sys = p_mux->p_sys;
572     asf_track_t    *tk;
573
574     int i_size;
575     sout_buffer_t *out;
576     bo_t          bo;
577     int           i;
578
579     /* calculate header size */
580     i_size = 30 + 104 + 46;
581     for( i = 1; i < p_sys->i_track; i++ )
582     {
583         i_size += 78 + p_sys->track[i].i_extra;
584     }
585     out = sout_BufferNew( p_mux->p_sout, i_size + 50 );
586     bo_init( &bo, out->p_buffer, i_size + 50 );
587
588     /* header object */
589     bo_add_guid ( &bo, &asf_object_header_guid );
590     bo_addle_u64( &bo, i_size );
591     bo_addle_u32( &bo, 2 + p_sys->i_track );
592     bo_add_u8   ( &bo, 1 );
593     bo_add_u8   ( &bo, 2 );
594
595     /* sub object */
596
597     /* file properties */
598     bo_add_guid ( &bo, &asf_object_file_properties_guid );
599     bo_addle_u64( &bo, 104 );
600     bo_add_guid ( &bo, &p_sys->fid );
601     bo_addle_u64( &bo, i_size + p_sys->i_packet_count *
602                                 p_sys->i_packet_size ); /* file size */
603     bo_addle_u64( &bo, 0 );             /* creation date */
604     bo_addle_u64( &bo, p_sys->i_packet_count );
605     bo_addle_u64( &bo, 0 ) ;            /* play duration */
606     bo_addle_u64( &bo, 0 );             /* send duration */
607     bo_addle_u64( &bo, 10000 );         /* preroll duration */
608     bo_addle_u32( &bo, b_broadcast ? 0x01 : 0x00);      /* flags */
609     bo_addle_u32( &bo, p_sys->i_packet_size );  /* packet size min */
610     bo_addle_u32( &bo, p_sys->i_packet_size );  /* packet size max */
611     bo_addle_u32( &bo, 0 );             /* maxbitrate */
612
613     /* header extention */
614     bo_add_guid ( &bo, &asf_object_header_extention_guid );
615     bo_addle_u64( &bo, 46 );
616     bo_add_guid ( &bo, &asf_guid_reserved_1 );
617     bo_addle_u16( &bo, 6 );
618     bo_addle_u32( &bo, 0 );
619
620     /* stream properties */
621     for( i = 1; i < p_sys->i_track; i++ )
622     {
623         tk = &p_sys->track[i];
624
625         bo_add_guid ( &bo, &asf_object_stream_properties_guid );
626         bo_addle_u64( &bo, 78 + tk->i_extra );
627         if( tk->i_cat == AUDIO_ES )
628         {
629             bo_add_guid( &bo, &asf_object_stream_type_audio );
630             bo_add_guid( &bo, &asf_guid_audio_conceal_none );
631         }
632         else if( tk->i_cat == VIDEO_ES )
633         {
634             bo_add_guid( &bo, &asf_object_stream_type_video );
635             bo_add_guid( &bo, &asf_guid_video_conceal_none );
636         }
637         bo_addle_u64( &bo, 0 );         /* time offset */
638         bo_addle_u32( &bo, tk->i_extra );
639         bo_addle_u32( &bo, 0 );         /* 0 */
640         bo_addle_u16( &bo, tk->i_id );  /* stream number */
641         bo_addle_u32( &bo, 0 );
642         bo_add_mem  ( &bo, tk->p_extra, tk->i_extra );
643     }
644
645     /* data object */
646     bo_add_guid ( &bo, &asf_object_data_guid );
647     bo_addle_u64( &bo, 50 + p_sys->i_packet_count * p_sys->i_packet_size );
648     bo_add_guid ( &bo, &p_sys->fid );
649     bo_addle_u64( &bo, p_sys->i_packet_count );
650     bo_addle_u16( &bo, 0x101 );
651
652     return out;
653 }
654
655 /****************************************************************************
656  *
657  ****************************************************************************/
658 static sout_buffer_t *asf_packet_create( sout_mux_t *p_mux,
659                                          asf_track_t *tk, sout_buffer_t *data )
660 {
661     sout_mux_sys_t *p_sys = p_mux->p_sys;
662
663     int     i_data = data->i_size;
664     int     i_pos  = 0;
665     uint8_t *p_data= data->p_buffer;
666     sout_buffer_t *first = NULL, **last = &first;
667
668     while( i_pos < i_data )
669     {
670         bo_t          bo;
671         int           i_payload;
672
673         if( p_sys->pk == NULL )
674         {
675             p_sys->pk = sout_BufferNew( p_mux->p_sout, p_sys->i_packet_size );
676             /* reserve 14 bytes for the packet header */
677             p_sys->i_pk_used = 14;
678             p_sys->i_pk_frame = 0;
679             p_sys->i_pk_dts = data->i_dts;
680         }
681
682
683         bo_init( &bo, &p_sys->pk->p_buffer[p_sys->i_pk_used],
684                       p_sys->i_packet_size - p_sys->i_pk_used );
685
686         /* add payload (header size = 17) */
687         i_payload = __MIN( i_data - i_pos,
688                            p_sys->i_packet_size - p_sys->i_pk_used - 17 );
689         bo_add_u8   ( &bo, 0x80 | tk->i_id );
690         bo_add_u8   ( &bo, tk->i_sequence );
691         bo_addle_u32( &bo, i_pos );
692         bo_add_u8   ( &bo, 0x08 );  /* flags */
693         bo_addle_u32( &bo, i_data );
694         bo_addle_u32( &bo, ( data->i_dts - p_sys->i_dts_first )/ 1000 );
695         bo_addle_u16( &bo, i_payload );
696         bo_add_mem  ( &bo, &p_data[i_pos], i_payload );
697         i_pos += i_payload;
698         p_sys->i_pk_used += 17 + i_payload;
699
700         p_sys->i_pk_frame++;
701
702         if( p_sys->i_pk_used + 14 >= p_sys->i_packet_size )
703         {
704             /* not enough data for another payload, flush the packet */
705             int i_pad = p_sys->i_packet_size - p_sys->i_pk_used;
706
707             bo_init( &bo, p_sys->pk->p_buffer, 14 );
708             bo_add_u8   ( &bo, 0x82 );
709             bo_addle_u16( &bo, 0 );
710             bo_add_u8( &bo, 0x11 );
711             bo_add_u8( &bo, 0x5d );
712             bo_addle_u16( &bo, i_pad );
713             bo_addle_u32( &bo, ( p_sys->i_pk_dts - p_sys->i_dts_first )/ 1000 );
714             bo_addle_u16( &bo, 0 * data->i_length / 1000 );
715             bo_add_u8( &bo, 0x80 | p_sys->i_pk_frame );
716
717             /* append the packet */
718             *last = p_sys->pk;
719             last  = &p_sys->pk->p_next;
720
721             p_sys->pk = NULL;
722
723             p_sys->i_packet_count++;
724         }
725     }
726
727     tk->i_sequence++;
728     sout_BufferDelete( p_mux->p_sout, data );
729
730     return first;
731 }
732
733
734