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