]> git.sesse.net Git - vlc/blob - modules/mux/ogg.c
ogg: fix order of frees
[vlc] / modules / mux / ogg.c
1 /*****************************************************************************
2  * ogg.c: ogg muxer module for vlc
3  *****************************************************************************
4  * Copyright (C) 2001, 2002, 2006 VLC authors and VideoLAN
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 it
11  * under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * 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 #define INDEXINTVL_TEXT N_("Index interval")
48 #define INDEXINTVL_LONGTEXT N_("Minimal index interval, in microseconds. " \
49     "Set to 0 to disable index creation.")
50 #define INDEXRATIO_TEXT N_("Index size ratio")
51 #define INDEXRATIO_LONGTEXT N_(\
52     "Set index size ratio. Alters default (60min content) or estimated size." )
53
54 static int  Open   ( vlc_object_t * );
55 static void Close  ( vlc_object_t * );
56
57 #define SOUT_CFG_PREFIX "sout-ogg-"
58
59 vlc_module_begin ()
60     set_description( N_("Ogg/OGM muxer") )
61     set_capability( "sout mux", 10 )
62     set_category( CAT_SOUT )
63     set_subcategory( SUBCAT_SOUT_MUX )
64     add_shortcut( "ogg", "ogm" )
65     add_integer_with_range( SOUT_CFG_PREFIX "indexintvl", 1000, 0, INT_MAX,
66                             INDEXINTVL_TEXT, INDEXINTVL_LONGTEXT, true )
67     add_float_with_range( SOUT_CFG_PREFIX "indexratio", 1.0, 1.0, 1000,
68                           INDEXRATIO_TEXT, INDEXRATIO_LONGTEXT, true )
69     set_callbacks( Open, Close )
70 vlc_module_end ()
71
72
73 /*****************************************************************************
74  * Exported prototypes
75  *****************************************************************************/
76 static int Control  ( sout_mux_t *, int, va_list );
77 static int AddStream( sout_mux_t *, sout_input_t * );
78 static int DelStream( sout_mux_t *, sout_input_t * );
79 static int Mux      ( sout_mux_t * );
80 static int MuxBlock ( sout_mux_t *, sout_input_t * );
81
82 static bool OggCreateHeaders( sout_mux_t * );
83 static void OggFillSkeletonFishead( uint8_t *p_buffer, sout_mux_t *p_mux );
84
85 /*****************************************************************************
86  * Misc declarations
87  *****************************************************************************/
88
89 /* Skeleton */
90 #define FISBONE_BASE_SIZE 52
91 #define FISBONE_BASE_OFFSET 44
92 #define INDEX_BASE_SIZE 42
93
94 /* Structures used for OggDS headers used in ogm files */
95
96 #define PACKET_TYPE_HEADER   0x01
97 #define PACKET_TYPE_COMMENT  0x03
98 #define PACKET_IS_SYNCPOINT  0x08
99
100 typedef struct
101 {
102     int32_t i_width;
103     int32_t i_height;
104 } oggds_header_video_t;
105
106 typedef struct
107 {
108     int16_t i_channels;
109     int16_t i_block_align;
110     int32_t i_avgbytespersec;
111 } oggds_header_audio_t;
112
113 typedef struct
114 {
115     uint8_t i_packet_type;
116
117     char stream_type[8];
118     char sub_type[4];
119
120     int32_t i_size;
121
122     int64_t i_time_unit;
123     int64_t i_samples_per_unit;
124     int32_t i_default_len;
125
126     int32_t i_buffer_size;
127     int16_t i_bits_per_sample;
128
129     int16_t i_padding_0; /* Because the original is using MSVC packing style */
130
131     union
132     {
133         oggds_header_video_t video;
134         oggds_header_audio_t audio;
135     } header;
136
137     int32_t i_padding_1; /* Because the original is using MSVC packing style */
138
139 } oggds_header_t;
140
141 /*****************************************************************************
142  * Definitions of structures and functions used by this plugins
143  *****************************************************************************/
144 typedef struct
145 {
146     int i_cat;
147     vlc_fourcc_t i_fourcc;
148
149     int b_new;
150
151     mtime_t i_dts;
152     mtime_t i_length;
153     int     i_packet_no;
154     int     i_serial_no;
155     int     i_keyframe_granule_shift; /* Theora only */
156     int     i_last_keyframe; /* dirac and theora */
157     int     i_num_frames; /* Theora only */
158     uint64_t u_last_granulepos; /* Used for correct EOS page */
159     int64_t i_num_keyframes;
160     ogg_stream_state os;
161
162     oggds_header_t *p_oggds_header;
163     bool b_started;
164     bool b_finished;
165
166     struct
167     {
168          bool b_fisbone_done;
169          bool b_index_done;
170          /* Skeleton index storage */
171          unsigned char *p_index;
172          uint64_t i_index_size;
173          uint64_t i_index_payload; /* real index size */
174          uint64_t i_index_count;
175          /* backup values for rewriting index page later */
176          uint64_t i_index_offset;  /* sout offset of the index page */
177          int64_t i_index_packetno;  /* index packet no */
178          int i_index_pageno;
179          /* index creation tracking values */
180          uint64_t i_last_keyframe_pos;
181          uint64_t i_last_keyframe_time;
182     } skeleton;
183 } ogg_stream_t;
184
185 struct sout_mux_sys_t
186 {
187     int     i_streams;
188
189     mtime_t i_start_dts;
190     int     i_next_serial_no;
191
192     /* number of logical streams pending to be added */
193     int i_add_streams;
194     bool b_can_add_streams;
195
196     /* logical streams pending to be deleted */
197     int i_del_streams;
198     ogg_stream_t **pp_del_streams;
199
200     /* Skeleton */
201     struct
202     {
203         bool b_create;
204         int i_serial_no;
205         int i_packet_no;
206         ogg_stream_state os;
207         bool b_head_done;
208         /* backup values for rewriting fishead page later */
209         uint64_t i_fishead_offset;  /* sout offset of the fishead page */
210         int i_index_intvl;
211         float i_index_ratio;
212     } skeleton;
213
214     /* access position */
215     ssize_t i_pos;
216     ssize_t i_data_start;
217     ssize_t i_segment_start;
218 };
219
220 static void OggSetDate( block_t *, mtime_t , mtime_t  );
221 static block_t *OggStreamFlush( sout_mux_t *, ogg_stream_state *, mtime_t );
222 static void OggCreateStreamFooter( sout_mux_t *p_mux, ogg_stream_t *p_stream );
223 static void OggRewriteFisheadPage( sout_mux_t *p_mux );
224 static bool AllocateIndex( sout_mux_t *p_mux, sout_input_t *p_input );
225
226 /*****************************************************************************
227  * Open: Open muxer
228  *****************************************************************************/
229 static int Open( vlc_object_t *p_this )
230 {
231     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
232     sout_mux_sys_t  *p_sys;
233
234     msg_Info( p_mux, "Open" );
235
236     p_sys                 = malloc( sizeof( sout_mux_sys_t ) );
237     if( !p_sys )
238         return VLC_ENOMEM;
239     p_sys->i_streams      = 0;
240     p_sys->i_add_streams  = 0;
241     p_sys->b_can_add_streams = true;
242     p_sys->i_del_streams  = 0;
243     p_sys->pp_del_streams = 0;
244     p_sys->i_pos = 0;
245     p_sys->skeleton.b_create = false;
246     p_sys->skeleton.b_head_done = false;
247     p_sys->skeleton.i_index_intvl =
248             var_InheritInteger( p_this, SOUT_CFG_PREFIX "indexintvl" );
249     p_sys->skeleton.i_index_ratio =
250             var_InheritFloat( p_this, SOUT_CFG_PREFIX "indexratio" );
251     p_mux->p_sys        = p_sys;
252     p_mux->pf_control   = Control;
253     p_mux->pf_addstream = AddStream;
254     p_mux->pf_delstream = DelStream;
255     p_mux->pf_mux       = Mux;
256
257     /* First serial number is random.
258      * (Done like this because on win32 you need to seed the random number
259      *  generator once per thread). */
260     uint32_t r;
261     vlc_rand_bytes(&r, sizeof(r));
262     p_sys->i_next_serial_no = r & INT_MAX;
263
264     return VLC_SUCCESS;
265 }
266
267 /*****************************************************************************
268  * Close: Finalize ogg bitstream and close muxer
269  *****************************************************************************/
270 static void Close( vlc_object_t * p_this )
271 {
272     sout_mux_t     *p_mux = (sout_mux_t*)p_this;
273     sout_mux_sys_t *p_sys = p_mux->p_sys;
274     ogg_stream_t *p_stream;
275
276     msg_Info( p_mux, "Close" );
277
278     if( p_sys->i_del_streams )
279     {
280         /* Close the current ogg stream */
281         msg_Dbg( p_mux, "writing footers" );
282
283         for(int i = 0; i < p_mux->i_nb_inputs; i++ )
284         {
285             p_stream = (ogg_stream_t *) p_mux->pp_inputs[i]->p_sys;
286             OggCreateStreamFooter( p_mux, p_stream );
287             free( p_stream->skeleton.p_index );
288         }
289
290         /* Remove deleted logical streams */
291         for(int i = 0; i < p_sys->i_del_streams; i++ )
292         {
293             OggCreateStreamFooter( p_mux, p_sys->pp_del_streams[i] );
294             free( p_sys->pp_del_streams[i]->p_oggds_header );
295             free( p_sys->pp_del_streams[i]->skeleton.p_index );
296             free( p_sys->pp_del_streams[i] );
297         }
298         free( p_sys->pp_del_streams );
299         p_sys->i_streams -= p_sys->i_del_streams;
300     }
301
302     /* rewrite fishead with final values */
303     if ( p_sys->skeleton.b_create && p_sys->skeleton.b_head_done )
304     {
305         OggRewriteFisheadPage( p_mux );
306     }
307
308     free( p_sys );
309 }
310
311 /*****************************************************************************
312  * Control:
313  *****************************************************************************/
314 static int Control( sout_mux_t *p_mux, int i_query, va_list args )
315 {
316     VLC_UNUSED(p_mux);
317     bool *pb_bool;
318     char **ppsz;
319
320    switch( i_query )
321    {
322        case MUX_CAN_ADD_STREAM_WHILE_MUXING:
323            pb_bool = (bool*)va_arg( args, bool * );
324            *pb_bool = true;
325            return VLC_SUCCESS;
326
327        case MUX_GET_ADD_STREAM_WAIT:
328            pb_bool = (bool*)va_arg( args, bool * );
329            *pb_bool = true;
330            return VLC_SUCCESS;
331
332        case MUX_GET_MIME:
333            ppsz = (char**)va_arg( args, char ** );
334            *ppsz = strdup( "application/ogg" );
335            return VLC_SUCCESS;
336
337         default:
338             return VLC_EGENERIC;
339    }
340 }
341 /*****************************************************************************
342  * AddStream: Add an elementary stream to the muxed stream
343  *****************************************************************************/
344 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
345 {
346     sout_mux_sys_t *p_sys = p_mux->p_sys;
347     ogg_stream_t   *p_stream;
348     uint16_t i_tag;
349
350     msg_Dbg( p_mux, "adding input" );
351
352     p_input->p_sys = p_stream = calloc( 1, sizeof( ogg_stream_t ) );
353     if( !p_stream )
354         return VLC_ENOMEM;
355
356     p_stream->i_cat       = p_input->p_fmt->i_cat;
357     p_stream->i_fourcc    = p_input->p_fmt->i_codec;
358     p_stream->i_serial_no = p_sys->i_next_serial_no++;
359     p_stream->i_packet_no = 0;
360     p_stream->i_last_keyframe = 0;
361     p_stream->i_num_keyframes = 0;
362     p_stream->i_num_frames = 0;
363
364     p_stream->p_oggds_header = 0;
365
366     switch( p_input->p_fmt->i_cat )
367     {
368     case VIDEO_ES:
369         if( !p_input->p_fmt->video.i_frame_rate ||
370             !p_input->p_fmt->video.i_frame_rate_base )
371         {
372             msg_Warn( p_mux, "Missing frame rate, assuming 25fps" );
373             p_input->p_fmt->video.i_frame_rate = 25;
374             p_input->p_fmt->video.i_frame_rate_base = 1;
375         }
376
377         switch( p_stream->i_fourcc )
378         {
379         case VLC_CODEC_MP4V:
380         case VLC_CODEC_MPGV:
381         case VLC_CODEC_DIV3:
382         case VLC_CODEC_MJPG:
383         case VLC_CODEC_WMV1:
384         case VLC_CODEC_WMV2:
385         case VLC_CODEC_WMV3:
386             p_stream->p_oggds_header = calloc( 1, sizeof(oggds_header_t) );
387             if( !p_stream->p_oggds_header )
388             {
389                 free( p_stream );
390                 return VLC_ENOMEM;
391             }
392             p_stream->p_oggds_header->i_packet_type = PACKET_TYPE_HEADER;
393
394             memcpy( p_stream->p_oggds_header->stream_type, "video", 5 );
395             if( p_stream->i_fourcc == VLC_CODEC_MP4V )
396             {
397                 memcpy( p_stream->p_oggds_header->sub_type, "XVID", 4 );
398             }
399             else if( p_stream->i_fourcc == VLC_CODEC_DIV3 )
400             {
401                 memcpy( p_stream->p_oggds_header->sub_type, "DIV3", 4 );
402             }
403             else
404             {
405                 memcpy( p_stream->p_oggds_header->sub_type,
406                         &p_stream->i_fourcc, 4 );
407             }
408             p_stream->p_oggds_header->i_size = 0 ;
409             p_stream->p_oggds_header->i_time_unit =
410                      INT64_C(10000000) * p_input->p_fmt->video.i_frame_rate_base /
411                      (int64_t)p_input->p_fmt->video.i_frame_rate;
412             p_stream->p_oggds_header->i_samples_per_unit = 1;
413             p_stream->p_oggds_header->i_default_len = 1 ; /* ??? */
414             p_stream->p_oggds_header->i_buffer_size = 1024*1024;
415             p_stream->p_oggds_header->i_bits_per_sample = 0;
416             p_stream->p_oggds_header->header.video.i_width = p_input->p_fmt->video.i_width;
417             p_stream->p_oggds_header->header.video.i_height = p_input->p_fmt->video.i_height;
418             msg_Dbg( p_mux, "%4.4s stream", (char *)&p_stream->i_fourcc );
419             break;
420
421         case VLC_CODEC_DIRAC:
422             msg_Dbg( p_mux, "dirac stream" );
423             break;
424
425         case VLC_CODEC_THEORA:
426             msg_Dbg( p_mux, "theora stream" );
427             break;
428
429         default:
430             FREENULL( p_input->p_sys );
431             return VLC_EGENERIC;
432         }
433         break;
434
435     case AUDIO_ES:
436         switch( p_stream->i_fourcc )
437         {
438         case VLC_CODEC_OPUS:
439             msg_Dbg( p_mux, "opus stream" );
440             break;
441
442         case VLC_CODEC_VORBIS:
443             msg_Dbg( p_mux, "vorbis stream" );
444             break;
445
446         case VLC_CODEC_SPEEX:
447             msg_Dbg( p_mux, "speex stream" );
448             break;
449
450         case VLC_CODEC_FLAC:
451             msg_Dbg( p_mux, "flac stream" );
452             break;
453
454         default:
455             fourcc_to_wf_tag( p_stream->i_fourcc, &i_tag );
456             if( i_tag == WAVE_FORMAT_UNKNOWN )
457             {
458                 FREENULL( p_input->p_sys );
459                 return VLC_EGENERIC;
460             }
461
462             p_stream->p_oggds_header =
463                 malloc( sizeof(oggds_header_t) + p_input->p_fmt->i_extra );
464             if( !p_stream->p_oggds_header )
465             {
466                 free( p_stream );
467                 return VLC_ENOMEM;
468             }
469             memset( p_stream->p_oggds_header, 0, sizeof(oggds_header_t) );
470             p_stream->p_oggds_header->i_packet_type = PACKET_TYPE_HEADER;
471
472             p_stream->p_oggds_header->i_size = p_input->p_fmt->i_extra;
473
474             if( p_input->p_fmt->i_extra )
475             {
476                 memcpy( &p_stream->p_oggds_header[1],
477                         p_input->p_fmt->p_extra, p_input->p_fmt->i_extra );
478             }
479
480             memcpy( p_stream->p_oggds_header->stream_type, "audio", 5 );
481
482             memset( p_stream->p_oggds_header->sub_type, 0, 4 );
483             char buf[5];
484             snprintf( buf, sizeof(buf), "%"PRIx16, i_tag );
485             strncpy( p_stream->p_oggds_header->sub_type, buf, 4 );
486
487             p_stream->p_oggds_header->i_time_unit = INT64_C(10000000);
488             p_stream->p_oggds_header->i_default_len = 1;
489             p_stream->p_oggds_header->i_buffer_size = 30*1024 ;
490             p_stream->p_oggds_header->i_samples_per_unit = p_input->p_fmt->audio.i_rate;
491             p_stream->p_oggds_header->i_bits_per_sample = p_input->p_fmt->audio.i_bitspersample;
492             p_stream->p_oggds_header->header.audio.i_channels = p_input->p_fmt->audio.i_channels;
493             p_stream->p_oggds_header->header.audio.i_block_align =  p_input->p_fmt->audio.i_blockalign;
494             p_stream->p_oggds_header->header.audio.i_avgbytespersec =  p_input->p_fmt->i_bitrate / 8;
495             msg_Dbg( p_mux, "%4.4s stream", (char *)&p_stream->i_fourcc );
496             break;
497         }
498         break;
499
500     case SPU_ES:
501         switch( p_stream->i_fourcc )
502         {
503         case VLC_CODEC_SUBT:
504             p_stream->p_oggds_header = calloc( 1, sizeof(oggds_header_t) );
505             if( !p_stream->p_oggds_header )
506             {
507                 free( p_stream );
508                 return VLC_ENOMEM;
509             }
510             p_stream->p_oggds_header->i_packet_type = PACKET_TYPE_HEADER;
511
512             memcpy( p_stream->p_oggds_header->stream_type, "text", 4 );
513             msg_Dbg( p_mux, "subtitles stream" );
514             break;
515
516         default:
517             FREENULL( p_input->p_sys );
518             return VLC_EGENERIC;
519         }
520         break;
521     default:
522         FREENULL( p_input->p_sys );
523         return VLC_EGENERIC;
524     }
525
526     p_stream->b_new = true;
527
528     p_sys->i_add_streams++;
529
530     return VLC_SUCCESS;
531 }
532
533 /*****************************************************************************
534  * DelStream: Delete an elementary stream from the muxed stream
535  *****************************************************************************/
536 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
537 {
538     sout_mux_sys_t *p_sys  = p_mux->p_sys;
539     ogg_stream_t   *p_stream = (ogg_stream_t*)p_input->p_sys;
540     block_t *p_og;
541
542     msg_Dbg( p_mux, "removing input" );
543
544     /* flush all remaining data */
545     if( p_input->p_sys )
546     {
547         if( !p_stream->b_new )
548         {
549             while( block_FifoCount( p_input->p_fifo ) )
550                 MuxBlock( p_mux, p_input );
551         }
552
553         if( !p_stream->b_new &&
554             ( p_og = OggStreamFlush( p_mux, &p_stream->os, 0 ) ) )
555         {
556             OggSetDate( p_og, p_stream->i_dts, p_stream->i_length );
557             p_mux->p_sys->i_pos += sout_AccessOutWrite( p_mux->p_access, p_og );
558         }
559
560         /* move input in delete queue */
561         if( !p_stream->b_new )
562         {
563             p_sys->pp_del_streams = xrealloc( p_sys->pp_del_streams,
564                         (p_sys->i_del_streams + 1) * sizeof(ogg_stream_t *) );
565             p_sys->pp_del_streams[p_sys->i_del_streams++] = p_stream;
566         }
567         else
568         {
569             /* wasn't already added so get rid of it */
570             FREENULL( p_stream->p_oggds_header );
571             FREENULL( p_stream );
572             p_sys->i_add_streams--;
573         }
574     }
575
576     p_input->p_sys = NULL;
577
578     return 0;
579 }
580
581 /*****************************************************************************
582  * Ogg Skeleton helpers
583  *****************************************************************************/
584 static int WriteQWVariableLE( uint64_t i_64, uint64_t i_offset,
585                               uint8_t *p_buffer, int i_buffer_size )
586 {
587     uint8_t *p_dest = p_buffer + i_offset;
588     int i_written = 0;
589
590     for(;;)
591     {
592         if ( p_dest - p_buffer >= i_buffer_size ) return -1;
593
594         *p_dest = (uint8_t) ( i_64 & 0x7F );
595         i_64 >>= 7;
596         i_written++;
597
598         if ( i_64 == 0 )
599         {
600             *p_dest |= 0x80;
601             return i_written;
602         }
603
604         p_dest++;
605     }
606 }
607
608 static bool AddIndexEntry( sout_mux_t *p_mux, uint64_t i_time, sout_input_t *p_input )
609 {
610     sout_mux_sys_t *p_sys = p_mux->p_sys;
611     ogg_stream_t *p_stream = (ogg_stream_t *) p_input->p_sys;
612     uint64_t i_posdelta;
613     uint64_t i_timedelta;
614     if ( !p_sys->skeleton.b_create || p_mux->p_sys->skeleton.i_index_intvl == 0
615          || !p_stream->skeleton.p_index )
616         return false;
617
618     if ( p_stream->skeleton.i_last_keyframe_pos == 0 )
619         p_stream->skeleton.i_last_keyframe_pos = p_sys->i_segment_start;
620     i_posdelta = p_sys->i_pos - p_stream->skeleton.i_last_keyframe_pos;
621     i_timedelta = i_time - p_stream->skeleton.i_last_keyframe_time;
622
623     if ( i_timedelta <= ( (uint64_t) p_mux->p_sys->skeleton.i_index_intvl * 1000 )
624          || i_posdelta <= 0xFFFF )
625         return false;
626
627     /* do inserts */
628     int i_ret;
629     if ( !p_stream->skeleton.p_index ) return false;
630     uint64_t i_offset = p_stream->skeleton.i_index_payload;
631     i_ret = WriteQWVariableLE( i_posdelta, i_offset, p_stream->skeleton.p_index,
632                                p_stream->skeleton.i_index_size );
633     if ( i_ret == -1 ) return false;
634     i_offset += i_ret;
635     i_ret = WriteQWVariableLE( i_timedelta, i_offset, p_stream->skeleton.p_index,
636                                p_stream->skeleton.i_index_size );
637     if ( i_ret == -1 ) return false;
638     p_stream->skeleton.i_index_payload = i_offset + i_ret;
639     p_stream->skeleton.i_index_count++;
640
641     /* update diff points */
642     p_stream->skeleton.i_last_keyframe_pos = p_sys->i_pos;
643     p_stream->skeleton.i_last_keyframe_time = i_time;
644     msg_Dbg( p_mux, "Added index on stream %d entry %"PRId64" %"PRId64,
645              p_stream->i_serial_no, p_sys->i_pos - p_sys->i_segment_start, i_time );
646
647     return true;
648 }
649
650 /*****************************************************************************
651  * Ogg bitstream manipulation routines
652  *****************************************************************************/
653 static block_t *OggStreamGetPage( sout_mux_t *p_mux,
654                                   ogg_stream_state *p_os, mtime_t i_pts,
655                                   bool flush )
656 {
657     (void)p_mux;
658     block_t *p_og, *p_og_first = NULL;
659     ogg_page og;
660     int (*pager)( ogg_stream_state*, ogg_page* ) = flush ? ogg_stream_flush : ogg_stream_pageout;
661
662     while( pager( p_os, &og ) )
663     {
664         /* Flush all data */
665         p_og = block_Alloc( og.header_len + og.body_len );
666
667         memcpy( p_og->p_buffer, og.header, og.header_len );
668         memcpy( p_og->p_buffer + og.header_len, og.body, og.body_len );
669         p_og->i_dts     = 0;
670         p_og->i_pts     = i_pts;
671         p_og->i_length  = 0;
672
673         i_pts = 0; // write it only once
674
675         block_ChainAppend( &p_og_first, p_og );
676     }
677
678     return p_og_first;
679 }
680
681 static block_t *OggStreamFlush( sout_mux_t *p_mux,
682                                 ogg_stream_state *p_os, mtime_t i_pts )
683 {
684     return OggStreamGetPage( p_mux, p_os, i_pts, true );
685 }
686
687 static block_t *OggStreamPageOut( sout_mux_t *p_mux,
688                                   ogg_stream_state *p_os, mtime_t i_pts )
689 {
690     return OggStreamGetPage( p_mux, p_os, i_pts, false );
691 }
692
693 static void OggGetSkeletonIndex( uint8_t **pp_buffer, long *pi_size, ogg_stream_t *p_stream )
694 {
695     uint8_t *p_buffer = calloc( INDEX_BASE_SIZE + p_stream->skeleton.i_index_size, sizeof(uint8_t) );
696     if ( !p_buffer ) return;
697     *pp_buffer = p_buffer;
698
699     memcpy( p_buffer, "index", 6 );
700     SetDWLE( &p_buffer[6], p_stream->i_serial_no );
701     SetQWLE( &p_buffer[10], p_stream->skeleton.i_index_count ); /* num keypoints */
702     SetQWLE( &p_buffer[18], 1000000 );
703     SetQWLE( &p_buffer[34], p_stream->i_length );
704     memcpy( p_buffer + INDEX_BASE_SIZE, p_stream->skeleton.p_index, p_stream->skeleton.i_index_payload );
705     *pi_size = INDEX_BASE_SIZE + p_stream->skeleton.i_index_size;
706 }
707
708 static void OggGetSkeletonFisbone( uint8_t **pp_buffer, long *pi_size,
709                                    sout_input_t *p_input, sout_mux_t *p_mux )
710 {
711     uint8_t *psz_header;
712     uint8_t *p_buffer;
713     const char *psz_value = NULL;
714     ogg_stream_t *p_stream = (ogg_stream_t *) p_input->p_sys;
715     struct
716     {
717         char *psz_content_type;
718         char *psz_role;
719         long int i_size;
720         unsigned int i_count;
721     } headers = { NULL, NULL, 0, 0 };
722     *pi_size = 0;
723
724     switch( p_stream->i_fourcc )
725     {
726         case VLC_CODEC_VORBIS:
727             psz_value = "audio/vorbis";
728             break;
729         case VLC_CODEC_THEORA:
730             psz_value = "video/theora";
731             break;
732         case VLC_CODEC_SPEEX:
733             psz_value = "audio/speex";
734             break;
735         case VLC_CODEC_FLAC:
736             psz_value = "audio/flac";
737             break;
738         case VLC_CODEC_CMML:
739             psz_value = "text/cmml";
740             break;
741         case VLC_CODEC_KATE:
742             psz_value = "application/kate";
743             break;
744         default:
745             psz_value = "application/octet-stream";
746             msg_Warn( p_mux, "Unkown fourcc for stream %s, setting Content-Type to %s",
747                   vlc_fourcc_GetDescription( p_stream->i_cat, p_stream->i_fourcc ),
748                   psz_value );
749     }
750
751     /* Content Type Header */
752     if ( asprintf( &headers.psz_content_type, "Content-Type: %s\r\n", psz_value ) != -1 )
753     {
754         headers.i_size += strlen( headers.psz_content_type );
755         headers.i_count++;
756     }
757
758     /* Set Role Header */
759     if ( p_input->p_fmt->i_priority > ES_PRIORITY_NOT_SELECTABLE )
760     {
761         int i_max_prio = ES_PRIORITY_MIN;
762         for ( int i=0; i< p_mux->i_nb_inputs; i++ )
763         {
764             if ( p_mux->pp_inputs[i]->p_fmt->i_cat != p_input->p_fmt->i_cat ) continue;
765             i_max_prio = __MAX( p_mux->pp_inputs[i]->p_fmt->i_priority, i_max_prio );
766         }
767
768         psz_value = NULL;
769         if ( p_input->p_fmt->i_cat == AUDIO_ES || p_input->p_fmt->i_cat == VIDEO_ES )
770         {
771             if ( p_input->p_fmt->i_priority == i_max_prio && i_max_prio >= ES_PRIORITY_SELECTABLE_MIN )
772                 psz_value = ( p_input->p_fmt->i_cat == VIDEO_ES ) ?
773                             "video/main" : "audio/main";
774             else
775                 psz_value = ( p_input->p_fmt->i_cat == VIDEO_ES ) ?
776                             "video/alternate" : "audio/alternate";
777         }
778         else if ( p_input->p_fmt->i_cat == SPU_ES )
779         {
780             psz_value = ( p_input->p_fmt->i_codec == VLC_CODEC_KATE ) ?
781                         "text/karaoke" : "text/subtitle";
782         }
783
784         if ( psz_value && asprintf( &headers.psz_role, "Role: %s\r\n", psz_value ) != -1 )
785         {
786             headers.i_size += strlen( headers.psz_role );
787             headers.i_count++;
788         }
789     }
790
791     *pp_buffer = calloc( FISBONE_BASE_SIZE + headers.i_size, sizeof(uint8_t) );
792     if ( !*pp_buffer ) return;
793     p_buffer = *pp_buffer;
794
795     memcpy( p_buffer, "fisbone", 8 );
796     SetDWLE( &p_buffer[8], FISBONE_BASE_OFFSET ); /* offset to message headers */
797     SetDWLE( &p_buffer[12], p_stream->i_serial_no );
798     SetDWLE( &p_buffer[16], headers.i_count );
799
800     /* granulerate den */
801     switch ( p_input->p_fmt->i_cat )
802     {
803         case VIDEO_ES:
804             SetQWLE( &(*pp_buffer)[20], p_input->p_fmt->video.i_frame_rate );
805             SetQWLE( &(*pp_buffer)[28], p_input->p_fmt->video.i_frame_rate_base );
806         break;
807         case AUDIO_ES:
808             SetQWLE( &(*pp_buffer)[20], p_input->p_fmt->audio.i_rate );
809             SetQWLE( &(*pp_buffer)[28], 1 );
810         break;
811         default:
812             SetQWLE( &(*pp_buffer)[20], 1000 );
813             SetQWLE( &(*pp_buffer)[28], 1 );
814     }
815
816     /* preroll */
817     if ( p_input->p_fmt->p_extra )
818         SetDWLE( &(*pp_buffer)[44], xiph_CountHeaders( p_input->p_fmt->p_extra, p_input->p_fmt->i_extra ) );
819
820     psz_header = *pp_buffer + FISBONE_BASE_SIZE;
821     memcpy( psz_header, headers.psz_content_type, strlen( headers.psz_content_type ) );
822     psz_header += strlen( headers.psz_content_type );
823     if ( headers.psz_role )
824         memcpy( psz_header, headers.psz_role, strlen( headers.psz_role ) );
825
826     *pi_size = FISBONE_BASE_SIZE + headers.i_size;
827
828     free( headers.psz_content_type );
829     free( headers.psz_role );
830 }
831
832 static void OggFillSkeletonFishead( uint8_t *p_buffer, sout_mux_t *p_mux )
833 {
834     memcpy( p_buffer, "fishead", 8 );
835     SetWLE( &p_buffer[8], 4 );
836     SetWLE( &p_buffer[10], 0 );
837     SetQWLE( &p_buffer[20], 1000 );
838     SetQWLE( &p_buffer[36], 1000 );
839     SetQWLE( &p_buffer[64], p_mux->p_sys->i_pos - p_mux->p_sys->i_segment_start ); /* segment length */
840     SetQWLE( &p_buffer[72], p_mux->p_sys->i_data_start - p_mux->p_sys->i_segment_start ); /* data start offset */
841 }
842
843 static int32_t OggFillDsHeader( uint8_t *p_buffer, oggds_header_t *p_oggds_header, int i_cat )
844 {
845     int index = 0;
846     p_buffer[index] = p_oggds_header->i_packet_type;
847     index++;
848     memcpy( &p_buffer[index], p_oggds_header->stream_type, sizeof(p_oggds_header->stream_type) );
849     index += sizeof(p_oggds_header->stream_type);
850     memcpy(&p_buffer[index], p_oggds_header->sub_type, sizeof(p_oggds_header->sub_type) );
851     index += sizeof(p_oggds_header->sub_type);
852
853     /* The size is filled at the end */
854     uint8_t *p_isize = &p_buffer[index];
855     index += 4;
856
857     SetQWLE( &p_buffer[index], p_oggds_header->i_time_unit );
858     index += 8;
859     SetQWLE( &p_buffer[index], p_oggds_header->i_samples_per_unit );
860     index += 8;
861     SetDWLE( &p_buffer[index], p_oggds_header->i_default_len );
862     index += 4;
863     SetDWLE( &p_buffer[index], p_oggds_header->i_buffer_size );
864     index += 4;
865     SetWLE( &p_buffer[index], p_oggds_header->i_bits_per_sample );
866     index += 2;
867     SetWLE( &p_buffer[index], p_oggds_header->i_padding_0 );
868     index += 2;
869     /* audio or video */
870     switch( i_cat )
871     {
872     case VIDEO_ES:
873         SetDWLE( &p_buffer[index], p_oggds_header->header.video.i_width );
874         SetDWLE( &p_buffer[index+4], p_oggds_header->header.video.i_height );
875         break;
876     case AUDIO_ES:
877         SetWLE( &p_buffer[index], p_oggds_header->header.audio.i_channels );
878         SetWLE( &p_buffer[index+2], p_oggds_header->header.audio.i_block_align );
879         SetDWLE( &p_buffer[index+4], p_oggds_header->header.audio.i_avgbytespersec );
880         break;
881     }
882     index += 8;
883     SetDWLE( &p_buffer[index], p_oggds_header->i_padding_1 );
884     index += 4;
885
886     /* extra header */
887     if( p_oggds_header->i_size > 0 )
888     {
889         memcpy( &p_buffer[index], p_oggds_header + sizeof(*p_oggds_header), p_oggds_header->i_size );
890         index += p_oggds_header->i_size;
891     }
892
893     SetDWLE( p_isize, index-1 );
894     return index;
895 }
896
897 static bool OggCreateHeaders( sout_mux_t *p_mux )
898 {
899     block_t *p_hdr = NULL;
900     block_t *p_og = NULL;
901     ogg_packet op;
902     ogg_stream_t *p_stream;
903     sout_mux_sys_t *p_sys = p_mux->p_sys;
904     int i;
905
906     if( sout_AccessOutControl( p_mux->p_access,
907                                ACCESS_OUT_CAN_SEEK,
908                                &p_sys->skeleton.b_create ) )
909     {
910         p_sys->skeleton.b_create = false;
911     }
912
913     p_sys->skeleton.b_create &= !! p_mux->i_nb_inputs;
914
915     /* no skeleton for solo vorbis/speex/opus tracks */
916     if ( p_mux->i_nb_inputs == 1 && p_mux->pp_inputs[0]->p_fmt->i_cat == AUDIO_ES )
917     {
918         p_sys->skeleton.b_create = false;
919     }
920     else
921     {
922         for ( int i=0; i< p_mux->i_nb_inputs; i++ )
923         {
924             p_stream = (ogg_stream_t*) p_mux->pp_inputs[i]->p_sys;
925             if ( p_stream->p_oggds_header )
926             {
927                 /* We don't want skeleton for OggDS */
928                 p_sys->skeleton.b_create = false;
929                 break;
930             }
931         }
932     }
933
934     /* Skeleton's Fishead must be the first page of the stream */
935     if ( p_sys->skeleton.b_create && !p_sys->skeleton.b_head_done )
936     {
937         msg_Dbg( p_mux, "creating header for skeleton" );
938         p_sys->skeleton.i_serial_no = p_sys->i_next_serial_no++;
939         ogg_stream_init( &p_sys->skeleton.os, p_sys->skeleton.i_serial_no );
940         op.bytes = 80;
941         op.packet = calloc( 1, op.bytes );
942         if ( op.packet == NULL ) return false;
943         op.b_o_s = 1;
944         op.e_o_s = 0;
945         op.granulepos = 0;
946         op.packetno = 0;
947         OggFillSkeletonFishead( op.packet, p_mux );
948         ogg_stream_packetin( &p_sys->skeleton.os, &op );
949         p_og = OggStreamFlush( p_mux, &p_sys->skeleton.os, 0 );
950         block_ChainAppend( &p_hdr, p_og );
951         p_sys->skeleton.b_head_done = true;
952         p_sys->skeleton.i_fishead_offset = p_sys->i_pos;
953     }
954
955     /* Write header for each stream. All b_o_s (beginning of stream) packets
956      * must appear first in the ogg stream so we take care of them first. */
957     for( int pass = 0; pass < 2; pass++ )
958     {
959         for( i = 0; i < p_mux->i_nb_inputs; i++ )
960         {
961             sout_input_t *p_input = p_mux->pp_inputs[i];
962             p_stream = (ogg_stream_t*)p_input->p_sys;
963
964             bool video = ( p_stream->i_fourcc == VLC_CODEC_THEORA || p_stream->i_fourcc == VLC_CODEC_DIRAC );
965             if( ( ( pass == 0 && !video ) || ( pass == 1 && video ) ) )
966                 continue;
967
968             msg_Dbg( p_mux, "creating header for %4.4s",
969                      (char *)&p_stream->i_fourcc );
970
971             ogg_stream_init( &p_stream->os, p_stream->i_serial_no );
972             p_stream->b_new = false;
973             p_stream->i_packet_no = 0;
974             p_stream->b_started = true;
975
976             if( p_stream->i_fourcc == VLC_CODEC_VORBIS ||
977                 p_stream->i_fourcc == VLC_CODEC_SPEEX ||
978                 p_stream->i_fourcc == VLC_CODEC_OPUS ||
979                 p_stream->i_fourcc == VLC_CODEC_THEORA )
980             {
981                 /* First packet in order: vorbis/speex/theora info */
982                 unsigned pi_size[XIPH_MAX_HEADER_COUNT];
983                 void     *pp_data[XIPH_MAX_HEADER_COUNT];
984                 unsigned i_count;
985                 if( xiph_SplitHeaders( pi_size, pp_data, &i_count,
986                                        p_input->p_fmt->i_extra, p_input->p_fmt->p_extra ) )
987                 {
988                     i_count = 0;
989                     pi_size[0] = 0;
990                     pp_data[0] = NULL;
991                 }
992
993                 op.bytes  = pi_size[0];
994                 op.packet = pp_data[0];
995                 if( pi_size[0] <= 0 )
996                     msg_Err( p_mux, "header data corrupted");
997
998                 op.b_o_s  = 1;
999                 op.e_o_s  = 0;
1000                 op.granulepos = 0;
1001                 op.packetno = p_stream->i_packet_no++;
1002                 ogg_stream_packetin( &p_stream->os, &op );
1003                 p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
1004
1005                 /* Get keyframe_granule_shift for theora granulepos calculation */
1006                 if( p_stream->i_fourcc == VLC_CODEC_THEORA )
1007                 {
1008                     p_stream->i_keyframe_granule_shift =
1009                         ( (op.packet[40] & 0x03) << 3 ) | ( (op.packet[41] & 0xe0) >> 5 );
1010                 }
1011             }
1012             else if( p_stream->i_fourcc == VLC_CODEC_DIRAC )
1013             {
1014                 op.packet = p_input->p_fmt->p_extra;
1015                 op.bytes  = p_input->p_fmt->i_extra;
1016                 op.b_o_s  = 1;
1017                 op.e_o_s  = 0;
1018                 op.granulepos = ~0;
1019                 op.packetno = p_stream->i_packet_no++;
1020                 ogg_stream_packetin( &p_stream->os, &op );
1021                 p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
1022             }
1023             else if( p_stream->i_fourcc == VLC_CODEC_FLAC )
1024             {
1025                 /* flac stream marker (yeah, only that in the 1st packet) */
1026                 op.packet = (unsigned char *)"fLaC";
1027                 op.bytes  = 4;
1028                 op.b_o_s  = 1;
1029                 op.e_o_s  = 0;
1030                 op.granulepos = 0;
1031                 op.packetno = p_stream->i_packet_no++;
1032                 ogg_stream_packetin( &p_stream->os, &op );
1033                 p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
1034             }
1035             else if( p_stream->p_oggds_header )
1036             {
1037                 /* ds header */
1038                 op.packet = malloc( sizeof(*p_stream->p_oggds_header) + p_stream->p_oggds_header->i_size );
1039                 if( !op.packet )
1040                     return false;
1041                 op.bytes  = OggFillDsHeader( op.packet, p_stream->p_oggds_header, p_stream->i_cat );
1042                 op.b_o_s  = 1;
1043                 op.e_o_s  = 0;
1044                 op.granulepos = 0;
1045                 op.packetno = p_stream->i_packet_no++;
1046                 ogg_stream_packetin( &p_stream->os, &op );
1047                 p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
1048                 free( op.packet );
1049             }
1050
1051             block_ChainAppend( &p_hdr, p_og );
1052         }
1053     }
1054
1055     /* Create fisbones if any */
1056     if ( p_sys->skeleton.b_create )
1057     {
1058         for( i = 0; i < p_mux->i_nb_inputs; i++ )
1059         {
1060             sout_input_t *p_input = p_mux->pp_inputs[i];
1061             ogg_stream_t *p_stream = (ogg_stream_t*)p_input->p_sys;
1062             if ( p_stream->skeleton.b_fisbone_done ) continue;
1063             OggGetSkeletonFisbone( &op.packet, &op.bytes, p_input, p_mux );
1064             if ( op.packet == NULL ) return false;
1065             op.b_o_s = 0;
1066             op.e_o_s = 0;
1067             op.granulepos = 0;
1068             op.packetno = p_sys->skeleton.i_packet_no++;
1069             ogg_stream_packetin( &p_sys->skeleton.os, &op );
1070             p_og = OggStreamFlush( p_mux, &p_sys->skeleton.os, 0 );
1071             block_ChainAppend( &p_hdr, p_og );
1072             p_stream->skeleton.b_fisbone_done = true;
1073         }
1074     }
1075
1076     /* Write previous headers */
1077     p_mux->p_sys->i_pos += sout_AccessOutWrite( p_mux->p_access, p_hdr );
1078     p_hdr = NULL;
1079
1080     /* Create indexes if any */
1081     for( i = 0; i < p_mux->i_nb_inputs; i++ )
1082     {
1083         sout_input_t *p_input = p_mux->pp_inputs[i];
1084         ogg_stream_t *p_stream = (ogg_stream_t*)p_input->p_sys;
1085         /* flush stream && save offset */
1086         if ( p_sys->skeleton.b_create && !p_stream->skeleton.b_index_done )
1087         {
1088             if ( !p_stream->skeleton.p_index ) AllocateIndex( p_mux, p_input );
1089             if ( p_stream->skeleton.p_index )
1090             {
1091                 msg_Dbg( p_mux, "Creating index for stream %d", p_stream->i_serial_no );
1092                 OggGetSkeletonIndex( &op.packet, &op.bytes, p_stream );
1093                 if ( op.packet == NULL ) return false;
1094                 op.b_o_s = 0;
1095                 op.e_o_s = 0;
1096                 op.granulepos = 0;
1097                 op.packetno = p_sys->skeleton.i_packet_no++;
1098
1099                 /* backup some values */
1100                 p_stream->skeleton.i_index_offset = p_mux->p_sys->i_pos;
1101                 p_stream->skeleton.i_index_packetno = p_sys->skeleton.os.packetno;
1102                 p_stream->skeleton.i_index_pageno = p_sys->skeleton.os.pageno;
1103
1104                 ogg_stream_packetin( &p_sys->skeleton.os, &op );
1105                 p_og = OggStreamFlush( p_mux, &p_sys->skeleton.os, 0 );
1106                 p_mux->p_sys->i_pos += sout_AccessOutWrite( p_mux->p_access, p_og );
1107             }
1108             p_stream->skeleton.b_index_done = true;
1109         }
1110     }
1111
1112     /* Take care of the non b_o_s headers */
1113     for( i = 0; i < p_mux->i_nb_inputs; i++ )
1114     {
1115         sout_input_t *p_input = p_mux->pp_inputs[i];
1116         ogg_stream_t *p_stream = (ogg_stream_t*)p_input->p_sys;
1117
1118         if( p_stream->i_fourcc == VLC_CODEC_VORBIS ||
1119             p_stream->i_fourcc == VLC_CODEC_SPEEX ||
1120             p_stream->i_fourcc == VLC_CODEC_OPUS ||
1121             p_stream->i_fourcc == VLC_CODEC_THEORA )
1122         {
1123             unsigned pi_size[XIPH_MAX_HEADER_COUNT];
1124             void     *pp_data[XIPH_MAX_HEADER_COUNT];
1125             unsigned i_count;
1126             if( xiph_SplitHeaders( pi_size, pp_data, &i_count,
1127                                    p_input->p_fmt->i_extra, p_input->p_fmt->p_extra ) )
1128                 i_count = 0;
1129
1130             /* Special case, headers are already there in the incoming stream.
1131              * We need to gather them an mark them as headers. */
1132             for( unsigned i = 1; i < i_count; i++ )
1133             {
1134                 op.bytes  = pi_size[i];
1135                 op.packet = pp_data[i];
1136                 if( pi_size[i] <= 0 )
1137                     msg_Err( p_mux, "header data corrupted");
1138
1139                 op.b_o_s  = 0;
1140                 op.e_o_s  = 0;
1141                 op.granulepos = 0;
1142                 op.packetno = p_stream->i_packet_no++;
1143                 ogg_stream_packetin( &p_stream->os, &op );
1144                 msg_Dbg( p_mux, "adding non bos, secondary header" );
1145                 if( i == i_count - 1 )
1146                     p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
1147                 else
1148                     p_og = OggStreamPageOut( p_mux, &p_stream->os, 0 );
1149                 if( p_og )
1150                     block_ChainAppend( &p_hdr, p_og );
1151             }
1152         }
1153         else if( p_stream->i_fourcc != VLC_CODEC_FLAC &&
1154                  p_stream->i_fourcc != VLC_CODEC_DIRAC )
1155         {
1156             uint8_t com[128];
1157             int     i_com;
1158
1159             /* comment */
1160             com[0] = PACKET_TYPE_COMMENT;
1161             i_com = snprintf( (char *)(com+1), 127,
1162                               PACKAGE_VERSION" stream output" )
1163                      + 1;
1164             op.packet = com;
1165             op.bytes  = i_com;
1166             op.b_o_s  = 0;
1167             op.e_o_s  = 0;
1168             op.granulepos = 0;
1169             op.packetno = p_stream->i_packet_no++;
1170             ogg_stream_packetin( &p_stream->os, &op );
1171             p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
1172             block_ChainAppend( &p_hdr, p_og );
1173         }
1174
1175         /* Special case for mp4v and flac */
1176         if( ( p_stream->i_fourcc == VLC_CODEC_MP4V ||
1177               p_stream->i_fourcc == VLC_CODEC_FLAC ) &&
1178             p_input->p_fmt->i_extra )
1179         {
1180             /* Send a packet with the VOL data for mp4v
1181              * or STREAMINFO for flac */
1182             msg_Dbg( p_mux, "writing extra data" );
1183             op.bytes  = p_input->p_fmt->i_extra;
1184             op.packet = p_input->p_fmt->p_extra;
1185             uint8_t flac_streaminfo[34 + 4];
1186             if( p_stream->i_fourcc == VLC_CODEC_FLAC )
1187             {
1188                 if (op.bytes == 42 && !memcmp(op.packet, "fLaC", 4)) {
1189                     op.bytes -= 4;
1190                     memcpy(flac_streaminfo, op.packet + 4, 38);
1191                     op.packet = flac_streaminfo;
1192                 } else if (op.bytes == 34) {
1193                     op.bytes += 4;
1194                     memcpy(flac_streaminfo + 4, op.packet, 34);
1195                     flac_streaminfo[0] = 0x80; /* last block, streaminfo */
1196                     flac_streaminfo[1] = 0;
1197                     flac_streaminfo[2] = 0;
1198                     flac_streaminfo[3] = 34; /* block size */
1199                     op.packet = flac_streaminfo;
1200                 } else {
1201                     msg_Err(p_mux, "Invalid FLAC streaminfo (%ld bytes)",
1202                             op.bytes);
1203                 }
1204             }
1205             op.b_o_s  = 0;
1206             op.e_o_s  = 0;
1207             op.granulepos = 0;
1208             op.packetno = p_stream->i_packet_no++;
1209             ogg_stream_packetin( &p_stream->os, &op );
1210             p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
1211             block_ChainAppend( &p_hdr, p_og );
1212         }
1213     }
1214
1215     if ( p_sys->skeleton.b_create )
1216     {
1217         msg_Dbg( p_mux, "ending skeleton" );
1218         op.packet = NULL;
1219         op.bytes = 0;
1220         op.b_o_s = 0;
1221         op.e_o_s = 1;
1222         op.granulepos = 0;
1223         op.packetno = p_sys->skeleton.i_packet_no++;
1224         ogg_stream_packetin( &p_sys->skeleton.os, &op );
1225         p_og = OggStreamFlush( p_mux, &p_sys->skeleton.os, 0 );
1226         block_ChainAppend( &p_hdr, p_og );
1227     }
1228
1229     /* set HEADER flag */
1230     for( p_og = p_hdr; p_og != NULL; p_og = p_og->p_next )
1231     {
1232         p_og->i_flags |= BLOCK_FLAG_HEADER;
1233     }
1234
1235     /* Write previous headers */
1236     p_mux->p_sys->i_pos += sout_AccessOutWrite( p_mux->p_access, p_hdr );
1237
1238     return true;
1239 }
1240
1241 static void OggCreateStreamFooter( sout_mux_t *p_mux, ogg_stream_t *p_stream )
1242 {
1243     block_t *p_og;
1244     ogg_packet op;
1245     sout_mux_sys_t *p_sys = p_mux->p_sys;
1246
1247     /* as stream is finished, overwrite the index, if there was any */
1248     if ( p_sys->skeleton.b_create && p_stream->skeleton.p_index
1249          && p_stream->skeleton.i_index_payload )
1250     {
1251         sout_AccessOutSeek( p_mux->p_access, p_stream->skeleton.i_index_offset );
1252         OggGetSkeletonIndex( &op.packet, &op.bytes, p_stream );
1253         if ( op.packet != NULL )
1254         {
1255             msg_Dbg(p_mux, "Rewriting index at %"PRId64, p_stream->skeleton.i_index_offset );
1256             ogg_stream_reset_serialno( &p_sys->skeleton.os, p_sys->skeleton.i_serial_no );
1257             op.b_o_s = 0;
1258             op.e_o_s = 0;
1259             op.granulepos = 0;
1260             op.packetno = p_stream->skeleton.i_index_packetno + 1;
1261             /* fake our stream state */
1262             p_sys->skeleton.os.pageno = p_stream->skeleton.i_index_pageno;
1263             p_sys->skeleton.os.packetno = p_stream->skeleton.i_index_packetno;
1264             p_sys->skeleton.os.granulepos = 0;
1265             p_sys->skeleton.os.b_o_s = 1;
1266             p_sys->skeleton.os.e_o_s = 0;
1267             ogg_stream_packetin( &p_sys->skeleton.os, &op );
1268             p_og = OggStreamFlush( p_mux, &p_sys->skeleton.os, 0 );
1269             sout_AccessOutWrite( p_mux->p_access, p_og );
1270         }
1271         sout_AccessOutSeek( p_mux->p_access, p_sys->i_pos );
1272     }
1273
1274     /* clear skeleton */
1275     p_stream->skeleton.b_fisbone_done = false;
1276     p_stream->skeleton.b_index_done = false;
1277     p_stream->skeleton.i_index_offset = 0;
1278     p_stream->skeleton.i_index_payload = 0;
1279     p_stream->skeleton.i_last_keyframe_pos = 0;
1280     p_stream->skeleton.i_last_keyframe_time = 0;
1281     /* clear accounting */
1282     p_stream->i_num_frames = 0;
1283     p_stream->i_num_keyframes = 0;
1284
1285     /* Write eos packet for stream. */
1286     op.packet = NULL;
1287     op.bytes  = 0;
1288     op.b_o_s  = 0;
1289     op.e_o_s  = 1;
1290     op.granulepos = p_stream->u_last_granulepos;
1291     op.packetno = p_stream->i_packet_no++;
1292     ogg_stream_packetin( &p_stream->os, &op );
1293
1294     /* flush it with all remaining data */
1295     if( ( p_og = OggStreamFlush( p_mux, &p_stream->os, 0 ) ) )
1296     {
1297         /* Write footer */
1298         OggSetDate( p_og, p_stream->i_dts, p_stream->i_length );
1299         p_mux->p_sys->i_pos += sout_AccessOutWrite( p_mux->p_access, p_og );
1300     }
1301
1302     ogg_stream_clear( &p_stream->os );
1303 }
1304
1305 static void OggSetDate( block_t *p_og, mtime_t i_dts, mtime_t i_length )
1306 {
1307     int i_count;
1308     block_t *p_tmp;
1309     mtime_t i_delta;
1310
1311     for( p_tmp = p_og, i_count = 0; p_tmp != NULL; p_tmp = p_tmp->p_next )
1312     {
1313         i_count++;
1314     }
1315
1316     if( i_count == 0 ) return; /* ignore. */
1317
1318     i_delta = i_length / i_count;
1319
1320     for( p_tmp = p_og; p_tmp != NULL; p_tmp = p_tmp->p_next )
1321     {
1322         p_tmp->i_dts    = i_dts;
1323         p_tmp->i_length = i_delta;
1324
1325         i_dts += i_delta;
1326     }
1327 }
1328
1329 static void OggRewriteFisheadPage( sout_mux_t *p_mux )
1330 {
1331     sout_mux_sys_t *p_sys = p_mux->p_sys;
1332     ogg_packet op;
1333     op.bytes = 80;
1334     op.packet = calloc( 1, op.bytes );
1335     if ( op.packet != NULL )
1336     {
1337         op.b_o_s = 1;
1338         op.e_o_s = 0;
1339         op.granulepos = 0;
1340         op.packetno = 0;
1341         ogg_stream_reset_serialno( &p_sys->skeleton.os, p_sys->skeleton.i_serial_no );
1342         OggFillSkeletonFishead( op.packet, p_mux );
1343         ogg_stream_packetin( &p_sys->skeleton.os, &op );
1344         msg_Dbg( p_mux, "rewriting fishead at %"PRId64, p_mux->p_sys->skeleton.i_fishead_offset );
1345         sout_AccessOutSeek( p_mux->p_access, p_mux->p_sys->skeleton.i_fishead_offset );
1346         sout_AccessOutWrite( p_mux->p_access,
1347                              OggStreamFlush( p_mux, &p_sys->skeleton.os, 0 ) );
1348         sout_AccessOutSeek( p_mux->p_access, p_mux->p_sys->i_pos );
1349     }
1350 }
1351
1352 static bool AllocateIndex( sout_mux_t *p_mux, sout_input_t *p_input )
1353 {
1354     ogg_stream_t *p_stream = (ogg_stream_t *) p_input->p_sys;
1355     size_t i_size;
1356
1357     if ( p_stream->i_length )
1358     {
1359         uint64_t i_interval = (uint64_t)p_mux->p_sys->skeleton.i_index_intvl * 1000;
1360         uint64_t i;
1361
1362         if( p_input->p_fmt->i_cat == VIDEO_ES &&
1363                 p_input->p_fmt->video.i_frame_rate )
1364         {
1365             /* optimize for fps < 1 */
1366             i_interval= __MAX( p_mux->p_sys->skeleton.i_index_intvl * 1000,
1367                        INT64_C(10000000) *
1368                        p_input->p_fmt->video.i_frame_rate_base /
1369                        p_input->p_fmt->video.i_frame_rate );
1370         }
1371
1372         size_t i_tuple_size = 0;
1373         /* estimate length of pos value */
1374         if ( p_input->p_fmt->i_bitrate )
1375         {
1376             i = i_interval * p_input->p_fmt->i_bitrate / 1000000;
1377             while ( i <<= 1 ) i_tuple_size++;
1378         }
1379         else
1380         {
1381             /* Likely 64KB<<keyframe interval<<16MB */
1382             /* We can't really guess due to muxing */
1383             i_tuple_size = 24 / 8;
1384         }
1385
1386         /* add length of interval value */
1387         i = i_interval;
1388         while ( i <<= 1 ) i_tuple_size++;
1389
1390         i_size = i_tuple_size * ( p_stream->i_length / i_interval + 2 );
1391     }
1392     else
1393     {
1394         i_size = ( INT64_C(3600) * 11.2 * 1000 / p_mux->p_sys->skeleton.i_index_intvl )
1395                 * p_mux->p_sys->skeleton.i_index_ratio;
1396         msg_Dbg( p_mux, "No stream length, using default allocation for index" );
1397     }
1398     i_size *= ( 8.0 / 7 ); /* 7bits encoding overhead */
1399     msg_Dbg( p_mux, "allocating %"PRId64" bytes for index", i_size );
1400     p_stream->skeleton.p_index = calloc( i_size, sizeof(uint8_t) );
1401     if ( !p_stream->skeleton.p_index ) return false;
1402     p_stream->skeleton.i_index_size = i_size;
1403     p_stream->skeleton.i_index_payload = 0;
1404     return true;
1405 }
1406
1407 /*****************************************************************************
1408  * Mux: multiplex available data in input fifos into the Ogg bitstream
1409  *****************************************************************************/
1410 static int Mux( sout_mux_t *p_mux )
1411 {
1412     sout_mux_sys_t *p_sys = p_mux->p_sys;
1413     mtime_t        i_dts;
1414
1415     /* End any stream that ends in that group */
1416     if ( p_sys->i_del_streams )
1417     {
1418         /* Remove deleted logical streams */
1419         for( int i = 0; i < p_sys->i_del_streams; i++ )
1420         {
1421             OggCreateStreamFooter( p_mux, p_sys->pp_del_streams[i] );
1422             FREENULL( p_sys->pp_del_streams[i]->p_oggds_header );
1423             FREENULL( p_sys->pp_del_streams[i] );
1424         }
1425         FREENULL( p_sys->pp_del_streams );
1426         p_sys->i_del_streams = 0;
1427     }
1428
1429     if ( p_sys->i_streams == 0 )
1430     {
1431         /* All streams have been deleted, or none have ever been created
1432            From this point, we are allowed to start a new group of logical streams */
1433         p_sys->skeleton.b_head_done = false;
1434         p_sys->b_can_add_streams = true;
1435         p_sys->i_segment_start = p_sys->i_pos;
1436     }
1437
1438     if ( p_sys->i_add_streams )
1439     {
1440         if ( !p_sys->b_can_add_streams )
1441         {
1442             msg_Warn( p_mux, "Can't add new stream %d/%d: Considerer increasing sout-mux-caching variable", p_sys->i_del_streams, p_mux->p_sys->i_streams);
1443             msg_Warn( p_mux, "Resetting and setting new identity to current streams");
1444
1445             /* resetting all active streams */
1446             for ( int i=0; i < p_mux->p_sys->i_streams; i++ )
1447             {
1448                 ogg_stream_t * p_stream = (ogg_stream_t *) p_mux->pp_inputs[i]->p_sys;
1449                 if ( p_stream->b_finished || !p_stream->b_started ) continue;
1450                 OggCreateStreamFooter( p_mux, p_stream );
1451                 p_stream->i_serial_no = p_sys->i_next_serial_no++;
1452                 p_stream->i_packet_no = 0;
1453                 p_stream->b_finished = true;
1454             }
1455
1456             /* rewrite fishead with final values */
1457             if ( p_sys->skeleton.b_head_done )
1458             {
1459                 OggRewriteFisheadPage( p_mux );
1460             }
1461
1462             p_sys->b_can_add_streams = true;
1463             p_sys->skeleton.b_head_done = false;
1464             p_sys->i_segment_start = p_sys->i_pos;
1465         }
1466
1467         /* Open new ogg stream */
1468         if( sout_MuxGetStream( p_mux, 1, &i_dts) < 0 )
1469         {
1470             msg_Dbg( p_mux, "waiting for data..." );
1471             return VLC_SUCCESS;
1472         }
1473         msg_Dbg( p_mux, "writing streams headers" );
1474         p_sys->i_start_dts = i_dts;
1475         p_sys->i_streams = p_mux->i_nb_inputs;
1476         p_sys->i_del_streams = 0;
1477         p_sys->i_add_streams = 0;
1478         p_sys->skeleton.b_create = true;
1479
1480         if ( ! OggCreateHeaders( p_mux ) )
1481             return VLC_ENOMEM;
1482
1483         /* If we're switching to end of headers, then that's data start */
1484         if ( p_sys->b_can_add_streams )
1485         {
1486             msg_Dbg( p_mux, "data starts from %"PRId64, p_sys->i_pos );
1487             p_sys->i_data_start = p_sys->i_pos;
1488         }
1489
1490         /* Since we started sending secondaryheader or data pages,
1491              * we're no longer allowed to create new streams, until all streams end */
1492         p_sys->b_can_add_streams = false;
1493     }
1494
1495     /* Do the regular data mux thing */
1496     for( ;; )
1497     {
1498         int i_stream = sout_MuxGetStream( p_mux, 1, NULL );
1499         if( i_stream < 0 )
1500             return VLC_SUCCESS;
1501         MuxBlock( p_mux, p_mux->pp_inputs[i_stream] );
1502     }
1503
1504     return VLC_SUCCESS;
1505 }
1506
1507 static int MuxBlock( sout_mux_t *p_mux, sout_input_t *p_input )
1508 {
1509     sout_mux_sys_t *p_sys = p_mux->p_sys;
1510     ogg_stream_t *p_stream = (ogg_stream_t*)p_input->p_sys;
1511     block_t *p_data = block_FifoGet( p_input->p_fifo );
1512     block_t *p_og = NULL;
1513     ogg_packet op;
1514     uint64_t i_time;
1515
1516     if( p_stream->i_fourcc != VLC_CODEC_VORBIS &&
1517         p_stream->i_fourcc != VLC_CODEC_FLAC &&
1518         p_stream->i_fourcc != VLC_CODEC_SPEEX &&
1519         p_stream->i_fourcc != VLC_CODEC_OPUS &&
1520         p_stream->i_fourcc != VLC_CODEC_THEORA &&
1521         p_stream->i_fourcc != VLC_CODEC_DIRAC )
1522     {
1523         p_data = block_Realloc( p_data, 1, p_data->i_buffer );
1524         p_data->p_buffer[0] = PACKET_IS_SYNCPOINT;      // FIXME
1525     }
1526
1527     op.packet   = p_data->p_buffer;
1528     op.bytes    = p_data->i_buffer;
1529     op.b_o_s    = 0;
1530     op.e_o_s    = 0;
1531     op.packetno = p_stream->i_packet_no++;
1532     op.granulepos = -1;
1533
1534     if( p_stream->i_cat == AUDIO_ES )
1535     {
1536         if( p_stream->i_fourcc == VLC_CODEC_VORBIS ||
1537             p_stream->i_fourcc == VLC_CODEC_FLAC ||
1538             p_stream->i_fourcc == VLC_CODEC_OPUS ||
1539             p_stream->i_fourcc == VLC_CODEC_SPEEX )
1540         {
1541             /* number of sample from begining + current packet */
1542             op.granulepos =
1543                 ( p_data->i_dts - p_sys->i_start_dts + p_data->i_length ) *
1544                 (mtime_t)p_input->p_fmt->audio.i_rate / INT64_C(1000000);
1545
1546             i_time = p_data->i_dts - p_sys->i_start_dts;
1547             AddIndexEntry( p_mux, i_time, p_input );
1548         }
1549         else if( p_stream->p_oggds_header )
1550         {
1551             /* number of sample from begining */
1552             op.granulepos = ( p_data->i_dts - p_sys->i_start_dts ) *
1553                 p_stream->p_oggds_header->i_samples_per_unit / INT64_C(1000000);
1554         }
1555     }
1556     else if( p_stream->i_cat == VIDEO_ES )
1557     {
1558         if( p_stream->i_fourcc == VLC_CODEC_THEORA )
1559         {
1560             p_stream->i_num_frames++;
1561             if( p_data->i_flags & BLOCK_FLAG_TYPE_I )
1562             {
1563                 p_stream->i_num_keyframes++;
1564                 p_stream->i_last_keyframe = p_stream->i_num_frames;
1565
1566                 /* presentation time */
1567                 i_time = INT64_C(1000000) * ( p_stream->i_num_frames - 1 ) *
1568                          p_input->p_fmt->video.i_frame_rate_base /  p_input->p_fmt->video.i_frame_rate;
1569                 AddIndexEntry( p_mux, i_time, p_input );
1570             }
1571
1572             op.granulepos = (p_stream->i_last_keyframe << p_stream->i_keyframe_granule_shift )
1573                           | (p_stream->i_num_frames-p_stream->i_last_keyframe);
1574         }
1575         else if( p_stream->i_fourcc == VLC_CODEC_DIRAC )
1576         {
1577             mtime_t dt = (p_data->i_dts - p_sys->i_start_dts + 1)
1578                        * p_input->p_fmt->video.i_frame_rate *2
1579                        / p_input->p_fmt->video.i_frame_rate_base
1580                        / INT64_C(1000000);
1581             mtime_t delay = (p_data->i_pts - p_data->i_dts + 1)
1582                           * p_input->p_fmt->video.i_frame_rate *2
1583                           / p_input->p_fmt->video.i_frame_rate_base
1584                           / INT64_C(1000000);
1585             if( p_data->i_flags & BLOCK_FLAG_TYPE_I )
1586                 p_stream->i_last_keyframe = dt;
1587             mtime_t dist = dt - p_stream->i_last_keyframe;
1588             op.granulepos = dt << 31 | (dist&0xff00) << 14
1589                           | (delay&0x1fff) << 9 | (dist&0xff);
1590             AddIndexEntry( p_mux, dt, p_input );
1591         }
1592         else if( p_stream->p_oggds_header )
1593             op.granulepos = ( p_data->i_dts - p_sys->i_start_dts ) * INT64_C(10) /
1594                 p_stream->p_oggds_header->i_time_unit;
1595     }
1596     else if( p_stream->i_cat == SPU_ES )
1597     {
1598         /* granulepos is in millisec */
1599         op.granulepos = ( p_data->i_dts - p_sys->i_start_dts ) / 1000;
1600     }
1601     else
1602         return VLC_EGENERIC;
1603
1604     p_stream->u_last_granulepos = op.granulepos;
1605     ogg_stream_packetin( &p_stream->os, &op );
1606
1607     if( p_stream->i_cat == SPU_ES ||
1608         p_stream->i_fourcc == VLC_CODEC_SPEEX ||
1609         p_stream->i_fourcc == VLC_CODEC_DIRAC )
1610     {
1611         /* Subtitles or Speex packets are quite small so they
1612          * need to be flushed to be sent on time */
1613         /* The OggDirac mapping suggests ever so strongly that a
1614          * page flush occurs after each OggDirac packet, so to make
1615          * the timestamps unambiguous */
1616         p_og = OggStreamFlush( p_mux, &p_stream->os, p_data->i_dts );
1617     }
1618     else
1619     {
1620         p_og = OggStreamPageOut( p_mux, &p_stream->os, p_data->i_dts );
1621     }
1622
1623     if( p_og )
1624     {
1625         OggSetDate( p_og, p_stream->i_dts, p_stream->i_length );
1626         p_stream->i_dts = -1;
1627         p_stream->i_length = 0;
1628
1629         p_mux->p_sys->i_pos += sout_AccessOutWrite( p_mux->p_access, p_og );
1630     }
1631     else
1632     {
1633         if( p_stream->i_dts < 0 )
1634         {
1635             p_stream->i_dts = p_data->i_dts;
1636         }
1637         p_stream->i_length += p_data->i_length;
1638     }
1639
1640     block_Release( p_data );
1641     return VLC_SUCCESS;
1642 }