asf: fixed some headers errors.
[vlc.git] / modules / mux / asf.c
1 /*****************************************************************************
2  * asf.c
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id: asf.c,v 1.4 2003/08/25 23:39:20 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     add_shortcut( "asfh" );
46     set_callbacks( Open, Close );
47 vlc_module_end();
48
49 /*****************************************************************************
50  * Locales prototypes
51  *****************************************************************************/
52 static int  Capability(sout_mux_t *, int, void *, void * );
53 static int  AddStream( sout_mux_t *, sout_input_t * );
54 static int  DelStream( sout_mux_t *, sout_input_t * );
55 static int  Mux      ( sout_mux_t * );
56
57 typedef struct
58 {
59     uint32_t v1; /* le */
60     uint16_t v2; /* le */
61     uint16_t v3; /* le */
62     uint8_t  v4[8];
63 } guid_t;
64
65 typedef struct
66 {
67     int     i_id;
68     int     i_cat;
69     int     i_sequence;
70
71     int     i_extra;
72     uint8_t *p_extra;
73 } asf_track_t;
74
75 struct sout_mux_sys_t
76 {
77     guid_t          fid;    /* file id */
78     int             i_packet_size;
79     int64_t         i_packet_count;
80     mtime_t         i_dts_first;
81     mtime_t         i_dts_last;
82     int64_t         i_bitrate;
83
84     int             i_track;
85     asf_track_t     track[128];
86
87     vlc_bool_t      b_write_header;
88
89     sout_buffer_t   *pk;
90     int             i_pk_used;
91     int             i_pk_frame;
92     mtime_t         i_pk_dts;
93
94     vlc_bool_t      b_asf_http;
95     int             i_seq;
96 };
97
98 static int MuxGetStream( sout_mux_t *, int *pi_stream, mtime_t *pi_dts );
99
100 static sout_buffer_t *asf_header_create( sout_mux_t *, vlc_bool_t b_broadcast );
101 static sout_buffer_t *asf_packet_create( sout_mux_t *,
102                                          asf_track_t *, sout_buffer_t * );
103 static sout_buffer_t *asf_stream_end_create( sout_mux_t *);
104
105 typedef struct
106 {
107     int      i_buffer_size;
108     int      i_buffer;
109     uint8_t  *p_buffer;
110 } bo_t;
111
112 static void bo_init     ( bo_t *, uint8_t *, int  );
113 static void bo_add_u8   ( bo_t *, uint8_t  );
114 static void bo_addle_u16( bo_t *, uint16_t );
115 static void bo_addle_u32( bo_t *, uint32_t );
116 static void bo_addle_u64( bo_t *, uint64_t );
117 static void bo_add_mem  ( bo_t *, uint8_t *, int );
118
119
120 /*****************************************************************************
121  * Open:
122  *****************************************************************************/
123 static int Open( vlc_object_t *p_this )
124 {
125     sout_mux_t     *p_mux = (sout_mux_t*)p_this;
126     sout_mux_sys_t *p_sys;
127     int i;
128
129     msg_Dbg( p_mux, "Asf muxer opened" );
130
131     p_mux->pf_capacity  = Capability;
132     p_mux->pf_addstream = AddStream;
133     p_mux->pf_delstream = DelStream;
134     p_mux->pf_mux       = Mux;
135
136     p_mux->p_sys = p_sys = malloc( sizeof( sout_mux_sys_t ) );
137     p_sys->b_asf_http = p_mux->psz_mux && !strcmp( p_mux->psz_mux, "asfh" );
138     if( p_sys->b_asf_http )
139     {
140         msg_Dbg( p_mux, "creating asf stream to be used with mmsh" );
141     }
142     p_sys->pk = NULL;
143     p_sys->i_pk_used    = 0;
144     p_sys->i_pk_frame   = 0;
145     p_sys->i_dts_first  = -1;
146     p_sys->i_dts_last   = 0;
147     p_sys->i_bitrate    = 0;
148     p_sys->i_seq        = 0;
149
150     p_sys->b_write_header = VLC_TRUE;
151     p_sys->i_track = 1;
152     p_sys->i_packet_size = 4096;
153     p_sys->i_packet_count= 0;
154     /* generate a random fid */
155     srand( mdate() & 0xffffffff );
156     p_sys->fid.v1 = 0xbabac001;
157     p_sys->fid.v2 = ( (uint64_t)rand() << 16 ) / RAND_MAX;
158     p_sys->fid.v3 = ( (uint64_t)rand() << 16 ) / RAND_MAX;
159     for( i = 0; i < 8; i++ )
160     {
161         p_sys->fid.v4[i] = ( (uint64_t)rand() << 8 ) / RAND_MAX;
162     }
163
164
165     return VLC_SUCCESS;
166 }
167
168 /*****************************************************************************
169  * Close:
170  *****************************************************************************/
171 static void Close( vlc_object_t * p_this )
172 {
173     sout_mux_t     *p_mux = (sout_mux_t*)p_this;
174     sout_mux_sys_t *p_sys = p_mux->p_sys;
175     sout_buffer_t  *out;
176     int i;
177
178     msg_Dbg( p_mux, "Asf muxer closed" );
179
180     if( ( out = asf_stream_end_create( p_mux ) ) )
181     {
182         sout_AccessOutWrite( p_mux->p_access, out );
183     }
184
185     /* rewrite header */
186     if( !sout_AccessOutSeek( p_mux->p_access, 0 ) )
187     {
188         out = asf_header_create( p_mux, VLC_FALSE );
189         sout_AccessOutWrite( p_mux->p_access, out );
190     }
191
192     for( i = 1; i < p_sys->i_track; i++ )
193     {
194         free( p_sys->track[i].p_extra );
195     }
196     free( p_sys );
197 }
198
199 /*****************************************************************************
200  * Capability:
201  *****************************************************************************/
202 static int Capability( sout_mux_t *p_mux, int i_query,
203                        void *p_args, void *p_answer )
204 {
205    switch( i_query )
206    {
207         case SOUT_MUX_CAP_GET_ADD_STREAM_ANY_TIME:
208             *(vlc_bool_t*)p_answer = VLC_FALSE;
209             return( SOUT_MUX_CAP_ERR_OK );
210         default:
211             return( SOUT_MUX_CAP_ERR_UNIMPLEMENTED );
212    }
213 }
214
215 /*****************************************************************************
216  * AddStream:
217  *****************************************************************************/
218 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
219 {
220     sout_mux_sys_t   *p_sys = p_mux->p_sys;
221     asf_track_t      *tk;
222     bo_t             bo;
223
224     msg_Dbg( p_mux, "adding input" );
225     if( p_sys->i_track > 127 )
226     {
227         msg_Dbg( p_mux, "cannot add this track (too much track)" );
228         return VLC_EGENERIC;
229     }
230
231     tk = p_input->p_sys = &p_sys->track[p_sys->i_track];
232     tk->i_id  = p_sys->i_track;
233     tk->i_cat = p_input->p_fmt->i_cat;
234     tk->i_sequence = 0;
235
236     switch( tk->i_cat )
237     {
238         case AUDIO_ES:
239         {
240             uint16_t i_tag;
241             int      i_blockalign = p_input->p_fmt->i_block_align;
242             int      i_bitspersample = 0;
243             int      i_extra = 0;
244
245             switch( p_input->p_fmt->i_fourcc )
246             {
247                 case VLC_FOURCC( 'a', '5', '2', ' ' ):
248                     i_tag = WAVE_FORMAT_A52;
249                     break;
250                 case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
251                     i_tag = WAVE_FORMAT_MPEGLAYER3;
252                     i_extra = 12;
253                     break;
254                 case VLC_FOURCC( 'w', 'm', 'a', '1' ):
255                     i_tag = WAVE_FORMAT_WMA1;
256                     break;
257                 case VLC_FOURCC( 'w', 'm', 'a', '2' ):
258                     i_tag = WAVE_FORMAT_WMA2;
259                     break;
260                 case VLC_FOURCC( 'w', 'm', 'a', '3' ):
261                     i_tag = WAVE_FORMAT_WMA3;
262                     break;
263                     /* raw codec */
264                 case VLC_FOURCC( 'u', '8', ' ', ' ' ):
265                     i_tag = WAVE_FORMAT_PCM;
266                     i_blockalign= p_input->p_fmt->i_channels;
267                     i_bitspersample = 8;
268                     break;
269                 case VLC_FOURCC( 's', '1', '6', 'l' ):
270                     i_tag = WAVE_FORMAT_PCM;
271                     i_blockalign= 2 * p_input->p_fmt->i_channels;
272                     i_bitspersample = 16;
273                     break;
274                 case VLC_FOURCC( 's', '2', '4', 'l' ):
275                     i_tag = WAVE_FORMAT_PCM;
276                     i_blockalign= 3 * p_input->p_fmt->i_channels;
277                     i_bitspersample = 24;
278                     break;
279                 case VLC_FOURCC( 's', '3', '2', 'l' ):
280                     i_tag = WAVE_FORMAT_PCM;
281                     i_blockalign= 4 * p_input->p_fmt->i_channels;
282                     i_bitspersample = 32;
283                     break;
284                 default:
285                     return VLC_EGENERIC;
286             }
287
288             tk->i_extra = sizeof( WAVEFORMATEX ) + p_input->p_fmt->i_extra_data;
289             tk->p_extra = malloc( tk->i_extra );
290             bo_init( &bo, tk->p_extra, tk->i_extra );
291             bo_addle_u16( &bo, i_tag );
292             bo_addle_u16( &bo, p_input->p_fmt->i_channels );
293             bo_addle_u32( &bo, p_input->p_fmt->i_sample_rate );
294             bo_addle_u32( &bo, p_input->p_fmt->i_bitrate / 8 );
295             bo_addle_u16( &bo, i_blockalign );
296             bo_addle_u16( &bo, i_bitspersample );
297             if( p_input->p_fmt->i_extra_data > 0 )
298             {
299                 bo_addle_u16( &bo, p_input->p_fmt->i_extra_data );
300                 bo_add_mem  ( &bo, p_input->p_fmt->p_extra_data,
301                               p_input->p_fmt->i_extra_data );
302             }
303             else
304             {
305                 bo_addle_u16( &bo, i_extra );
306                 if( i_tag == WAVE_FORMAT_MPEGLAYER3 )
307                 {
308                     bo_addle_u16( &bo, 1 );     /* wId */
309                     bo_addle_u32( &bo, 2 );     /* fdwFlags */
310                     bo_addle_u16( &bo, 1152 );  /* nBlockSize */
311                     bo_addle_u16( &bo, 1 );     /* nFramesPerBlock */
312                     bo_addle_u16( &bo, 1393 );  /* nCodecDelay */
313                 }
314             }
315
316             if( p_input->p_fmt->i_bitrate > 24000 )
317             {
318                 p_sys->i_bitrate += p_input->p_fmt->i_bitrate;
319             }
320             else
321             {
322                 p_sys->i_bitrate += 512000;
323             }
324             break;
325         }
326         case VIDEO_ES:
327         {
328             tk->i_extra = 11 + sizeof( BITMAPINFOHEADER ) +
329                           p_input->p_fmt->i_extra_data;
330             tk->p_extra = malloc( tk->i_extra );
331             bo_init( &bo, tk->p_extra, tk->i_extra );
332             bo_addle_u32( &bo, p_input->p_fmt->i_width );
333             bo_addle_u32( &bo, p_input->p_fmt->i_height );
334             bo_add_u8   ( &bo, 0x02 );  /* flags */
335             bo_addle_u16( &bo, sizeof( BITMAPINFOHEADER ) +
336                                p_input->p_fmt->i_extra_data );
337             bo_addle_u32( &bo, sizeof( BITMAPINFOHEADER ) +
338                                p_input->p_fmt->i_extra_data );
339             bo_addle_u32( &bo, p_input->p_fmt->i_width );
340             bo_addle_u32( &bo, p_input->p_fmt->i_height );
341             bo_addle_u16( &bo, 1 );
342             bo_addle_u16( &bo, 24 );
343             if( p_input->p_fmt->i_fourcc == VLC_FOURCC('m','p','4','v') )
344             {
345                 bo_add_mem( &bo, "MP4S", 4 );
346             }
347             else if( p_input->p_fmt->i_fourcc == VLC_FOURCC('D','I','V','3') )
348             {
349                 bo_add_mem( &bo, "MP43", 4 );
350             }
351             else
352             {
353                 bo_add_mem( &bo, (uint8_t*)&p_input->p_fmt->i_fourcc, 4 );
354             }
355             bo_addle_u32( &bo, 0 );
356             bo_addle_u32( &bo, 0 );
357             bo_addle_u32( &bo, 0 );
358             bo_addle_u32( &bo, 0 );
359             bo_addle_u32( &bo, 0 );
360             if( p_input->p_fmt->i_extra_data > 0 )
361             {
362                 bo_add_mem  ( &bo, p_input->p_fmt->p_extra_data,
363                               p_input->p_fmt->i_extra_data );
364             }
365
366             p_sys->i_bitrate += 1000000;
367             break;
368         }
369         default:
370             msg_Err(p_mux, "unhandled track type" );
371             return VLC_EGENERIC;
372     }
373
374     p_sys->i_track++;
375     return VLC_SUCCESS;
376 }
377
378 /*****************************************************************************
379  * DelStream:
380  *****************************************************************************/
381 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
382 {
383     msg_Dbg( p_mux, "removing input" );
384     return VLC_SUCCESS;
385 }
386
387 /*****************************************************************************
388  * Mux:
389  *****************************************************************************/
390 static int Mux      ( sout_mux_t *p_mux )
391 {
392     sout_mux_sys_t *p_sys = p_mux->p_sys;
393
394     if( p_sys->b_write_header )
395     {
396         sout_buffer_t *out = asf_header_create( p_mux, VLC_TRUE );
397
398         out->i_flags |= SOUT_BUFFER_FLAGS_HEADER;
399         sout_AccessOutWrite( p_mux->p_access, out );
400
401         p_sys->b_write_header = VLC_FALSE;
402     }
403
404     for( ;; )
405     {
406         sout_input_t  *p_input;
407         asf_track_t   *tk;
408         int           i_stream;
409         mtime_t       i_dts;
410         sout_buffer_t *data;
411         sout_buffer_t *pk;
412
413         if( MuxGetStream( p_mux, &i_stream, &i_dts ) )
414         {
415             /* not enough data */
416             return VLC_SUCCESS;
417         }
418
419         if( p_sys->i_dts_first < 0 )
420         {
421             p_sys->i_dts_first = i_dts;
422         }
423         if( p_sys->i_dts_last < i_dts )
424         {
425             p_sys->i_dts_last = i_dts;
426         }
427
428         p_input = p_mux->pp_inputs[i_stream];
429         tk      = (asf_track_t*)p_input->p_sys;
430
431         data = sout_FifoGet( p_input->p_fifo );
432
433         if( ( pk = asf_packet_create( p_mux, tk, data ) ) )
434         {
435             sout_AccessOutWrite( p_mux->p_access, pk );
436         }
437     }
438
439     return VLC_SUCCESS;
440 }
441
442
443 static int MuxGetStream( sout_mux_t *p_mux,
444                          int        *pi_stream,
445                          mtime_t    *pi_dts )
446 {
447     mtime_t i_dts;
448     int     i_stream;
449     int     i;
450
451     for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ )
452     {
453         sout_input_t  *p_input = p_mux->pp_inputs[i];
454         sout_buffer_t *p_data;
455
456         if( p_input->p_fifo->i_depth <= 0 )
457         {
458             if( p_input->p_fmt->i_cat == AUDIO_ES ||
459                 p_input->p_fmt->i_cat == VIDEO_ES )
460             {
461                 /* We need that audio+video fifo contain at least 1 packet */
462                 return VLC_EGENERIC;
463             }
464             /* SPU */
465             continue;
466         }
467
468         p_data = sout_FifoShow( p_input->p_fifo );
469         if( i_stream == -1 ||
470             p_data->i_dts < i_dts )
471         {
472             i_stream = i;
473             i_dts    = p_data->i_dts;
474         }
475     }
476
477     *pi_stream = i_stream;
478     *pi_dts = i_dts;
479
480     return VLC_SUCCESS;
481 }
482
483 /****************************************************************************
484  * Asf header construction
485  ****************************************************************************/
486
487 /****************************************************************************
488  * Buffer out
489  ****************************************************************************/
490 static void bo_init( bo_t *p_bo, uint8_t *p_buffer, int i_size )
491 {
492     p_bo->i_buffer_size = i_size;
493     p_bo->i_buffer = 0;
494     p_bo->p_buffer = p_buffer;
495 }
496 static void bo_add_u8( bo_t *p_bo, uint8_t i )
497 {
498     if( p_bo->i_buffer < p_bo->i_buffer_size )
499     {
500         p_bo->p_buffer[p_bo->i_buffer] = i;
501     }
502     p_bo->i_buffer++;
503 }
504 static void bo_addle_u16( bo_t *p_bo, uint16_t i )
505 {
506     bo_add_u8( p_bo, i &0xff );
507     bo_add_u8( p_bo, ( ( i >> 8) &0xff ) );
508 }
509 static void bo_addle_u32( bo_t *p_bo, uint32_t i )
510 {
511     bo_addle_u16( p_bo, i &0xffff );
512     bo_addle_u16( p_bo, ( ( i >> 16) &0xffff ) );
513 }
514 static void bo_addle_u64( bo_t *p_bo, uint64_t i )
515 {
516     bo_addle_u32( p_bo, i &0xffffffff );
517     bo_addle_u32( p_bo, ( ( i >> 32) &0xffffffff ) );
518 }
519
520 static void bo_add_mem( bo_t *p_bo, uint8_t *p_mem, int i_size )
521 {
522     int i_copy = __MIN( i_size, p_bo->i_buffer_size - p_bo->i_buffer );
523
524     if( i_copy > 0 )
525     {
526         memcpy( &p_bo->p_buffer[p_bo->i_buffer],
527                 p_mem,
528                 i_copy );
529     }
530     p_bo->i_buffer += i_size;
531 }
532
533 /****************************************************************************
534  * guid
535  ****************************************************************************/
536 static void bo_add_guid( bo_t *p_bo, const guid_t *id )
537 {
538     int i;
539     bo_addle_u32( p_bo, id->v1 );
540     bo_addle_u16( p_bo, id->v2 );
541     bo_addle_u16( p_bo, id->v3 );
542     for( i = 0; i < 8; i++ )
543     {
544         bo_add_u8( p_bo, id->v4[i] );
545     }
546 }
547
548 static const guid_t asf_object_header_guid =
549 {
550     0x75B22630,
551     0x668E,
552     0x11CF,
553     { 0xA6,0xD9, 0x00,0xAA,0x00,0x62,0xCE,0x6C }
554 };
555 static const guid_t asf_object_data_guid =
556 {
557     0x75B22636,
558     0x668E,
559     0x11CF,
560     { 0xA6,0xD9, 0x00,0xAA,0x00,0x62,0xCE,0x6C }
561 };
562
563 static const guid_t asf_object_file_properties_guid =
564 {
565     0x8cabdca1,
566     0xa947,
567     0x11cf,
568     { 0x8e,0xe4, 0x00,0xC0,0x0C,0x20,0x53,0x65 }
569
570 };
571 static const guid_t asf_object_stream_properties_guid =
572 {
573     0xB7DC0791,
574     0xA9B7,
575     0x11CF,
576     { 0x8E,0xE6, 0x00,0xC0,0x0C,0x20,0x53,0x65 }
577
578 };
579 static const guid_t asf_object_header_extention_guid =
580 {
581    0x5FBF03B5,
582    0xA92E,
583    0x11CF,
584    { 0x8E,0xE3, 0x00,0xC0,0x0C,0x20,0x53,0x65 }
585 };
586
587 static const guid_t asf_object_stream_type_audio =
588 {
589     0xF8699E40,
590     0x5B4D,
591     0x11CF,
592     { 0xA8,0xFD, 0x00,0x80,0x5F,0x5C,0x44,0x2B }
593 };
594
595 static const guid_t asf_object_stream_type_video =
596 {
597     0xbc19efc0,
598     0x5B4D,
599     0x11CF,
600     { 0xA8,0xFD, 0x00,0x80,0x5F,0x5C,0x44,0x2B }
601 };
602
603 static const guid_t asf_guid_audio_conceal_none =
604 {
605     0x20FB5700,
606     0x5B55,
607     0x11CF,
608     { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B }
609 };
610 static const guid_t asf_guid_video_conceal_none =
611 {
612     0x20FB5700,
613     0x5B55,
614     0x11CF,
615     { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B }
616 };
617 static const guid_t asf_guid_reserved_1 =
618 {
619     0xABD3D211,
620     0xA9BA,
621     0x11cf,
622     { 0x8E, 0xE6,0x00, 0xC0, 0x0C ,0x20, 0x53, 0x65 }
623 };
624
625 static void asf_chunk_add( bo_t *bo,
626                            int i_type, int i_len, int i_flags, int i_seq )
627 {
628     bo_addle_u16( bo, i_type );
629     bo_addle_u16( bo, i_len + 8 );
630     bo_addle_u32( bo, i_seq );
631     bo_addle_u16( bo, i_flags );
632     bo_addle_u16( bo, i_len + 8 );
633 }
634
635 static sout_buffer_t *asf_header_create( sout_mux_t *p_mux,
636                                          vlc_bool_t b_broadcast )
637 {
638     sout_mux_sys_t *p_sys = p_mux->p_sys;
639     asf_track_t    *tk;
640
641     mtime_t        i_duration = 0;
642     int i_size;
643     sout_buffer_t *out;
644     bo_t          bo;
645     int           i;
646
647     if( p_sys->i_dts_first > 0 )
648     {
649         i_duration = p_sys->i_dts_last - p_sys->i_dts_first;
650         if( i_duration < 0 )
651         {
652             i_duration = 0;
653         }
654     }
655
656     /* calculate header size */
657     i_size = 30 + 104 + 46;
658     for( i = 1; i < p_sys->i_track; i++ )
659     {
660         i_size += 78 + p_sys->track[i].i_extra;
661     }
662
663     if( p_sys->b_asf_http )
664     {
665         out = sout_BufferNew( p_mux->p_sout, i_size + 50 + 12 );
666         bo_init( &bo, out->p_buffer, i_size + 50 + 12 );
667         asf_chunk_add( &bo, 0x4824, i_size + 50, 0xc00, p_sys->i_seq++ );
668     }
669     else
670     {
671         out = sout_BufferNew( p_mux->p_sout, i_size + 50 );
672         bo_init( &bo, out->p_buffer, i_size + 50 );
673     }
674     /* header object */
675     bo_add_guid ( &bo, &asf_object_header_guid );
676     bo_addle_u64( &bo, i_size );
677     bo_addle_u32( &bo, 2 + p_sys->i_track - 1 );
678     bo_add_u8   ( &bo, 1 );
679     bo_add_u8   ( &bo, 2 );
680
681     /* sub object */
682
683     /* file properties */
684     bo_add_guid ( &bo, &asf_object_file_properties_guid );
685     bo_addle_u64( &bo, 104 );
686     bo_add_guid ( &bo, &p_sys->fid );
687     bo_addle_u64( &bo, i_size + 50 + p_sys->i_packet_count *
688                                 p_sys->i_packet_size ); /* file size */
689     bo_addle_u64( &bo, 0 );                 /* creation date */
690     bo_addle_u64( &bo, b_broadcast ? 0xffffffffLL : p_sys->i_packet_count );
691     bo_addle_u64( &bo, i_duration * 10 );   /* play duration (100ns) */
692     bo_addle_u64( &bo, i_duration * 10 );   /* send duration (100ns) */
693     bo_addle_u64( &bo, 4000 );              /* preroll duration (ms) */
694     bo_addle_u32( &bo, b_broadcast ? 0x01 : 0x00);      /* flags */
695     bo_addle_u32( &bo, p_sys->i_packet_size );  /* packet size min */
696     bo_addle_u32( &bo, p_sys->i_packet_size );  /* packet size max */
697     bo_addle_u32( &bo, p_sys->i_bitrate );      /* maxbitrate */
698
699     /* header extention */
700     bo_add_guid ( &bo, &asf_object_header_extention_guid );
701     bo_addle_u64( &bo, 46 );
702     bo_add_guid ( &bo, &asf_guid_reserved_1 );
703     bo_addle_u16( &bo, 6 );
704     bo_addle_u32( &bo, 0 );
705
706     /* stream properties */
707     for( i = 1; i < p_sys->i_track; i++ )
708     {
709         tk = &p_sys->track[i];
710
711         bo_add_guid ( &bo, &asf_object_stream_properties_guid );
712         bo_addle_u64( &bo, 78 + tk->i_extra );
713         if( tk->i_cat == AUDIO_ES )
714         {
715             bo_add_guid( &bo, &asf_object_stream_type_audio );
716             bo_add_guid( &bo, &asf_guid_audio_conceal_none );
717         }
718         else if( tk->i_cat == VIDEO_ES )
719         {
720             bo_add_guid( &bo, &asf_object_stream_type_video );
721             bo_add_guid( &bo, &asf_guid_video_conceal_none );
722         }
723         bo_addle_u64( &bo, 0 );         /* time offset */
724         bo_addle_u32( &bo, tk->i_extra );
725         bo_addle_u32( &bo, 0 );         /* 0 */
726         bo_addle_u16( &bo, tk->i_id );  /* stream number */
727         bo_addle_u32( &bo, 0 );
728         bo_add_mem  ( &bo, tk->p_extra, tk->i_extra );
729     }
730
731     /* data object */
732     bo_add_guid ( &bo, &asf_object_data_guid );
733     bo_addle_u64( &bo, 50 + p_sys->i_packet_count * p_sys->i_packet_size );
734     bo_add_guid ( &bo, &p_sys->fid );
735     bo_addle_u64( &bo, p_sys->i_packet_count );
736     bo_addle_u16( &bo, 0x101 );
737
738     return out;
739 }
740
741 /****************************************************************************
742  *
743  ****************************************************************************/
744 static sout_buffer_t *asf_packet_create( sout_mux_t *p_mux,
745                                          asf_track_t *tk, sout_buffer_t *data )
746 {
747     sout_mux_sys_t *p_sys = p_mux->p_sys;
748
749     int     i_data = data->i_size;
750     int     i_pos  = 0;
751     uint8_t *p_data= data->p_buffer;
752     sout_buffer_t *first = NULL, **last = &first;
753     int     i_preheader = p_sys->b_asf_http ? 12 : 0;
754
755     while( i_pos < i_data )
756     {
757         bo_t          bo;
758         int           i_payload;
759
760         if( p_sys->pk == NULL )
761         {
762             p_sys->pk = sout_BufferNew( p_mux->p_sout,
763                                         p_sys->i_packet_size + i_preheader);
764             /* reserve 14 bytes for the packet header */
765             p_sys->i_pk_used = 14 + i_preheader;
766             p_sys->i_pk_frame = 0;
767             p_sys->i_pk_dts = data->i_dts;
768         }
769
770
771         bo_init( &bo, &p_sys->pk->p_buffer[p_sys->i_pk_used],
772                       p_sys->i_packet_size - p_sys->i_pk_used );
773
774         /* add payload (header size = 17) */
775         i_payload = __MIN( i_data - i_pos,
776                            p_sys->i_packet_size - p_sys->i_pk_used - 17 );
777         bo_add_u8   ( &bo, 0x80 | tk->i_id );
778         bo_add_u8   ( &bo, tk->i_sequence );
779         bo_addle_u32( &bo, i_pos );
780         bo_add_u8   ( &bo, 0x08 );  /* flags */
781         bo_addle_u32( &bo, i_data );
782         bo_addle_u32( &bo, ( data->i_dts - p_sys->i_dts_first )/ 1000 );
783         bo_addle_u16( &bo, i_payload );
784         bo_add_mem  ( &bo, &p_data[i_pos], i_payload );
785         i_pos += i_payload;
786         p_sys->i_pk_used += 17 + i_payload;
787
788         p_sys->i_pk_frame++;
789
790         if( p_sys->i_pk_used + 14 >= p_sys->i_packet_size )
791         {
792             /* not enough data for another payload, flush the packet */
793             int i_pad = p_sys->i_packet_size - p_sys->i_pk_used;
794
795             bo_init( &bo, p_sys->pk->p_buffer, 14 + i_preheader );
796
797             if( p_sys->b_asf_http )
798             {
799                 asf_chunk_add( &bo, 0x4424,
800                                p_sys->i_packet_size, 0x00, p_sys->i_seq++);
801             }
802             bo_add_u8   ( &bo, 0x82 );
803             bo_addle_u16( &bo, 0 );
804             bo_add_u8( &bo, 0x11 );
805             bo_add_u8( &bo, 0x5d );
806             bo_addle_u16( &bo, i_pad );
807             bo_addle_u32( &bo, ( p_sys->i_pk_dts - p_sys->i_dts_first )/ 1000 );
808             bo_addle_u16( &bo, 0 * data->i_length / 1000 );
809             bo_add_u8( &bo, 0x80 | p_sys->i_pk_frame );
810
811             /* append the packet */
812             *last = p_sys->pk;
813             last  = &p_sys->pk->p_next;
814
815             p_sys->pk = NULL;
816
817             p_sys->i_packet_count++;
818         }
819     }
820
821     tk->i_sequence++;
822     sout_BufferDelete( p_mux->p_sout, data );
823
824     return first;
825 }
826
827 static sout_buffer_t *asf_stream_end_create( sout_mux_t *p_mux )
828 {
829     sout_mux_sys_t *p_sys = p_mux->p_sys;
830
831     sout_buffer_t *out = NULL;
832     bo_t          bo;
833
834     if( p_sys->b_asf_http )
835     {
836         out = sout_BufferNew( p_mux->p_sout, 12 );
837         bo_init( &bo, out->p_buffer, 12 );
838         asf_chunk_add( &bo, 0x4524, 0, 0x00, p_sys->i_seq++ );
839     }
840     return out;
841 }