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