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

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * asf.c: asf muxer module for vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2003-2004 VideoLAN
  5.  * $Id: asf.c 8888 2004-10-02 17:57:33Z zorglub $
  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 <vlc/vlc.h>
  29. #include <vlc/input.h>
  30. #include <vlc/sout.h>
  31. #include "codecs.h"
  32. typedef GUID guid_t;
  33. #define MAX_ASF_TRACKS 128
  34. /*****************************************************************************
  35.  * Module descriptor
  36.  *****************************************************************************/
  37. static int  Open   ( vlc_object_t * );
  38. static void Close  ( vlc_object_t * );
  39. #define SOUT_CFG_PREFIX "sout-asf-"
  40. #define TITLE_TEXT N_("Title")
  41. #define TITLE_LONGTEXT N_("Allows you to define the title that will be put " 
  42.                           "in ASF comments.")
  43. #define AUTHOR_TEXT N_("Author")
  44. #define AUTHOR_LONGTEXT N_("Allows you to define the author that will be put "
  45.                            "in ASF comments.")
  46. #define COPYRIGHT_TEXT N_("Copyright")
  47. #define COPYRIGHT_LONGTEXT N_("Allows you to define the copyright string " 
  48.                               "that will be put in ASF comments.")
  49. #define COMMENT_TEXT N_("Comment")
  50. #define COMMENT_LONGTEXT N_("Allows you to define the comment that will be " 
  51.                             "put in ASF comments.")
  52. #define RATING_TEXT N_("Rating")
  53. #define RATING_LONGTEXT N_("Allows you to define the "rating" that will " 
  54.                            "be put in ASF comments.")
  55. vlc_module_begin();
  56.     set_description( _("ASF muxer") );
  57.     set_capability( "sout mux", 5 );
  58.     add_shortcut( "asf" );
  59.     add_shortcut( "asfh" );
  60.     set_callbacks( Open, Close );
  61.     add_string( SOUT_CFG_PREFIX "title", "", NULL, TITLE_TEXT, TITLE_LONGTEXT,
  62.                                  VLC_TRUE );
  63.     add_string( SOUT_CFG_PREFIX "author",   "", NULL, AUTHOR_TEXT,
  64.                                  AUTHOR_LONGTEXT, VLC_TRUE );
  65.     add_string( SOUT_CFG_PREFIX "copyright","", NULL, COPYRIGHT_TEXT,
  66.                                  COPYRIGHT_LONGTEXT, VLC_TRUE );
  67.     add_string( SOUT_CFG_PREFIX "comment",  "", NULL, COMMENT_TEXT,
  68.                                  COMMENT_LONGTEXT, VLC_TRUE );
  69.     add_string( SOUT_CFG_PREFIX "rating",  "", NULL, RATING_TEXT,
  70.                                  RATING_LONGTEXT, VLC_TRUE );
  71. vlc_module_end();
  72. /*****************************************************************************
  73.  * Locales prototypes
  74.  *****************************************************************************/
  75. static const char *ppsz_sout_options[] = {
  76.     "title", "author", "copyright", "comment", "rating", NULL
  77. };
  78. static int Control  ( sout_mux_t *, int, va_list );
  79. static int AddStream( sout_mux_t *, sout_input_t * );
  80. static int DelStream( sout_mux_t *, sout_input_t * );
  81. static int Mux      ( sout_mux_t * );
  82. typedef struct
  83. {
  84.     int          i_id;
  85.     int          i_cat;
  86.     /* codec information */
  87.     uint16_t     i_tag;     /* for audio */
  88.     vlc_fourcc_t i_fourcc;  /* for video */
  89.     char         *psz_name; /* codec name */
  90.     int          i_sequence;
  91.     int          i_extra;
  92.     uint8_t      *p_extra;
  93.     es_format_t  fmt;
  94. } asf_track_t;
  95. struct sout_mux_sys_t
  96. {
  97.     guid_t          fid;    /* file id */
  98.     int             i_packet_size;
  99.     int64_t         i_packet_count;
  100.     mtime_t         i_dts_first;
  101.     mtime_t         i_dts_last;
  102.     mtime_t         i_preroll_time;
  103.     int64_t         i_bitrate;
  104.     int             i_track;
  105.     asf_track_t     track[MAX_ASF_TRACKS];
  106.     vlc_bool_t      b_write_header;
  107.     block_t         *pk;
  108.     int             i_pk_used;
  109.     int             i_pk_frame;
  110.     mtime_t         i_pk_dts;
  111.     vlc_bool_t      b_asf_http;
  112.     int             i_seq;
  113.     /* meta data */
  114.     char            *psz_title;
  115.     char            *psz_author;
  116.     char            *psz_copyright;
  117.     char            *psz_comment;
  118.     char            *psz_rating;
  119. };
  120. static int MuxGetStream( sout_mux_t *, int *pi_stream, mtime_t *pi_dts );
  121. static block_t *asf_header_create( sout_mux_t *, vlc_bool_t );
  122. static block_t *asf_packet_create( sout_mux_t *, asf_track_t *, block_t * );
  123. static block_t *asf_stream_end_create( sout_mux_t *);
  124. static block_t *asf_packet_flush( sout_mux_t * );
  125. typedef struct
  126. {
  127.     int      i_buffer_size;
  128.     int      i_buffer;
  129.     uint8_t  *p_buffer;
  130. } bo_t;
  131. static void bo_init     ( bo_t *, uint8_t *, int  );
  132. static void bo_add_u8   ( bo_t *, uint8_t  );
  133. static void bo_addle_u16( bo_t *, uint16_t );
  134. static void bo_addle_u32( bo_t *, uint32_t );
  135. static void bo_addle_u64( bo_t *, uint64_t );
  136. static void bo_add_mem  ( bo_t *, uint8_t *, int );
  137. static void bo_addle_str16( bo_t *, char * );
  138. /*****************************************************************************
  139.  * Open:
  140.  *****************************************************************************/
  141. static int Open( vlc_object_t *p_this )
  142. {
  143.     sout_mux_t     *p_mux = (sout_mux_t*)p_this;
  144.     sout_mux_sys_t *p_sys;
  145.     vlc_value_t    val;
  146.     int i;
  147.     msg_Dbg( p_mux, "Asf muxer opened" );
  148.     sout_CfgParse( p_mux, SOUT_CFG_PREFIX, ppsz_sout_options, p_mux->p_cfg );
  149.     p_mux->pf_control   = Control;
  150.     p_mux->pf_addstream = AddStream;
  151.     p_mux->pf_delstream = DelStream;
  152.     p_mux->pf_mux       = Mux;
  153.     p_mux->p_sys = p_sys = malloc( sizeof( sout_mux_sys_t ) );
  154.     p_sys->b_asf_http = p_mux->psz_mux && !strcmp( p_mux->psz_mux, "asfh" );
  155.     if( p_sys->b_asf_http )
  156.     {
  157.         msg_Dbg( p_mux, "creating asf stream to be used with mmsh" );
  158.     }
  159.     p_sys->pk = NULL;
  160.     p_sys->i_pk_used    = 0;
  161.     p_sys->i_pk_frame   = 0;
  162.     p_sys->i_dts_first  = -1;
  163.     p_sys->i_dts_last   = 0;
  164.     p_sys->i_preroll_time = 2000;
  165.     p_sys->i_bitrate    = 0;
  166.     p_sys->i_seq        = 0;
  167.     p_sys->b_write_header = VLC_TRUE;
  168.     p_sys->i_track = 0;
  169.     p_sys->i_packet_size = 4096;
  170.     p_sys->i_packet_count= 0;
  171.     /* Generate a random fid */
  172.     srand( mdate() & 0xffffffff );
  173.     p_sys->fid.Data1 = 0xbabac001;
  174.     p_sys->fid.Data2 = ( (uint64_t)rand() << 16 ) / RAND_MAX;
  175.     p_sys->fid.Data3 = ( (uint64_t)rand() << 16 ) / RAND_MAX;
  176.     for( i = 0; i < 8; i++ )
  177.     {
  178.         p_sys->fid.Data4[i] = ( (uint64_t)rand() << 8 ) / RAND_MAX;
  179.     }
  180.     /* Meta data */
  181.     var_Get( p_mux, SOUT_CFG_PREFIX "title", &val );
  182.     p_sys->psz_title = val.psz_string;
  183.     var_Get( p_mux, SOUT_CFG_PREFIX "author", &val );
  184.     p_sys->psz_author = val.psz_string;
  185.     var_Get( p_mux, SOUT_CFG_PREFIX "copyright", &val );
  186.     p_sys->psz_copyright = val.psz_string;
  187.     var_Get( p_mux, SOUT_CFG_PREFIX "comment", &val );
  188.     p_sys->psz_comment = val.psz_string;
  189.     var_Get( p_mux, SOUT_CFG_PREFIX "rating", &val );
  190.     p_sys->psz_rating = val.psz_string;
  191.     msg_Dbg( p_mux, "meta data: title='%s' author='%s' copyright='%s' "
  192.              "comment='%s' rating='%s'",
  193.              p_sys->psz_title, p_sys->psz_author, p_sys->psz_copyright,
  194.              p_sys->psz_comment, p_sys->psz_rating );
  195.     return VLC_SUCCESS;
  196. }
  197. /*****************************************************************************
  198.  * Close:
  199.  *****************************************************************************/
  200. static void Close( vlc_object_t * p_this )
  201. {
  202.     sout_mux_t     *p_mux = (sout_mux_t*)p_this;
  203.     sout_mux_sys_t *p_sys = p_mux->p_sys;
  204.     block_t  *out;
  205.     int i;
  206.     msg_Dbg( p_mux, "Asf muxer closed" );
  207.     /* Flush last packet if any */
  208.     if( (out = asf_packet_flush( p_mux ) ) )
  209.     {
  210.         sout_AccessOutWrite( p_mux->p_access, out );
  211.     }
  212.     if( ( out = asf_stream_end_create( p_mux ) ) )
  213.     {
  214.         sout_AccessOutWrite( p_mux->p_access, out );
  215.     }
  216.     /* rewrite header */
  217.     if( !sout_AccessOutSeek( p_mux->p_access, 0 ) )
  218.     {
  219.         out = asf_header_create( p_mux, VLC_FALSE );
  220.         sout_AccessOutWrite( p_mux->p_access, out );
  221.     }
  222.     for( i = 0; i < p_sys->i_track; i++ )
  223.     {
  224.         free( p_sys->track[i].p_extra );
  225.         es_format_Clean( &p_sys->track[i].fmt );
  226.     }
  227.     free( p_sys );
  228. }
  229. /*****************************************************************************
  230.  * Capability:
  231.  *****************************************************************************/
  232. static int Control( sout_mux_t *p_mux, int i_query, va_list args )
  233. {
  234.     sout_mux_sys_t *p_sys = p_mux->p_sys;
  235.     vlc_bool_t *pb_bool;
  236.     char **ppsz;
  237.     switch( i_query )
  238.     {
  239.        case MUX_CAN_ADD_STREAM_WHILE_MUXING:
  240.            pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
  241.            if( p_sys->b_asf_http ) *pb_bool = VLC_TRUE;
  242.            else *pb_bool = VLC_FALSE;
  243.            return VLC_SUCCESS;
  244.        case MUX_GET_ADD_STREAM_WAIT:
  245.            pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
  246.            *pb_bool = VLC_TRUE;
  247.            return VLC_SUCCESS;
  248.        case MUX_GET_MIME:
  249.            ppsz = (char**)va_arg( args, char ** );
  250.            if( p_sys->b_asf_http )
  251.                *ppsz = strdup( "video/x-ms-asf-stream" );
  252.            else
  253.                *ppsz = strdup( "video/x-ms-asf" );
  254.            return VLC_SUCCESS;
  255.         default:
  256.             return VLC_EGENERIC;
  257.     }
  258. }
  259. /*****************************************************************************
  260.  * AddStream:
  261.  *****************************************************************************/
  262. static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
  263. {
  264.     sout_mux_sys_t   *p_sys = p_mux->p_sys;
  265.     asf_track_t      *tk;
  266.     bo_t             bo;
  267.     msg_Dbg( p_mux, "adding input" );
  268.     if( p_sys->i_track >= MAX_ASF_TRACKS )
  269.     {
  270.         msg_Dbg( p_mux, "cannot add this track (too much track)" );
  271.         return VLC_EGENERIC;
  272.     }
  273.     tk = p_input->p_sys = &p_sys->track[p_sys->i_track];
  274.     tk->i_id  = p_sys->i_track + 1;
  275.     tk->i_cat = p_input->p_fmt->i_cat;
  276.     tk->i_sequence = 0;
  277.     switch( tk->i_cat )
  278.     {
  279.         case AUDIO_ES:
  280.         {
  281.             int i_blockalign = p_input->p_fmt->audio.i_blockalign;
  282.             int i_bitspersample = 0;
  283.             int i_extra = 0;
  284.             switch( p_input->p_fmt->i_codec )
  285.             {
  286.                 case VLC_FOURCC( 'a', '5', '2', ' ' ):
  287.                     tk->i_tag = WAVE_FORMAT_A52;
  288.                     tk->psz_name = "A/52";
  289.                     break;
  290.                 case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
  291. #if 1
  292.                     tk->psz_name = "MPEG Audio Layer 3";
  293.                     tk->i_tag = WAVE_FORMAT_MPEGLAYER3;
  294.                     i_blockalign = 1;
  295.                     i_extra = 12;
  296.                     break;
  297. #else
  298.                     tk->psz_name = "MPEG Audio Layer 1/2";
  299.                     tk->i_tag = WAVE_FORMAT_MPEG;
  300.                     i_blockalign = 1;
  301.                     i_extra = 22;
  302.                     break;
  303. #endif
  304.                 case VLC_FOURCC( 'w', 'm', 'a', '1' ):
  305.                     tk->psz_name = "Windows Media Audio 1";
  306.                     tk->i_tag = WAVE_FORMAT_WMA1;
  307.                     break;
  308.                 case VLC_FOURCC( 'w', 'm', 'a', '2' ):
  309.                     tk->psz_name = "Windows Media Audio 2";
  310.                     tk->i_tag = WAVE_FORMAT_WMA2;
  311.                     break;
  312.                 case VLC_FOURCC( 'w', 'm', 'a', '3' ):
  313.                     tk->psz_name = "Windows Media Audio 3";
  314.                     tk->i_tag = WAVE_FORMAT_WMA3;
  315.                     break;
  316.                     /* raw codec */
  317.                 case VLC_FOURCC( 'u', '8', ' ', ' ' ):
  318.                     tk->psz_name = "Raw audio 8bits";
  319.                     tk->i_tag = WAVE_FORMAT_PCM;
  320.                     i_blockalign= p_input->p_fmt->audio.i_channels;
  321.                     i_bitspersample = 8;
  322.                     break;
  323.                 case VLC_FOURCC( 's', '1', '6', 'l' ):
  324.                     tk->psz_name = "Raw audio 16bits";
  325.                     tk->i_tag = WAVE_FORMAT_PCM;
  326.                     i_blockalign= 2 * p_input->p_fmt->audio.i_channels;
  327.                     i_bitspersample = 16;
  328.                     break;
  329.                 case VLC_FOURCC( 's', '2', '4', 'l' ):
  330.                     tk->psz_name = "Raw audio 24bits";
  331.                     tk->i_tag = WAVE_FORMAT_PCM;
  332.                     i_blockalign= 3 * p_input->p_fmt->audio.i_channels;
  333.                     i_bitspersample = 24;
  334.                     break;
  335.                 case VLC_FOURCC( 's', '3', '2', 'l' ):
  336.                     tk->psz_name = "Raw audio 32bits";
  337.                     tk->i_tag = WAVE_FORMAT_PCM;
  338.                     i_blockalign= 4 * p_input->p_fmt->audio.i_channels;
  339.                     i_bitspersample = 32;
  340.                     break;
  341.                 default:
  342.                     return VLC_EGENERIC;
  343.             }
  344.             tk->i_extra = sizeof( WAVEFORMATEX ) +
  345.                           p_input->p_fmt->i_extra + i_extra;
  346.             tk->p_extra = malloc( tk->i_extra );
  347.             bo_init( &bo, tk->p_extra, tk->i_extra );
  348.             bo_addle_u16( &bo, tk->i_tag );
  349.             bo_addle_u16( &bo, p_input->p_fmt->audio.i_channels );
  350.             bo_addle_u32( &bo, p_input->p_fmt->audio.i_rate );
  351.             bo_addle_u32( &bo, p_input->p_fmt->i_bitrate / 8 );
  352.             bo_addle_u16( &bo, i_blockalign );
  353.             bo_addle_u16( &bo, i_bitspersample );
  354.             if( p_input->p_fmt->i_extra > 0 )
  355.             {
  356.                 bo_addle_u16( &bo, p_input->p_fmt->i_extra );
  357.                 bo_add_mem  ( &bo, p_input->p_fmt->p_extra,
  358.                               p_input->p_fmt->i_extra );
  359.             }
  360.             else
  361.             {
  362.                 bo_addle_u16( &bo, i_extra );
  363.                 if( tk->i_tag == WAVE_FORMAT_MPEGLAYER3 )
  364.                 {
  365.                     msg_Dbg( p_mux, "adding mp3 header" );
  366.                     bo_addle_u16( &bo, 1 );     /* wId */
  367.                     bo_addle_u32( &bo, 2 );     /* fdwFlags */
  368.                     bo_addle_u16( &bo, 1152 );  /* nBlockSize */
  369.                     bo_addle_u16( &bo, 1 );     /* nFramesPerBlock */
  370.                     bo_addle_u16( &bo, 1393 );  /* nCodecDelay */
  371.                 }
  372.                 else if( tk->i_tag == WAVE_FORMAT_MPEG )
  373.                 {
  374.                     msg_Dbg( p_mux, "adding mp2 header" );
  375.                     bo_addle_u16( &bo, 2 );     /* fwHeadLayer */
  376.                     bo_addle_u32( &bo, p_input->p_fmt->i_bitrate );
  377.                     bo_addle_u16( &bo, p_input->p_fmt->audio.i_channels == 2 ?1:8 );
  378.                     bo_addle_u16( &bo, 0 );     /* fwHeadModeExt */
  379.                     bo_addle_u16( &bo, 1 );     /* wHeadEmphasis */
  380.                     bo_addle_u16( &bo, 16 );    /* fwHeadFlags */
  381.                     bo_addle_u32( &bo, 0 );     /* dwPTSLow */
  382.                     bo_addle_u32( &bo, 0 );     /* dwPTSHigh */
  383.                 }
  384.             }
  385.             if( p_input->p_fmt->i_bitrate > 24000 )
  386.             {
  387.                 p_sys->i_bitrate += p_input->p_fmt->i_bitrate;
  388.             }
  389.             else
  390.             {
  391.                 p_sys->i_bitrate += 512000;
  392.             }
  393.             break;
  394.         }
  395.         case VIDEO_ES:
  396.         {
  397.             tk->i_extra = 11 + sizeof( BITMAPINFOHEADER ) +
  398.                           p_input->p_fmt->i_extra;
  399.             tk->p_extra = malloc( tk->i_extra );
  400.             bo_init( &bo, tk->p_extra, tk->i_extra );
  401.             bo_addle_u32( &bo, p_input->p_fmt->video.i_width );
  402.             bo_addle_u32( &bo, p_input->p_fmt->video.i_height );
  403.             bo_add_u8   ( &bo, 0x02 );  /* flags */
  404.             bo_addle_u16( &bo, sizeof( BITMAPINFOHEADER ) +
  405.                                p_input->p_fmt->i_extra );
  406.             bo_addle_u32( &bo, sizeof( BITMAPINFOHEADER ) +
  407.                                p_input->p_fmt->i_extra );
  408.             bo_addle_u32( &bo, p_input->p_fmt->video.i_width );
  409.             bo_addle_u32( &bo, p_input->p_fmt->video.i_height );
  410.             bo_addle_u16( &bo, 1 );
  411.             bo_addle_u16( &bo, 24 );
  412.             if( p_input->p_fmt->i_codec == VLC_FOURCC('m','p','4','v') )
  413.             {
  414.                 tk->psz_name = "MPEG-4 Video";
  415.                 tk->i_fourcc = VLC_FOURCC( 'M', 'P', '4', 'S' );
  416.             }
  417.             else if( p_input->p_fmt->i_codec == VLC_FOURCC('D','I','V','3') )
  418.             {
  419.                 tk->psz_name = "MSMPEG-4 V3 Video";
  420.                 tk->i_fourcc = VLC_FOURCC( 'M', 'P', '4', '3' );
  421.             }
  422.             else if( p_input->p_fmt->i_codec == VLC_FOURCC('D','I','V','2') )
  423.             {
  424.                 tk->psz_name = "MSMPEG-4 V2 Video";
  425.                 tk->i_fourcc = VLC_FOURCC( 'M', 'P', '4', '2' );
  426.             }
  427.             else if( p_input->p_fmt->i_codec == VLC_FOURCC('D','I','V','1') )
  428.             {
  429.                 tk->psz_name = "MSMPEG-4 V1 Video";
  430.                 tk->i_fourcc = VLC_FOURCC( 'M', 'P', 'G', '4' );
  431.             }
  432.             else if( p_input->p_fmt->i_codec == VLC_FOURCC('W','M','V','1') )
  433.             {
  434.                 tk->psz_name = "Windows Media Video 1";
  435.                 tk->i_fourcc = VLC_FOURCC( 'W', 'M', 'V', '1' );
  436.             }
  437.             else if( p_input->p_fmt->i_codec == VLC_FOURCC('W','M','V','2') )
  438.             {
  439.                 tk->psz_name = "Windows Media Video 2";
  440.                 tk->i_fourcc = VLC_FOURCC( 'W', 'M', 'V', '2' );
  441.             }
  442.             else if( p_input->p_fmt->i_codec == VLC_FOURCC('W','M','V','3') )
  443.             {
  444.                 tk->psz_name = "Windows Media Video 3";
  445.                 tk->i_fourcc = VLC_FOURCC( 'W', 'M', 'V', '3' );
  446.             }
  447.             else
  448.             {
  449.                 tk->psz_name = _("Unknown Video");
  450.                 tk->i_fourcc = p_input->p_fmt->i_codec;
  451.             }
  452.             bo_add_mem( &bo, (uint8_t*)&tk->i_fourcc, 4 );
  453.             bo_addle_u32( &bo, 0 );
  454.             bo_addle_u32( &bo, 0 );
  455.             bo_addle_u32( &bo, 0 );
  456.             bo_addle_u32( &bo, 0 );
  457.             bo_addle_u32( &bo, 0 );
  458.             if( p_input->p_fmt->i_extra > 0 )
  459.             {
  460.                 bo_add_mem  ( &bo, p_input->p_fmt->p_extra,
  461.                               p_input->p_fmt->i_extra );
  462.             }
  463.             if( p_input->p_fmt->i_bitrate > 50000 )
  464.             {
  465.                 p_sys->i_bitrate += p_input->p_fmt->i_bitrate;
  466.             }
  467.             else
  468.             {
  469.                 p_sys->i_bitrate += 1000000;
  470.             }
  471.             break;
  472.         }
  473.         default:
  474.             msg_Err(p_mux, "unhandled track type" );
  475.             return VLC_EGENERIC;
  476.     }
  477.     es_format_Copy( &tk->fmt, p_input->p_fmt );
  478.     p_sys->i_track++;
  479.     return VLC_SUCCESS;
  480. }
  481. /*****************************************************************************
  482.  * DelStream:
  483.  *****************************************************************************/
  484. static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
  485. {
  486.     msg_Dbg( p_mux, "removing input" );
  487.     return VLC_SUCCESS;
  488. }
  489. /*****************************************************************************
  490.  * Mux:
  491.  *****************************************************************************/
  492. static int Mux( sout_mux_t *p_mux )
  493. {
  494.     sout_mux_sys_t *p_sys = p_mux->p_sys;
  495.     if( p_sys->b_write_header )
  496.     {
  497.         block_t *out = asf_header_create( p_mux, VLC_TRUE );
  498.         out->i_flags |= BLOCK_FLAG_HEADER;
  499.         sout_AccessOutWrite( p_mux->p_access, out );
  500.         p_sys->b_write_header = VLC_FALSE;
  501.     }
  502.     for( ;; )
  503.     {
  504.         sout_input_t  *p_input;
  505.         asf_track_t   *tk;
  506.         int           i_stream;
  507.         mtime_t       i_dts;
  508.         block_t *data;
  509.         block_t *pk;
  510.         if( MuxGetStream( p_mux, &i_stream, &i_dts ) )
  511.         {
  512.             /* not enough data */
  513.             return VLC_SUCCESS;
  514.         }
  515.         if( p_sys->i_dts_first < 0 )
  516.         {
  517.             p_sys->i_dts_first = i_dts;
  518.         }
  519.         if( p_sys->i_dts_last < i_dts )
  520.         {
  521.             p_sys->i_dts_last = i_dts;
  522.         }
  523.         p_input = p_mux->pp_inputs[i_stream];
  524.         tk      = (asf_track_t*)p_input->p_sys;
  525.         data = block_FifoGet( p_input->p_fifo );
  526.         if( ( pk = asf_packet_create( p_mux, tk, data ) ) )
  527.         {
  528.             sout_AccessOutWrite( p_mux->p_access, pk );
  529.         }
  530.     }
  531.     return VLC_SUCCESS;
  532. }
  533. static int MuxGetStream( sout_mux_t *p_mux, int *pi_stream, mtime_t *pi_dts )
  534. {
  535.     mtime_t i_dts;
  536.     int     i_stream;
  537.     int     i;
  538.     for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ )
  539.     {
  540.         sout_input_t  *p_input = p_mux->pp_inputs[i];
  541.         block_t *p_data;
  542.         if( p_input->p_fifo->i_depth <= 0 )
  543.         {
  544.             if( p_input->p_fmt->i_cat == AUDIO_ES ||
  545.                 p_input->p_fmt->i_cat == VIDEO_ES )
  546.             {
  547.                 /* We need that audio+video fifo contain at least 1 packet */
  548.                 return VLC_EGENERIC;
  549.             }
  550.             /* SPU */
  551.             continue;
  552.         }
  553.         p_data = block_FifoShow( p_input->p_fifo );
  554.         if( i_stream == -1 || p_data->i_dts < i_dts )
  555.         {
  556.             i_stream = i;
  557.             i_dts    = p_data->i_dts;
  558.         }
  559.     }
  560.     *pi_stream = i_stream;
  561.     *pi_dts = i_dts;
  562.     return VLC_SUCCESS;
  563. }
  564. /****************************************************************************
  565.  * Asf header construction
  566.  ****************************************************************************/
  567. /****************************************************************************
  568.  * Buffer out
  569.  ****************************************************************************/
  570. static void bo_init( bo_t *p_bo, uint8_t *p_buffer, int i_size )
  571. {
  572.     p_bo->i_buffer_size = i_size;
  573.     p_bo->i_buffer = 0;
  574.     p_bo->p_buffer = p_buffer;
  575. }
  576. static void bo_add_u8( bo_t *p_bo, uint8_t i )
  577. {
  578.     if( p_bo->i_buffer < p_bo->i_buffer_size )
  579.     {
  580.         p_bo->p_buffer[p_bo->i_buffer] = i;
  581.     }
  582.     p_bo->i_buffer++;
  583. }
  584. static void bo_addle_u16( bo_t *p_bo, uint16_t i )
  585. {
  586.     bo_add_u8( p_bo, i &0xff );
  587.     bo_add_u8( p_bo, ( ( i >> 8) &0xff ) );
  588. }
  589. static void bo_addle_u32( bo_t *p_bo, uint32_t i )
  590. {
  591.     bo_addle_u16( p_bo, i &0xffff );
  592.     bo_addle_u16( p_bo, ( ( i >> 16) &0xffff ) );
  593. }
  594. static void bo_addle_u64( bo_t *p_bo, uint64_t i )
  595. {
  596.     bo_addle_u32( p_bo, i &0xffffffff );
  597.     bo_addle_u32( p_bo, ( ( i >> 32) &0xffffffff ) );
  598. }
  599. static void bo_add_mem( bo_t *p_bo, uint8_t *p_mem, int i_size )
  600. {
  601.     int i_copy = __MIN( i_size, p_bo->i_buffer_size - p_bo->i_buffer );
  602.     if( i_copy > 0 )
  603.     {
  604.         memcpy( &p_bo->p_buffer[p_bo->i_buffer], p_mem, i_copy );
  605.     }
  606.     p_bo->i_buffer += i_size;
  607. }
  608. static void bo_addle_str16( bo_t *bo, char *str )
  609. {
  610.     bo_addle_u16( bo, strlen( str ) + 1 );
  611.     for( ;; )
  612.     {
  613.         uint16_t c = (uint8_t)*str++;
  614.         bo_addle_u16( bo, c );
  615.         if( c == '' ) break;
  616.     }
  617. }
  618. static void bo_addle_str16_nosize( bo_t *bo, char *str )
  619. {
  620.     for( ;; )
  621.     {
  622.         uint16_t c = (uint8_t)*str++;
  623.         bo_addle_u16( bo, c );
  624.         if( c == '' ) break;
  625.     }
  626. }
  627. /****************************************************************************
  628.  * GUID definitions
  629.  ****************************************************************************/
  630. static void bo_add_guid( bo_t *p_bo, const guid_t *id )
  631. {
  632.     int i;
  633.     bo_addle_u32( p_bo, id->Data1 );
  634.     bo_addle_u16( p_bo, id->Data2 );
  635.     bo_addle_u16( p_bo, id->Data3 );
  636.     for( i = 0; i < 8; i++ )
  637.     {
  638.         bo_add_u8( p_bo, id->Data4[i] );
  639.     }
  640. }
  641. static const guid_t asf_object_header_guid =
  642. {0x75B22630, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
  643. static const guid_t asf_object_data_guid =
  644. {0x75B22636, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
  645. static const guid_t asf_object_file_properties_guid =
  646. {0x8cabdca1, 0xa947, 0x11cf, {0x8e, 0xe4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
  647. static const guid_t asf_object_stream_properties_guid =
  648. {0xB7DC0791, 0xA9B7, 0x11CF, {0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
  649. static const guid_t asf_object_header_extention_guid =
  650. {0x5FBF03B5, 0xA92E, 0x11CF, {0x8E, 0xE3, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
  651. static const guid_t asf_object_stream_type_audio =
  652. {0xF8699E40, 0x5B4D, 0x11CF, {0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}};
  653. static const guid_t asf_object_stream_type_video =
  654. {0xbc19efc0, 0x5B4D, 0x11CF, {0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}};
  655. static const guid_t asf_guid_audio_conceal_none =
  656. {0x20FB5700, 0x5B55, 0x11CF, {0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}};
  657. static const guid_t asf_guid_video_conceal_none =
  658. {0x20FB5700, 0x5B55, 0x11CF, {0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}};
  659. static const guid_t asf_guid_reserved_1 =
  660. {0xABD3D211, 0xA9BA, 0x11cf, {0x8E, 0xE6, 0x00, 0xC0, 0x0C ,0x20, 0x53, 0x65}};
  661. static const guid_t asf_object_codec_comment_guid =
  662. {0x86D15240, 0x311D, 0x11D0, {0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6}};
  663. static const guid_t asf_object_codec_comment_reserved_guid =
  664. {0x86D15241, 0x311D, 0x11D0, {0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6}};
  665. static const guid_t asf_object_content_description_guid =
  666. {0x75B22633, 0x668E, 0x11CF, {0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c}};
  667. static const guid_t asf_object_index_guid =
  668. {0x33000890, 0xE5B1, 0x11CF, {0x89, 0xF4, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xCB}};
  669. static const guid_t asf_object_metadata_guid =
  670. {0xC5F8CBEA, 0x5BAF, 0x4877, {0x84, 0x67, 0xAA, 0x8C, 0x44, 0xFA, 0x4C, 0xCA}};
  671. /****************************************************************************
  672.  * Misc
  673.  ****************************************************************************/
  674. static void asf_chunk_add( bo_t *bo,
  675.                            int i_type, int i_len, int i_flags, int i_seq )
  676. {
  677.     bo_addle_u16( bo, i_type );
  678.     bo_addle_u16( bo, i_len + 8 );
  679.     bo_addle_u32( bo, i_seq );
  680.     bo_addle_u16( bo, i_flags );
  681.     bo_addle_u16( bo, i_len + 8 );
  682. }
  683. static block_t *asf_header_create( sout_mux_t *p_mux, vlc_bool_t b_broadcast )
  684. {
  685.     sout_mux_sys_t *p_sys = p_mux->p_sys;
  686.     asf_track_t    *tk;
  687.     mtime_t i_duration = 0;
  688.     int i_size, i;
  689.     int i_ci_size, i_cm_size = 0, i_cd_size = 0;
  690.     block_t *out;
  691.     bo_t bo;
  692.     msg_Dbg( p_mux, "Asf muxer creating header" );
  693.     if( p_sys->i_dts_first > 0 )
  694.     {
  695.         i_duration = p_sys->i_dts_last - p_sys->i_dts_first;
  696.         if( i_duration < 0 ) i_duration = 0;
  697.     }
  698.     /* calculate header size */
  699.     i_size = 30 + 104 + 46;
  700.     i_ci_size = 44;
  701.     for( i = 0; i < p_sys->i_track; i++ )
  702.     {
  703.         i_size += 78 + p_sys->track[i].i_extra;
  704.         i_ci_size += 8 + 2 * strlen( p_sys->track[i].psz_name );
  705.         if( p_sys->track[i].i_cat == AUDIO_ES )
  706.         {
  707.             i_ci_size += 4;
  708.         }
  709.         else if( p_sys->track[i].i_cat == VIDEO_ES )
  710.         {
  711.             i_ci_size += 6;
  712.         }
  713.     }
  714.     /* size of the content description object */
  715.     if( *p_sys->psz_title || *p_sys->psz_author || *p_sys->psz_copyright ||
  716.         *p_sys->psz_comment || *p_sys->psz_rating )
  717.     {
  718.         i_cd_size = 34 + 2 * ( strlen( p_sys->psz_title ) + 1 +
  719.                              strlen( p_sys->psz_author ) + 1 +
  720.                              strlen( p_sys->psz_copyright ) + 1 +
  721.                              strlen( p_sys->psz_comment ) + 1 +
  722.                              strlen( p_sys->psz_rating ) + 1 );
  723.     }
  724.     /* size of the metadata object */
  725.     for( i = 0; i < p_sys->i_track; i++ )
  726.     {
  727.         if( p_sys->track[i].i_cat == VIDEO_ES )
  728.         {
  729.             i_cm_size = 26 + 2 * (16 + 2 * sizeof("AspectRatio?"));
  730.             break;
  731.         }
  732.     }
  733.     i_size += i_ci_size + i_cd_size + i_cm_size;
  734.     if( p_sys->b_asf_http )
  735.     {
  736.         out = block_New( p_mux, i_size + 50 + 12 );
  737.         bo_init( &bo, out->p_buffer, i_size + 50 + 12 );
  738.         asf_chunk_add( &bo, 0x4824, i_size + 50, 0xc00, p_sys->i_seq++ );
  739.     }
  740.     else
  741.     {
  742.         out = block_New( p_mux, i_size + 50 );
  743.         bo_init( &bo, out->p_buffer, i_size + 50 );
  744.     }
  745.     /* header object */
  746.     bo_add_guid ( &bo, &asf_object_header_guid );
  747.     bo_addle_u64( &bo, i_size );
  748.     bo_addle_u32( &bo, 2 + p_sys->i_track );
  749.     bo_add_u8   ( &bo, 1 );
  750.     bo_add_u8   ( &bo, 2 );
  751.     /* sub object */
  752.     /* file properties */
  753.     bo_add_guid ( &bo, &asf_object_file_properties_guid );
  754.     bo_addle_u64( &bo, 104 );
  755.     bo_add_guid ( &bo, &p_sys->fid );
  756.     bo_addle_u64( &bo, i_size + 50 + p_sys->i_packet_count *
  757.                                 p_sys->i_packet_size ); /* file size */
  758.     bo_addle_u64( &bo, 0 );                 /* creation date */
  759.     bo_addle_u64( &bo, b_broadcast ? 0xffffffffLL : p_sys->i_packet_count );
  760.     bo_addle_u64( &bo, i_duration * 10 );   /* play duration (100ns) */
  761.     bo_addle_u64( &bo, i_duration * 10 );   /* send duration (100ns) */
  762.     bo_addle_u64( &bo, p_sys->i_preroll_time ); /* preroll duration (ms) */
  763.     bo_addle_u32( &bo, b_broadcast ? 0x01 : 0x00);      /* flags */
  764.     bo_addle_u32( &bo, p_sys->i_packet_size );  /* packet size min */
  765.     bo_addle_u32( &bo, p_sys->i_packet_size );  /* packet size max */
  766.     bo_addle_u32( &bo, p_sys->i_bitrate );      /* maxbitrate */
  767.     /* header extention */
  768.     bo_add_guid ( &bo, &asf_object_header_extention_guid );
  769.     bo_addle_u64( &bo, 46 + i_cm_size );
  770.     bo_add_guid ( &bo, &asf_guid_reserved_1 );
  771.     bo_addle_u16( &bo, 6 );
  772.     bo_addle_u32( &bo, 0 + i_cm_size );
  773.     /* metadata object (part of header extension) */
  774.     if( i_cm_size )
  775.     {
  776.         int64_t i_num, i_den;
  777.         int i_dst_num, i_dst_den;
  778.         for( i = 0; i < p_sys->i_track; i++ )
  779.             if( p_sys->track[i].i_cat == VIDEO_ES ) break;
  780.         i_num = p_sys->track[i].fmt.video.i_aspect *
  781.             (int64_t)p_sys->track[i].fmt.video.i_height;
  782.         i_den = VOUT_ASPECT_FACTOR * p_sys->track[i].fmt.video.i_width;
  783.         vlc_reduce( &i_dst_num, &i_dst_den, i_num, i_den, 0 );
  784.         msg_Dbg( p_mux, "pixel aspect-ratio: %i/%i", i_dst_num, i_dst_den );
  785.         bo_add_guid ( &bo, &asf_object_metadata_guid );
  786.         bo_addle_u64( &bo, i_cm_size );
  787.         bo_addle_u16( &bo, 2 ); /* description records count */
  788.         /* 1st description record */
  789.         bo_addle_u16( &bo, 0 ); /* reserved */
  790.         bo_addle_u16( &bo, i + 1 ); /* stream number (0 for the whole file) */
  791.         bo_addle_u16( &bo, 2 * sizeof("AspectRatioX") ); /* name length */
  792.         bo_addle_u16( &bo, 0x3 /* DWORD */ ); /* data type */
  793.         bo_addle_u32( &bo, 4 ); /* data length */
  794.         bo_addle_str16_nosize( &bo, "AspectRatioX" );
  795.         bo_addle_u32( &bo, i_dst_num ); /* data */
  796.         /* 2nd description record */
  797.         bo_addle_u16( &bo, 0 ); /* reserved */
  798.         bo_addle_u16( &bo, i + 1 ); /* stream number (0 for the whole file) */
  799.         bo_addle_u16( &bo, 2 * sizeof("AspectRatioY") ); /* name length */
  800.         bo_addle_u16( &bo, 0x3 /* DWORD */ ); /* data type */
  801.         bo_addle_u32( &bo, 4 ); /* data length */
  802.         bo_addle_str16_nosize( &bo, "AspectRatioY" );
  803.         bo_addle_u32( &bo, i_dst_den ); /* data */
  804.     }
  805.     /* content description header */
  806.     if( i_cd_size > 0 )
  807.     {
  808.         bo_add_guid ( &bo, &asf_object_content_description_guid );
  809.         bo_addle_u64( &bo, i_cd_size );
  810.         bo_addle_u16( &bo, 2 * strlen( p_sys->psz_title ) + 2 );
  811.         bo_addle_u16( &bo, 2 * strlen( p_sys->psz_author ) + 2 );
  812.         bo_addle_u16( &bo, 2 * strlen( p_sys->psz_copyright ) + 2 );
  813.         bo_addle_u16( &bo, 2 * strlen( p_sys->psz_comment ) + 2 );
  814.         bo_addle_u16( &bo, 2 * strlen( p_sys->psz_rating ) + 2 );
  815.         bo_addle_str16_nosize( &bo, p_sys->psz_title );
  816.         bo_addle_str16_nosize( &bo, p_sys->psz_author );
  817.         bo_addle_str16_nosize( &bo, p_sys->psz_copyright );
  818.         bo_addle_str16_nosize( &bo, p_sys->psz_comment );
  819.         bo_addle_str16_nosize( &bo, p_sys->psz_rating );
  820.     }
  821.     /* stream properties */
  822.     for( i = 0; i < p_sys->i_track; i++ )
  823.     {
  824.         tk = &p_sys->track[i];
  825.         bo_add_guid ( &bo, &asf_object_stream_properties_guid );
  826.         bo_addle_u64( &bo, 78 + tk->i_extra );
  827.         if( tk->i_cat == AUDIO_ES )
  828.         {
  829.             bo_add_guid( &bo, &asf_object_stream_type_audio );
  830.             bo_add_guid( &bo, &asf_guid_audio_conceal_none );
  831.         }
  832.         else if( tk->i_cat == VIDEO_ES )
  833.         {
  834.             bo_add_guid( &bo, &asf_object_stream_type_video );
  835.             bo_add_guid( &bo, &asf_guid_video_conceal_none );
  836.         }
  837.         bo_addle_u64( &bo, 0 );         /* time offset */
  838.         bo_addle_u32( &bo, tk->i_extra );
  839.         bo_addle_u32( &bo, 0 );         /* 0 */
  840.         bo_addle_u16( &bo, tk->i_id );  /* stream number */
  841.         bo_addle_u32( &bo, 0 );
  842.         bo_add_mem  ( &bo, tk->p_extra, tk->i_extra );
  843.     }
  844.     /* Codec Infos */
  845.     bo_add_guid ( &bo, &asf_object_codec_comment_guid );
  846.     bo_addle_u64( &bo, i_ci_size );
  847.     bo_add_guid ( &bo, &asf_object_codec_comment_reserved_guid );
  848.     bo_addle_u32( &bo, p_sys->i_track );
  849.     for( i = 0; i < p_sys->i_track; i++ )
  850.     {
  851.         tk = &p_sys->track[i];
  852.         bo_addle_u16( &bo, tk->i_id );
  853.         bo_addle_str16( &bo, tk->psz_name );
  854.         bo_addle_u16( &bo, 0 );
  855.         if( tk->i_cat == AUDIO_ES )
  856.         {
  857.             bo_addle_u16( &bo, 2 );
  858.             bo_addle_u16( &bo, tk->i_tag );
  859.         }
  860.         else if( tk->i_cat == VIDEO_ES )
  861.         {
  862.             bo_addle_u16( &bo, 4 );
  863.             bo_add_mem  ( &bo, (uint8_t*)&tk->i_fourcc, 4 );
  864.         }
  865.     }
  866.     /* data object */
  867.     bo_add_guid ( &bo, &asf_object_data_guid );
  868.     bo_addle_u64( &bo, 50 + p_sys->i_packet_count * p_sys->i_packet_size );
  869.     bo_add_guid ( &bo, &p_sys->fid );
  870.     bo_addle_u64( &bo, p_sys->i_packet_count );
  871.     bo_addle_u16( &bo, 0x101 );
  872.     return out;
  873. }
  874. /****************************************************************************
  875.  *
  876.  ****************************************************************************/
  877. static block_t *asf_packet_flush( sout_mux_t *p_mux )
  878. {
  879.     sout_mux_sys_t *p_sys = p_mux->p_sys;
  880.     int i_pad, i_preheader = p_sys->b_asf_http ? 12 : 0;
  881.     block_t *pk;
  882.     bo_t bo;
  883.     if( !p_sys->pk ) return 0;
  884.     i_pad = p_sys->i_packet_size - p_sys->i_pk_used;
  885.     memset( p_sys->pk->p_buffer + p_sys->i_pk_used, 0, i_pad );
  886.     bo_init( &bo, p_sys->pk->p_buffer, 14 + i_preheader );
  887.     if( p_sys->b_asf_http )
  888.         asf_chunk_add( &bo, 0x4424, p_sys->i_packet_size, 0x0, p_sys->i_seq++);
  889.     bo_add_u8   ( &bo, 0x82 );
  890.     bo_addle_u16( &bo, 0 );
  891.     bo_add_u8( &bo, 0x11 );
  892.     bo_add_u8( &bo, 0x5d );
  893.     bo_addle_u16( &bo, i_pad );
  894.     bo_addle_u32( &bo, (p_sys->i_pk_dts - p_sys->i_dts_first) / 1000 +
  895.                   p_sys->i_preroll_time );
  896.     bo_addle_u16( &bo, 0 /* data->i_length */ );
  897.     bo_add_u8( &bo, 0x80 | p_sys->i_pk_frame );
  898.     pk = p_sys->pk;
  899.     p_sys->pk = NULL;
  900.     p_sys->i_packet_count++;
  901.     return pk;
  902. }
  903. static block_t *asf_packet_create( sout_mux_t *p_mux,
  904.                                    asf_track_t *tk, block_t *data )
  905. {
  906.     sout_mux_sys_t *p_sys = p_mux->p_sys;
  907.     int     i_data = data->i_buffer;
  908.     int     i_pos  = 0;
  909.     uint8_t *p_data= data->p_buffer;
  910.     block_t *first = NULL, **last = &first;
  911.     int     i_preheader = p_sys->b_asf_http ? 12 : 0;
  912.     while( i_pos < i_data )
  913.     {
  914.         bo_t bo;
  915.         int i_payload;
  916.         if( p_sys->pk == NULL )
  917.         {
  918.             p_sys->pk = block_New( p_mux, p_sys->i_packet_size + i_preheader );
  919.             /* reserve 14 bytes for the packet header */
  920.             p_sys->i_pk_used = 14 + i_preheader;
  921.             p_sys->i_pk_frame = 0;
  922.             p_sys->i_pk_dts = data->i_dts;
  923.         }
  924.         bo_init( &bo, &p_sys->pk->p_buffer[p_sys->i_pk_used],
  925.                  p_sys->i_packet_size - p_sys->i_pk_used );
  926.         /* add payload (header size = 17) */
  927.         i_payload = __MIN( i_data - i_pos,
  928.                            p_sys->i_packet_size - p_sys->i_pk_used - 17 );
  929.         bo_add_u8   ( &bo, !(data->i_flags & BLOCK_FLAG_TYPE_P ||
  930.                       data->i_flags & BLOCK_FLAG_TYPE_B) ?
  931.                       0x80 | tk->i_id : tk->i_id );
  932.         bo_add_u8   ( &bo, tk->i_sequence );
  933.         bo_addle_u32( &bo, i_pos );
  934.         bo_add_u8   ( &bo, 0x08 );  /* flags */
  935.         bo_addle_u32( &bo, i_data );
  936.         bo_addle_u32( &bo, (data->i_dts - p_sys->i_dts_first) / 1000 +
  937.                       p_sys->i_preroll_time );
  938.         bo_addle_u16( &bo, i_payload );
  939.         bo_add_mem  ( &bo, &p_data[i_pos], i_payload );
  940.         i_pos += i_payload;
  941.         p_sys->i_pk_used += 17 + i_payload;
  942.         p_sys->i_pk_frame++;
  943.         if( p_sys->i_pk_used + 17 >= p_sys->i_packet_size )
  944.         {
  945.             /* Not enough data for another payload, flush the packet */
  946.             *last = asf_packet_flush( p_mux );
  947.             last  = &(*last)->p_next;
  948.         }
  949.     }
  950.     tk->i_sequence++;
  951.     block_Release( data );
  952.     return first;
  953. }
  954. static block_t *asf_stream_end_create( sout_mux_t *p_mux )
  955. {
  956.     sout_mux_sys_t *p_sys = p_mux->p_sys;
  957.     block_t *out = NULL;
  958.     bo_t bo;
  959.     if( p_sys->b_asf_http )
  960.     {
  961.         out = block_New( p_mux, 12 );
  962.         bo_init( &bo, out->p_buffer, 12 );
  963.         asf_chunk_add( &bo, 0x4524, 0, 0x00, p_sys->i_seq++ );
  964.     }
  965.     else
  966.     {
  967.         /* Create index */
  968.         out = block_New( p_mux, 56 );
  969.         bo_init( &bo, out->p_buffer, 56 );
  970.         bo_add_guid ( &bo, &asf_object_index_guid );
  971.         bo_addle_u64( &bo, 56 );
  972.         bo_add_guid ( &bo, &p_sys->fid );
  973.         bo_addle_u64( &bo, 10000000 );
  974.         bo_addle_u32( &bo, 5 );
  975.         bo_addle_u32( &bo, 0 );
  976.     }
  977.     return out;
  978. }