91d9d458006976d61ef9a01083e1837b455b664d
[vlc.git] / modules / mux / asf.c
1 /*****************************************************************************
2  * asf.c
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id: asf.c,v 1.5 2003/08/26 23:14:11 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 #if 1
252                     i_tag = WAVE_FORMAT_MPEGLAYER3;
253                     i_blockalign = 1;
254                     i_extra = 12;
255                     break;
256 #else
257                     i_tag = WAVE_FORMAT_MPEG;
258                     i_blockalign = 1;
259                     i_extra = 22;
260                     break;
261 #endif
262                 case VLC_FOURCC( 'w', 'm', 'a', '1' ):
263                     i_tag = WAVE_FORMAT_WMA1;
264                     break;
265                 case VLC_FOURCC( 'w', 'm', 'a', '2' ):
266                     i_tag = WAVE_FORMAT_WMA2;
267                     break;
268                 case VLC_FOURCC( 'w', 'm', 'a', '3' ):
269                     i_tag = WAVE_FORMAT_WMA3;
270                     break;
271                     /* raw codec */
272                 case VLC_FOURCC( 'u', '8', ' ', ' ' ):
273                     i_tag = WAVE_FORMAT_PCM;
274                     i_blockalign= p_input->p_fmt->i_channels;
275                     i_bitspersample = 8;
276                     break;
277                 case VLC_FOURCC( 's', '1', '6', 'l' ):
278                     i_tag = WAVE_FORMAT_PCM;
279                     i_blockalign= 2 * p_input->p_fmt->i_channels;
280                     i_bitspersample = 16;
281                     break;
282                 case VLC_FOURCC( 's', '2', '4', 'l' ):
283                     i_tag = WAVE_FORMAT_PCM;
284                     i_blockalign= 3 * p_input->p_fmt->i_channels;
285                     i_bitspersample = 24;
286                     break;
287                 case VLC_FOURCC( 's', '3', '2', 'l' ):
288                     i_tag = WAVE_FORMAT_PCM;
289                     i_blockalign= 4 * p_input->p_fmt->i_channels;
290                     i_bitspersample = 32;
291                     break;
292                 default:
293                     return VLC_EGENERIC;
294             }
295
296             tk->i_extra = sizeof( WAVEFORMATEX ) +
297                           p_input->p_fmt->i_extra_data + i_extra;
298             tk->p_extra = malloc( tk->i_extra );
299             bo_init( &bo, tk->p_extra, tk->i_extra );
300             bo_addle_u16( &bo, i_tag );
301             bo_addle_u16( &bo, p_input->p_fmt->i_channels );
302             bo_addle_u32( &bo, p_input->p_fmt->i_sample_rate );
303             bo_addle_u32( &bo, p_input->p_fmt->i_bitrate / 8 );
304             bo_addle_u16( &bo, i_blockalign );
305             bo_addle_u16( &bo, i_bitspersample );
306             if( p_input->p_fmt->i_extra_data > 0 )
307             {
308                 bo_addle_u16( &bo, p_input->p_fmt->i_extra_data );
309                 bo_add_mem  ( &bo, p_input->p_fmt->p_extra_data,
310                               p_input->p_fmt->i_extra_data );
311             }
312             else
313             {
314                 bo_addle_u16( &bo, i_extra );
315                 if( i_tag == WAVE_FORMAT_MPEGLAYER3 )
316                 {
317                     msg_Dbg( p_mux, "adding mp3 header" );
318                     bo_addle_u16( &bo, 1 );     /* wId */
319                     bo_addle_u32( &bo, 2 );     /* fdwFlags */
320                     bo_addle_u16( &bo, 1152 );  /* nBlockSize */
321                     bo_addle_u16( &bo, 1 );     /* nFramesPerBlock */
322                     bo_addle_u16( &bo, 1393 );  /* nCodecDelay */
323                 }
324                 else if( i_tag == WAVE_FORMAT_MPEG )
325                 {
326                     msg_Dbg( p_mux, "adding mp2 header" );
327                     bo_addle_u16( &bo, 2 );     /* fwHeadLayer */
328                     bo_addle_u32( &bo, p_input->p_fmt->i_bitrate );
329                     bo_addle_u16( &bo, p_input->p_fmt->i_channels == 2 ?1:8 );
330                     bo_addle_u16( &bo, 0 );     /* fwHeadModeExt */
331                     bo_addle_u16( &bo, 1 );     /* wHeadEmphasis */
332                     bo_addle_u16( &bo, 16 );    /* fwHeadFlags */
333                     bo_addle_u32( &bo, 0 );     /* dwPTSLow */
334                     bo_addle_u32( &bo, 0 );     /* dwPTSHigh */
335                 }
336             }
337
338             if( p_input->p_fmt->i_bitrate > 24000 )
339             {
340                 p_sys->i_bitrate += p_input->p_fmt->i_bitrate;
341             }
342             else
343             {
344                 p_sys->i_bitrate += 512000;
345             }
346             break;
347         }
348         case VIDEO_ES:
349         {
350             tk->i_extra = 11 + sizeof( BITMAPINFOHEADER ) +
351                           p_input->p_fmt->i_extra_data;
352             tk->p_extra = malloc( tk->i_extra );
353             bo_init( &bo, tk->p_extra, tk->i_extra );
354             bo_addle_u32( &bo, p_input->p_fmt->i_width );
355             bo_addle_u32( &bo, p_input->p_fmt->i_height );
356             bo_add_u8   ( &bo, 0x02 );  /* flags */
357             bo_addle_u16( &bo, sizeof( BITMAPINFOHEADER ) +
358                                p_input->p_fmt->i_extra_data );
359             bo_addle_u32( &bo, sizeof( BITMAPINFOHEADER ) +
360                                p_input->p_fmt->i_extra_data );
361             bo_addle_u32( &bo, p_input->p_fmt->i_width );
362             bo_addle_u32( &bo, p_input->p_fmt->i_height );
363             bo_addle_u16( &bo, 1 );
364             bo_addle_u16( &bo, 24 );
365             if( p_input->p_fmt->i_fourcc == VLC_FOURCC('m','p','4','v') )
366             {
367                 bo_add_mem( &bo, "MP4S", 4 );
368             }
369             else if( p_input->p_fmt->i_fourcc == VLC_FOURCC('D','I','V','3') )
370             {
371                 bo_add_mem( &bo, "MP43", 4 );
372             }
373             else if( p_input->p_fmt->i_fourcc == VLC_FOURCC('D','I','V','2') )
374             {
375                 bo_add_mem( &bo, "MP42", 4 );
376             }
377             else if( p_input->p_fmt->i_fourcc == VLC_FOURCC('D','I','V','1') )
378             {
379                 bo_add_mem( &bo, "MPG4", 4 );
380             }
381             else
382             {
383                 bo_add_mem( &bo, (uint8_t*)&p_input->p_fmt->i_fourcc, 4 );
384             }
385             bo_addle_u32( &bo, 0 );
386             bo_addle_u32( &bo, 0 );
387             bo_addle_u32( &bo, 0 );
388             bo_addle_u32( &bo, 0 );
389             bo_addle_u32( &bo, 0 );
390             if( p_input->p_fmt->i_extra_data > 0 )
391             {
392                 bo_add_mem  ( &bo, p_input->p_fmt->p_extra_data,
393                               p_input->p_fmt->i_extra_data );
394             }
395
396             if( p_input->p_fmt->i_bitrate > 50000 )
397             {
398                 p_sys->i_bitrate += p_input->p_fmt->i_bitrate;
399             }
400             else
401             {
402                 p_sys->i_bitrate += 1000000;
403             }
404             break;
405         }
406         default:
407             msg_Err(p_mux, "unhandled track type" );
408             return VLC_EGENERIC;
409     }
410
411     p_sys->i_track++;
412     return VLC_SUCCESS;
413 }
414
415 /*****************************************************************************
416  * DelStream:
417  *****************************************************************************/
418 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
419 {
420     msg_Dbg( p_mux, "removing input" );
421     return VLC_SUCCESS;
422 }
423
424 /*****************************************************************************
425  * Mux:
426  *****************************************************************************/
427 static int Mux      ( sout_mux_t *p_mux )
428 {
429     sout_mux_sys_t *p_sys = p_mux->p_sys;
430
431     if( p_sys->b_write_header )
432     {
433         sout_buffer_t *out = asf_header_create( p_mux, VLC_TRUE );
434
435         out->i_flags |= SOUT_BUFFER_FLAGS_HEADER;
436         sout_AccessOutWrite( p_mux->p_access, out );
437
438         p_sys->b_write_header = VLC_FALSE;
439     }
440
441     for( ;; )
442     {
443         sout_input_t  *p_input;
444         asf_track_t   *tk;
445         int           i_stream;
446         mtime_t       i_dts;
447         sout_buffer_t *data;
448         sout_buffer_t *pk;
449
450         if( MuxGetStream( p_mux, &i_stream, &i_dts ) )
451         {
452             /* not enough data */
453             return VLC_SUCCESS;
454         }
455
456         if( p_sys->i_dts_first < 0 )
457         {
458             p_sys->i_dts_first = i_dts;
459         }
460         if( p_sys->i_dts_last < i_dts )
461         {
462             p_sys->i_dts_last = i_dts;
463         }
464
465         p_input = p_mux->pp_inputs[i_stream];
466         tk      = (asf_track_t*)p_input->p_sys;
467
468         data = sout_FifoGet( p_input->p_fifo );
469
470         if( ( pk = asf_packet_create( p_mux, tk, data ) ) )
471         {
472             sout_AccessOutWrite( p_mux->p_access, pk );
473         }
474     }
475
476     return VLC_SUCCESS;
477 }
478
479
480 static int MuxGetStream( sout_mux_t *p_mux,
481                          int        *pi_stream,
482                          mtime_t    *pi_dts )
483 {
484     mtime_t i_dts;
485     int     i_stream;
486     int     i;
487
488     for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ )
489     {
490         sout_input_t  *p_input = p_mux->pp_inputs[i];
491         sout_buffer_t *p_data;
492
493         if( p_input->p_fifo->i_depth <= 0 )
494         {
495             if( p_input->p_fmt->i_cat == AUDIO_ES ||
496                 p_input->p_fmt->i_cat == VIDEO_ES )
497             {
498                 /* We need that audio+video fifo contain at least 1 packet */
499                 return VLC_EGENERIC;
500             }
501             /* SPU */
502             continue;
503         }
504
505         p_data = sout_FifoShow( p_input->p_fifo );
506         if( i_stream == -1 ||
507             p_data->i_dts < i_dts )
508         {
509             i_stream = i;
510             i_dts    = p_data->i_dts;
511         }
512     }
513
514     *pi_stream = i_stream;
515     *pi_dts = i_dts;
516
517     return VLC_SUCCESS;
518 }
519
520 /****************************************************************************
521  * Asf header construction
522  ****************************************************************************/
523
524 /****************************************************************************
525  * Buffer out
526  ****************************************************************************/
527 static void bo_init( bo_t *p_bo, uint8_t *p_buffer, int i_size )
528 {
529     p_bo->i_buffer_size = i_size;
530     p_bo->i_buffer = 0;
531     p_bo->p_buffer = p_buffer;
532 }
533 static void bo_add_u8( bo_t *p_bo, uint8_t i )
534 {
535     if( p_bo->i_buffer < p_bo->i_buffer_size )
536     {
537         p_bo->p_buffer[p_bo->i_buffer] = i;
538     }
539     p_bo->i_buffer++;
540 }
541 static void bo_addle_u16( bo_t *p_bo, uint16_t i )
542 {
543     bo_add_u8( p_bo, i &0xff );
544     bo_add_u8( p_bo, ( ( i >> 8) &0xff ) );
545 }
546 static void bo_addle_u32( bo_t *p_bo, uint32_t i )
547 {
548     bo_addle_u16( p_bo, i &0xffff );
549     bo_addle_u16( p_bo, ( ( i >> 16) &0xffff ) );
550 }
551 static void bo_addle_u64( bo_t *p_bo, uint64_t i )
552 {
553     bo_addle_u32( p_bo, i &0xffffffff );
554     bo_addle_u32( p_bo, ( ( i >> 32) &0xffffffff ) );
555 }
556
557 static void bo_add_mem( bo_t *p_bo, uint8_t *p_mem, int i_size )
558 {
559     int i_copy = __MIN( i_size, p_bo->i_buffer_size - p_bo->i_buffer );
560
561     if( i_copy > 0 )
562     {
563         memcpy( &p_bo->p_buffer[p_bo->i_buffer],
564                 p_mem,
565                 i_copy );
566     }
567     p_bo->i_buffer += i_size;
568 }
569
570 /****************************************************************************
571  * guid
572  ****************************************************************************/
573 static void bo_add_guid( bo_t *p_bo, const guid_t *id )
574 {
575     int i;
576     bo_addle_u32( p_bo, id->v1 );
577     bo_addle_u16( p_bo, id->v2 );
578     bo_addle_u16( p_bo, id->v3 );
579     for( i = 0; i < 8; i++ )
580     {
581         bo_add_u8( p_bo, id->v4[i] );
582     }
583 }
584
585 static const guid_t asf_object_header_guid =
586 {
587     0x75B22630,
588     0x668E,
589     0x11CF,
590     { 0xA6,0xD9, 0x00,0xAA,0x00,0x62,0xCE,0x6C }
591 };
592 static const guid_t asf_object_data_guid =
593 {
594     0x75B22636,
595     0x668E,
596     0x11CF,
597     { 0xA6,0xD9, 0x00,0xAA,0x00,0x62,0xCE,0x6C }
598 };
599
600 static const guid_t asf_object_file_properties_guid =
601 {
602     0x8cabdca1,
603     0xa947,
604     0x11cf,
605     { 0x8e,0xe4, 0x00,0xC0,0x0C,0x20,0x53,0x65 }
606
607 };
608 static const guid_t asf_object_stream_properties_guid =
609 {
610     0xB7DC0791,
611     0xA9B7,
612     0x11CF,
613     { 0x8E,0xE6, 0x00,0xC0,0x0C,0x20,0x53,0x65 }
614
615 };
616 static const guid_t asf_object_header_extention_guid =
617 {
618    0x5FBF03B5,
619    0xA92E,
620    0x11CF,
621    { 0x8E,0xE3, 0x00,0xC0,0x0C,0x20,0x53,0x65 }
622 };
623
624 static const guid_t asf_object_stream_type_audio =
625 {
626     0xF8699E40,
627     0x5B4D,
628     0x11CF,
629     { 0xA8,0xFD, 0x00,0x80,0x5F,0x5C,0x44,0x2B }
630 };
631
632 static const guid_t asf_object_stream_type_video =
633 {
634     0xbc19efc0,
635     0x5B4D,
636     0x11CF,
637     { 0xA8,0xFD, 0x00,0x80,0x5F,0x5C,0x44,0x2B }
638 };
639
640 static const guid_t asf_guid_audio_conceal_none =
641 {
642     0x20FB5700,
643     0x5B55,
644     0x11CF,
645     { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B }
646 };
647 static const guid_t asf_guid_video_conceal_none =
648 {
649     0x20FB5700,
650     0x5B55,
651     0x11CF,
652     { 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B }
653 };
654 static const guid_t asf_guid_reserved_1 =
655 {
656     0xABD3D211,
657     0xA9BA,
658     0x11cf,
659     { 0x8E, 0xE6,0x00, 0xC0, 0x0C ,0x20, 0x53, 0x65 }
660 };
661
662 static void asf_chunk_add( bo_t *bo,
663                            int i_type, int i_len, int i_flags, int i_seq )
664 {
665     bo_addle_u16( bo, i_type );
666     bo_addle_u16( bo, i_len + 8 );
667     bo_addle_u32( bo, i_seq );
668     bo_addle_u16( bo, i_flags );
669     bo_addle_u16( bo, i_len + 8 );
670 }
671
672 static sout_buffer_t *asf_header_create( sout_mux_t *p_mux,
673                                          vlc_bool_t b_broadcast )
674 {
675     sout_mux_sys_t *p_sys = p_mux->p_sys;
676     asf_track_t    *tk;
677
678     mtime_t        i_duration = 0;
679     int i_size;
680     sout_buffer_t *out;
681     bo_t          bo;
682     int           i;
683
684     if( p_sys->i_dts_first > 0 )
685     {
686         i_duration = p_sys->i_dts_last - p_sys->i_dts_first;
687         if( i_duration < 0 )
688         {
689             i_duration = 0;
690         }
691     }
692
693     /* calculate header size */
694     i_size = 30 + 104 + 46;
695     for( i = 1; i < p_sys->i_track; i++ )
696     {
697         i_size += 78 + p_sys->track[i].i_extra;
698     }
699
700     if( p_sys->b_asf_http )
701     {
702         out = sout_BufferNew( p_mux->p_sout, i_size + 50 + 12 );
703         bo_init( &bo, out->p_buffer, i_size + 50 + 12 );
704         asf_chunk_add( &bo, 0x4824, i_size + 50, 0xc00, p_sys->i_seq++ );
705     }
706     else
707     {
708         out = sout_BufferNew( p_mux->p_sout, i_size + 50 );
709         bo_init( &bo, out->p_buffer, i_size + 50 );
710     }
711     /* header object */
712     bo_add_guid ( &bo, &asf_object_header_guid );
713     bo_addle_u64( &bo, i_size );
714     bo_addle_u32( &bo, 2 + p_sys->i_track - 1 );
715     bo_add_u8   ( &bo, 1 );
716     bo_add_u8   ( &bo, 2 );
717
718     /* sub object */
719
720     /* file properties */
721     bo_add_guid ( &bo, &asf_object_file_properties_guid );
722     bo_addle_u64( &bo, 104 );
723     bo_add_guid ( &bo, &p_sys->fid );
724     bo_addle_u64( &bo, i_size + 50 + p_sys->i_packet_count *
725                                 p_sys->i_packet_size ); /* file size */
726     bo_addle_u64( &bo, 0 );                 /* creation date */
727     bo_addle_u64( &bo, b_broadcast ? 0xffffffffLL : p_sys->i_packet_count );
728     bo_addle_u64( &bo, i_duration * 10 );   /* play duration (100ns) */
729     bo_addle_u64( &bo, i_duration * 10 );   /* send duration (100ns) */
730     bo_addle_u64( &bo, 3000 );              /* preroll duration (ms) */
731     bo_addle_u32( &bo, b_broadcast ? 0x01 : 0x00);      /* flags */
732     bo_addle_u32( &bo, p_sys->i_packet_size );  /* packet size min */
733     bo_addle_u32( &bo, p_sys->i_packet_size );  /* packet size max */
734     bo_addle_u32( &bo, p_sys->i_bitrate );      /* maxbitrate */
735
736     /* header extention */
737     bo_add_guid ( &bo, &asf_object_header_extention_guid );
738     bo_addle_u64( &bo, 46 );
739     bo_add_guid ( &bo, &asf_guid_reserved_1 );
740     bo_addle_u16( &bo, 6 );
741     bo_addle_u32( &bo, 0 );
742
743     /* stream properties */
744     for( i = 1; i < p_sys->i_track; i++ )
745     {
746         tk = &p_sys->track[i];
747
748         bo_add_guid ( &bo, &asf_object_stream_properties_guid );
749         bo_addle_u64( &bo, 78 + tk->i_extra );
750         if( tk->i_cat == AUDIO_ES )
751         {
752             bo_add_guid( &bo, &asf_object_stream_type_audio );
753             bo_add_guid( &bo, &asf_guid_audio_conceal_none );
754         }
755         else if( tk->i_cat == VIDEO_ES )
756         {
757             bo_add_guid( &bo, &asf_object_stream_type_video );
758             bo_add_guid( &bo, &asf_guid_video_conceal_none );
759         }
760         bo_addle_u64( &bo, 0 );         /* time offset */
761         bo_addle_u32( &bo, tk->i_extra );
762         bo_addle_u32( &bo, 0 );         /* 0 */
763         bo_addle_u16( &bo, tk->i_id );  /* stream number */
764         bo_addle_u32( &bo, 0 );
765         bo_add_mem  ( &bo, tk->p_extra, tk->i_extra );
766     }
767
768     /* data object */
769     bo_add_guid ( &bo, &asf_object_data_guid );
770     bo_addle_u64( &bo, 50 + p_sys->i_packet_count * p_sys->i_packet_size );
771     bo_add_guid ( &bo, &p_sys->fid );
772     bo_addle_u64( &bo, p_sys->i_packet_count );
773     bo_addle_u16( &bo, 0x101 );
774
775     return out;
776 }
777
778 /****************************************************************************
779  *
780  ****************************************************************************/
781 static sout_buffer_t *asf_packet_create( sout_mux_t *p_mux,
782                                          asf_track_t *tk, sout_buffer_t *data )
783 {
784     sout_mux_sys_t *p_sys = p_mux->p_sys;
785
786     int     i_data = data->i_size;
787     int     i_pos  = 0;
788     uint8_t *p_data= data->p_buffer;
789     sout_buffer_t *first = NULL, **last = &first;
790     int     i_preheader = p_sys->b_asf_http ? 12 : 0;
791
792     while( i_pos < i_data )
793     {
794         bo_t          bo;
795         int           i_payload;
796
797         if( p_sys->pk == NULL )
798         {
799             p_sys->pk = sout_BufferNew( p_mux->p_sout,
800                                         p_sys->i_packet_size + i_preheader);
801             /* reserve 14 bytes for the packet header */
802             p_sys->i_pk_used = 14 + i_preheader;
803             p_sys->i_pk_frame = 0;
804             p_sys->i_pk_dts = data->i_dts;
805         }
806
807
808         bo_init( &bo, &p_sys->pk->p_buffer[p_sys->i_pk_used],
809                       p_sys->i_packet_size - p_sys->i_pk_used );
810
811         /* add payload (header size = 17) */
812         i_payload = __MIN( i_data - i_pos,
813                            p_sys->i_packet_size - p_sys->i_pk_used - 17 );
814         bo_add_u8   ( &bo, 0x80 | tk->i_id );
815         bo_add_u8   ( &bo, tk->i_sequence );
816         bo_addle_u32( &bo, i_pos );
817         bo_add_u8   ( &bo, 0x08 );  /* flags */
818         bo_addle_u32( &bo, i_data );
819         bo_addle_u32( &bo, ( data->i_dts - p_sys->i_dts_first )/ 1000 );
820         bo_addle_u16( &bo, i_payload );
821         bo_add_mem  ( &bo, &p_data[i_pos], i_payload );
822         i_pos += i_payload;
823         p_sys->i_pk_used += 17 + i_payload;
824
825         p_sys->i_pk_frame++;
826
827         if( p_sys->i_pk_used + 14 >= p_sys->i_packet_size )
828         {
829             /* not enough data for another payload, flush the packet */
830             int i_pad = p_sys->i_packet_size - p_sys->i_pk_used;
831
832             bo_init( &bo, p_sys->pk->p_buffer, 14 + i_preheader );
833
834             if( p_sys->b_asf_http )
835             {
836                 asf_chunk_add( &bo, 0x4424,
837                                p_sys->i_packet_size, 0x00, p_sys->i_seq++);
838             }
839             bo_add_u8   ( &bo, 0x82 );
840             bo_addle_u16( &bo, 0 );
841             bo_add_u8( &bo, 0x11 );
842             bo_add_u8( &bo, 0x5d );
843             bo_addle_u16( &bo, i_pad );
844             bo_addle_u32( &bo, ( p_sys->i_pk_dts - p_sys->i_dts_first )/ 1000 );
845             bo_addle_u16( &bo, 0 * data->i_length / 1000 );
846             bo_add_u8( &bo, 0x80 | p_sys->i_pk_frame );
847
848             /* append the packet */
849             *last = p_sys->pk;
850             last  = &p_sys->pk->p_next;
851
852             p_sys->pk = NULL;
853
854             p_sys->i_packet_count++;
855         }
856     }
857
858     tk->i_sequence++;
859     sout_BufferDelete( p_mux->p_sout, data );
860
861     return first;
862 }
863
864 static sout_buffer_t *asf_stream_end_create( sout_mux_t *p_mux )
865 {
866     sout_mux_sys_t *p_sys = p_mux->p_sys;
867
868     sout_buffer_t *out = NULL;
869     bo_t          bo;
870
871     if( p_sys->b_asf_http )
872     {
873         out = sout_BufferNew( p_mux->p_sout, 12 );
874         bo_init( &bo, out->p_buffer, 12 );
875         asf_chunk_add( &bo, 0x4524, 0, 0x00, p_sys->i_seq++ );
876     }
877     return out;
878 }