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

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * avi.c
  3.  *****************************************************************************
  4.  * Copyright (C) 2001, 2002 VideoLAN
  5.  * $Id: avi.c 8373 2004-08-04 20:09:31Z fenrir $
  6.  *
  7.  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 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 General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. /* TODO: add OpenDML write support */
  27. #include <stdlib.h>
  28. #include <vlc/vlc.h>
  29. #include <vlc/input.h>
  30. #include <vlc/sout.h>
  31. #include "codecs.h"
  32. /*****************************************************************************
  33.  * Module descriptor
  34.  *****************************************************************************/
  35. static int  Open   ( vlc_object_t * );
  36. static void Close  ( vlc_object_t * );
  37. vlc_module_begin();
  38.     set_description( _("AVI muxer") );
  39.     set_capability( "sout mux", 5 );
  40.     add_shortcut( "avi" );
  41.     set_callbacks( Open, Close );
  42. vlc_module_end();
  43. /*****************************************************************************
  44.  * Local prototypes
  45.  *****************************************************************************/
  46. static int Control( sout_mux_t *, int, va_list );
  47. static int AddStream( sout_mux_t *, sout_input_t * );
  48. static int DelStream( sout_mux_t *, sout_input_t * );
  49. static int Mux      ( sout_mux_t * );
  50. typedef struct avi_stream_s
  51. {
  52.     int i_cat;
  53.     char fcc[4];
  54.     mtime_t i_duration;       // in 祍
  55.     int     i_frames;        // total frame count
  56.     int64_t i_totalsize;    // total stream size
  57.     float   f_fps;
  58.     int     i_bitrate;
  59.     BITMAPINFOHEADER    *p_bih;
  60.     WAVEFORMATEX        *p_wf;
  61. } avi_stream_t;
  62. typedef struct avi_idx1_entry_s
  63. {
  64.     char     fcc[4];
  65.     uint32_t i_flags;
  66.     uint32_t i_pos;
  67.     uint32_t i_length;
  68. } avi_idx1_entry_t;
  69. typedef struct avi_idx1_s
  70. {
  71.     unsigned int i_entry_count;
  72.     unsigned int i_entry_max;
  73.     avi_idx1_entry_t *entry;
  74. } avi_idx1_t;
  75. struct sout_mux_sys_t
  76. {
  77.     vlc_bool_t b_write_header;
  78.     int i_streams;
  79.     int i_stream_video;
  80.     off_t i_movi_size;
  81.     avi_stream_t stream[100];
  82.     avi_idx1_t idx1;
  83.     off_t i_idx1_size;
  84. };
  85. // FIXME FIXME
  86. #define HDR_SIZE 10240
  87. /* Flags in avih */
  88. #define AVIF_HASINDEX       0x00000010  // Index at end of file?
  89. #define AVIF_ISINTERLEAVED  0x00000100
  90. #define AVIF_TRUSTCKTYPE    0x00000800  // Use CKType to find key frames?
  91. /* Flags for index */
  92. #define AVIIF_KEYFRAME      0x00000010L /* this frame is a key frame.*/
  93. static block_t *avi_HeaderCreateRIFF( sout_mux_t * );
  94. static block_t *avi_HeaderCreateidx1( sout_mux_t * );
  95. static void SetFCC( uint8_t *p, char *fcc )
  96. {
  97.     memcpy( p, fcc, 4 );
  98. }
  99. /*****************************************************************************
  100.  * Open:
  101.  *****************************************************************************/
  102. static int Open( vlc_object_t *p_this )
  103. {
  104.     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
  105.     sout_mux_sys_t  *p_sys = p_mux->p_sys;
  106.     msg_Dbg( p_mux, "AVI muxer opened" );
  107.     p_sys = malloc( sizeof( sout_mux_sys_t ) );
  108.     p_sys->i_streams = 0;
  109.     p_sys->i_stream_video = -1;
  110.     p_sys->i_movi_size = 0;
  111.     p_sys->idx1.i_entry_count = 0;
  112.     p_sys->idx1.i_entry_max = 10000;
  113.     p_sys->idx1.entry = calloc( p_sys->idx1.i_entry_max,
  114.                                 sizeof( avi_idx1_entry_t ) );
  115.     p_sys->b_write_header = VLC_TRUE;
  116.     p_mux->pf_control   = Control;
  117.     p_mux->pf_addstream = AddStream;
  118.     p_mux->pf_delstream = DelStream;
  119.     p_mux->pf_mux       = Mux;
  120.     p_mux->p_sys        = p_sys;
  121.     return VLC_SUCCESS;
  122. }
  123. /*****************************************************************************
  124.  * Close:
  125.  *****************************************************************************/
  126. static void Close( vlc_object_t * p_this )
  127. {
  128.     sout_mux_t      *p_mux = (sout_mux_t*)p_this;
  129.     sout_mux_sys_t  *p_sys = p_mux->p_sys;
  130.     block_t       *p_hdr, *p_idx1;
  131.     int                 i_stream;
  132.     msg_Dbg( p_mux, "AVI muxer closed" );
  133.     /* first create idx1 chunk (write at the end of the stream */
  134.     p_idx1 = avi_HeaderCreateidx1( p_mux );
  135.     p_sys->i_idx1_size = p_idx1->i_buffer;
  136.     sout_AccessOutWrite( p_mux->p_access, p_idx1 );
  137.     /* calculate some value for headers creations */
  138.     for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
  139.     {
  140.         avi_stream_t *p_stream;
  141.         p_stream = &p_sys->stream[i_stream];
  142.         p_stream->f_fps = 25;
  143.         if( p_stream->i_duration > 0 )
  144.         {
  145.             p_stream->f_fps = (float)p_stream->i_frames /
  146.                               ( (float)p_stream->i_duration /
  147.                                 (float)1000000 );
  148.         }
  149.         p_stream->i_bitrate = 128 * 1024;
  150.         if( p_stream->i_duration > 0 )
  151.         {
  152.             p_stream->i_bitrate =
  153.                 8 * (uint64_t)1000000 *
  154.                     (uint64_t)p_stream->i_totalsize /
  155.                     (uint64_t)p_stream->i_duration;
  156.         }
  157.         msg_Info( p_mux, "stream[%d] duration:"I64Fd" totalsize:"I64Fd
  158.                   " frames:%d fps:%f kb/s:%d",
  159.                   i_stream,
  160.                   (int64_t)p_stream->i_duration / (int64_t)1000000,
  161.                   p_stream->i_totalsize,
  162.                   p_stream->i_frames,
  163.                   p_stream->f_fps, p_stream->i_bitrate/1024 );
  164.     }
  165.     p_hdr = avi_HeaderCreateRIFF( p_mux );
  166.     sout_AccessOutSeek( p_mux->p_access, 0 );
  167.     sout_AccessOutWrite( p_mux->p_access, p_hdr );
  168. }
  169. static int Control( sout_mux_t *p_mux, int i_query, va_list args )
  170. {
  171.     vlc_bool_t *pb_bool;
  172.     char **ppsz;
  173.    switch( i_query )
  174.    {
  175.        case MUX_CAN_ADD_STREAM_WHILE_MUXING:
  176.            pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
  177.            *pb_bool = VLC_FALSE;
  178.            return VLC_SUCCESS;
  179.        case MUX_GET_ADD_STREAM_WAIT:
  180.            pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
  181.            *pb_bool = VLC_TRUE;
  182.            return VLC_SUCCESS;
  183.        case MUX_GET_MIME:
  184.            ppsz = (char**)va_arg( args, char ** );
  185.            *ppsz = strdup( "video/avi" );
  186.            return VLC_SUCCESS;
  187.         default:
  188.             return VLC_EGENERIC;
  189.    }
  190. }
  191. static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
  192. {
  193.     sout_mux_sys_t  *p_sys = p_mux->p_sys;
  194.     avi_stream_t    *p_stream;
  195.     if( p_sys->i_streams >= 100 )
  196.     {
  197.         msg_Err( p_mux, "too many streams" );
  198.         return( -1 );
  199.     }
  200.     msg_Dbg( p_mux, "adding input" );
  201.     p_input->p_sys = malloc( sizeof( int ) );
  202.     *((int*)p_input->p_sys) = p_sys->i_streams;
  203.     p_stream = &p_sys->stream[p_sys->i_streams];
  204.     switch( p_input->p_fmt->i_cat )
  205.     {
  206.         case AUDIO_ES:
  207.             p_stream->i_cat = AUDIO_ES;
  208.             p_stream->fcc[0] = '0' + p_sys->i_streams / 10;
  209.             p_stream->fcc[1] = '0' + p_sys->i_streams % 10;
  210.             p_stream->fcc[2] = 'w';
  211.             p_stream->fcc[3] = 'b';
  212.             p_stream->p_bih = NULL;
  213.             p_stream->p_wf  = malloc( sizeof( WAVEFORMATEX ) +
  214.                                       p_input->p_fmt->i_extra );
  215. #define p_wf p_stream->p_wf
  216.             p_wf->cbSize = p_input->p_fmt->i_extra;
  217.             if( p_wf->cbSize > 0 )
  218.             {
  219.                 memcpy( &p_wf[1],
  220.                         p_input->p_fmt->p_extra,
  221.                         p_input->p_fmt->i_extra );
  222.             }
  223.             p_wf->nChannels      = p_input->p_fmt->audio.i_channels;
  224.             p_wf->nSamplesPerSec = p_input->p_fmt->audio.i_rate;
  225.             p_wf->nBlockAlign    = p_input->p_fmt->audio.i_blockalign;
  226.             p_wf->nAvgBytesPerSec= p_input->p_fmt->i_bitrate / 8;
  227.             p_wf->wBitsPerSample = 0;
  228.             switch( p_input->p_fmt->i_codec )
  229.             {
  230.                 case VLC_FOURCC( 'a', '5', '2', ' ' ):
  231.                     p_wf->wFormatTag = WAVE_FORMAT_A52;
  232.                     break;
  233.                 case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
  234.                     p_wf->wFormatTag = WAVE_FORMAT_MPEGLAYER3;
  235.                     break;
  236.                 case VLC_FOURCC( 'w', 'm', 'a', '1' ):
  237.                     p_wf->wFormatTag = WAVE_FORMAT_WMA1;
  238.                     break;
  239.                 case VLC_FOURCC( 'w', 'm', 'a', '2' ):
  240.                     p_wf->wFormatTag = WAVE_FORMAT_WMA2;
  241.                     break;
  242.                 case VLC_FOURCC( 'w', 'm', 'a', '3' ):
  243.                     p_wf->wFormatTag = WAVE_FORMAT_WMA3;
  244.                     break;
  245.                     /* raw codec */
  246.                 case VLC_FOURCC( 'u', '8', ' ', ' ' ):
  247.                     p_wf->wFormatTag = WAVE_FORMAT_PCM;
  248.                     p_wf->nBlockAlign= p_wf->nChannels;
  249.                     p_wf->wBitsPerSample = 8;
  250.                     break;
  251.                 case VLC_FOURCC( 's', '1', '6', 'l' ):
  252.                     p_wf->wFormatTag = WAVE_FORMAT_PCM;
  253.                     p_wf->nBlockAlign= 2 * p_wf->nChannels;
  254.                     p_wf->wBitsPerSample = 16;
  255.                     break;
  256.                 case VLC_FOURCC( 's', '2', '4', 'l' ):
  257.                     p_wf->wFormatTag = WAVE_FORMAT_PCM;
  258.                     p_wf->nBlockAlign= 3 * p_wf->nChannels;
  259.                     p_wf->wBitsPerSample = 24;
  260.                     break;
  261.                 case VLC_FOURCC( 's', '3', '2', 'l' ):
  262.                     p_wf->wFormatTag = WAVE_FORMAT_PCM;
  263.                     p_wf->nBlockAlign= 4 * p_wf->nChannels;
  264.                     p_wf->wBitsPerSample = 32;
  265.                     break;
  266.                 default:
  267.                     return VLC_EGENERIC;
  268.             }
  269. #undef p_wf
  270.             break;
  271.         case VIDEO_ES:
  272.             p_stream->i_cat = VIDEO_ES;
  273.             p_stream->fcc[0] = '0' + p_sys->i_streams / 10;
  274.             p_stream->fcc[1] = '0' + p_sys->i_streams % 10;
  275.             p_stream->fcc[2] = 'd';
  276.             p_stream->fcc[3] = 'c';
  277.             if( p_sys->i_stream_video < 0 )
  278.             {
  279.                 p_sys->i_stream_video = p_sys->i_streams;
  280.             }
  281.             p_stream->p_wf  = NULL;
  282.             p_stream->p_bih = malloc( sizeof( BITMAPINFOHEADER ) +
  283.                                       p_input->p_fmt->i_extra );
  284. #define p_bih p_stream->p_bih
  285.             p_bih->biSize  = sizeof( BITMAPINFOHEADER ) +
  286.                              p_input->p_fmt->i_extra;
  287.             if( p_input->p_fmt->i_extra > 0 )
  288.             {
  289.                 memcpy( &p_bih[1],
  290.                         p_input->p_fmt->p_extra,
  291.                         p_input->p_fmt->i_extra );
  292.             }
  293.             p_bih->biWidth = p_input->p_fmt->video.i_width;
  294.             p_bih->biHeight= p_input->p_fmt->video.i_height;
  295.             p_bih->biPlanes= 1;
  296.             p_bih->biBitCount       = 24;
  297.             p_bih->biSizeImage      = 0;
  298.             p_bih->biXPelsPerMeter  = 0;
  299.             p_bih->biYPelsPerMeter  = 0;
  300.             p_bih->biClrUsed        = 0;
  301.             p_bih->biClrImportant   = 0;
  302.             switch( p_input->p_fmt->i_codec )
  303.             {
  304.                 case VLC_FOURCC( 'm', 'p', '4', 'v' ):
  305.                     p_bih->biCompression = VLC_FOURCC( 'X', 'V', 'I', 'D' );
  306.                     break;
  307.                 default:
  308.                     p_bih->biCompression = p_input->p_fmt->i_codec;
  309.                     break;
  310.             }
  311. #undef p_bih
  312.             break;
  313.         default:
  314.             return( VLC_EGENERIC );
  315.     }
  316.     p_stream->i_totalsize = 0;
  317.     p_stream->i_frames    = 0;
  318.     p_stream->i_duration  = 0;
  319.     /* fixed later */
  320.     p_stream->f_fps = 25;
  321.     p_stream->i_bitrate = 128 * 1024;
  322.     p_sys->i_streams++;
  323.     return( VLC_SUCCESS );
  324. }
  325. static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
  326. {
  327.     msg_Dbg( p_mux, "removing input" );
  328.     free( p_input->p_sys );
  329.     return( 0 );
  330. }
  331. static int Mux      ( sout_mux_t *p_mux )
  332. {
  333.     sout_mux_sys_t  *p_sys = p_mux->p_sys;
  334.     avi_stream_t    *p_stream;
  335.     int i_stream;
  336.     int i;
  337.     if( p_sys->b_write_header )
  338.     {
  339.         block_t *p_hdr;
  340.         msg_Dbg( p_mux, "writing header" );
  341.         p_hdr = avi_HeaderCreateRIFF( p_mux );
  342.         sout_AccessOutWrite( p_mux->p_access, p_hdr );
  343.         p_sys->b_write_header = VLC_FALSE;
  344.     }
  345.     for( i = 0; i < p_mux->i_nb_inputs; i++ )
  346.     {
  347.         int i_count;
  348.         block_fifo_t *p_fifo;
  349.         i_stream = *((int*)p_mux->pp_inputs[i]->p_sys );
  350.         p_stream = &p_sys->stream[i_stream];
  351.         p_fifo = p_mux->pp_inputs[i]->p_fifo;
  352.         i_count = p_fifo->i_depth;
  353.         while( i_count > 1 )
  354.         {
  355.             avi_idx1_entry_t *p_idx;
  356.             block_t *p_data;
  357.             p_data = block_FifoGet( p_fifo );
  358.             if( p_fifo->i_depth > 0 )
  359.             {
  360.                 block_t *p_next = block_FifoShow( p_fifo );
  361.                 p_data->i_length = p_next->i_dts - p_data->i_dts;
  362.             }
  363.             p_stream->i_frames++;
  364.             if( p_data->i_length < 0 )
  365.             {
  366.                 msg_Warn( p_mux, "argg length < 0 l" );
  367.                 block_Release( p_data );
  368.                 i_count--;
  369.                 continue;
  370.             }
  371.             p_stream->i_duration  += p_data->i_length;
  372.             p_stream->i_totalsize += p_data->i_buffer;
  373.             /* add idx1 entry for this frame */
  374.             p_idx = &p_sys->idx1.entry[p_sys->idx1.i_entry_count];
  375.             memcpy( p_idx->fcc, p_stream->fcc, 4 );
  376.             p_idx->i_flags = AVIIF_KEYFRAME;
  377.             p_idx->i_pos   = p_sys->i_movi_size + 4;
  378.             p_idx->i_length= p_data->i_buffer;
  379.             p_sys->idx1.i_entry_count++;
  380.             if( p_sys->idx1.i_entry_count >= p_sys->idx1.i_entry_max )
  381.             {
  382.                 p_sys->idx1.i_entry_max += 10000;
  383.                 p_sys->idx1.entry = realloc( p_sys->idx1.entry,
  384.                                              p_sys->idx1.i_entry_max * sizeof( avi_idx1_entry_t ) );
  385.             }
  386.             p_data = block_Realloc( p_data, 8, p_data->i_buffer );
  387.             if( p_data )
  388.             {
  389.                 SetFCC( p_data->p_buffer, p_stream->fcc );
  390.                 SetDWLE( p_data->p_buffer + 4, p_data->i_buffer - 8 );
  391.                 if( p_data->i_buffer & 0x01 )
  392.                 {
  393.                     p_data = block_Realloc( p_data, 0, p_data->i_buffer + 1 );
  394.                 }
  395.                 p_sys->i_movi_size += p_data->i_buffer;
  396.                 sout_AccessOutWrite( p_mux->p_access, p_data );
  397.             }
  398.             i_count--;
  399.         }
  400.     }
  401.     return( 0 );
  402. }
  403. /****************************************************************************/
  404. /****************************************************************************/
  405. /****************************************************************************/
  406. /****************************************************************************/
  407. typedef struct buffer_out_s
  408. {
  409.     int      i_buffer_size;
  410.     int      i_buffer;
  411.     uint8_t  *p_buffer;
  412. } buffer_out_t;
  413. static void bo_Init( buffer_out_t *p_bo, int i_size, uint8_t *p_buffer )
  414. {
  415.     p_bo->i_buffer_size = i_size;
  416.     p_bo->i_buffer = 0;
  417.     p_bo->p_buffer = p_buffer;
  418. }
  419. static void bo_AddByte( buffer_out_t *p_bo, uint8_t i )
  420. {
  421.     if( p_bo->i_buffer < p_bo->i_buffer_size )
  422.     {
  423.         p_bo->p_buffer[p_bo->i_buffer] = i;
  424.     }
  425.     p_bo->i_buffer++;
  426. }
  427. static void bo_AddWordLE( buffer_out_t *p_bo, uint16_t i )
  428. {
  429.     bo_AddByte( p_bo, i &0xff );
  430.     bo_AddByte( p_bo, ( ( i >> 8) &0xff ) );
  431. }
  432. static void bo_AddWordBE( buffer_out_t *p_bo, uint16_t i )
  433. {
  434.     bo_AddByte( p_bo, ( ( i >> 8) &0xff ) );
  435.     bo_AddByte( p_bo, i &0xff );
  436. }
  437. static void bo_AddDWordLE( buffer_out_t *p_bo, uint32_t i )
  438. {
  439.     bo_AddWordLE( p_bo, i &0xffff );
  440.     bo_AddWordLE( p_bo, ( ( i >> 16) &0xffff ) );
  441. }
  442. static void bo_AddDWordBE( buffer_out_t *p_bo, uint32_t i )
  443. {
  444.     bo_AddWordBE( p_bo, ( ( i >> 16) &0xffff ) );
  445.     bo_AddWordBE( p_bo, i &0xffff );
  446. }
  447. #if 0
  448. static void bo_AddLWordLE( buffer_out_t *p_bo, uint64_t i )
  449. {
  450.     bo_AddDWordLE( p_bo, i &0xffffffff );
  451.     bo_AddDWordLE( p_bo, ( ( i >> 32) &0xffffffff ) );
  452. }
  453. static void bo_AddLWordBE( buffer_out_t *p_bo, uint64_t i )
  454. {
  455.     bo_AddDWordBE( p_bo, ( ( i >> 32) &0xffffffff ) );
  456.     bo_AddDWordBE( p_bo, i &0xffffffff );
  457. }
  458. #endif
  459. static void bo_AddFCC( buffer_out_t *p_bo, char *fcc )
  460. {
  461.     bo_AddByte( p_bo, fcc[0] );
  462.     bo_AddByte( p_bo, fcc[1] );
  463.     bo_AddByte( p_bo, fcc[2] );
  464.     bo_AddByte( p_bo, fcc[3] );
  465. }
  466. static void bo_AddMem( buffer_out_t *p_bo, int i_size, uint8_t *p_mem )
  467. {
  468.     int i;
  469.     for( i = 0; i < i_size; i++ )
  470.     {
  471.         bo_AddByte( p_bo, p_mem[i] );
  472.     }
  473. }
  474. /****************************************************************************
  475.  ****************************************************************************
  476.  **
  477.  ** avi header generation
  478.  **
  479.  ****************************************************************************
  480.  ****************************************************************************/
  481. #define AVI_BOX_ENTER( fcc ) 
  482.     buffer_out_t _bo_sav_; 
  483.     bo_AddFCC( p_bo, fcc ); 
  484.     _bo_sav_ = *p_bo; 
  485.     bo_AddDWordLE( p_bo, 0 )
  486. #define AVI_BOX_ENTER_LIST( fcc ) 
  487.     AVI_BOX_ENTER( "LIST" ); 
  488.     bo_AddFCC( p_bo, fcc )
  489. #define AVI_BOX_EXIT( i_err ) 
  490.     if( p_bo->i_buffer&0x01 ) bo_AddByte( p_bo, 0 ); 
  491.     bo_AddDWordLE( &_bo_sav_, p_bo->i_buffer - _bo_sav_.i_buffer - 4 ); 
  492.     return( i_err );
  493. static int avi_HeaderAdd_avih( sout_mux_t *p_mux,
  494.                                buffer_out_t *p_bo )
  495. {
  496.     sout_mux_sys_t  *p_sys = p_mux->p_sys;
  497.     avi_stream_t    *p_video = NULL;
  498.     int         i_stream;
  499.     uint32_t    i_microsecperframe;
  500.     int         i_maxbytespersec;
  501.     int         i_totalframes;
  502.     AVI_BOX_ENTER( "avih" );
  503.     if( p_sys->i_stream_video >= 0 )
  504.     {
  505.         p_video = &p_sys->stream[p_sys->i_stream_video];
  506.         if( p_video->i_frames <= 0 )
  507.         {
  508.         //    p_video = NULL;
  509.         }
  510.     }
  511.     if( p_video )
  512.     {
  513.         i_microsecperframe =
  514.             (uint32_t)( (float)1000000 /
  515.                         (float)p_sys->stream[p_sys->i_stream_video].f_fps );
  516.         i_totalframes = p_sys->stream[p_sys->i_stream_video].i_frames;
  517.     }
  518.     else
  519.     {
  520.         msg_Warn( p_mux, "avi file without video track isn't a good idea..." );
  521.         i_microsecperframe = 0;
  522.         i_totalframes = 0;
  523.     }
  524.     for( i_stream = 0,i_maxbytespersec = 0; i_stream < p_sys->i_streams; i_stream++ )
  525.     {
  526.         if( p_sys->stream[i_stream].i_duration > 0 )
  527.         {
  528.             i_maxbytespersec +=
  529.                 p_sys->stream[p_sys->i_stream_video].i_totalsize /
  530.                 p_sys->stream[p_sys->i_stream_video].i_duration;
  531.         }
  532.     }
  533.     bo_AddDWordLE( p_bo, i_microsecperframe );
  534.     bo_AddDWordLE( p_bo, i_maxbytespersec );
  535.     bo_AddDWordLE( p_bo, 0 );                   /* padding */
  536.     bo_AddDWordLE( p_bo, AVIF_TRUSTCKTYPE |
  537.                          AVIF_HASINDEX |
  538.                          AVIF_ISINTERLEAVED );  /* flags */
  539.     bo_AddDWordLE( p_bo, i_totalframes );
  540.     bo_AddDWordLE( p_bo, 0 );                   /* initial frame */
  541.     bo_AddDWordLE( p_bo, p_sys->i_streams );    /* streams count */
  542.     bo_AddDWordLE( p_bo, 1024 * 1024 );         /* suggested buffer size */
  543.     if( p_video )
  544.     {
  545.         bo_AddDWordLE( p_bo, p_video->p_bih->biWidth );
  546.         bo_AddDWordLE( p_bo, p_video->p_bih->biHeight );
  547.     }
  548.     else
  549.     {
  550.         bo_AddDWordLE( p_bo, 0 );
  551.         bo_AddDWordLE( p_bo, 0 );
  552.     }
  553.     bo_AddDWordLE( p_bo, 0 );                   /* ???? */
  554.     bo_AddDWordLE( p_bo, 0 );                   /* ???? */
  555.     bo_AddDWordLE( p_bo, 0 );                   /* ???? */
  556.     bo_AddDWordLE( p_bo, 0 );                   /* ???? */
  557.     AVI_BOX_EXIT( 0 );
  558. }
  559. static int avi_HeaderAdd_strh( sout_mux_t   *p_mux,
  560.                                buffer_out_t *p_bo,
  561.                                avi_stream_t *p_stream )
  562. {
  563.     AVI_BOX_ENTER( "strh" );
  564.     switch( p_stream->i_cat )
  565.     {
  566.         case VIDEO_ES:
  567.             {
  568.                 bo_AddFCC( p_bo, "vids" );
  569.                 bo_AddDWordBE( p_bo, p_stream->p_bih->biCompression );
  570.                 bo_AddDWordLE( p_bo, 0 );   /* flags */
  571.                 bo_AddWordLE(  p_bo, 0 );   /* priority */
  572.                 bo_AddWordLE(  p_bo, 0 );   /* langage */
  573.                 bo_AddDWordLE( p_bo, 0 );   /* initial frame */
  574.                 bo_AddDWordLE( p_bo, 1000 );/* scale */
  575.                 bo_AddDWordLE( p_bo, (uint32_t)( 1000 * p_stream->f_fps ));
  576.                 bo_AddDWordLE( p_bo, 0 );   /* start */
  577.                 bo_AddDWordLE( p_bo, p_stream->i_frames );
  578.                 bo_AddDWordLE( p_bo, 1024 * 1024 );
  579.                 bo_AddDWordLE( p_bo, -1 );  /* quality */
  580.                 bo_AddDWordLE( p_bo, 0 );   /* samplesize */
  581.                 bo_AddWordLE(  p_bo, 0 );   /* ??? */
  582.                 bo_AddWordLE(  p_bo, 0 );   /* ??? */
  583.                 bo_AddWordLE(  p_bo, p_stream->p_bih->biWidth );
  584.                 bo_AddWordLE(  p_bo, p_stream->p_bih->biHeight );
  585.             }
  586.             break;
  587.         case AUDIO_ES:
  588.             {
  589.                 int i_rate, i_scale, i_samplesize;
  590.                 i_samplesize = p_stream->p_wf->nBlockAlign;
  591.                 if( i_samplesize > 1 )
  592.                 {
  593.                     i_scale = i_samplesize;
  594.                     i_rate = /*i_scale **/ p_stream->i_bitrate / 8;
  595.                 }
  596.                 else
  597.                 {
  598.                     i_samplesize = 1;
  599.                     i_scale = 1000;
  600.                     i_rate = 1000 * p_stream->i_bitrate / 8;
  601.                 }
  602.                 bo_AddFCC( p_bo, "auds" );
  603.                 bo_AddDWordLE( p_bo, 0 );   /* tag */
  604.                 bo_AddDWordLE( p_bo, 0 );   /* flags */
  605.                 bo_AddWordLE(  p_bo, 0 );   /* priority */
  606.                 bo_AddWordLE(  p_bo, 0 );   /* langage */
  607.                 bo_AddDWordLE( p_bo, 0 );   /* initial frame */
  608.                 bo_AddDWordLE( p_bo, i_scale );/* scale */
  609.                 bo_AddDWordLE( p_bo, i_rate );
  610.                 bo_AddDWordLE( p_bo, 0 );   /* start */
  611.                 bo_AddDWordLE( p_bo, p_stream->i_frames );
  612.                 bo_AddDWordLE( p_bo, 10 * 1024 );
  613.                 bo_AddDWordLE( p_bo, -1 );  /* quality */
  614.                 bo_AddDWordLE( p_bo, i_samplesize );
  615.                 bo_AddWordLE(  p_bo, 0 );   /* ??? */
  616.                 bo_AddWordLE(  p_bo, 0 );   /* ??? */
  617.                 bo_AddWordLE(  p_bo, 0 );
  618.                 bo_AddWordLE(  p_bo, 0 );
  619.             }
  620.             break;
  621.     }
  622.     AVI_BOX_EXIT( 0 );
  623. }
  624. static int avi_HeaderAdd_strf( sout_mux_t *p_mux,
  625.                                buffer_out_t *p_bo,
  626.                                avi_stream_t *p_stream )
  627. {
  628.     AVI_BOX_ENTER( "strf" );
  629.     switch( p_stream->i_cat )
  630.     {
  631.         case AUDIO_ES:
  632.             bo_AddWordLE( p_bo, p_stream->p_wf->wFormatTag );
  633.             bo_AddWordLE( p_bo, p_stream->p_wf->nChannels );
  634.             bo_AddDWordLE( p_bo, p_stream->p_wf->nSamplesPerSec );
  635.             bo_AddDWordLE( p_bo, p_stream->p_wf->nAvgBytesPerSec );
  636.             bo_AddWordLE( p_bo, p_stream->p_wf->nBlockAlign );
  637.             bo_AddWordLE( p_bo, p_stream->p_wf->wBitsPerSample );
  638.             bo_AddWordLE( p_bo, p_stream->p_wf->cbSize );
  639.             bo_AddMem( p_bo, p_stream->p_wf->cbSize, (uint8_t*)&p_stream->p_wf[1] );
  640.             break;
  641.         case VIDEO_ES:
  642.             bo_AddDWordLE( p_bo, p_stream->p_bih->biSize );
  643.             bo_AddDWordLE( p_bo, p_stream->p_bih->biWidth );
  644.             bo_AddDWordLE( p_bo, p_stream->p_bih->biHeight );
  645.             bo_AddWordLE( p_bo, p_stream->p_bih->biPlanes );
  646.             bo_AddWordLE( p_bo, p_stream->p_bih->biBitCount );
  647.             if( VLC_FOURCC( 0, 0, 0, 1 ) == 0x00000001 )
  648.             {
  649.                 bo_AddDWordBE( p_bo, p_stream->p_bih->biCompression );
  650.             }
  651.             else
  652.             {
  653.                 bo_AddDWordLE( p_bo, p_stream->p_bih->biCompression );
  654.             }
  655.             bo_AddDWordLE( p_bo, p_stream->p_bih->biSizeImage );
  656.             bo_AddDWordLE( p_bo, p_stream->p_bih->biXPelsPerMeter );
  657.             bo_AddDWordLE( p_bo, p_stream->p_bih->biYPelsPerMeter );
  658.             bo_AddDWordLE( p_bo, p_stream->p_bih->biClrUsed );
  659.             bo_AddDWordLE( p_bo, p_stream->p_bih->biClrImportant );
  660.             bo_AddMem( p_bo,
  661.                        p_stream->p_bih->biSize - sizeof( BITMAPINFOHEADER ),
  662.                        (uint8_t*)&p_stream->p_bih[1] );
  663.             break;
  664.     }
  665.     AVI_BOX_EXIT( 0 );
  666. }
  667. static int avi_HeaderAdd_strl( sout_mux_t *p_mux,
  668.                                buffer_out_t *p_bo,
  669.                                avi_stream_t *p_stream )
  670. {
  671.     AVI_BOX_ENTER_LIST( "strl" );
  672.     avi_HeaderAdd_strh( p_mux, p_bo, p_stream );
  673.     avi_HeaderAdd_strf( p_mux, p_bo, p_stream );
  674.     AVI_BOX_EXIT( 0 );
  675. }
  676. static block_t *avi_HeaderCreateRIFF( sout_mux_t *p_mux )
  677. {
  678.     sout_mux_sys_t      *p_sys = p_mux->p_sys;
  679.     block_t       *p_hdr;
  680.     int                 i_stream;
  681.     int                 i_maxbytespersec;
  682.     int                 i_junk;
  683.     buffer_out_t        bo;
  684.     p_hdr = block_New( p_mux, HDR_SIZE );
  685.     memset( p_hdr->p_buffer, 0, HDR_SIZE );
  686.     bo_Init( &bo, HDR_SIZE, p_hdr->p_buffer );
  687.     bo_AddFCC( &bo, "RIFF" );
  688.     bo_AddDWordLE( &bo, p_sys->i_movi_size + HDR_SIZE - 8 + p_sys->i_idx1_size );
  689.     bo_AddFCC( &bo, "AVI " );
  690.     bo_AddFCC( &bo, "LIST" );
  691.     bo_AddDWordLE( &bo, HDR_SIZE - 8);
  692.     bo_AddFCC( &bo, "hdrl" );
  693.     avi_HeaderAdd_avih( p_mux, &bo );
  694.     for( i_stream = 0,i_maxbytespersec = 0; i_stream < p_sys->i_streams; i_stream++ )
  695.     {
  696.         avi_HeaderAdd_strl( p_mux, &bo, &p_sys->stream[i_stream] );
  697.     }
  698.     i_junk = HDR_SIZE - bo.i_buffer - 8 - 12;
  699.     bo_AddFCC( &bo, "JUNK" );
  700.     bo_AddDWordLE( &bo, i_junk );
  701.     bo.i_buffer += i_junk;
  702.     bo_AddFCC( &bo, "LIST" );
  703.     bo_AddDWordLE( &bo, p_sys->i_movi_size + 4 );
  704.     bo_AddFCC( &bo, "movi" );
  705.     return( p_hdr );
  706. }
  707. static block_t * avi_HeaderCreateidx1( sout_mux_t *p_mux )
  708. {
  709.     sout_mux_sys_t      *p_sys = p_mux->p_sys;
  710.     block_t       *p_idx1;
  711.     uint32_t            i_idx1_size;
  712.     unsigned int        i;
  713.     buffer_out_t        bo;
  714.     i_idx1_size = 16 * p_sys->idx1.i_entry_count;
  715.     p_idx1 = block_New( p_mux, i_idx1_size + 8 );
  716.     memset( p_idx1->p_buffer, 0, i_idx1_size );
  717.     bo_Init( &bo, i_idx1_size, p_idx1->p_buffer );
  718.     bo_AddFCC( &bo, "idx1" );
  719.     bo_AddDWordLE( &bo, i_idx1_size );
  720.     for( i = 0; i < p_sys->idx1.i_entry_count; i++ )
  721.     {
  722.         bo_AddFCC( &bo, p_sys->idx1.entry[i].fcc );
  723.         bo_AddDWordLE( &bo, p_sys->idx1.entry[i].i_flags );
  724.         bo_AddDWordLE( &bo, p_sys->idx1.entry[i].i_pos );
  725.         bo_AddDWordLE( &bo, p_sys->idx1.entry[i].i_length );
  726.     }
  727.     return( p_idx1 );
  728. }