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