ogg.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:32k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * ogg.c: ogg muxer module for vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2001, 2002 VideoLAN
  5.  * $Id: ogg.c 8566 2004-08-29 11:42:43Z gbazin $
  6.  *
  7.  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  8.  *          Gildas Bazin <gbazin@videolan.org>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  23.  *****************************************************************************/
  24. /*****************************************************************************
  25.  * Preamble
  26.  *****************************************************************************/
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #ifdef HAVE_TIME_H
  30. #   include <time.h>
  31. #endif
  32. #include <vlc/vlc.h>
  33. #include <vlc/input.h>
  34. #include <vlc/sout.h>
  35. #include "codecs.h"
  36. #include <ogg/ogg.h>
  37. /*****************************************************************************
  38.  * Module descriptor
  39.  *****************************************************************************/
  40. static int  Open   ( vlc_object_t * );
  41. static void Close  ( vlc_object_t * );
  42. vlc_module_begin();
  43.     set_description( _("Ogg/ogm muxer") );
  44.     set_capability( "sout mux", 10 );
  45.     add_shortcut( "ogg" );
  46.     add_shortcut( "ogm" );
  47.     set_callbacks( Open, Close );
  48. vlc_module_end();
  49. /*****************************************************************************
  50.  * Exported prototypes
  51.  *****************************************************************************/
  52. static int Control  ( sout_mux_t *, int, va_list );
  53. static int AddStream( sout_mux_t *, sout_input_t * );
  54. static int DelStream( sout_mux_t *, sout_input_t * );
  55. static int Mux      ( sout_mux_t * );
  56. static int MuxBlock ( sout_mux_t *, sout_input_t * );
  57. static block_t *OggCreateHeader( sout_mux_t *, mtime_t );
  58. static block_t *OggCreateFooter( sout_mux_t *, mtime_t );
  59. /*****************************************************************************
  60.  * Misc declarations
  61.  *****************************************************************************/
  62. #define FREE( p ) if( p ) { free( p ); (p) = NULL; }
  63. /* Structures used for OggDS headers used in ogm files */
  64. #define PACKET_TYPE_HEADER   0x01
  65. #define PACKET_TYPE_COMMENT  0x03
  66. #define PACKET_IS_SYNCPOINT  0x08
  67. typedef struct
  68. #ifdef HAVE_ATTRIBUTE_PACKED
  69.     __attribute__((__packed__))
  70. #endif
  71. {
  72.     int32_t i_width;
  73.     int32_t i_height;
  74. } oggds_header_video_t;
  75. typedef struct
  76. #ifdef HAVE_ATTRIBUTE_PACKED
  77.     __attribute__((__packed__))
  78. #endif
  79. {
  80.     int16_t i_channels;
  81.     int16_t i_block_align;
  82.     int32_t i_avgbytespersec;
  83. } oggds_header_audio_t;
  84. typedef struct
  85. #ifdef HAVE_ATTRIBUTE_PACKED
  86.     __attribute__((__packed__))
  87. #endif
  88. {
  89.     uint8_t i_packet_type;
  90.     char stream_type[8];
  91.     char sub_type[4];
  92.     int32_t i_size;
  93.     int64_t i_time_unit;
  94.     int64_t i_samples_per_unit;
  95.     int32_t i_default_len;
  96.     int32_t i_buffer_size;
  97.     int16_t i_bits_per_sample;
  98.     int16_t i_padding_0; /* Because the original is using MSVC packing style */
  99.     union
  100.     {
  101.         oggds_header_video_t video;
  102.         oggds_header_audio_t audio;
  103.     } header;
  104.     int32_t i_padding_1; /* Because the original is using MSVC packing style */
  105. } oggds_header_t;
  106. /*
  107.  * TODO  move this function to src/stream_output.c (used by nearly all muxers)
  108.  */
  109. static int MuxGetStream( sout_mux_t *p_mux, int *pi_stream, mtime_t *pi_dts )
  110. {
  111.     mtime_t i_dts;
  112.     int     i_stream;
  113.     int     i;
  114.     for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ )
  115.     {
  116.         block_fifo_t  *p_fifo;
  117.         p_fifo = p_mux->pp_inputs[i]->p_fifo;
  118.         /* We don't really need to have anything in the SPU fifo */
  119.         if( p_mux->pp_inputs[i]->p_fmt->i_cat == SPU_ES &&
  120.             p_fifo->i_depth == 0 ) continue;
  121.         if( p_fifo->i_depth )
  122.         {
  123.             block_t *p_buf;
  124.             p_buf = block_FifoShow( p_fifo );
  125.             if( i_stream < 0 || p_buf->i_dts < i_dts )
  126.             {
  127.                 i_dts = p_buf->i_dts;
  128.                 i_stream = i;
  129.             }
  130.         }
  131.         else return -1;
  132.     }
  133.     if( pi_stream ) *pi_stream = i_stream;
  134.     if( pi_dts ) *pi_dts = i_dts;
  135.     return i_stream;
  136. }
  137. /*****************************************************************************
  138.  * Definitions of structures and functions used by this plugins 
  139.  *****************************************************************************/
  140. typedef struct
  141. {
  142.     int i_cat;
  143.     int i_fourcc;
  144.     int b_new;
  145.     mtime_t i_dts;
  146.     mtime_t i_length;
  147.     int     i_packet_no;
  148.     int     i_serial_no;
  149.     int     i_keyframe_granule_shift; /* Theora only */
  150.     ogg_stream_state os;
  151.     oggds_header_t *p_oggds_header;
  152. } ogg_stream_t;
  153. struct sout_mux_sys_t
  154. {
  155.     int     i_streams;
  156.     mtime_t i_start_dts;
  157.     int     i_next_serial_no;
  158.     /* number of logical streams pending to be added */
  159.     int i_add_streams;
  160.     /* logical streams pending to be deleted */
  161.     int i_del_streams;
  162.     ogg_stream_t **pp_del_streams;
  163. };
  164. static void OggSetDate( block_t *, mtime_t , mtime_t  );
  165. static block_t *OggStreamFlush( sout_mux_t *, ogg_stream_state *, mtime_t );
  166. /*****************************************************************************
  167.  * Open: Open muxer
  168.  *****************************************************************************/
  169. static int Open( vlc_object_t *p_this )
  170. {
  171.     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
  172.     sout_mux_sys_t  *p_sys;
  173.     msg_Info( p_mux, "Open" );
  174.     p_sys                 = malloc( sizeof( sout_mux_sys_t ) );
  175.     p_sys->i_streams      = 0;
  176.     p_sys->i_add_streams  = 0;
  177.     p_sys->i_del_streams  = 0;
  178.     p_sys->pp_del_streams = 0;
  179.     p_mux->p_sys        = p_sys;
  180.     p_mux->pf_control   = Control;
  181.     p_mux->pf_addstream = AddStream;
  182.     p_mux->pf_delstream = DelStream;
  183.     p_mux->pf_mux       = Mux;
  184.     /* First serial number is random.
  185.      * (Done like this because on win32 you need to seed the random number
  186.      *  generator once per thread). */
  187.     srand( (unsigned int)time( NULL ) );
  188.     p_sys->i_next_serial_no = rand();
  189.     return VLC_SUCCESS;
  190. }
  191. /*****************************************************************************
  192.  * Close: Finalize ogg bitstream and close muxer
  193.  *****************************************************************************/
  194. static void Close( vlc_object_t * p_this )
  195. {
  196.     sout_mux_t     *p_mux = (sout_mux_t*)p_this;
  197.     sout_mux_sys_t *p_sys = p_mux->p_sys;
  198.     msg_Info( p_mux, "Close" );
  199.     if( p_sys->i_del_streams )
  200.     {
  201.         block_t *p_og = NULL;
  202.         mtime_t i_dts = -1;
  203.         int i;
  204.         /* Close the current ogg stream */
  205.         msg_Dbg( p_mux, "writing footer" );
  206.         block_ChainAppend( &p_og, OggCreateFooter( p_mux, 0 ) );
  207.         /* Remove deleted logical streams */
  208.         for( i = 0; i < p_sys->i_del_streams; i++ )
  209.         {
  210.             i_dts = p_sys->pp_del_streams[i]->i_dts;
  211.             ogg_stream_clear( &p_sys->pp_del_streams[i]->os );
  212.             FREE( p_sys->pp_del_streams[i]->p_oggds_header );
  213.             FREE( p_sys->pp_del_streams[i] );
  214.         }
  215.         FREE( p_sys->pp_del_streams );
  216.         p_sys->i_streams -= p_sys->i_del_streams;
  217.         /* Write footer */
  218.         OggSetDate( p_og, i_dts, 0 );
  219.         sout_AccessOutWrite( p_mux->p_access, p_og );
  220.     }
  221.     free( p_sys );
  222. }
  223. /*****************************************************************************
  224.  * Control:
  225.  *****************************************************************************/
  226. static int Control( sout_mux_t *p_mux, int i_query, va_list args )
  227. {
  228.     vlc_bool_t *pb_bool;
  229.     char **ppsz;
  230.    switch( i_query )
  231.    {
  232.        case MUX_CAN_ADD_STREAM_WHILE_MUXING:
  233.            pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
  234.            *pb_bool = VLC_TRUE;
  235.            return VLC_SUCCESS;
  236.        case MUX_GET_ADD_STREAM_WAIT:
  237.            pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
  238.            *pb_bool = VLC_TRUE;
  239.            return VLC_SUCCESS;
  240.        case MUX_GET_MIME:
  241.            ppsz = (char**)va_arg( args, char ** );
  242.            *ppsz = strdup( "application/ogg" );
  243.            return VLC_SUCCESS;
  244.         default:
  245.             return VLC_EGENERIC;
  246.    }
  247. }
  248. /*****************************************************************************
  249.  * AddStream: Add an elementary stream to the muxed stream
  250.  *****************************************************************************/
  251. static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
  252. {
  253.     sout_mux_sys_t *p_sys = p_mux->p_sys;
  254.     ogg_stream_t   *p_stream;
  255.     uint16_t i_tag;
  256.     msg_Dbg( p_mux, "adding input" );
  257.     p_input->p_sys = p_stream = malloc( sizeof( ogg_stream_t ) );
  258.     p_stream->i_cat       = p_input->p_fmt->i_cat;
  259.     p_stream->i_fourcc    = p_input->p_fmt->i_codec;
  260.     p_stream->i_serial_no = p_sys->i_next_serial_no++;
  261.     p_stream->i_packet_no = 0;
  262.     p_stream->p_oggds_header = 0;
  263.     switch( p_input->p_fmt->i_cat )
  264.     {
  265.     case VIDEO_ES:
  266.         if( !p_input->p_fmt->video.i_frame_rate ||
  267.             !p_input->p_fmt->video.i_frame_rate_base )
  268.         {
  269.             msg_Warn( p_mux, "Missing frame rate, assuming 25fps" );
  270.             p_input->p_fmt->video.i_frame_rate = 25;
  271.             p_input->p_fmt->video.i_frame_rate_base = 1;
  272.         }
  273.         switch( p_stream->i_fourcc )
  274.         {
  275.         case VLC_FOURCC( 'm', 'p', 'g', 'v' ):
  276.         case VLC_FOURCC( 'm', 'p', '4', 'v' ):
  277.         case VLC_FOURCC( 'D', 'I', 'V', '3' ):
  278.         case VLC_FOURCC( 'M', 'J', 'P', 'G' ):
  279.         case VLC_FOURCC( 'W', 'M', 'V', '1' ):
  280.         case VLC_FOURCC( 'W', 'M', 'V', '2' ):
  281.         case VLC_FOURCC( 'W', 'M', 'V', '3' ):
  282.         case VLC_FOURCC( 'S', 'N', 'O', 'W' ):
  283.             p_stream->p_oggds_header = malloc( sizeof(oggds_header_t) );
  284.             memset( p_stream->p_oggds_header, 0, sizeof(oggds_header_t) );
  285.             p_stream->p_oggds_header->i_packet_type = PACKET_TYPE_HEADER;
  286.             memcpy( p_stream->p_oggds_header->stream_type, "video", 5 );
  287.             if( p_stream->i_fourcc == VLC_FOURCC( 'm', 'p', '4', 'v' ) )
  288.             {
  289.                 memcpy( p_stream->p_oggds_header->sub_type, "XVID", 4 );
  290.             }
  291.             else if( p_stream->i_fourcc == VLC_FOURCC( 'D', 'I', 'V', '3' ) )
  292.             {
  293.                 memcpy( p_stream->p_oggds_header->sub_type, "DIV3", 4 );
  294.             }
  295.             else
  296.             {
  297.                 memcpy( p_stream->p_oggds_header->sub_type,
  298.                         &p_stream->i_fourcc, 4 );
  299.             }
  300.             SetDWLE( &p_stream->p_oggds_header->i_size,
  301.                      sizeof( oggds_header_t ) - 1 );
  302.             SetQWLE( &p_stream->p_oggds_header->i_time_unit,
  303.                      I64C(10000000) * p_input->p_fmt->video.i_frame_rate_base /
  304.                      (int64_t)p_input->p_fmt->video.i_frame_rate );
  305.             SetQWLE( &p_stream->p_oggds_header->i_samples_per_unit, 1 );
  306.             SetDWLE( &p_stream->p_oggds_header->i_default_len, 1 ); /* ??? */
  307.             SetDWLE( &p_stream->p_oggds_header->i_buffer_size, 1024*1024 );
  308.             SetWLE( &p_stream->p_oggds_header->i_bits_per_sample, 0 );
  309.             SetDWLE( &p_stream->p_oggds_header->header.video.i_width,
  310.                      p_input->p_fmt->video.i_width );
  311.             SetDWLE( &p_stream->p_oggds_header->header.video.i_height,
  312.                      p_input->p_fmt->video.i_height );
  313.             msg_Dbg( p_mux, "%4.4s stream", (char *)&p_stream->i_fourcc );
  314.             break;
  315.         case VLC_FOURCC( 't', 'h', 'e', 'o' ):
  316.             msg_Dbg( p_mux, "theora stream" );
  317.             break;
  318.         default:
  319.             FREE( p_input->p_sys );
  320.             return VLC_EGENERIC;
  321.         }
  322.         break;
  323.     case AUDIO_ES:
  324.         switch( p_stream->i_fourcc )
  325.         {
  326.         case VLC_FOURCC( 'v', 'o', 'r', 'b' ):
  327.             msg_Dbg( p_mux, "vorbis stream" );
  328.             break;
  329.         case VLC_FOURCC( 's', 'p', 'x', ' ' ):
  330.             msg_Dbg( p_mux, "speex stream" );
  331.             break;
  332.         case VLC_FOURCC( 'f', 'l', 'a', 'c' ):
  333.             msg_Dbg( p_mux, "flac stream" );
  334.             break;
  335.         default:
  336.             fourcc_to_wf_tag( p_stream->i_fourcc, &i_tag );
  337.             if( i_tag == WAVE_FORMAT_UNKNOWN )
  338.             {
  339.                 FREE( p_input->p_sys );
  340.                 return VLC_EGENERIC;
  341.             }
  342.             p_stream->p_oggds_header =
  343.                 malloc( sizeof(oggds_header_t) + p_input->p_fmt->i_extra );
  344.             memset( p_stream->p_oggds_header, 0, sizeof(oggds_header_t) );
  345.             p_stream->p_oggds_header->i_packet_type = PACKET_TYPE_HEADER;
  346.             SetDWLE( &p_stream->p_oggds_header->i_size,
  347.                      sizeof( oggds_header_t ) - 1 + p_input->p_fmt->i_extra );
  348.             if( p_input->p_fmt->i_extra )
  349.             {
  350.                 memcpy( &p_stream->p_oggds_header[1],
  351.                         p_input->p_fmt->p_extra, p_input->p_fmt->i_extra );
  352.             }
  353.             memcpy( p_stream->p_oggds_header->stream_type, "audio", 5 );
  354.             memset( p_stream->p_oggds_header->sub_type, 0, 4 );
  355.             sprintf( p_stream->p_oggds_header->sub_type, "%-x", i_tag );
  356.             SetQWLE( &p_stream->p_oggds_header->i_time_unit, I64C(10000000) );
  357.             SetDWLE( &p_stream->p_oggds_header->i_default_len, 1 );
  358.             SetDWLE( &p_stream->p_oggds_header->i_buffer_size, 30*1024 );
  359.             SetQWLE( &p_stream->p_oggds_header->i_samples_per_unit,
  360.                      p_input->p_fmt->audio.i_rate );
  361.             SetWLE( &p_stream->p_oggds_header->i_bits_per_sample,
  362.                     p_input->p_fmt->audio.i_bitspersample );
  363.             SetDWLE( &p_stream->p_oggds_header->header.audio.i_channels,
  364.                      p_input->p_fmt->audio.i_channels );
  365.             SetDWLE( &p_stream->p_oggds_header->header.audio.i_block_align,
  366.                      p_input->p_fmt->audio.i_blockalign );
  367.             SetDWLE( &p_stream->p_oggds_header->header.audio.i_avgbytespersec,
  368.                      p_input->p_fmt->i_bitrate / 8);
  369.             msg_Dbg( p_mux, "%4.4s stream", (char *)&p_stream->i_fourcc );
  370.             break;
  371.         }
  372.         break;
  373.     case SPU_ES:
  374.         switch( p_stream->i_fourcc )
  375.         {
  376.         case VLC_FOURCC( 's', 'u','b', 't' ):
  377.             p_stream->p_oggds_header = malloc( sizeof(oggds_header_t) );
  378.             memset( p_stream->p_oggds_header, 0, sizeof(oggds_header_t) );
  379.             p_stream->p_oggds_header->i_packet_type = PACKET_TYPE_HEADER;
  380.             memcpy( p_stream->p_oggds_header->stream_type, "text", 4 );
  381.             msg_Dbg( p_mux, "subtitles stream" );
  382.             break;
  383.         default:
  384.             FREE( p_input->p_sys );
  385.             return VLC_EGENERIC;
  386.         }
  387.         break;
  388.     default:
  389.         FREE( p_input->p_sys );
  390.         return VLC_EGENERIC;
  391.     }
  392.     p_stream->b_new = VLC_TRUE;
  393.     p_sys->i_add_streams++;
  394.     return VLC_SUCCESS;
  395. }
  396. /*****************************************************************************
  397.  * DelStream: Delete an elementary stream from the muxed stream
  398.  *****************************************************************************/
  399. static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
  400. {
  401.     sout_mux_sys_t *p_sys  = p_mux->p_sys;
  402.     ogg_stream_t   *p_stream = (ogg_stream_t*)p_input->p_sys;
  403.     block_t *p_og;
  404.     msg_Dbg( p_mux, "removing input" );
  405.     /* flush all remaining data */
  406.     if( p_input->p_sys )
  407.     {
  408.         if( !p_stream->b_new )
  409.         {
  410.             while( p_input->p_fifo->i_depth ) MuxBlock( p_mux, p_input );
  411.         }
  412.         if( !p_stream->b_new &&
  413.             ( p_og = OggStreamFlush( p_mux, &p_stream->os, 0 ) ) )
  414.         {
  415.             OggSetDate( p_og, p_stream->i_dts, p_stream->i_length );
  416.             sout_AccessOutWrite( p_mux->p_access, p_og );
  417.         }
  418.         /* move input in delete queue */
  419.         if( !p_stream->b_new )
  420.         {
  421.             p_sys->pp_del_streams = realloc( p_sys->pp_del_streams,
  422.                                              (p_sys->i_del_streams + 1) *
  423.                                              sizeof(ogg_stream_t *) );
  424.             p_sys->pp_del_streams[p_sys->i_del_streams++] = p_stream;
  425.         }
  426.         else
  427.         {
  428.             /* Wasn't already added so get rid of it */
  429.             FREE( p_stream->p_oggds_header );
  430.             FREE( p_stream );
  431.             p_sys->i_add_streams--;
  432.         }
  433.     }
  434.     p_input->p_sys = NULL;
  435.     return 0;
  436. }
  437. /*****************************************************************************
  438.  * Ogg bitstream manipulation routines
  439.  *****************************************************************************/
  440. static block_t *OggStreamFlush( sout_mux_t *p_mux,
  441.                                 ogg_stream_state *p_os, mtime_t i_pts )
  442. {
  443.     block_t *p_og, *p_og_first = NULL;
  444.     ogg_page og;
  445.     while( ogg_stream_flush( p_os, &og ) )
  446.     {
  447.         /* Flush all data */
  448.         p_og = block_New( p_mux, og.header_len + og.body_len );
  449.         memcpy( p_og->p_buffer, og.header, og.header_len );
  450.         memcpy( p_og->p_buffer + og.header_len, og.body, og.body_len );
  451.         p_og->i_dts     = 0;
  452.         p_og->i_pts     = i_pts;
  453.         p_og->i_length  = 0;
  454.         i_pts = 0; // write it only once
  455.         block_ChainAppend( &p_og_first, p_og );
  456.     }
  457.     return p_og_first;
  458. }
  459. static block_t *OggStreamPageOut( sout_mux_t *p_mux,
  460.                                   ogg_stream_state *p_os, mtime_t i_pts )
  461. {
  462.     block_t *p_og, *p_og_first = NULL;
  463.     ogg_page og;
  464.     while( ogg_stream_pageout( p_os, &og ) )
  465.     {
  466.         /* Flush all data */
  467.         p_og = block_New( p_mux, og.header_len + og.body_len );
  468.         memcpy( p_og->p_buffer, og.header, og.header_len );
  469.         memcpy( p_og->p_buffer + og.header_len, og.body, og.body_len );
  470.         p_og->i_dts     = 0;
  471.         p_og->i_pts     = i_pts;
  472.         p_og->i_length  = 0;
  473.         i_pts = 0; // write them only once
  474.         block_ChainAppend( &p_og_first, p_og );
  475.     }
  476.     return p_og_first;
  477. }
  478. static block_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts )
  479. {
  480.     block_t *p_hdr = NULL;
  481.     block_t *p_og = NULL;
  482.     ogg_packet op;
  483.     uint8_t *p_extra;
  484.     int i, i_extra;
  485.     /* Write header for each stream. All b_o_s (beginning of stream) packets
  486.      * must appear first in the ogg stream so we take care of them first. */
  487.     for( i = 0; i < p_mux->i_nb_inputs; i++ )
  488.     {
  489.         sout_input_t *p_input = p_mux->pp_inputs[i];
  490.         ogg_stream_t *p_stream = (ogg_stream_t*)p_input->p_sys;
  491.         p_stream->b_new = VLC_FALSE;
  492.         msg_Dbg( p_mux, "creating header for %4.4s",
  493.                  (char *)&p_stream->i_fourcc );
  494.         ogg_stream_init( &p_stream->os, p_stream->i_serial_no );
  495.         p_stream->i_packet_no = 0;
  496.         if( p_stream->i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) ||
  497.             p_stream->i_fourcc == VLC_FOURCC( 's', 'p', 'x', ' ' ) ||
  498.             p_stream->i_fourcc == VLC_FOURCC( 't', 'h', 'e', 'o' ) )
  499.         {
  500.             /* First packet in order: vorbis/speex/theora info */
  501.             p_extra = p_input->p_fmt->p_extra;
  502.             i_extra = p_input->p_fmt->i_extra;
  503.             op.bytes = *(p_extra++) << 8;
  504.             op.bytes |= (*(p_extra++) & 0xFF);
  505.             op.packet = p_extra;
  506.             i_extra -= (op.bytes + 2);
  507.             if( i_extra < 0 )
  508.             {
  509.                 msg_Err( p_mux, "header data corrupted");
  510.                 op.bytes += i_extra;
  511.             }
  512.             op.b_o_s  = 1;
  513.             op.e_o_s  = 0;
  514.             op.granulepos = 0;
  515.             op.packetno = p_stream->i_packet_no++;
  516.             ogg_stream_packetin( &p_stream->os, &op );
  517.             p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
  518.             /* Get keyframe_granule_shift for theora granulepos calculation */
  519.             if( p_stream->i_fourcc == VLC_FOURCC( 't', 'h', 'e', 'o' ) )
  520.             {
  521.                 int i_keyframe_frequency_force =
  522.                       1 << ((op.packet[40] << 6 >> 3) | (op.packet[41] >> 5));
  523.                 /* granule_shift = i_log( frequency_force -1 ) */
  524.                 p_stream->i_keyframe_granule_shift = 0;
  525.                 i_keyframe_frequency_force--;
  526.                 while( i_keyframe_frequency_force )
  527.                 {
  528.                     p_stream->i_keyframe_granule_shift++;
  529.                     i_keyframe_frequency_force >>= 1;
  530.                 }
  531.             }
  532.         }
  533.         else if( p_stream->i_fourcc == VLC_FOURCC( 'f', 'l', 'a', 'c' ) )
  534.         {
  535.             /* flac stream marker (yeah, only that in the 1st packet) */
  536.             op.packet = "fLaC";
  537.             op.bytes  = 4;
  538.             op.b_o_s  = 1;
  539.             op.e_o_s  = 0;
  540.             op.granulepos = 0;
  541.             op.packetno = p_stream->i_packet_no++;
  542.             ogg_stream_packetin( &p_stream->os, &op );
  543.             p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
  544.         }
  545.         else if( p_stream->p_oggds_header )
  546.         {
  547.             /* ds header */
  548.             op.packet = (uint8_t*)p_stream->p_oggds_header;
  549.             op.bytes  = p_stream->p_oggds_header->i_size + 1;
  550.             op.b_o_s  = 1;
  551.             op.e_o_s  = 0;
  552.             op.granulepos = 0;
  553.             op.packetno = p_stream->i_packet_no++;
  554.             ogg_stream_packetin( &p_stream->os, &op );
  555.             p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
  556.         }
  557.         block_ChainAppend( &p_hdr, p_og );
  558.     }
  559.     /* Take care of the non b_o_s headers */
  560.     for( i = 0; i < p_mux->i_nb_inputs; i++ )
  561.     {
  562.         sout_input_t *p_input = p_mux->pp_inputs[i];
  563.         ogg_stream_t *p_stream = (ogg_stream_t*)p_input->p_sys;
  564.         if( p_stream->i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) ||
  565.             p_stream->i_fourcc == VLC_FOURCC( 's', 'p', 'x', ' ' ) ||
  566.             p_stream->i_fourcc == VLC_FOURCC( 't', 'h', 'e', 'o' ) )
  567.         {
  568.             /* Special case, headers are already there in the incoming stream.
  569.              * We need to gather them an mark them as headers. */
  570.             int j = 2;
  571.             if( p_stream->i_fourcc == VLC_FOURCC( 's', 'p', 'x', ' ' ) ) j = 1;
  572.             p_extra = p_input->p_fmt->p_extra;
  573.             i_extra = p_input->p_fmt->i_extra;
  574.             /* Skip 1 header */
  575.             op.bytes = *(p_extra++) << 8;
  576.             op.bytes |= (*(p_extra++) & 0xFF);
  577.             op.packet = p_extra;
  578.             p_extra += op.bytes;
  579.             i_extra -= (op.bytes + 2);
  580.             while( j-- )
  581.             {
  582.                 op.bytes = *(p_extra++) << 8;
  583.                 op.bytes |= (*(p_extra++) & 0xFF);
  584.                 op.packet = p_extra;
  585.                 p_extra += op.bytes;
  586.                 i_extra -= (op.bytes + 2);
  587.                 if( i_extra < 0 )
  588.                 {
  589.                     msg_Err( p_mux, "header data corrupted");
  590.                     op.bytes += i_extra;
  591.                 }
  592.                 op.b_o_s  = 0;
  593.                 op.e_o_s  = 0;
  594.                 op.granulepos = 0;
  595.                 op.packetno = p_stream->i_packet_no++;
  596.                 ogg_stream_packetin( &p_stream->os, &op );
  597.                 p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
  598.                 block_ChainAppend( &p_hdr, p_og );
  599.             }
  600.         }
  601.         else if( p_stream->i_fourcc != VLC_FOURCC( 'f', 'l', 'a', 'c' ) )
  602.         {
  603.             uint8_t com[128];
  604.             int     i_com;
  605.             /* comment */
  606.             com[0] = PACKET_TYPE_COMMENT;
  607.             i_com = snprintf( &com[1], 128, PACKAGE_VERSION" stream output" )
  608.                      + 1;
  609.             op.packet = com;
  610.             op.bytes  = i_com;
  611.             op.b_o_s  = 0;
  612.             op.e_o_s  = 0;
  613.             op.granulepos = 0;
  614.             op.packetno = p_stream->i_packet_no++;
  615.             ogg_stream_packetin( &p_stream->os, &op );
  616.             p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
  617.             block_ChainAppend( &p_hdr, p_og );
  618.         }
  619.         /* Special case for mp4v and flac */
  620.         if( ( p_stream->i_fourcc == VLC_FOURCC( 'm', 'p', '4', 'v' ) ||
  621.               p_stream->i_fourcc == VLC_FOURCC( 'f', 'l', 'a', 'c' ) ) &&
  622.             p_input->p_fmt->i_extra )
  623.         {
  624.             /* Send a packet with the VOL data for mp4v
  625.              * or STREAMINFO for flac */
  626.             msg_Dbg( p_mux, "writing extra data" );
  627.             op.bytes  = p_input->p_fmt->i_extra;
  628.             op.packet = p_input->p_fmt->p_extra;
  629.             if( p_stream->i_fourcc == VLC_FOURCC( 'f', 'l', 'a', 'c' ) )
  630.             {
  631.                 /* Skip the flac stream marker */
  632.                 op.bytes -= 4;
  633.                 op.packet+= 4;
  634.             }
  635.             op.b_o_s  = 0;
  636.             op.e_o_s  = 0;
  637.             op.granulepos = 0;
  638.             op.packetno = p_stream->i_packet_no++;
  639.             ogg_stream_packetin( &p_stream->os, &op );
  640.             p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
  641.             block_ChainAppend( &p_hdr, p_og );
  642.         }
  643.     }
  644.     /* set HEADER flag */
  645.     for( p_og = p_hdr; p_og != NULL; p_og = p_og->p_next )
  646.     {
  647.         p_og->i_flags |= BLOCK_FLAG_HEADER;
  648.     }
  649.     return p_hdr;
  650. }
  651. static block_t *OggCreateFooter( sout_mux_t *p_mux, mtime_t i_dts )
  652. {
  653.     sout_mux_sys_t *p_sys = p_mux->p_sys;
  654.     block_t *p_hdr = NULL;
  655.     block_t *p_og;
  656.     ogg_packet    op;
  657.     int i;
  658.     /* flush all remaining data */
  659.     for( i = 0; i < p_mux->i_nb_inputs; i++ )
  660.     {
  661.         ogg_stream_t *p_stream = p_mux->pp_inputs[i]->p_sys;
  662.         /* skip newly added streams */
  663.         if( p_stream->b_new ) continue;
  664.         if( ( p_og = OggStreamFlush( p_mux, &p_stream->os, 0 ) ) )
  665.         {
  666.             OggSetDate( p_og, p_stream->i_dts, p_stream->i_length );
  667.             sout_AccessOutWrite( p_mux->p_access, p_og );
  668.         }
  669.     }
  670.     /* Write eos packets for each stream. */
  671.     for( i = 0; i < p_mux->i_nb_inputs; i++ )
  672.     {
  673.         ogg_stream_t *p_stream = p_mux->pp_inputs[i]->p_sys;
  674.         /* skip newly added streams */
  675.         if( p_stream->b_new ) continue;
  676.         op.packet = NULL;
  677.         op.bytes  = 0;
  678.         op.b_o_s  = 0;
  679.         op.e_o_s  = 1;
  680.         op.granulepos = -1;
  681.         op.packetno = p_stream->i_packet_no++;
  682.         ogg_stream_packetin( &p_stream->os, &op );
  683.         p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
  684.         block_ChainAppend( &p_hdr, p_og );
  685.         ogg_stream_clear( &p_stream->os );
  686.     }
  687.     for( i = 0; i < p_sys->i_del_streams; i++ )
  688.     {
  689.         op.packet = NULL;
  690.         op.bytes  = 0;
  691.         op.b_o_s  = 0;
  692.         op.e_o_s  = 1;
  693.         op.granulepos = -1;
  694.         op.packetno = p_sys->pp_del_streams[i]->i_packet_no++;
  695.         ogg_stream_packetin( &p_sys->pp_del_streams[i]->os, &op );
  696.         p_og = OggStreamFlush( p_mux, &p_sys->pp_del_streams[i]->os, 0 );
  697.         block_ChainAppend( &p_hdr, p_og );
  698.         ogg_stream_clear( &p_sys->pp_del_streams[i]->os );
  699.     }
  700.     return p_hdr;
  701. }
  702. static void OggSetDate( block_t *p_og, mtime_t i_dts, mtime_t i_length )
  703. {
  704.     int i_count;
  705.     block_t *p_tmp;
  706.     mtime_t i_delta;
  707.     for( p_tmp = p_og, i_count = 0; p_tmp != NULL; p_tmp = p_tmp->p_next )
  708.     {
  709.         i_count++;
  710.     }
  711.     i_delta = i_length / i_count;
  712.     for( p_tmp = p_og; p_tmp != NULL; p_tmp = p_tmp->p_next )
  713.     {
  714.         p_tmp->i_dts    = i_dts;
  715.         p_tmp->i_length = i_delta;
  716.         i_dts += i_delta;
  717.     }
  718. }
  719. /*****************************************************************************
  720.  * Mux: multiplex available data in input fifos into the Ogg bitstream
  721.  *****************************************************************************/
  722. static int Mux( sout_mux_t *p_mux )
  723. {
  724.     sout_mux_sys_t *p_sys = p_mux->p_sys;
  725.     block_t        *p_og = NULL;
  726.     int            i_stream;
  727.     mtime_t        i_dts;
  728.     if( p_sys->i_add_streams || p_sys->i_del_streams )
  729.     {
  730.         /* Open new ogg stream */
  731.         if( MuxGetStream( p_mux, &i_stream, &i_dts) < 0 )
  732.         {
  733.             msg_Dbg( p_mux, "waiting for data..." );
  734.             return VLC_SUCCESS;
  735.         }
  736.         if( p_sys->i_streams )
  737.         {
  738.             /* Close current ogg stream */
  739.             int i;
  740.             msg_Dbg( p_mux, "writing footer" );
  741.             block_ChainAppend( &p_og, OggCreateFooter( p_mux, 0 ) );
  742.             /* Remove deleted logical streams */
  743.             for( i = 0; i < p_sys->i_del_streams; i++ )
  744.             {
  745.                 FREE( p_sys->pp_del_streams[i]->p_oggds_header );
  746.                 FREE( p_sys->pp_del_streams[i] );
  747.             }
  748.             FREE( p_sys->pp_del_streams );
  749.             p_sys->i_streams = 0;
  750.         }
  751.         msg_Dbg( p_mux, "writing header" );
  752.         p_sys->i_start_dts = i_dts;
  753.         p_sys->i_streams = p_mux->i_nb_inputs;
  754.         p_sys->i_del_streams = 0;
  755.         p_sys->i_add_streams = 0;
  756.         block_ChainAppend( &p_og, OggCreateHeader( p_mux, i_dts ) );
  757.         /* Write header and/or footer */
  758.         OggSetDate( p_og, i_dts, 0 );
  759.         sout_AccessOutWrite( p_mux->p_access, p_og );
  760.         p_og = NULL;
  761.     }
  762.     for( ;; )
  763.     {
  764.         if( MuxGetStream( p_mux, &i_stream, 0 ) < 0 ) return VLC_SUCCESS;
  765.         MuxBlock( p_mux, p_mux->pp_inputs[i_stream] );
  766.     }
  767.     return VLC_SUCCESS;
  768. }
  769. static int MuxBlock( sout_mux_t *p_mux, sout_input_t *p_input )
  770. {
  771.     sout_mux_sys_t *p_sys = p_mux->p_sys;
  772.     ogg_stream_t *p_stream = (ogg_stream_t*)p_input->p_sys;
  773.     block_t *p_data = block_FifoGet( p_input->p_fifo );
  774.     block_t *p_og = NULL;
  775.     ogg_packet op;
  776.     if( p_stream->i_fourcc != VLC_FOURCC( 'v', 'o', 'r', 'b' ) &&
  777.         p_stream->i_fourcc != VLC_FOURCC( 'f', 'l', 'a', 'c' ) &&
  778.         p_stream->i_fourcc != VLC_FOURCC( 's', 'p', 'x', ' ' ) &&
  779.         p_stream->i_fourcc != VLC_FOURCC( 't', 'h', 'e', 'o' ) )
  780.     {
  781.         p_data = block_Realloc( p_data, 1, p_data->i_buffer );
  782.         p_data->p_buffer[0] = PACKET_IS_SYNCPOINT;      // FIXME
  783.     }
  784.     op.packet   = p_data->p_buffer;
  785.     op.bytes    = p_data->i_buffer;
  786.     op.b_o_s    = 0;
  787.     op.e_o_s    = 0;
  788.     op.packetno = p_stream->i_packet_no++;
  789.     if( p_stream->i_cat == AUDIO_ES )
  790.     {
  791.         if( p_stream->i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) ||
  792.             p_stream->i_fourcc == VLC_FOURCC( 'f', 'l', 'a', 'c' ) ||
  793.             p_stream->i_fourcc == VLC_FOURCC( 's', 'p', 'x', ' ' ) )
  794.         {
  795.             /* number of sample from begining + current packet */
  796.             op.granulepos =
  797.                 ( p_data->i_dts - p_sys->i_start_dts + p_data->i_length ) *
  798.                 (mtime_t)p_input->p_fmt->audio.i_rate / I64C(1000000);
  799.         }
  800.         else if( p_stream->p_oggds_header )
  801.         {
  802.             /* number of sample from begining */
  803.             op.granulepos = ( p_data->i_dts - p_sys->i_start_dts ) *
  804.                 p_stream->p_oggds_header->i_samples_per_unit / I64C(1000000);
  805.         }
  806.     }
  807.     else if( p_stream->i_cat == VIDEO_ES )
  808.     {
  809.         if( p_stream->i_fourcc == VLC_FOURCC( 't', 'h', 'e', 'o' ) )
  810.         {
  811.             /* FIXME, we assume only keyframes */
  812.             op.granulepos = ( ( p_data->i_dts - p_sys->i_start_dts ) *
  813.                 p_input->p_fmt->video.i_frame_rate /
  814.                 p_input->p_fmt->video.i_frame_rate_base /
  815.                 I64C(1000000) ) << p_stream->i_keyframe_granule_shift;
  816.         }
  817.         else if( p_stream->p_oggds_header )
  818.             op.granulepos = ( p_data->i_dts - p_sys->i_start_dts ) * I64C(10) /
  819.                 p_stream->p_oggds_header->i_time_unit;
  820.     }
  821.     else if( p_stream->i_cat == SPU_ES )
  822.     {
  823.         /* granulepos is in milisec */
  824.         op.granulepos = ( p_data->i_dts - p_sys->i_start_dts ) / 1000;
  825.     }
  826.     ogg_stream_packetin( &p_stream->os, &op );
  827.     if( p_stream->i_cat == SPU_ES ||
  828.         p_stream->i_fourcc == VLC_FOURCC( 's', 'p', 'x', ' ' ) )
  829.     {
  830.         /* Subtitles or Speex packets are quite small so they 
  831.          * need to be flushed to be sent on time */
  832.         p_og = OggStreamFlush( p_mux, &p_stream->os, p_data->i_dts );
  833.     }
  834.     else
  835.     {
  836.         p_og = OggStreamPageOut( p_mux, &p_stream->os, p_data->i_dts );
  837.     }
  838.     if( p_og )
  839.     {
  840.         OggSetDate( p_og, p_stream->i_dts, p_stream->i_length );
  841.         p_stream->i_dts = -1;
  842.         p_stream->i_length = 0;
  843.         sout_AccessOutWrite( p_mux->p_access, p_og );
  844.     }
  845.     else
  846.     {
  847.         if( p_stream->i_dts < 0 )
  848.         {
  849.             p_stream->i_dts = p_data->i_dts;
  850.         }
  851.         p_stream->i_length += p_data->i_length;
  852.     }
  853.     block_Release( p_data );
  854.     return VLC_SUCCESS;
  855. }