41e2507a1fa65c2562598d2a3aa5c8020aa11c2e
[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
845     if ( headers.i_size > 0 )
846     {
847         psz_header = *pp_buffer + FISBONE_BASE_SIZE;
848         memcpy( psz_header, headers.psz_content_type, strlen( headers.psz_content_type ) );
849         psz_header += strlen( headers.psz_content_type );
850         if ( headers.psz_role )
851             memcpy( psz_header, headers.psz_role, strlen( headers.psz_role ) );
852     }
853     *pi_size = FISBONE_BASE_SIZE + headers.i_size;
854
855     free( headers.psz_content_type );
856     free( headers.psz_role );
857 }
858
859 static void OggFillSkeletonFishead( uint8_t *p_buffer, sout_mux_t *p_mux )
860 {
861     sout_mux_sys_t *p_sys = p_mux->p_sys;
862     memcpy( p_buffer, "fishead", 8 );
863     SetWLE( &p_buffer[8], 4 );
864     SetWLE( &p_buffer[10], 0 );
865     SetQWLE( &p_buffer[20], 1000 );
866     SetQWLE( &p_buffer[36], 1000 );
867     SetQWLE( &p_buffer[64], p_sys->i_pos - p_sys->i_segment_start ); /* segment length */
868     SetQWLE( &p_buffer[72], p_sys->i_data_start - p_sys->i_segment_start ); /* data start offset */
869 }
870
871 static int32_t OggFillDsHeader( uint8_t *p_buffer, oggds_header_t *p_oggds_header, int i_cat )
872 {
873     int index = 0;
874     p_buffer[index] = p_oggds_header->i_packet_type;
875     index++;
876     memcpy( &p_buffer[index], p_oggds_header->stream_type, sizeof(p_oggds_header->stream_type) );
877     index += sizeof(p_oggds_header->stream_type);
878     memcpy(&p_buffer[index], p_oggds_header->sub_type, sizeof(p_oggds_header->sub_type) );
879     index += sizeof(p_oggds_header->sub_type);
880
881     /* The size is filled at the end */
882     uint8_t *p_isize = &p_buffer[index];
883     index += 4;
884
885     SetQWLE( &p_buffer[index], p_oggds_header->i_time_unit );
886     index += 8;
887     SetQWLE( &p_buffer[index], p_oggds_header->i_samples_per_unit );
888     index += 8;
889     SetDWLE( &p_buffer[index], p_oggds_header->i_default_len );
890     index += 4;
891     SetDWLE( &p_buffer[index], p_oggds_header->i_buffer_size );
892     index += 4;
893     SetWLE( &p_buffer[index], p_oggds_header->i_bits_per_sample );
894     index += 2;
895     SetWLE( &p_buffer[index], p_oggds_header->i_padding_0 );
896     index += 2;
897     /* audio or video */
898     switch( i_cat )
899     {
900     case VIDEO_ES:
901         SetDWLE( &p_buffer[index], p_oggds_header->header.video.i_width );
902         SetDWLE( &p_buffer[index+4], p_oggds_header->header.video.i_height );
903         break;
904     case AUDIO_ES:
905         SetWLE( &p_buffer[index], p_oggds_header->header.audio.i_channels );
906         SetWLE( &p_buffer[index+2], p_oggds_header->header.audio.i_block_align );
907         SetDWLE( &p_buffer[index+4], p_oggds_header->header.audio.i_avgbytespersec );
908         break;
909     }
910     index += 8;
911     SetDWLE( &p_buffer[index], p_oggds_header->i_padding_1 );
912     index += 4;
913
914     /* extra header */
915     if( p_oggds_header->i_size > 0 )
916     {
917         memcpy( &p_buffer[index], (uint8_t *) p_oggds_header + sizeof(*p_oggds_header), p_oggds_header->i_size );
918         index += p_oggds_header->i_size;
919     }
920
921     SetDWLE( p_isize, index-1 );
922     return index;
923 }
924
925 static void OggFillVP8Header( uint8_t *p_buffer, sout_input_t *p_input )
926 {
927     ogg_stream_t *p_stream = (ogg_stream_t *) p_input->p_sys;
928
929     memcpy( p_buffer, "OVP80\x01\x01\x00", 8 );
930     SetWBE( &p_buffer[8], p_input->p_fmt->video.i_width );
931     SetDWBE( &p_buffer[14], p_input->p_fmt->video.i_sar_den );/* 24 bits, 15~ */
932     SetDWBE( &p_buffer[11], p_input->p_fmt->video.i_sar_num );/* 24 bits, 12~ */
933     SetWBE( &p_buffer[10], p_input->p_fmt->video.i_height );
934     SetDWBE( &p_buffer[18], p_stream->fmt.video.i_frame_rate );
935     SetDWBE( &p_buffer[22], p_stream->fmt.video.i_frame_rate_base );
936 }
937
938 static bool OggCreateHeaders( sout_mux_t *p_mux )
939 {
940     block_t *p_hdr = NULL;
941     block_t *p_og = NULL;
942     ogg_packet op;
943     sout_mux_sys_t *p_sys = p_mux->p_sys;
944
945     if( sout_AccessOutControl( p_mux->p_access,
946                                ACCESS_OUT_CAN_SEEK,
947                                &p_sys->skeleton.b_create ) )
948     {
949         p_sys->skeleton.b_create = false;
950     }
951
952     p_sys->skeleton.b_create &= !! p_mux->i_nb_inputs;
953
954     /* no skeleton for solo vorbis/speex/opus tracks */
955     if ( p_mux->i_nb_inputs == 1 && p_mux->pp_inputs[0]->p_fmt->i_cat == AUDIO_ES )
956     {
957         p_sys->skeleton.b_create = false;
958     }
959     else
960     {
961         for ( int i=0; i< p_mux->i_nb_inputs; i++ )
962         {
963             ogg_stream_t *p_stream = p_mux->pp_inputs[i]->p_sys;
964             if( p_stream->p_oggds_header )
965             {
966                 /* We don't want skeleton for OggDS */
967                 p_sys->skeleton.b_create = false;
968                 break;
969             }
970         }
971     }
972
973     /* Skeleton's Fishead must be the first page of the stream */
974     if ( p_sys->skeleton.b_create && !p_sys->skeleton.b_head_done )
975     {
976         msg_Dbg( p_mux, "creating header for skeleton" );
977         p_sys->skeleton.i_serial_no = p_sys->i_next_serial_no++;
978         ogg_stream_init( &p_sys->skeleton.os, p_sys->skeleton.i_serial_no );
979         op.bytes = 80;
980         op.packet = calloc( 1, op.bytes );
981         if ( op.packet == NULL ) return false;
982         op.b_o_s = 1;
983         op.e_o_s = 0;
984         op.granulepos = 0;
985         op.packetno = 0;
986         OggFillSkeletonFishead( op.packet, p_mux );
987         ogg_stream_packetin( &p_sys->skeleton.os, &op );
988         ogg_packet_clear( &op );
989         p_og = OggStreamFlush( p_mux, &p_sys->skeleton.os, 0 );
990         block_ChainAppend( &p_hdr, p_og );
991         p_sys->skeleton.b_head_done = true;
992         p_sys->skeleton.i_fishead_offset = p_sys->i_pos;
993     }
994
995     /* Write header for each stream. All b_o_s (beginning of stream) packets
996      * must appear first in the ogg stream so we take care of them first. */
997     for( int pass = 0; pass < 2; pass++ )
998     {
999         for( int i = 0; i < p_mux->i_nb_inputs; i++ )
1000         {
1001             sout_input_t *p_input = p_mux->pp_inputs[i];
1002             ogg_stream_t *p_stream = p_input->p_sys;
1003
1004             bool video = ( p_stream->fmt.i_codec == VLC_CODEC_THEORA ||
1005                            p_stream->fmt.i_codec == VLC_CODEC_DIRAC ||
1006                            p_stream->fmt.i_codec == VLC_CODEC_DAALA );
1007             if( ( ( pass == 0 && !video ) || ( pass == 1 && video ) ) )
1008                 continue;
1009
1010             msg_Dbg( p_mux, "creating header for %4.4s",
1011                      (char *)&p_stream->fmt.i_codec );
1012
1013             ogg_stream_init( &p_stream->os, p_stream->i_serial_no );
1014             p_stream->b_new = false;
1015             p_stream->i_packet_no = 0;
1016             p_stream->b_started = true;
1017
1018             if( p_stream->fmt.i_codec == VLC_CODEC_VORBIS ||
1019                 p_stream->fmt.i_codec == VLC_CODEC_SPEEX ||
1020                 p_stream->fmt.i_codec == VLC_CODEC_OPUS ||
1021                 p_stream->fmt.i_codec == VLC_CODEC_THEORA ||
1022                 p_stream->fmt.i_codec == VLC_CODEC_DAALA )
1023             {
1024                 /* First packet in order: vorbis/speex/opus/theora/daala info */
1025                 unsigned pi_size[XIPH_MAX_HEADER_COUNT];
1026                 const void *pp_data[XIPH_MAX_HEADER_COUNT];
1027                 unsigned i_count;
1028
1029                 if( xiph_SplitHeaders( pi_size, pp_data, &i_count,
1030                                        p_input->p_fmt->i_extra, p_input->p_fmt->p_extra ) )
1031                 {
1032                     i_count = 0;
1033                     pi_size[0] = 0;
1034                     pp_data[0] = NULL;
1035                 }
1036
1037                 op.bytes  = pi_size[0];
1038                 op.packet = (void *)pp_data[0];
1039                 if( pi_size[0] <= 0 )
1040                     msg_Err( p_mux, "header data corrupted");
1041
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
1049                 /* Get keyframe_granule_shift for theora or daala granulepos calculation */
1050                 if( p_stream->fmt.i_codec == VLC_CODEC_THEORA ||
1051                     p_stream->fmt.i_codec == VLC_CODEC_DAALA )
1052                 {
1053                     p_stream->i_keyframe_granule_shift =
1054                         ( (op.packet[40] & 0x03) << 3 ) | ( (op.packet[41] & 0xe0) >> 5 );
1055                 }
1056             }
1057             else if( p_stream->fmt.i_codec == VLC_CODEC_DIRAC )
1058             {
1059                 op.packet = p_input->p_fmt->p_extra;
1060                 op.bytes  = p_input->p_fmt->i_extra;
1061                 op.b_o_s  = 1;
1062                 op.e_o_s  = 0;
1063                 op.granulepos = ~0;
1064                 op.packetno = p_stream->i_packet_no++;
1065                 ogg_stream_packetin( &p_stream->os, &op );
1066                 p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
1067             }
1068             else if( p_stream->fmt.i_codec == VLC_CODEC_FLAC )
1069             {
1070                 /* flac stream marker (yeah, only that in the 1st packet) */
1071                 op.packet = (unsigned char *)"fLaC";
1072                 op.bytes  = 4;
1073                 op.b_o_s  = 1;
1074                 op.e_o_s  = 0;
1075                 op.granulepos = 0;
1076                 op.packetno = p_stream->i_packet_no++;
1077                 ogg_stream_packetin( &p_stream->os, &op );
1078                 p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
1079             }
1080             else if( p_stream->fmt.i_codec == VLC_CODEC_VP8 )
1081             {
1082                 /* VP8 Header */
1083                 op.packet = malloc( 26 );
1084                 if( !op.packet )
1085                     return false;
1086                 op.bytes = 26;
1087                 OggFillVP8Header( op.packet, p_input );
1088                 op.b_o_s = 1;
1089                 op.e_o_s = 0;
1090                 op.granulepos = 0;
1091                 op.packetno = p_stream->i_packet_no++;
1092                 ogg_stream_packetin( &p_stream->os, &op );
1093                 p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
1094                 free( op.packet );
1095             }
1096             else if( p_stream->p_oggds_header )
1097             {
1098                 /* ds header */
1099                 op.packet = malloc( sizeof(*p_stream->p_oggds_header) + p_stream->p_oggds_header->i_size );
1100                 if( !op.packet )
1101                     return false;
1102                 op.bytes  = OggFillDsHeader( op.packet, p_stream->p_oggds_header, p_stream->fmt.i_cat );
1103                 op.b_o_s  = 1;
1104                 op.e_o_s  = 0;
1105                 op.granulepos = 0;
1106                 op.packetno = p_stream->i_packet_no++;
1107                 ogg_stream_packetin( &p_stream->os, &op );
1108                 p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
1109                 free( op.packet );
1110             }
1111
1112             block_ChainAppend( &p_hdr, p_og );
1113         }
1114     }
1115
1116     /* Create fisbones if any */
1117     if ( p_sys->skeleton.b_create )
1118     {
1119         for( int i = 0; i < p_mux->i_nb_inputs; i++ )
1120         {
1121             sout_input_t *p_input = p_mux->pp_inputs[i];
1122             ogg_stream_t *p_stream = p_input->p_sys;
1123             if ( p_stream->skeleton.b_fisbone_done ) continue;
1124             OggGetSkeletonFisbone( &op.packet, &op.bytes, p_input, p_mux );
1125             if ( op.packet == NULL ) return false;
1126             op.b_o_s = 0;
1127             op.e_o_s = 0;
1128             op.granulepos = 0;
1129             op.packetno = p_sys->skeleton.i_packet_no++;
1130             ogg_stream_packetin( &p_sys->skeleton.os, &op );
1131             ogg_packet_clear( &op );
1132             p_og = OggStreamFlush( p_mux, &p_sys->skeleton.os, 0 );
1133             block_ChainAppend( &p_hdr, p_og );
1134             p_stream->skeleton.b_fisbone_done = true;
1135         }
1136     }
1137
1138     /* Write previous headers */
1139     for( p_og = p_hdr; p_og != NULL; p_og = p_og->p_next )
1140     {
1141         /* flag headers to be resent for streaming clients */
1142         p_og->i_flags |= BLOCK_FLAG_HEADER;
1143     }
1144     p_sys->i_pos += sout_AccessOutWrite( p_mux->p_access, p_hdr );
1145     p_hdr = NULL;
1146
1147     /* Create indexes if any */
1148     for( int i = 0; i < p_mux->i_nb_inputs; i++ )
1149     {
1150         sout_input_t *p_input = p_mux->pp_inputs[i];
1151         ogg_stream_t *p_stream = (ogg_stream_t*)p_input->p_sys;
1152         /* flush stream && save offset */
1153         if ( p_sys->skeleton.b_create && !p_stream->skeleton.b_index_done )
1154         {
1155             if ( !p_stream->skeleton.p_index ) AllocateIndex( p_mux, p_input );
1156             if ( p_stream->skeleton.p_index )
1157             {
1158                 msg_Dbg( p_mux, "Creating index for stream %d", p_stream->i_serial_no );
1159                 OggGetSkeletonIndex( &op.packet, &op.bytes, p_stream );
1160                 if ( op.packet == NULL ) return false;
1161                 op.b_o_s = 0;
1162                 op.e_o_s = 0;
1163                 op.granulepos = 0;
1164                 op.packetno = p_sys->skeleton.i_packet_no++;
1165
1166                 /* backup some values */
1167                 p_stream->skeleton.i_index_offset = p_sys->i_pos;
1168                 p_stream->skeleton.i_index_packetno = p_sys->skeleton.os.packetno;
1169                 p_stream->skeleton.i_index_pageno = p_sys->skeleton.os.pageno;
1170
1171                 ogg_stream_packetin( &p_sys->skeleton.os, &op );
1172                 ogg_packet_clear( &op );
1173                 p_og = OggStreamFlush( p_mux, &p_sys->skeleton.os, 0 );
1174                 p_sys->i_pos += sout_AccessOutWrite( p_mux->p_access, p_og );
1175             }
1176             p_stream->skeleton.b_index_done = true;
1177         }
1178     }
1179
1180     /* Take care of the non b_o_s headers */
1181     for( int i = 0; i < p_mux->i_nb_inputs; i++ )
1182     {
1183         sout_input_t *p_input = p_mux->pp_inputs[i];
1184         ogg_stream_t *p_stream = (ogg_stream_t*)p_input->p_sys;
1185
1186         if( p_stream->fmt.i_codec == VLC_CODEC_VORBIS ||
1187             p_stream->fmt.i_codec == VLC_CODEC_SPEEX ||
1188             p_stream->fmt.i_codec == VLC_CODEC_OPUS ||
1189             p_stream->fmt.i_codec == VLC_CODEC_THEORA ||
1190             p_stream->fmt.i_codec == VLC_CODEC_DAALA )
1191         {
1192             unsigned pi_size[XIPH_MAX_HEADER_COUNT];
1193             const void *pp_data[XIPH_MAX_HEADER_COUNT];
1194             unsigned i_count;
1195
1196             if( xiph_SplitHeaders( pi_size, pp_data, &i_count,
1197                                    p_input->p_fmt->i_extra, p_input->p_fmt->p_extra ) )
1198                 i_count = 0;
1199
1200             /* Special case, headers are already there in the incoming stream.
1201              * We need to gather them an mark them as headers. */
1202             for( unsigned j = 1; j < i_count; j++ )
1203             {
1204                 op.bytes  = pi_size[j];
1205                 op.packet = (void *)pp_data[j];
1206                 if( pi_size[j] <= 0 )
1207                     msg_Err( p_mux, "header data corrupted");
1208
1209                 op.b_o_s  = 0;
1210                 op.e_o_s  = 0;
1211                 op.granulepos = 0;
1212                 op.packetno = p_stream->i_packet_no++;
1213                 ogg_stream_packetin( &p_stream->os, &op );
1214                 msg_Dbg( p_mux, "adding non bos, secondary header" );
1215                 if( j == i_count - 1 )
1216                     p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
1217                 else
1218                     p_og = OggStreamPageOut( p_mux, &p_stream->os, 0 );
1219                 if( p_og )
1220                     block_ChainAppend( &p_hdr, p_og );
1221             }
1222         }
1223         else if( p_stream->fmt.i_codec != VLC_CODEC_FLAC &&
1224                  p_stream->fmt.i_codec != VLC_CODEC_DIRAC )
1225         {
1226             uint8_t com[128];
1227             int     i_com;
1228
1229             /* comment */
1230             com[0] = PACKET_TYPE_COMMENT;
1231             i_com = snprintf( (char *)(com+1), 127,
1232                               PACKAGE_VERSION" stream output" )
1233                      + 1;
1234             op.packet = com;
1235             op.bytes  = i_com;
1236             op.b_o_s  = 0;
1237             op.e_o_s  = 0;
1238             op.granulepos = 0;
1239             op.packetno = p_stream->i_packet_no++;
1240             ogg_stream_packetin( &p_stream->os, &op );
1241             p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
1242             block_ChainAppend( &p_hdr, p_og );
1243         }
1244
1245         /* Special case for mp4v and flac */
1246         if( ( p_stream->fmt.i_codec == VLC_CODEC_MP4V ||
1247               p_stream->fmt.i_codec == VLC_CODEC_FLAC ) &&
1248             p_input->p_fmt->i_extra )
1249         {
1250             /* Send a packet with the VOL data for mp4v
1251              * or STREAMINFO for flac */
1252             msg_Dbg( p_mux, "writing extra data" );
1253             op.bytes  = p_input->p_fmt->i_extra;
1254             op.packet = p_input->p_fmt->p_extra;
1255             uint8_t flac_streaminfo[34 + 4];
1256             if( p_stream->fmt.i_codec == VLC_CODEC_FLAC )
1257             {
1258                 if (op.bytes == 42 && !memcmp(op.packet, "fLaC", 4)) {
1259                     op.bytes -= 4;
1260                     memcpy(flac_streaminfo, op.packet + 4, 38);
1261                     op.packet = flac_streaminfo;
1262                 } else if (op.bytes == 34) {
1263                     op.bytes += 4;
1264                     memcpy(flac_streaminfo + 4, op.packet, 34);
1265                     flac_streaminfo[0] = 0x80; /* last block, streaminfo */
1266                     flac_streaminfo[1] = 0;
1267                     flac_streaminfo[2] = 0;
1268                     flac_streaminfo[3] = 34; /* block size */
1269                     op.packet = flac_streaminfo;
1270                 } else {
1271                     msg_Err(p_mux, "Invalid FLAC streaminfo (%ld bytes)",
1272                             op.bytes);
1273                 }
1274             }
1275             op.b_o_s  = 0;
1276             op.e_o_s  = 0;
1277             op.granulepos = 0;
1278             op.packetno = p_stream->i_packet_no++;
1279             ogg_stream_packetin( &p_stream->os, &op );
1280             p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
1281             block_ChainAppend( &p_hdr, p_og );
1282         }
1283     }
1284
1285     if ( p_sys->skeleton.b_create )
1286     {
1287         msg_Dbg( p_mux, "ending skeleton" );
1288         op.packet = NULL;
1289         op.bytes = 0;
1290         op.b_o_s = 0;
1291         op.e_o_s = 1;
1292         op.granulepos = 0;
1293         op.packetno = p_sys->skeleton.i_packet_no++;
1294         ogg_stream_packetin( &p_sys->skeleton.os, &op );
1295         p_og = OggStreamFlush( p_mux, &p_sys->skeleton.os, 0 );
1296         block_ChainAppend( &p_hdr, p_og );
1297     }
1298
1299     /* set HEADER flag */
1300     /* flag headers to be resent for streaming clients */
1301     for( p_og = p_hdr; p_og != NULL; p_og = p_og->p_next )
1302     {
1303         p_og->i_flags |= BLOCK_FLAG_HEADER;
1304     }
1305
1306     /* Write previous headers */
1307     p_sys->i_pos += sout_AccessOutWrite( p_mux->p_access, p_hdr );
1308
1309     return true;
1310 }
1311
1312 static void OggCreateStreamFooter( sout_mux_t *p_mux, ogg_stream_t *p_stream )
1313 {
1314     block_t *p_og;
1315     ogg_packet op;
1316     sout_mux_sys_t *p_sys = p_mux->p_sys;
1317
1318     /* as stream is finished, overwrite the index, if there was any */
1319     if ( p_sys->skeleton.b_create && p_stream->skeleton.p_index
1320          && p_stream->skeleton.i_index_payload )
1321     {
1322         sout_AccessOutSeek( p_mux->p_access, p_stream->skeleton.i_index_offset );
1323         OggGetSkeletonIndex( &op.packet, &op.bytes, p_stream );
1324         if ( op.packet != NULL )
1325         {
1326             msg_Dbg(p_mux, "Rewriting index at %"PRId64, p_stream->skeleton.i_index_offset );
1327             ogg_stream_reset_serialno( &p_sys->skeleton.os, p_sys->skeleton.i_serial_no );
1328             op.b_o_s = 0;
1329             op.e_o_s = 0;
1330             op.granulepos = 0;
1331             op.packetno = p_stream->skeleton.i_index_packetno + 1;
1332             /* fake our stream state */
1333             p_sys->skeleton.os.pageno = p_stream->skeleton.i_index_pageno;
1334             p_sys->skeleton.os.packetno = p_stream->skeleton.i_index_packetno;
1335             p_sys->skeleton.os.granulepos = 0;
1336             p_sys->skeleton.os.b_o_s = 1;
1337             p_sys->skeleton.os.e_o_s = 0;
1338             ogg_stream_packetin( &p_sys->skeleton.os, &op );
1339             ogg_packet_clear( &op );
1340             p_og = OggStreamFlush( p_mux, &p_sys->skeleton.os, 0 );
1341             sout_AccessOutWrite( p_mux->p_access, p_og );
1342         }
1343         sout_AccessOutSeek( p_mux->p_access, p_sys->i_pos );
1344     }
1345
1346     /* clear skeleton */
1347     p_stream->skeleton.b_fisbone_done = false;
1348     p_stream->skeleton.b_index_done = false;
1349     p_stream->skeleton.i_index_offset = 0;
1350     p_stream->skeleton.i_index_payload = 0;
1351     p_stream->skeleton.i_last_keyframe_pos = 0;
1352     p_stream->skeleton.i_last_keyframe_time = 0;
1353     /* clear accounting */
1354     p_stream->i_num_frames = 0;
1355     p_stream->i_num_keyframes = 0;
1356
1357     /* Write eos packet for stream. */
1358     op.packet = NULL;
1359     op.bytes  = 0;
1360     op.b_o_s  = 0;
1361     op.e_o_s  = 1;
1362     op.granulepos = p_stream->u_last_granulepos;
1363     op.packetno = p_stream->i_packet_no++;
1364     ogg_stream_packetin( &p_stream->os, &op );
1365
1366     /* flush it with all remaining data */
1367     if( ( p_og = OggStreamFlush( p_mux, &p_stream->os, 0 ) ) )
1368     {
1369         /* Write footer */
1370         OggSetDate( p_og, p_stream->i_dts, p_stream->i_length );
1371         p_sys->i_pos += sout_AccessOutWrite( p_mux->p_access, p_og );
1372     }
1373
1374     ogg_stream_clear( &p_stream->os );
1375 }
1376
1377 static void OggSetDate( block_t *p_og, vlc_tick_t i_dts, vlc_tick_t i_length )
1378 {
1379     int i_count;
1380     block_t *p_tmp;
1381     vlc_tick_t i_delta;
1382
1383     for( p_tmp = p_og, i_count = 0; p_tmp != NULL; p_tmp = p_tmp->p_next )
1384     {
1385         i_count++;
1386     }
1387
1388     if( i_count == 0 ) return; /* ignore. */
1389
1390     i_delta = i_length / i_count;
1391
1392     for( p_tmp = p_og; p_tmp != NULL; p_tmp = p_tmp->p_next )
1393     {
1394         p_tmp->i_dts    = i_dts;
1395         p_tmp->i_length = i_delta;
1396
1397         i_dts += i_delta;
1398     }
1399 }
1400
1401 static void OggRewriteFisheadPage( sout_mux_t *p_mux )
1402 {
1403     sout_mux_sys_t *p_sys = p_mux->p_sys;
1404     ogg_packet op;
1405     op.bytes = 80;
1406     op.packet = calloc( 1, op.bytes );
1407     if ( op.packet != NULL )
1408     {
1409         op.b_o_s = 1;
1410         op.e_o_s = 0;
1411         op.granulepos = 0;
1412         op.packetno = 0;
1413         ogg_stream_reset_serialno( &p_sys->skeleton.os, p_sys->skeleton.i_serial_no );
1414         OggFillSkeletonFishead( op.packet, p_mux );
1415         ogg_stream_packetin( &p_sys->skeleton.os, &op );
1416         ogg_packet_clear( &op );
1417         msg_Dbg( p_mux, "rewriting fishead at %"PRId64, p_sys->skeleton.i_fishead_offset );
1418         sout_AccessOutSeek( p_mux->p_access, p_sys->skeleton.i_fishead_offset );
1419         sout_AccessOutWrite( p_mux->p_access,
1420                              OggStreamFlush( p_mux, &p_sys->skeleton.os, 0 ) );
1421         sout_AccessOutSeek( p_mux->p_access, p_sys->i_pos );
1422     }
1423 }
1424
1425 static bool AllocateIndex( sout_mux_t *p_mux, sout_input_t *p_input )
1426 {
1427     sout_mux_sys_t *p_sys = p_mux->p_sys;
1428     ogg_stream_t *p_stream = (ogg_stream_t *) p_input->p_sys;
1429     size_t i_size;
1430
1431     if ( p_stream->i_length )
1432     {
1433         vlc_tick_t i_interval = p_sys->skeleton.i_index_intvl;
1434         uint64_t i;
1435
1436         if( p_input->p_fmt->i_cat == VIDEO_ES &&
1437                 p_stream->fmt.video.i_frame_rate )
1438         {
1439             /* optimize for fps < 1 */
1440             i_interval= __MAX( i_interval,
1441                        VLC_TICK_FROM_SEC(10) *
1442                        p_stream->fmt.video.i_frame_rate_base /
1443                        p_stream->fmt.video.i_frame_rate );
1444         }
1445
1446         size_t i_tuple_size = 0;
1447         /* estimate length of pos value */
1448         if ( p_input->p_fmt->i_bitrate )
1449         {
1450             i = samples_from_vlc_tick(i_interval, p_input->p_fmt->i_bitrate);
1451             while ( i <<= 1 ) i_tuple_size++;
1452         }
1453         else
1454         {
1455             /* Likely 64KB<<keyframe interval<<16MB */
1456             /* We can't really guess due to muxing */
1457             i_tuple_size = 24 / 8;
1458         }
1459
1460         /* add length of interval value */
1461         i = i_interval;
1462         while ( i <<= 1 ) i_tuple_size++;
1463
1464         i_size = i_tuple_size * ( p_stream->i_length / i_interval + 2 );
1465     }
1466     else
1467     {
1468         i_size = ( INT64_C(3600) * 11.2 * CLOCK_FREQ / p_sys->skeleton.i_index_intvl )
1469                 * p_sys->skeleton.i_index_ratio;
1470         msg_Dbg( p_mux, "No stream length, using default allocation for index" );
1471     }
1472     i_size *= ( 8.0 / 7 ); /* 7bits encoding overhead */
1473     msg_Dbg( p_mux, "allocating %zu bytes for index", i_size );
1474     p_stream->skeleton.p_index = calloc( i_size, sizeof(uint8_t) );
1475     if ( !p_stream->skeleton.p_index ) return false;
1476     p_stream->skeleton.i_index_size = i_size;
1477     p_stream->skeleton.i_index_payload = 0;
1478     return true;
1479 }
1480
1481 /*****************************************************************************
1482  * Mux: multiplex available data in input fifos into the Ogg bitstream
1483  *****************************************************************************/
1484 static int Mux( sout_mux_t *p_mux )
1485 {
1486     sout_mux_sys_t *p_sys = p_mux->p_sys;
1487     vlc_tick_t     i_dts;
1488
1489     /* End any stream that ends in that group */
1490     if ( p_sys->i_del_streams )
1491     {
1492         /* Remove deleted logical streams */
1493         for( int i = 0; i < p_sys->i_del_streams; i++ )
1494         {
1495             OggCreateStreamFooter( p_mux, p_sys->pp_del_streams[i] );
1496             FREENULL( p_sys->pp_del_streams[i]->p_oggds_header );
1497             FREENULL( p_sys->pp_del_streams[i] );
1498         }
1499         FREENULL( p_sys->pp_del_streams );
1500         p_sys->i_del_streams = 0;
1501     }
1502
1503     if ( p_sys->i_streams == 0 )
1504     {
1505         /* All streams have been deleted, or none have ever been created
1506            From this point, we are allowed to start a new group of logical streams */
1507         p_sys->skeleton.b_head_done = false;
1508         p_sys->b_can_add_streams = true;
1509         p_sys->i_segment_start = p_sys->i_pos;
1510     }
1511
1512     if ( p_sys->i_add_streams )
1513     {
1514         if ( !p_sys->b_can_add_streams )
1515         {
1516             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);
1517             msg_Warn( p_mux, "Resetting and setting new identity to current streams");
1518
1519             /* resetting all active streams */
1520             for ( int i=0; i < p_sys->i_streams; i++ )
1521             {
1522                 ogg_stream_t * p_stream = (ogg_stream_t *) p_mux->pp_inputs[i]->p_sys;
1523                 if ( p_stream->b_finished || !p_stream->b_started ) continue;
1524                 OggCreateStreamFooter( p_mux, p_stream );
1525                 p_stream->i_serial_no = p_sys->i_next_serial_no++;
1526                 p_stream->i_packet_no = 0;
1527                 p_stream->b_finished = true;
1528             }
1529
1530             /* rewrite fishead with final values */
1531             if ( p_sys->skeleton.b_head_done )
1532             {
1533                 OggRewriteFisheadPage( p_mux );
1534             }
1535
1536             p_sys->b_can_add_streams = true;
1537             p_sys->skeleton.b_head_done = false;
1538             p_sys->i_segment_start = p_sys->i_pos;
1539         }
1540
1541         /* Open new ogg stream */
1542         if( sout_MuxGetStream( p_mux, 1, &i_dts) < 0 )
1543         {
1544             msg_Dbg( p_mux, "waiting for data..." );
1545             return VLC_SUCCESS;
1546         }
1547         msg_Dbg( p_mux, "writing streams headers" );
1548         p_sys->i_start_dts = i_dts;
1549         p_sys->i_streams = p_mux->i_nb_inputs;
1550         p_sys->i_del_streams = 0;
1551         p_sys->i_add_streams = 0;
1552         p_sys->skeleton.b_create = true;
1553
1554         if ( ! OggCreateHeaders( p_mux ) )
1555             return VLC_ENOMEM;
1556
1557         /* If we're switching to end of headers, then that's data start */
1558         if ( p_sys->b_can_add_streams )
1559         {
1560             msg_Dbg( p_mux, "data starts from %zu", p_sys->i_pos );
1561             p_sys->i_data_start = p_sys->i_pos;
1562         }
1563
1564         /* Since we started sending secondaryheader or data pages,
1565              * we're no longer allowed to create new streams, until all streams end */
1566         p_sys->b_can_add_streams = false;
1567     }
1568
1569     /* Do the regular data mux thing */
1570     for( ;; )
1571     {
1572         int i_stream = sout_MuxGetStream( p_mux, 1, NULL );
1573         if( i_stream < 0 )
1574             return VLC_SUCCESS;
1575         MuxBlock( p_mux, p_mux->pp_inputs[i_stream] );
1576     }
1577
1578     return VLC_SUCCESS;
1579 }
1580
1581 static int MuxBlock( sout_mux_t *p_mux, sout_input_t *p_input )
1582 {
1583     sout_mux_sys_t *p_sys = p_mux->p_sys;
1584     ogg_stream_t *p_stream = (ogg_stream_t*)p_input->p_sys;
1585     block_t *p_data = block_FifoGet( p_input->p_fifo );
1586     block_t *p_og = NULL;
1587     ogg_packet op;
1588     vlc_tick_t i_time;
1589
1590     if( p_stream->fmt.i_codec != VLC_CODEC_VORBIS &&
1591         p_stream->fmt.i_codec != VLC_CODEC_FLAC &&
1592         p_stream->fmt.i_codec != VLC_CODEC_SPEEX &&
1593         p_stream->fmt.i_codec != VLC_CODEC_OPUS &&
1594         p_stream->fmt.i_codec != VLC_CODEC_THEORA &&
1595         p_stream->fmt.i_codec != VLC_CODEC_DAALA &&
1596         p_stream->fmt.i_codec != VLC_CODEC_VP8 &&
1597         p_stream->fmt.i_codec != VLC_CODEC_DIRAC )
1598     {
1599         p_data = block_Realloc( p_data, 1, p_data->i_buffer );
1600         p_data->p_buffer[0] = PACKET_IS_SYNCPOINT;      // FIXME
1601     }
1602
1603     if ( p_stream->fmt.i_codec == VLC_CODEC_DIRAC && p_stream->i_baseptsdelay < 0 )
1604         p_stream->i_baseptsdelay = p_data->i_pts - p_data->i_dts;
1605
1606     op.packet   = p_data->p_buffer;
1607     op.bytes    = p_data->i_buffer;
1608     op.b_o_s    = 0;
1609     op.e_o_s    = 0;
1610     op.packetno = p_stream->i_packet_no++;
1611     op.granulepos = -1;
1612
1613     if( p_stream->fmt.i_cat == AUDIO_ES )
1614     {
1615         if( p_stream->fmt.i_codec == VLC_CODEC_VORBIS ||
1616             p_stream->fmt.i_codec == VLC_CODEC_FLAC ||
1617             p_stream->fmt.i_codec == VLC_CODEC_OPUS ||
1618             p_stream->fmt.i_codec == VLC_CODEC_SPEEX )
1619         {
1620             /* number of sample from begining + current packet */
1621             op.granulepos =
1622                 samples_from_vlc_tick( p_data->i_dts - p_sys->i_start_dts + p_data->i_length,
1623                                        p_input->p_fmt->audio.i_rate );
1624
1625             i_time = p_data->i_dts - p_sys->i_start_dts;
1626             AddIndexEntry( p_mux, i_time, p_input );
1627         }
1628         else if( p_stream->p_oggds_header )
1629         {
1630             /* number of sample from begining */
1631             op.granulepos = samples_from_vlc_tick( p_data->i_dts - p_sys->i_start_dts,
1632                                   p_stream->p_oggds_header->i_samples_per_unit );
1633         }
1634     }
1635     else if( p_stream->fmt.i_cat == VIDEO_ES )
1636     {
1637         if( p_stream->fmt.i_codec == VLC_CODEC_THEORA ||
1638             p_stream->fmt.i_codec == VLC_CODEC_DAALA )
1639         {
1640             p_stream->i_num_frames++;
1641             if( p_data->i_flags & BLOCK_FLAG_TYPE_I )
1642             {
1643                 p_stream->i_num_keyframes++;
1644                 p_stream->i_last_keyframe = p_stream->i_num_frames;
1645
1646                 /* presentation time */
1647                 i_time = vlc_tick_from_samples( (p_stream->i_num_frames - 1 ) *
1648                         p_stream->fmt.video.i_frame_rate_base,
1649                         p_stream->fmt.video.i_frame_rate );
1650                 AddIndexEntry( p_mux, i_time, p_input );
1651             }
1652
1653             op.granulepos = (p_stream->i_last_keyframe << p_stream->i_keyframe_granule_shift )
1654                           | (p_stream->i_num_frames-p_stream->i_last_keyframe);
1655         }
1656         else if( p_stream->fmt.i_codec == VLC_CODEC_DIRAC )
1657         {
1658
1659 #define FRAME_ROUND(a) \
1660     if ( ( a + 5000 / CLOCK_FREQ ) > ( a / CLOCK_FREQ ) )\
1661         a += 5000;\
1662     a /= CLOCK_FREQ;
1663
1664             int64_t dt = (p_data->i_dts - p_sys->i_start_dts) * p_stream->fmt.video.i_frame_rate /
1665                     p_stream->fmt.video.i_frame_rate_base;
1666             FRAME_ROUND( dt );
1667
1668             int64_t pt = (p_data->i_pts - p_sys->i_start_dts - p_stream->i_baseptsdelay ) *
1669                     p_stream->fmt.video.i_frame_rate / p_stream->fmt.video.i_frame_rate_base;
1670             FRAME_ROUND( pt );
1671
1672             /* (shro) some PTS could be repeated within 1st frames */
1673             if ( pt == p_stream->i_dirac_last_pt )
1674                 pt++;
1675             else
1676                 p_stream->i_dirac_last_pt = pt;
1677
1678             /* (shro) some DTS could be repeated within 1st frames */
1679             if ( dt == p_stream->i_dirac_last_dt )
1680                 dt++;
1681             else
1682                 p_stream->i_dirac_last_dt = dt;
1683
1684             if( p_data->i_flags & BLOCK_FLAG_TYPE_I )
1685                 p_stream->i_last_keyframe = dt;
1686             int64_t dist = dt - p_stream->i_last_keyframe;
1687
1688             /* Everything increments by two for progressive */
1689             if ( true )
1690             {
1691                 pt *=2;
1692                 dt *=2;
1693             }
1694
1695             int64_t delay = llabs(pt - dt);
1696
1697             op.granulepos = (pt - delay) << 31 | (dist&0xff00) << 14
1698                           | (delay&0x1fff) << 9 | (dist&0xff);
1699 #ifndef NDEBUG
1700             msg_Dbg( p_mux, "dts %"PRId64" pts %"PRId64" dt %"PRId64" pt %"PRId64" delay %"PRId64" granule %"PRId64,
1701                      (p_data->i_dts - p_sys->i_start_dts),
1702                      (p_data->i_pts - p_sys->i_start_dts ),
1703                      dt, pt, delay, op.granulepos );
1704 #endif
1705
1706             AddIndexEntry( p_mux, dt, p_input );
1707         }
1708         else if( p_stream->fmt.i_codec == VLC_CODEC_VP8 )
1709         {
1710             p_stream->i_num_frames++;
1711             if( p_data->i_flags & BLOCK_FLAG_TYPE_I )
1712             {
1713                 p_stream->i_num_keyframes++;
1714                 p_stream->i_last_keyframe = p_stream->i_num_frames;
1715
1716                 /* presentation time */
1717                 i_time = vlc_tick_from_samples( ( p_stream->i_num_frames - 1 ) *
1718                          p_stream->fmt.video.i_frame_rate_base, p_stream->fmt.video.i_frame_rate );
1719                 AddIndexEntry( p_mux, i_time, p_input );
1720             }
1721             op.granulepos = ( ((int64_t)p_stream->i_num_frames) << 32 ) |
1722             ( ( ( p_stream->i_num_frames - p_stream->i_last_keyframe ) & 0x07FFFFFF ) << 3 );
1723         }
1724         else if( p_stream->p_oggds_header )
1725             op.granulepos = MSFTIME_FROM_VLC_TICK( p_data->i_dts - p_sys->i_start_dts ) /
1726                 p_stream->p_oggds_header->i_time_unit;
1727     }
1728     else if( p_stream->fmt.i_cat == SPU_ES )
1729     {
1730         /* granulepos is in millisec */
1731         op.granulepos = MS_FROM_VLC_TICK( p_data->i_dts - p_sys->i_start_dts );
1732     }
1733     else
1734         return VLC_EGENERIC;
1735
1736     p_stream->u_last_granulepos = op.granulepos;
1737     ogg_stream_packetin( &p_stream->os, &op );
1738
1739     if( p_stream->fmt.i_cat == SPU_ES ||
1740         p_stream->fmt.i_codec == VLC_CODEC_SPEEX ||
1741         p_stream->fmt.i_codec == VLC_CODEC_DIRAC )
1742     {
1743         /* Subtitles or Speex packets are quite small so they
1744          * need to be flushed to be sent on time */
1745         /* The OggDirac mapping suggests ever so strongly that a
1746          * page flush occurs after each OggDirac packet, so to make
1747          * the timestamps unambiguous */
1748         p_og = OggStreamFlush( p_mux, &p_stream->os, p_data->i_dts );
1749     }
1750     else
1751     {
1752         p_og = OggStreamPageOut( p_mux, &p_stream->os, p_data->i_dts );
1753     }
1754
1755     if( p_og )
1756     {
1757         OggSetDate( p_og, p_stream->i_dts, p_stream->i_length );
1758         p_stream->i_dts = -1;
1759         p_stream->i_length = 0;
1760         p_sys->i_pos += sout_AccessOutWrite( p_mux->p_access, p_og );
1761     }
1762     else
1763     {
1764         if( p_stream->i_dts < 0 )
1765         {
1766             p_stream->i_dts = p_data->i_dts;
1767         }
1768         p_stream->i_length += p_data->i_length;
1769     }
1770
1771     block_Release( p_data );
1772     return VLC_SUCCESS;
1773 }