wav.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:19k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * wav.c : wav file input module for vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2001-2008 the VideoLAN team
  5.  * $Id: 988b305e7d2ab8de948453807dbba6bef2c55615 $
  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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #ifdef HAVE_CONFIG_H
  27. # include "config.h"
  28. #endif
  29. #include <vlc_common.h>
  30. #include <vlc_plugin.h>
  31. #include <vlc_demux.h>
  32. #include <vlc_aout.h>
  33. #include <vlc_codecs.h>
  34. /*****************************************************************************
  35.  * Module descriptor
  36.  *****************************************************************************/
  37. static int  Open ( vlc_object_t * );
  38. static void Close( vlc_object_t * );
  39. vlc_module_begin ()
  40.     set_description( N_("WAV demuxer") )
  41.     set_category( CAT_INPUT )
  42.     set_subcategory( SUBCAT_INPUT_DEMUX )
  43.     set_capability( "demux", 142 )
  44.     set_callbacks( Open, Close )
  45. vlc_module_end ()
  46. /*****************************************************************************
  47.  * Local prototypes
  48.  *****************************************************************************/
  49. static int Demux  ( demux_t * );
  50. static int Control( demux_t *, int i_query, va_list args );
  51. struct demux_sys_t
  52. {
  53.     es_format_t     fmt;
  54.     es_out_id_t     *p_es;
  55.     int64_t         i_data_pos;
  56.     unsigned int    i_data_size;
  57.     unsigned int    i_frame_size;
  58.     int             i_frame_samples;
  59.     date_t          pts;
  60.     uint32_t i_channel_mask;
  61.     bool b_chan_reorder;              /* do we need channel reordering */
  62.     int pi_chan_table[AOUT_CHAN_MAX];
  63. };
  64. static int ChunkFind( demux_t *, const char *, unsigned int * );
  65. static int FrameInfo_IMA_ADPCM( unsigned int *, int *, const es_format_t * );
  66. static int FrameInfo_MS_ADPCM ( unsigned int *, int *, const es_format_t * );
  67. static int FrameInfo_PCM      ( unsigned int *, int *, const es_format_t * );
  68. static int FrameInfo_MSGSM    ( unsigned int *, int *, const es_format_t * );
  69. static const uint32_t pi_channels_src[] =
  70.     { WAVE_SPEAKER_FRONT_LEFT, WAVE_SPEAKER_FRONT_RIGHT,
  71.       WAVE_SPEAKER_FRONT_CENTER, WAVE_SPEAKER_LOW_FREQUENCY,
  72.       WAVE_SPEAKER_BACK_LEFT, WAVE_SPEAKER_BACK_RIGHT, WAVE_SPEAKER_BACK_CENTER,
  73.       WAVE_SPEAKER_SIDE_LEFT, WAVE_SPEAKER_SIDE_RIGHT, 0 };
  74. static const uint32_t pi_channels_in[] =
  75.     { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
  76.       AOUT_CHAN_CENTER, AOUT_CHAN_LFE,
  77.       AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, AOUT_CHAN_REARCENTER,
  78.       AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT, 0 };
  79. /*****************************************************************************
  80.  * Open: check file and initializes structures
  81.  *****************************************************************************/
  82. static int Open( vlc_object_t * p_this )
  83. {
  84.     demux_t     *p_demux = (demux_t*)p_this;
  85.     demux_sys_t *p_sys;
  86.     const uint8_t *p_peek;
  87.     unsigned int i_size;
  88.     unsigned int i_extended;
  89.     const char        *psz_name;
  90.     WAVEFORMATEXTENSIBLE *p_wf_ext = NULL;
  91.     WAVEFORMATEX         *p_wf = NULL;
  92.     /* Is it a wav file ? */
  93.     if( stream_Peek( p_demux->s, &p_peek, 12 ) < 12 )
  94.         return VLC_EGENERIC;
  95.     if( memcmp( p_peek, "RIFF", 4 ) || memcmp( &p_peek[8], "WAVE", 4 ) )
  96.     {
  97.         return VLC_EGENERIC;
  98.     }
  99.     p_demux->pf_demux   = Demux;
  100.     p_demux->pf_control = Control;
  101.     p_demux->p_sys      = p_sys = malloc( sizeof( *p_sys ) );
  102.     if( p_sys == NULL )
  103.         return VLC_ENOMEM;
  104.     p_sys->p_es         = NULL;
  105.     p_sys->b_chan_reorder = false;
  106.     p_sys->i_channel_mask = 0;
  107.     /* skip riff header */
  108.     if( stream_Read( p_demux->s, NULL, 12 ) != 12 )
  109.         goto error;
  110.     /* search fmt chunk */
  111.     if( ChunkFind( p_demux, "fmt ", &i_size ) )
  112.     {
  113.         msg_Err( p_demux, "cannot find 'fmt ' chunk" );
  114.         goto error;
  115.     }
  116.     i_size += 2;
  117.     if( i_size < sizeof( WAVEFORMATEX ) )
  118.     {
  119.         msg_Err( p_demux, "invalid 'fmt ' chunk" );
  120.         goto error;
  121.     }
  122.     if( stream_Read( p_demux->s, NULL, 8 ) != 8 )
  123.         goto error;
  124.     /* load waveformatex */
  125.     p_wf_ext = malloc( i_size );
  126.     if( p_wf_ext == NULL )
  127.          goto error;
  128.     p_wf = &p_wf_ext->Format;
  129.     p_wf->cbSize = 0;
  130.     i_size -= 2;
  131.     if( stream_Read( p_demux->s, p_wf, i_size ) != (int)i_size ||
  132.         ( ( i_size & 1 ) && stream_Read( p_demux->s, NULL, 1 ) != 1 ) )
  133.     {
  134.         msg_Err( p_demux, "cannot load 'fmt ' chunk" );
  135.         goto error;
  136.     }
  137.     es_format_Init( &p_sys->fmt, AUDIO_ES, 0 );
  138.     wf_tag_to_fourcc( GetWLE( &p_wf->wFormatTag ), &p_sys->fmt.i_codec,
  139.                       &psz_name );
  140.     p_sys->fmt.audio.i_channels = GetWLE ( &p_wf->nChannels );
  141.     p_sys->fmt.audio.i_rate = GetDWLE( &p_wf->nSamplesPerSec );
  142.     p_sys->fmt.audio.i_blockalign = GetWLE( &p_wf->nBlockAlign );
  143.     p_sys->fmt.i_bitrate = GetDWLE( &p_wf->nAvgBytesPerSec ) * 8;
  144.     p_sys->fmt.audio.i_bitspersample = GetWLE( &p_wf->wBitsPerSample );
  145.     if( i_size >= sizeof(WAVEFORMATEX) )
  146.         p_sys->fmt.i_extra = __MIN( GetWLE( &p_wf->cbSize ), i_size - sizeof(WAVEFORMATEX) );
  147.     i_extended = 0;
  148.     /* Handle new WAVE_FORMAT_EXTENSIBLE wav files */
  149.     /* see the following link for more information:
  150.      * http://www.microsoft.com/whdc/device/audio/multichaud.mspx#EFAA */
  151.     if( GetWLE( &p_wf->wFormatTag ) == WAVE_FORMAT_EXTENSIBLE &&
  152.         i_size >= sizeof( WAVEFORMATEXTENSIBLE ) &&
  153.         ( p_sys->fmt.i_extra + sizeof( WAVEFORMATEX )
  154.             >= sizeof( WAVEFORMATEXTENSIBLE ) ) )
  155.     {
  156.         unsigned i, i_channel_mask;
  157.         GUID guid_subformat;
  158.         guid_subformat = p_wf_ext->SubFormat;
  159.         guid_subformat.Data1 = GetDWLE( &p_wf_ext->SubFormat.Data1 );
  160.         guid_subformat.Data2 = GetWLE( &p_wf_ext->SubFormat.Data2 );
  161.         guid_subformat.Data3 = GetWLE( &p_wf_ext->SubFormat.Data3 );
  162.         sf_tag_to_fourcc( &guid_subformat, &p_sys->fmt.i_codec, &psz_name );
  163.         i_extended = sizeof( WAVEFORMATEXTENSIBLE ) - sizeof( WAVEFORMATEX );
  164.         p_sys->fmt.i_extra -= i_extended;
  165.         i_channel_mask = GetDWLE( &p_wf_ext->dwChannelMask );
  166.         if( i_channel_mask )
  167.         {
  168.             int i_match = 0;
  169.             for( i = 0; i < sizeof(pi_channels_src)/sizeof(*pi_channels_src); i++ )
  170.             {
  171.                 if( i_channel_mask & pi_channels_src[i] )
  172.                 {
  173.                     if( !( p_sys->i_channel_mask & pi_channels_in[i] ) )
  174.                         i_match++;
  175.                     i_channel_mask &= ~pi_channels_src[i];
  176.                     p_sys->i_channel_mask |= pi_channels_in[i];
  177.                     if( i_match >= p_sys->fmt.audio.i_channels )
  178.                         break;
  179.                 }
  180.             }
  181.             if( i_channel_mask )
  182.                 msg_Warn( p_demux, "Some channels are unrecognized or uselessly specified (0x%x)", i_channel_mask );
  183.             if( i_match < p_sys->fmt.audio.i_channels )
  184.             {
  185.                 int i_missing = p_sys->fmt.audio.i_channels - i_match;
  186.                 msg_Warn( p_demux, "Trying to fill up unspecified position for %d channels", p_sys->fmt.audio.i_channels - i_match );
  187.                 static const uint32_t pi_pair[] = { AOUT_CHAN_REARLEFT|AOUT_CHAN_REARRIGHT,
  188.                                                     AOUT_CHAN_MIDDLELEFT|AOUT_CHAN_MIDDLERIGHT,
  189.                                                     AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT };
  190.                 static const uint32_t pi_center[] = { AOUT_CHAN_REARCENTER,
  191.                                                       0,
  192.                                                       AOUT_CHAN_CENTER };
  193.                 /* Try to complete with pair */
  194.                 for( unsigned i = 0; i < sizeof(pi_pair)/sizeof(*pi_pair); i++ )
  195.                 {
  196.                     if( i_missing >= 2 && !(p_sys->i_channel_mask & pi_pair[i] ) )
  197.                     {
  198.                         i_missing -= 2;
  199.                         p_sys->i_channel_mask |= pi_pair[i];
  200.                     }
  201.                 }
  202.                 /* Well fill up with what we can */
  203.                 for( unsigned i = 0; i < sizeof(pi_channels_in)/sizeof(*pi_channels_in) && i_missing > 0; i++ )
  204.                 {
  205.                     if( !( p_sys->i_channel_mask & pi_channels_in[i] ) )
  206.                     {
  207.                         p_sys->i_channel_mask |= pi_channels_in[i];
  208.                         i_missing--;
  209.                         if( i_missing <= 0 )
  210.                             break;
  211.                     }
  212.                 }
  213.                 i_match = p_sys->fmt.audio.i_channels - i_missing;
  214.             }
  215.             if( i_match < p_sys->fmt.audio.i_channels )
  216.             {
  217.                 msg_Err( p_demux, "Invalid/unsupported channel mask" );
  218.                 p_sys->i_channel_mask = 0;
  219.             }
  220.         }
  221.     }
  222.     else if( GetWLE( &p_wf->wFormatTag ) == WAVE_FORMAT_PCM &&
  223.              p_sys->fmt.audio.i_channels > 2 && p_sys->fmt.audio.i_channels <= 9 )
  224.     {
  225.         for( int i = 0; i < p_sys->fmt.audio.i_channels; i++ )
  226.             p_sys->i_channel_mask |= pi_channels_in[i];
  227.     }
  228.     if( p_sys->i_channel_mask )
  229.     {
  230.         if( p_sys->fmt.i_codec == VLC_FOURCC('a','r','a','w') ||
  231.             p_sys->fmt.i_codec == VLC_FOURCC('p','c','m',' ') ||
  232.             p_sys->fmt.i_codec == VLC_FOURCC('a','f','l','t') )
  233.             p_sys->b_chan_reorder =
  234.                 aout_CheckChannelReorder( pi_channels_in, NULL,
  235.                                           p_sys->i_channel_mask,
  236.                                           p_sys->fmt.audio.i_channels,
  237.                                           p_sys->pi_chan_table );
  238.         msg_Dbg( p_demux, "channel mask: %x, reordering: %i",
  239.                  p_sys->i_channel_mask, (int)p_sys->b_chan_reorder );
  240.     }
  241.     p_sys->fmt.audio.i_physical_channels =
  242.     p_sys->fmt.audio.i_original_channels = p_sys->i_channel_mask;
  243.     if( p_sys->fmt.i_extra > 0 )
  244.     {
  245.         p_sys->fmt.p_extra = malloc( p_sys->fmt.i_extra );
  246.         if( !p_sys->fmt.p_extra )
  247.         {
  248.             p_sys->fmt.i_extra = 0;
  249.             goto error;
  250.         }
  251.         memcpy( p_sys->fmt.p_extra, ((uint8_t *)p_wf) + i_extended,
  252.                 p_sys->fmt.i_extra );
  253.     }
  254.     msg_Dbg( p_demux, "format: 0x%4.4x, fourcc: %4.4s, channels: %d, "
  255.              "freq: %u Hz, bitrate: %uKo/s, blockalign: %d, bits/samples: %d, "
  256.              "extra size: %d",
  257.              GetWLE( &p_wf->wFormatTag ), (char *)&p_sys->fmt.i_codec,
  258.              p_sys->fmt.audio.i_channels, p_sys->fmt.audio.i_rate,
  259.              p_sys->fmt.i_bitrate / 8 / 1024, p_sys->fmt.audio.i_blockalign,
  260.              p_sys->fmt.audio.i_bitspersample, p_sys->fmt.i_extra );
  261.     free( p_wf );
  262.     p_wf = NULL;
  263.     switch( p_sys->fmt.i_codec )
  264.     {
  265.     case VLC_FOURCC( 'a', 'r', 'a', 'w' ):
  266.     case VLC_FOURCC( 'a', 'f', 'l', 't' ):
  267.     case VLC_FOURCC( 'u', 'l', 'a', 'w' ):
  268.     case VLC_FOURCC( 'a', 'l', 'a', 'w' ):
  269.     case VLC_FOURCC( 'm', 'l', 'a', 'w' ):
  270.     case VLC_FOURCC( 'p', 'c', 'm', ' ' ):
  271.         if( FrameInfo_PCM( &p_sys->i_frame_size, &p_sys->i_frame_samples,
  272.                            &p_sys->fmt ) )
  273.             goto error;
  274.         break;
  275.     case VLC_FOURCC( 'm', 's', 0x00, 0x02 ):
  276.         if( FrameInfo_MS_ADPCM( &p_sys->i_frame_size, &p_sys->i_frame_samples,
  277.                                 &p_sys->fmt ) )
  278.             goto error;
  279.         break;
  280.     case VLC_FOURCC( 'm', 's', 0x00, 0x11 ):
  281.         if( FrameInfo_IMA_ADPCM( &p_sys->i_frame_size, &p_sys->i_frame_samples,
  282.                                  &p_sys->fmt ) )
  283.             goto error;
  284.         break;
  285.     case VLC_FOURCC( 'm', 's', 0x00, 0x61 ):
  286.     case VLC_FOURCC( 'm', 's', 0x00, 0x62 ):
  287.         /* FIXME not sure at all FIXME */
  288.         if( FrameInfo_MS_ADPCM( &p_sys->i_frame_size, &p_sys->i_frame_samples,
  289.                                 &p_sys->fmt ) )
  290.             goto error;
  291.         break;
  292.     case VLC_FOURCC( 'm', 'p', 'g', 'a' ):
  293.     case VLC_FOURCC( 'a', '5', '2', ' ' ):
  294.         /* FIXME set end of area FIXME */
  295.         goto error;
  296.     case VLC_FOURCC( 'a', 'g', 's', 'm' ):
  297.     case VLC_FOURCC( 'g', '7', '2', '6' ):
  298.         if( FrameInfo_MSGSM( &p_sys->i_frame_size, &p_sys->i_frame_samples,
  299.                              &p_sys->fmt ) )
  300.             goto error;
  301.         break;
  302.     default:
  303.         msg_Err( p_demux, "unsupported codec (%4.4s)",
  304.                  (char*)&p_sys->fmt.i_codec );
  305.         goto error;
  306.     }
  307.     if( p_sys->i_frame_size <= 0 || p_sys->i_frame_samples <= 0 )
  308.     {
  309.         msg_Dbg( p_demux, "invalid frame size: %i %i", p_sys->i_frame_size,
  310.                                                        p_sys->i_frame_samples );
  311.         goto error;
  312.     }
  313.     if( p_sys->fmt.audio.i_rate <= 0 )
  314.     {
  315.         msg_Dbg( p_demux, "invalid sample rate: %i", p_sys->fmt.audio.i_rate );
  316.         goto error;
  317.     }
  318.     msg_Dbg( p_demux, "found %s audio format", psz_name );
  319.     if( ChunkFind( p_demux, "data", &p_sys->i_data_size ) )
  320.     {
  321.         msg_Err( p_demux, "cannot find 'data' chunk" );
  322.         goto error;
  323.     }
  324.     if( stream_Read( p_demux->s, NULL, 8 ) != 8 )
  325.         goto error;
  326.     p_sys->i_data_pos = stream_Tell( p_demux->s );
  327.     if( p_sys->fmt.i_bitrate <= 0 )
  328.     {
  329.         p_sys->fmt.i_bitrate = (int64_t)p_sys->i_frame_size *
  330.             p_sys->fmt.audio.i_rate * 8 / p_sys->i_frame_samples;
  331.     }
  332.     p_sys->p_es = es_out_Add( p_demux->out, &p_sys->fmt );
  333.     date_Init( &p_sys->pts, p_sys->fmt.audio.i_rate, 1 );
  334.     date_Set( &p_sys->pts, 1 );
  335.     return VLC_SUCCESS;
  336. error:
  337.     msg_Err( p_demux, "An error occured during wav demuxing" );
  338.     free( p_wf );
  339.     free( p_sys );
  340.     return VLC_EGENERIC;
  341. }
  342. /*****************************************************************************
  343.  * Demux: read packet and send them to decoders
  344.  *****************************************************************************
  345.  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
  346.  *****************************************************************************/
  347. static int Demux( demux_t *p_demux )
  348. {
  349.     demux_sys_t *p_sys = p_demux->p_sys;
  350.     block_t     *p_block;
  351.     const int64_t i_pos = stream_Tell( p_demux->s );
  352.     if( p_sys->i_data_size > 0 &&
  353.         i_pos >= p_sys->i_data_pos + p_sys->i_data_size )
  354.     {
  355.         /* EOF */
  356.         return 0;
  357.     }
  358.     if( ( p_block = stream_Block( p_demux->s, p_sys->i_frame_size ) ) == NULL )
  359.     {
  360.         msg_Warn( p_demux, "cannot read data" );
  361.         return 0;
  362.     }
  363.     p_block->i_dts =
  364.     p_block->i_pts = date_Increment( &p_sys->pts, p_sys->i_frame_samples );
  365.     /* set PCR */
  366.     es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block->i_pts );
  367.     /* Do the channel reordering */
  368.     if( p_sys->b_chan_reorder )
  369.         aout_ChannelReorder( p_block->p_buffer, p_block->i_buffer,
  370.                              p_sys->fmt.audio.i_channels,
  371.                              p_sys->pi_chan_table,
  372.                              p_sys->fmt.audio.i_bitspersample );
  373.     es_out_Send( p_demux->out, p_sys->p_es, p_block );
  374.     return 1;
  375. }
  376. /*****************************************************************************
  377.  * Close: frees unused data
  378.  *****************************************************************************/
  379. static void Close ( vlc_object_t * p_this )
  380. {
  381.     demux_t     *p_demux = (demux_t*)p_this;
  382.     demux_sys_t *p_sys  = p_demux->p_sys;
  383.     free( p_sys );
  384. }
  385. /*****************************************************************************
  386.  * Control:
  387.  *****************************************************************************/
  388. static int Control( demux_t *p_demux, int i_query, va_list args )
  389. {
  390.     demux_sys_t *p_sys  = p_demux->p_sys;
  391.     int64_t i_end = -1;
  392.     if( p_sys->i_data_size > 0 )
  393.         i_end = p_sys->i_data_pos + p_sys->i_data_size;
  394.     return demux_vaControlHelper( p_demux->s, p_sys->i_data_pos, i_end,
  395.                                    p_sys->fmt.i_bitrate,
  396.                                    p_sys->fmt.audio.i_blockalign,
  397.                                    i_query, args );
  398. }
  399. /*****************************************************************************
  400.  * Local functions
  401.  *****************************************************************************/
  402. static int ChunkFind( demux_t *p_demux, const char *fcc, unsigned int *pi_size )
  403. {
  404.     const uint8_t *p_peek;
  405.     for( ;; )
  406.     {
  407.         uint32_t i_size;
  408.         if( stream_Peek( p_demux->s, &p_peek, 8 ) < 8 )
  409.         {
  410.             msg_Err( p_demux, "cannot peek" );
  411.             return VLC_EGENERIC;
  412.         }
  413.         i_size = GetDWLE( p_peek + 4 );
  414.         msg_Dbg( p_demux, "chunk: fcc=`%4.4s` size=%"PRIu32, p_peek, i_size );
  415.         if( !memcmp( p_peek, fcc, 4 ) )
  416.         {
  417.             if( pi_size )
  418.             {
  419.                 *pi_size = i_size;
  420.             }
  421.             return VLC_SUCCESS;
  422.         }
  423.         /* Skip chunk */
  424.         if( stream_Read( p_demux->s, NULL, 8 ) != 8 ||
  425.             stream_Read( p_demux->s, NULL, i_size ) != (int)i_size ||
  426.             ( (i_size & 1) && stream_Read( p_demux->s, NULL, 1 ) != 1 ) )
  427.             return VLC_EGENERIC;
  428.     }
  429. }
  430. static int FrameInfo_PCM( unsigned int *pi_size, int *pi_samples,
  431.                           const es_format_t *p_fmt )
  432. {
  433.     int i_bytes;
  434.     /* read samples for 50ms of */
  435.     *pi_samples = __MAX( p_fmt->audio.i_rate / 20, 1 );
  436.     i_bytes = *pi_samples * p_fmt->audio.i_channels *
  437.         ( (p_fmt->audio.i_bitspersample + 7) / 8 );
  438.     if( p_fmt->audio.i_blockalign > 0 )
  439.     {
  440.         const int i_modulo = i_bytes % p_fmt->audio.i_blockalign;
  441.         if( i_modulo > 0 )
  442.             i_bytes += p_fmt->audio.i_blockalign - i_modulo;
  443.     }
  444.     *pi_size = i_bytes;
  445.     return VLC_SUCCESS;
  446. }
  447. static int FrameInfo_MS_ADPCM( unsigned int *pi_size, int *pi_samples,
  448.                                const es_format_t *p_fmt )
  449. {
  450.     if( p_fmt->audio.i_channels <= 0 )
  451.         return VLC_EGENERIC;
  452.     *pi_samples = 2 + 2 * ( p_fmt->audio.i_blockalign -
  453.         7 * p_fmt->audio.i_channels ) / p_fmt->audio.i_channels;
  454.     *pi_size = p_fmt->audio.i_blockalign;
  455.     return VLC_SUCCESS;
  456. }
  457. static int FrameInfo_IMA_ADPCM( unsigned int *pi_size, int *pi_samples,
  458.                                 const es_format_t *p_fmt )
  459. {
  460.     if( p_fmt->audio.i_channels <= 0 )
  461.         return VLC_EGENERIC;
  462.     *pi_samples = 2 * ( p_fmt->audio.i_blockalign -
  463.         4 * p_fmt->audio.i_channels ) / p_fmt->audio.i_channels;
  464.     *pi_size = p_fmt->audio.i_blockalign;
  465.     return VLC_SUCCESS;
  466. }
  467. static int FrameInfo_MSGSM( unsigned int *pi_size, int *pi_samples,
  468.                             const es_format_t *p_fmt )
  469. {
  470.     if( p_fmt->i_bitrate <= 0 )
  471.         return VLC_EGENERIC;
  472.     *pi_samples = ( p_fmt->audio.i_blockalign * p_fmt->audio.i_rate * 8)
  473.                     / p_fmt->i_bitrate;
  474.     *pi_size = p_fmt->audio.i_blockalign;
  475.     return VLC_SUCCESS;
  476. }