]> git.sesse.net Git - vlc/blob - modules/mux/ogg.c
Mux: kill srand() use
[vlc] / modules / mux / ogg.c
1 /*****************************************************************************
2  * ogg.c: ogg muxer module for vlc
3  *****************************************************************************
4  * Copyright (C) 2001, 2002, 2006 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *          Gildas Bazin <gbazin@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_sout.h>
36 #include <vlc_block.h>
37 #include <vlc_codecs.h>
38 #include <limits.h>
39 #include <vlc_rand.h>
40 #include "../demux/xiph.h"
41
42 #include <ogg/ogg.h>
43
44 /*****************************************************************************
45  * Module descriptor
46  *****************************************************************************/
47 static int  Open   ( vlc_object_t * );
48 static void Close  ( vlc_object_t * );
49
50 vlc_module_begin ()
51     set_description( N_("Ogg/OGM muxer") )
52     set_capability( "sout mux", 10 )
53     set_category( CAT_SOUT )
54     set_subcategory( SUBCAT_SOUT_MUX )
55     add_shortcut( "ogg" )
56     add_shortcut( "ogm" )
57     set_callbacks( Open, Close )
58 vlc_module_end ()
59
60
61 /*****************************************************************************
62  * Exported prototypes
63  *****************************************************************************/
64 static int Control  ( sout_mux_t *, int, va_list );
65 static int AddStream( sout_mux_t *, sout_input_t * );
66 static int DelStream( sout_mux_t *, sout_input_t * );
67 static int Mux      ( sout_mux_t * );
68 static int MuxBlock ( sout_mux_t *, sout_input_t * );
69
70 static block_t *OggCreateHeader( sout_mux_t * );
71 static block_t *OggCreateFooter( sout_mux_t * );
72
73 /*****************************************************************************
74  * Misc declarations
75  *****************************************************************************/
76
77 /* Structures used for OggDS headers used in ogm files */
78
79 #define PACKET_TYPE_HEADER   0x01
80 #define PACKET_TYPE_COMMENT  0x03
81 #define PACKET_IS_SYNCPOINT  0x08
82
83 typedef struct
84 #ifdef HAVE_ATTRIBUTE_PACKED
85     __attribute__((__packed__))
86 #endif
87 {
88     int32_t i_width;
89     int32_t i_height;
90 } oggds_header_video_t;
91
92 typedef struct
93 #ifdef HAVE_ATTRIBUTE_PACKED
94     __attribute__((__packed__))
95 #endif
96 {
97     int16_t i_channels;
98     int16_t i_block_align;
99     int32_t i_avgbytespersec;
100 } oggds_header_audio_t;
101
102 typedef struct
103 #ifdef HAVE_ATTRIBUTE_PACKED
104     __attribute__((__packed__))
105 #endif
106 {
107     uint8_t i_packet_type;
108
109     char stream_type[8];
110     char sub_type[4];
111
112     int32_t i_size;
113
114     int64_t i_time_unit;
115     int64_t i_samples_per_unit;
116     int32_t i_default_len;
117
118     int32_t i_buffer_size;
119     int16_t i_bits_per_sample;
120
121     int16_t i_padding_0; /* Because the original is using MSVC packing style */
122
123     union
124     {
125         oggds_header_video_t video;
126         oggds_header_audio_t audio;
127     } header;
128
129     int32_t i_padding_1; /* Because the original is using MSVC packing style */
130
131 } oggds_header_t;
132
133 /*****************************************************************************
134  * Definitions of structures and functions used by this plugins
135  *****************************************************************************/
136 typedef struct
137 {
138     int i_cat;
139     int i_fourcc;
140
141     int b_new;
142
143     mtime_t i_dts;
144     mtime_t i_length;
145     int     i_packet_no;
146     int     i_serial_no;
147     int     i_keyframe_granule_shift; /* Theora only */
148     int     i_last_keyframe; /* dirac and theora */
149     int     i_num_frames; /* Theora only */
150     uint64_t u_last_granulepos; /* Used for correct EOS page */
151     int64_t i_num_keyframes;
152     ogg_stream_state os;
153
154     oggds_header_t *p_oggds_header;
155
156 } ogg_stream_t;
157
158 struct sout_mux_sys_t
159 {
160     int     i_streams;
161
162     mtime_t i_start_dts;
163     int     i_next_serial_no;
164
165     /* number of logical streams pending to be added */
166     int i_add_streams;
167
168     /* logical streams pending to be deleted */
169     int i_del_streams;
170     ogg_stream_t **pp_del_streams;
171 };
172
173 static void OggSetDate( block_t *, mtime_t , mtime_t  );
174 static block_t *OggStreamFlush( sout_mux_t *, ogg_stream_state *, mtime_t );
175
176 /*****************************************************************************
177  * Open: Open muxer
178  *****************************************************************************/
179 static int Open( vlc_object_t *p_this )
180 {
181     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
182     sout_mux_sys_t  *p_sys;
183
184     msg_Info( p_mux, "Open" );
185
186     p_sys                 = malloc( sizeof( sout_mux_sys_t ) );
187     if( !p_sys )
188         return VLC_ENOMEM;
189     p_sys->i_streams      = 0;
190     p_sys->i_add_streams  = 0;
191     p_sys->i_del_streams  = 0;
192     p_sys->pp_del_streams = 0;
193
194     p_mux->p_sys        = p_sys;
195     p_mux->pf_control   = Control;
196     p_mux->pf_addstream = AddStream;
197     p_mux->pf_delstream = DelStream;
198     p_mux->pf_mux       = Mux;
199
200     /* First serial number is random.
201      * (Done like this because on win32 you need to seed the random number
202      *  generator once per thread). */
203     uint32_t r;
204     vlc_rand_bytes(&r, sizeof(r));
205     p_sys->i_next_serial_no = r & INT_MAX;
206
207     return VLC_SUCCESS;
208 }
209
210 /*****************************************************************************
211  * Close: Finalize ogg bitstream and close muxer
212  *****************************************************************************/
213 static void Close( vlc_object_t * p_this )
214 {
215     sout_mux_t     *p_mux = (sout_mux_t*)p_this;
216     sout_mux_sys_t *p_sys = p_mux->p_sys;
217
218     msg_Info( p_mux, "Close" );
219
220     if( p_sys->i_del_streams )
221     {
222         block_t *p_og = NULL;
223         mtime_t i_dts = p_sys->pp_del_streams[p_sys->i_del_streams - 1]->i_dts;
224
225         /* Close the current ogg stream */
226         msg_Dbg( p_mux, "writing footer" );
227         block_ChainAppend( &p_og, OggCreateFooter( p_mux ) );
228
229         /* Remove deleted logical streams */
230         for(int i = 0; i < p_sys->i_del_streams; i++ )
231         {
232             ogg_stream_clear( &p_sys->pp_del_streams[i]->os );
233             FREENULL( p_sys->pp_del_streams[i]->p_oggds_header );
234             FREENULL( p_sys->pp_del_streams[i] );
235         }
236         FREENULL( p_sys->pp_del_streams );
237         p_sys->i_streams -= p_sys->i_del_streams;
238
239         /* Write footer */
240         OggSetDate( p_og, i_dts, 0 );
241         sout_AccessOutWrite( p_mux->p_access, p_og );
242     }
243
244     free( p_sys );
245 }
246
247 /*****************************************************************************
248  * Control:
249  *****************************************************************************/
250 static int Control( sout_mux_t *p_mux, int i_query, va_list args )
251 {
252     VLC_UNUSED(p_mux);
253     bool *pb_bool;
254     char **ppsz;
255
256    switch( i_query )
257    {
258        case MUX_CAN_ADD_STREAM_WHILE_MUXING:
259            pb_bool = (bool*)va_arg( args, bool * );
260            *pb_bool = true;
261            return VLC_SUCCESS;
262
263        case MUX_GET_ADD_STREAM_WAIT:
264            pb_bool = (bool*)va_arg( args, bool * );
265            *pb_bool = true;
266            return VLC_SUCCESS;
267
268        case MUX_GET_MIME:
269            ppsz = (char**)va_arg( args, char ** );
270            *ppsz = strdup( "application/ogg" );
271            return VLC_SUCCESS;
272
273         default:
274             return VLC_EGENERIC;
275    }
276 }
277 /*****************************************************************************
278  * AddStream: Add an elementary stream to the muxed stream
279  *****************************************************************************/
280 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
281 {
282     sout_mux_sys_t *p_sys = p_mux->p_sys;
283     ogg_stream_t   *p_stream;
284     uint16_t i_tag;
285
286     msg_Dbg( p_mux, "adding input" );
287
288     p_input->p_sys = p_stream = calloc( 1, sizeof( ogg_stream_t ) );
289     if( !p_stream )
290         return VLC_ENOMEM;
291
292     p_stream->i_cat       = p_input->p_fmt->i_cat;
293     p_stream->i_fourcc    = p_input->p_fmt->i_codec;
294     p_stream->i_serial_no = p_sys->i_next_serial_no++;
295     p_stream->i_packet_no = 0;
296     p_stream->i_last_keyframe = 0;
297     p_stream->i_num_keyframes = 0;
298     p_stream->i_num_frames = 0;
299
300     p_stream->p_oggds_header = 0;
301
302     switch( p_input->p_fmt->i_cat )
303     {
304     case VIDEO_ES:
305         if( !p_input->p_fmt->video.i_frame_rate ||
306             !p_input->p_fmt->video.i_frame_rate_base )
307         {
308             msg_Warn( p_mux, "Missing frame rate, assuming 25fps" );
309             p_input->p_fmt->video.i_frame_rate = 25;
310             p_input->p_fmt->video.i_frame_rate_base = 1;
311         }
312
313         switch( p_stream->i_fourcc )
314         {
315         case VLC_CODEC_MP4V:
316         case VLC_CODEC_MPGV:
317         case VLC_CODEC_DIV3:
318         case VLC_CODEC_MJPG:
319         case VLC_CODEC_WMV1:
320         case VLC_CODEC_WMV2:
321         case VLC_CODEC_WMV3:
322         case VLC_CODEC_SNOW:
323             p_stream->p_oggds_header = calloc( 1, sizeof(oggds_header_t) );
324             if( !p_stream->p_oggds_header )
325             {
326                 free( p_stream );
327                 return VLC_ENOMEM;
328             }
329             p_stream->p_oggds_header->i_packet_type = PACKET_TYPE_HEADER;
330
331             memcpy( p_stream->p_oggds_header->stream_type, "video", 5 );
332             if( p_stream->i_fourcc == VLC_CODEC_MP4V )
333             {
334                 memcpy( p_stream->p_oggds_header->sub_type, "XVID", 4 );
335             }
336             else if( p_stream->i_fourcc == VLC_CODEC_DIV3 )
337             {
338                 memcpy( p_stream->p_oggds_header->sub_type, "DIV3", 4 );
339             }
340             else
341             {
342                 memcpy( p_stream->p_oggds_header->sub_type,
343                         &p_stream->i_fourcc, 4 );
344             }
345             SetDWLE( &p_stream->p_oggds_header->i_size,
346                      sizeof( oggds_header_t ) - 1 );
347             SetQWLE( &p_stream->p_oggds_header->i_time_unit,
348                      INT64_C(10000000) * p_input->p_fmt->video.i_frame_rate_base /
349                      (int64_t)p_input->p_fmt->video.i_frame_rate );
350             SetQWLE( &p_stream->p_oggds_header->i_samples_per_unit, 1 );
351             SetDWLE( &p_stream->p_oggds_header->i_default_len, 1 ); /* ??? */
352             SetDWLE( &p_stream->p_oggds_header->i_buffer_size, 1024*1024 );
353             SetWLE( &p_stream->p_oggds_header->i_bits_per_sample, 0 );
354             SetDWLE( &p_stream->p_oggds_header->header.video.i_width,
355                      p_input->p_fmt->video.i_width );
356             SetDWLE( &p_stream->p_oggds_header->header.video.i_height,
357                      p_input->p_fmt->video.i_height );
358             msg_Dbg( p_mux, "%4.4s stream", (char *)&p_stream->i_fourcc );
359             break;
360
361         case VLC_CODEC_DIRAC:
362             msg_Dbg( p_mux, "dirac stream" );
363             break;
364
365         case VLC_CODEC_THEORA:
366             msg_Dbg( p_mux, "theora stream" );
367             break;
368
369         default:
370             FREENULL( p_input->p_sys );
371             return VLC_EGENERIC;
372         }
373         break;
374
375     case AUDIO_ES:
376         switch( p_stream->i_fourcc )
377         {
378         case VLC_CODEC_VORBIS:
379             msg_Dbg( p_mux, "vorbis stream" );
380             break;
381
382         case VLC_CODEC_SPEEX:
383             msg_Dbg( p_mux, "speex stream" );
384             break;
385
386         case VLC_CODEC_FLAC:
387             msg_Dbg( p_mux, "flac stream" );
388             break;
389
390         default:
391             fourcc_to_wf_tag( p_stream->i_fourcc, &i_tag );
392             if( i_tag == WAVE_FORMAT_UNKNOWN )
393             {
394                 FREENULL( p_input->p_sys );
395                 return VLC_EGENERIC;
396             }
397
398             p_stream->p_oggds_header =
399                 malloc( sizeof(oggds_header_t) + p_input->p_fmt->i_extra );
400             if( !p_stream->p_oggds_header )
401             {
402                 free( p_stream );
403                 return VLC_ENOMEM;
404             }
405             memset( p_stream->p_oggds_header, 0, sizeof(oggds_header_t) );
406             p_stream->p_oggds_header->i_packet_type = PACKET_TYPE_HEADER;
407
408             SetDWLE( &p_stream->p_oggds_header->i_size,
409                      sizeof( oggds_header_t ) - 1 + p_input->p_fmt->i_extra );
410
411             if( p_input->p_fmt->i_extra )
412             {
413                 memcpy( &p_stream->p_oggds_header[1],
414                         p_input->p_fmt->p_extra, p_input->p_fmt->i_extra );
415             }
416
417             memcpy( p_stream->p_oggds_header->stream_type, "audio", 5 );
418
419             memset( p_stream->p_oggds_header->sub_type, 0, 4 );
420             sprintf( p_stream->p_oggds_header->sub_type, "%-x", i_tag );
421
422             SetQWLE( &p_stream->p_oggds_header->i_time_unit, INT64_C(10000000) );
423             SetDWLE( &p_stream->p_oggds_header->i_default_len, 1 );
424             SetDWLE( &p_stream->p_oggds_header->i_buffer_size, 30*1024 );
425             SetQWLE( &p_stream->p_oggds_header->i_samples_per_unit,
426                      p_input->p_fmt->audio.i_rate );
427             SetWLE( &p_stream->p_oggds_header->i_bits_per_sample,
428                     p_input->p_fmt->audio.i_bitspersample );
429             SetDWLE( &p_stream->p_oggds_header->header.audio.i_channels,
430                      p_input->p_fmt->audio.i_channels );
431             SetDWLE( &p_stream->p_oggds_header->header.audio.i_block_align,
432                      p_input->p_fmt->audio.i_blockalign );
433             SetDWLE( &p_stream->p_oggds_header->header.audio.i_avgbytespersec,
434                      p_input->p_fmt->i_bitrate / 8);
435             msg_Dbg( p_mux, "%4.4s stream", (char *)&p_stream->i_fourcc );
436             break;
437         }
438         break;
439
440     case SPU_ES:
441         switch( p_stream->i_fourcc )
442         {
443         case VLC_CODEC_SUBT:
444             p_stream->p_oggds_header = calloc( 1, sizeof(oggds_header_t) );
445             if( !p_stream->p_oggds_header )
446             {
447                 free( p_stream );
448                 return VLC_ENOMEM;
449             }
450             p_stream->p_oggds_header->i_packet_type = PACKET_TYPE_HEADER;
451
452             memcpy( p_stream->p_oggds_header->stream_type, "text", 4 );
453             msg_Dbg( p_mux, "subtitles stream" );
454             break;
455
456         default:
457             FREENULL( p_input->p_sys );
458             return VLC_EGENERIC;
459         }
460         break;
461     default:
462         FREENULL( p_input->p_sys );
463         return VLC_EGENERIC;
464     }
465
466     p_stream->b_new = true;
467
468     p_sys->i_add_streams++;
469
470     return VLC_SUCCESS;
471 }
472
473 /*****************************************************************************
474  * DelStream: Delete an elementary stream from the muxed stream
475  *****************************************************************************/
476 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
477 {
478     sout_mux_sys_t *p_sys  = p_mux->p_sys;
479     ogg_stream_t   *p_stream = (ogg_stream_t*)p_input->p_sys;
480     block_t *p_og;
481
482     msg_Dbg( p_mux, "removing input" );
483
484     /* flush all remaining data */
485     if( p_input->p_sys )
486     {
487         if( !p_stream->b_new )
488         {
489             while( block_FifoCount( p_input->p_fifo ) )
490                 MuxBlock( p_mux, p_input );
491         }
492
493         if( !p_stream->b_new &&
494             ( p_og = OggStreamFlush( p_mux, &p_stream->os, 0 ) ) )
495         {
496             OggSetDate( p_og, p_stream->i_dts, p_stream->i_length );
497             sout_AccessOutWrite( p_mux->p_access, p_og );
498         }
499
500         /* move input in delete queue */
501         if( !p_stream->b_new )
502         {
503             p_sys->pp_del_streams = xrealloc( p_sys->pp_del_streams,
504                         (p_sys->i_del_streams + 1) * sizeof(ogg_stream_t *) );
505             p_sys->pp_del_streams[p_sys->i_del_streams++] = p_stream;
506         }
507         else
508         {
509             /* wasn't already added so get rid of it */
510             FREENULL( p_stream->p_oggds_header );
511             FREENULL( p_stream );
512             p_sys->i_add_streams--;
513         }
514     }
515
516     p_input->p_sys = NULL;
517
518     return 0;
519 }
520
521 /*****************************************************************************
522  * Ogg bitstream manipulation routines
523  *****************************************************************************/
524 static block_t *OggStreamGetPage( sout_mux_t *p_mux,
525                                   ogg_stream_state *p_os, mtime_t i_pts,
526                                   bool flush )
527 {
528     (void)p_mux;
529     block_t *p_og, *p_og_first = NULL;
530     ogg_page og;
531     int (*pager)( ogg_stream_state*, ogg_page* ) = flush ? ogg_stream_flush : ogg_stream_pageout;
532
533     while( pager( p_os, &og ) )
534     {
535         /* Flush all data */
536         p_og = block_New( p_mux, og.header_len + og.body_len );
537
538         memcpy( p_og->p_buffer, og.header, og.header_len );
539         memcpy( p_og->p_buffer + og.header_len, og.body, og.body_len );
540         p_og->i_dts     = 0;
541         p_og->i_pts     = i_pts;
542         p_og->i_length  = 0;
543
544         i_pts = 0; // write it only once
545
546         block_ChainAppend( &p_og_first, p_og );
547     }
548
549     return p_og_first;
550 }
551
552 static block_t *OggStreamFlush( sout_mux_t *p_mux,
553                                 ogg_stream_state *p_os, mtime_t i_pts )
554 {
555     return OggStreamGetPage( p_mux, p_os, i_pts, true );
556 }
557
558 static block_t *OggStreamPageOut( sout_mux_t *p_mux,
559                                   ogg_stream_state *p_os, mtime_t i_pts )
560 {
561     return OggStreamGetPage( p_mux, p_os, i_pts, false );
562 }
563
564 static block_t *OggCreateHeader( sout_mux_t *p_mux )
565 {
566     block_t *p_hdr = NULL;
567     block_t *p_og = NULL;
568     ogg_packet op;
569     int i;
570
571     /* Write header for each stream. All b_o_s (beginning of stream) packets
572      * must appear first in the ogg stream so we take care of them first. */
573     for( int pass = 0; pass < 2; pass++ )
574     {
575         for( i = 0; i < p_mux->i_nb_inputs; i++ )
576         {
577             sout_input_t *p_input = p_mux->pp_inputs[i];
578             ogg_stream_t *p_stream = (ogg_stream_t*)p_input->p_sys;
579
580             bool video = ( p_stream->i_fourcc == VLC_CODEC_THEORA || p_stream->i_fourcc == VLC_CODEC_DIRAC );
581             if( ( ( pass == 0 && !video ) || ( pass == 1 && video ) ) )
582                 continue;
583
584             msg_Dbg( p_mux, "creating header for %4.4s",
585                      (char *)&p_stream->i_fourcc );
586
587             ogg_stream_init( &p_stream->os, p_stream->i_serial_no );
588             p_stream->b_new = false;
589             p_stream->i_packet_no = 0;
590
591             if( p_stream->i_fourcc == VLC_CODEC_VORBIS ||
592                 p_stream->i_fourcc == VLC_CODEC_SPEEX ||
593                 p_stream->i_fourcc == VLC_CODEC_THEORA )
594             {
595                 /* First packet in order: vorbis/speex/theora info */
596                 unsigned pi_size[XIPH_MAX_HEADER_COUNT];
597                 void     *pp_data[XIPH_MAX_HEADER_COUNT];
598                 unsigned i_count;
599                 if( xiph_SplitHeaders( pi_size, pp_data, &i_count,
600                                        p_input->p_fmt->i_extra, p_input->p_fmt->p_extra ) )
601                 {
602                     i_count = 0;
603                     pi_size[0] = 0;
604                     pp_data[0] = NULL;
605                 }
606
607                 op.bytes  = pi_size[0];
608                 op.packet = pp_data[0];
609                 if( pi_size[0] <= 0 )
610                     msg_Err( p_mux, "header data corrupted");
611
612                 op.b_o_s  = 1;
613                 op.e_o_s  = 0;
614                 op.granulepos = 0;
615                 op.packetno = p_stream->i_packet_no++;
616                 ogg_stream_packetin( &p_stream->os, &op );
617                 p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
618
619                 /* Get keyframe_granule_shift for theora granulepos calculation */
620                 if( p_stream->i_fourcc == VLC_CODEC_THEORA )
621                 {
622                     p_stream->i_keyframe_granule_shift =
623                         ( (op.packet[40] & 0x03) << 3 ) | ( (op.packet[41] & 0xe0) >> 5 );
624                 }
625
626                 for( unsigned i = 0; i < i_count; i++ )
627                     free( pp_data[i] );
628             }
629             else if( p_stream->i_fourcc == VLC_CODEC_DIRAC )
630             {
631                 op.packet = p_input->p_fmt->p_extra;
632                 op.bytes  = p_input->p_fmt->i_extra;
633                 op.b_o_s  = 1;
634                 op.e_o_s  = 0;
635                 op.granulepos = ~0;
636                 op.packetno = p_stream->i_packet_no++;
637                 ogg_stream_packetin( &p_stream->os, &op );
638                 p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
639             }
640             else if( p_stream->i_fourcc == VLC_CODEC_FLAC )
641             {
642                 /* flac stream marker (yeah, only that in the 1st packet) */
643                 op.packet = (unsigned char *)"fLaC";
644                 op.bytes  = 4;
645                 op.b_o_s  = 1;
646                 op.e_o_s  = 0;
647                 op.granulepos = 0;
648                 op.packetno = p_stream->i_packet_no++;
649                 ogg_stream_packetin( &p_stream->os, &op );
650                 p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
651             }
652             else if( p_stream->p_oggds_header )
653             {
654                 /* ds header */
655                 op.packet = (uint8_t*)p_stream->p_oggds_header;
656                 op.bytes  = p_stream->p_oggds_header->i_size + 1;
657                 op.b_o_s  = 1;
658                 op.e_o_s  = 0;
659                 op.granulepos = 0;
660                 op.packetno = p_stream->i_packet_no++;
661                 ogg_stream_packetin( &p_stream->os, &op );
662                 p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
663             }
664
665             block_ChainAppend( &p_hdr, p_og );
666         }
667     }
668
669     /* Take care of the non b_o_s headers */
670     for( i = 0; i < p_mux->i_nb_inputs; i++ )
671     {
672         sout_input_t *p_input = p_mux->pp_inputs[i];
673         ogg_stream_t *p_stream = (ogg_stream_t*)p_input->p_sys;
674
675         if( p_stream->i_fourcc == VLC_CODEC_VORBIS ||
676             p_stream->i_fourcc == VLC_CODEC_SPEEX ||
677             p_stream->i_fourcc == VLC_CODEC_THEORA )
678         {
679             unsigned pi_size[XIPH_MAX_HEADER_COUNT];
680             void     *pp_data[XIPH_MAX_HEADER_COUNT];
681             unsigned i_count;
682             if( xiph_SplitHeaders( pi_size, pp_data, &i_count,
683                                    p_input->p_fmt->i_extra, p_input->p_fmt->p_extra ) )
684                 i_count = 0;
685
686             /* Special case, headers are already there in the incoming stream.
687              * We need to gather them an mark them as headers. */
688             for( unsigned i = 1; i < i_count; i++ )
689             {
690                 op.bytes  = pi_size[i];
691                 op.packet = pp_data[i];
692                 if( pi_size[i] <= 0 )
693                     msg_Err( p_mux, "header data corrupted");
694
695                 op.b_o_s  = 0;
696                 op.e_o_s  = 0;
697                 op.granulepos = 0;
698                 op.packetno = p_stream->i_packet_no++;
699                 ogg_stream_packetin( &p_stream->os, &op );
700
701                 if( i == i_count - 1 )
702                     p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
703                 else
704                     p_og = OggStreamPageOut( p_mux, &p_stream->os, 0 );
705                 if( p_og )
706                     block_ChainAppend( &p_hdr, p_og );
707             }
708             for( unsigned i = 0; i < i_count; i++ )
709                 free( pp_data[i] );
710         }
711         else if( p_stream->i_fourcc != VLC_CODEC_FLAC &&
712                  p_stream->i_fourcc != VLC_CODEC_DIRAC )
713         {
714             uint8_t com[128];
715             int     i_com;
716
717             /* comment */
718             com[0] = PACKET_TYPE_COMMENT;
719             i_com = snprintf( (char *)(com+1), 127,
720                               PACKAGE_VERSION" stream output" )
721                      + 1;
722             op.packet = com;
723             op.bytes  = i_com;
724             op.b_o_s  = 0;
725             op.e_o_s  = 0;
726             op.granulepos = 0;
727             op.packetno = p_stream->i_packet_no++;
728             ogg_stream_packetin( &p_stream->os, &op );
729             p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
730             block_ChainAppend( &p_hdr, p_og );
731         }
732
733         /* Special case for mp4v and flac */
734         if( ( p_stream->i_fourcc == VLC_CODEC_MP4V ||
735               p_stream->i_fourcc == VLC_CODEC_FLAC ) &&
736             p_input->p_fmt->i_extra )
737         {
738             /* Send a packet with the VOL data for mp4v
739              * or STREAMINFO for flac */
740             msg_Dbg( p_mux, "writing extra data" );
741             op.bytes  = p_input->p_fmt->i_extra;
742             op.packet = p_input->p_fmt->p_extra;
743             if( p_stream->i_fourcc == VLC_CODEC_FLAC )
744             {
745                 /* Skip the flac stream marker */
746                 op.bytes -= 4;
747                 op.packet+= 4;
748             }
749             op.b_o_s  = 0;
750             op.e_o_s  = 0;
751             op.granulepos = 0;
752             op.packetno = p_stream->i_packet_no++;
753             ogg_stream_packetin( &p_stream->os, &op );
754             p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
755             block_ChainAppend( &p_hdr, p_og );
756         }
757     }
758
759     /* set HEADER flag */
760     for( p_og = p_hdr; p_og != NULL; p_og = p_og->p_next )
761     {
762         p_og->i_flags |= BLOCK_FLAG_HEADER;
763     }
764     return p_hdr;
765 }
766
767 static block_t *OggCreateFooter( sout_mux_t *p_mux )
768 {
769     sout_mux_sys_t *p_sys = p_mux->p_sys;
770     block_t *p_hdr = NULL;
771     block_t *p_og;
772     ogg_packet    op;
773     int     i;
774
775     /* flush all remaining data */
776     for( i = 0; i < p_mux->i_nb_inputs; i++ )
777     {
778         ogg_stream_t *p_stream = p_mux->pp_inputs[i]->p_sys;
779
780         /* skip newly added streams */
781         if( p_stream->b_new ) continue;
782
783         if( ( p_og = OggStreamFlush( p_mux, &p_stream->os, 0 ) ) )
784         {
785             OggSetDate( p_og, p_stream->i_dts, p_stream->i_length );
786             sout_AccessOutWrite( p_mux->p_access, p_og );
787         }
788     }
789
790     /* Write eos packets for each stream. */
791     for( i = 0; i < p_mux->i_nb_inputs; i++ )
792     {
793         ogg_stream_t *p_stream = p_mux->pp_inputs[i]->p_sys;
794
795         /* skip newly added streams */
796         if( p_stream->b_new ) continue;
797
798         op.packet = NULL;
799         op.bytes  = 0;
800         op.b_o_s  = 0;
801         op.e_o_s  = 1;
802         op.granulepos = p_stream->u_last_granulepos;
803         op.packetno = p_stream->i_packet_no++;
804         ogg_stream_packetin( &p_stream->os, &op );
805
806         p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
807         block_ChainAppend( &p_hdr, p_og );
808         ogg_stream_clear( &p_stream->os );
809     }
810
811     for( i = 0; i < p_sys->i_del_streams; i++ )
812     {
813         op.packet = NULL;
814         op.bytes  = 0;
815         op.b_o_s  = 0;
816         op.e_o_s  = 1;
817         op.granulepos = p_sys->pp_del_streams[i]->u_last_granulepos;
818         op.packetno = p_sys->pp_del_streams[i]->i_packet_no++;
819         ogg_stream_packetin( &p_sys->pp_del_streams[i]->os, &op );
820
821         p_og = OggStreamFlush( p_mux, &p_sys->pp_del_streams[i]->os, 0 );
822         block_ChainAppend( &p_hdr, p_og );
823         ogg_stream_clear( &p_sys->pp_del_streams[i]->os );
824     }
825
826     return p_hdr;
827 }
828
829 static void OggSetDate( block_t *p_og, mtime_t i_dts, mtime_t i_length )
830 {
831     int i_count;
832     block_t *p_tmp;
833     mtime_t i_delta;
834
835     for( p_tmp = p_og, i_count = 0; p_tmp != NULL; p_tmp = p_tmp->p_next )
836     {
837         i_count++;
838     }
839
840     if( i_count == 0 ) return; /* ignore. */
841
842     i_delta = i_length / i_count;
843
844     for( p_tmp = p_og; p_tmp != NULL; p_tmp = p_tmp->p_next )
845     {
846         p_tmp->i_dts    = i_dts;
847         p_tmp->i_length = i_delta;
848
849         i_dts += i_delta;
850     }
851 }
852
853 /*****************************************************************************
854  * Mux: multiplex available data in input fifos into the Ogg bitstream
855  *****************************************************************************/
856 static int Mux( sout_mux_t *p_mux )
857 {
858     sout_mux_sys_t *p_sys = p_mux->p_sys;
859     block_t        *p_og = NULL;
860     mtime_t        i_dts;
861
862     if( p_sys->i_add_streams || p_sys->i_del_streams )
863     {
864         /* Open new ogg stream */
865         if( sout_MuxGetStream( p_mux, 1, &i_dts) < 0 )
866         {
867             msg_Dbg( p_mux, "waiting for data..." );
868             return VLC_SUCCESS;
869         }
870
871         if( p_sys->i_streams )
872         {
873             /* Close current ogg stream */
874             int i;
875
876             msg_Dbg( p_mux, "writing footer" );
877             block_ChainAppend( &p_og, OggCreateFooter( p_mux ) );
878
879             /* Remove deleted logical streams */
880             for( i = 0; i < p_sys->i_del_streams; i++ )
881             {
882                 FREENULL( p_sys->pp_del_streams[i]->p_oggds_header );
883                 FREENULL( p_sys->pp_del_streams[i] );
884             }
885             FREENULL( p_sys->pp_del_streams );
886             p_sys->i_streams = 0;
887         }
888
889         msg_Dbg( p_mux, "writing header" );
890         p_sys->i_start_dts = i_dts;
891         p_sys->i_streams = p_mux->i_nb_inputs;
892         p_sys->i_del_streams = 0;
893         p_sys->i_add_streams = 0;
894         block_ChainAppend( &p_og, OggCreateHeader( p_mux ) );
895
896         /* Write header and/or footer */
897         OggSetDate( p_og, i_dts, 0 );
898         sout_AccessOutWrite( p_mux->p_access, p_og );
899         p_og = NULL;
900     }
901
902     for( ;; )
903     {
904         int i_stream = sout_MuxGetStream( p_mux, 1, NULL );
905         if( i_stream < 0 )
906             return VLC_SUCCESS;
907         MuxBlock( p_mux, p_mux->pp_inputs[i_stream] );
908     }
909
910     return VLC_SUCCESS;
911 }
912
913 static int MuxBlock( sout_mux_t *p_mux, sout_input_t *p_input )
914 {
915     sout_mux_sys_t *p_sys = p_mux->p_sys;
916     ogg_stream_t *p_stream = (ogg_stream_t*)p_input->p_sys;
917     block_t *p_data = block_FifoGet( p_input->p_fifo );
918     block_t *p_og = NULL;
919     ogg_packet op;
920
921     if( p_stream->i_fourcc != VLC_CODEC_VORBIS &&
922         p_stream->i_fourcc != VLC_CODEC_FLAC &&
923         p_stream->i_fourcc != VLC_CODEC_SPEEX &&
924         p_stream->i_fourcc != VLC_CODEC_THEORA &&
925         p_stream->i_fourcc != VLC_CODEC_DIRAC )
926     {
927         p_data = block_Realloc( p_data, 1, p_data->i_buffer );
928         p_data->p_buffer[0] = PACKET_IS_SYNCPOINT;      // FIXME
929     }
930
931     op.packet   = p_data->p_buffer;
932     op.bytes    = p_data->i_buffer;
933     op.b_o_s    = 0;
934     op.e_o_s    = 0;
935     op.packetno = p_stream->i_packet_no++;
936
937     if( p_stream->i_cat == AUDIO_ES )
938     {
939         if( p_stream->i_fourcc == VLC_CODEC_VORBIS ||
940             p_stream->i_fourcc == VLC_CODEC_FLAC ||
941             p_stream->i_fourcc == VLC_CODEC_SPEEX )
942         {
943             /* number of sample from begining + current packet */
944             op.granulepos =
945                 ( p_data->i_dts - p_sys->i_start_dts + p_data->i_length ) *
946                 (mtime_t)p_input->p_fmt->audio.i_rate / INT64_C(1000000);
947         }
948         else if( p_stream->p_oggds_header )
949         {
950             /* number of sample from begining */
951             op.granulepos = ( p_data->i_dts - p_sys->i_start_dts ) *
952                 p_stream->p_oggds_header->i_samples_per_unit / INT64_C(1000000);
953         }
954     }
955     else if( p_stream->i_cat == VIDEO_ES )
956     {
957         if( p_stream->i_fourcc == VLC_CODEC_THEORA )
958         {
959             p_stream->i_num_frames++;
960             if( p_data->i_flags & BLOCK_FLAG_TYPE_I )
961             {
962                 p_stream->i_num_keyframes++;
963                 p_stream->i_last_keyframe = p_stream->i_num_frames;
964             }
965
966             op.granulepos = (p_stream->i_last_keyframe << p_stream->i_keyframe_granule_shift )
967                           | (p_stream->i_num_frames-p_stream->i_last_keyframe);
968         }
969         else if( p_stream->i_fourcc == VLC_CODEC_DIRAC )
970         {
971             mtime_t dt = (p_data->i_dts - p_sys->i_start_dts + 1)
972                        * p_input->p_fmt->video.i_frame_rate *2
973                        / p_input->p_fmt->video.i_frame_rate_base
974                        / INT64_C(1000000);
975             mtime_t delay = (p_data->i_pts - p_data->i_dts + 1)
976                           * p_input->p_fmt->video.i_frame_rate *2
977                           / p_input->p_fmt->video.i_frame_rate_base
978                           / INT64_C(1000000);
979             if( p_data->i_flags & BLOCK_FLAG_TYPE_I )
980                 p_stream->i_last_keyframe = dt;
981             mtime_t dist = dt - p_stream->i_last_keyframe;
982             op.granulepos = dt << 31 | (dist&0xff00) << 14
983                           | (delay&0x1fff) << 9 | (dist&0xff);
984         }
985         else if( p_stream->p_oggds_header )
986             op.granulepos = ( p_data->i_dts - p_sys->i_start_dts ) * INT64_C(10) /
987                 p_stream->p_oggds_header->i_time_unit;
988     }
989     else if( p_stream->i_cat == SPU_ES )
990     {
991         /* granulepos is in millisec */
992         op.granulepos = ( p_data->i_dts - p_sys->i_start_dts ) / 1000;
993     }
994
995     p_stream->u_last_granulepos = op.granulepos;
996     ogg_stream_packetin( &p_stream->os, &op );
997
998     if( p_stream->i_cat == SPU_ES ||
999         p_stream->i_fourcc == VLC_CODEC_SPEEX ||
1000         p_stream->i_fourcc == VLC_CODEC_DIRAC )
1001     {
1002         /* Subtitles or Speex packets are quite small so they
1003          * need to be flushed to be sent on time */
1004         /* The OggDirac mapping suggests ever so strongly that a
1005          * page flush occurs after each OggDirac packet, so to make
1006          * the timestamps unambiguous */
1007         p_og = OggStreamFlush( p_mux, &p_stream->os, p_data->i_dts );
1008     }
1009     else
1010     {
1011         p_og = OggStreamPageOut( p_mux, &p_stream->os, p_data->i_dts );
1012     }
1013
1014     if( p_og )
1015     {
1016         OggSetDate( p_og, p_stream->i_dts, p_stream->i_length );
1017         p_stream->i_dts = -1;
1018         p_stream->i_length = 0;
1019
1020         sout_AccessOutWrite( p_mux->p_access, p_og );
1021     }
1022     else
1023     {
1024         if( p_stream->i_dts < 0 )
1025         {
1026             p_stream->i_dts = p_data->i_dts;
1027         }
1028         p_stream->i_length += p_data->i_length;
1029     }
1030
1031     block_Release( p_data );
1032     return VLC_SUCCESS;
1033 }