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