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

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * wma.c: wma decoder using integer decoder from Rockbox, based on FFmpeg
  3.  *****************************************************************************
  4.  * Copyright (C) 2008-2009 M2X
  5.  *
  6.  * Authors: Rafaël Carré <rcarre@m2x.nl>
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License as published by
  10.  * the Free Software Foundation; either version 2 of the License, or
  11.  * (at your option) any later version.
  12.  *
  13.  * This program is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  * GNU General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU General Public License
  19.  * along with this program; if not, write to the Free Software
  20.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  21.  *****************************************************************************/
  22. /*****************************************************************************
  23.  * Preamble
  24.  *****************************************************************************/
  25. #ifdef HAVE_CONFIG_H
  26. # include "config.h"
  27. #endif
  28. #include <vlc_common.h>
  29. #include <vlc_plugin.h>
  30. #include <vlc_codec.h>
  31. #include <vlc_aout.h>
  32. #include <vlc_block_helper.h>
  33. #include <vlc_bits.h>
  34. #include <assert.h>
  35. #include "wmadec.h"
  36. /*****************************************************************************
  37.  * decoder_sys_t : wma decoder descriptor
  38.  *****************************************************************************/
  39. struct decoder_sys_t
  40. {
  41.     audio_date_t end_date; /* To set the PTS */
  42.     WMADecodeContext wmadec; /* name is self explanative */
  43.     int32_t *p_output; /* buffer where the frames are rendered */
  44.     /* to not give too much samples at once to the audio output */
  45.     int8_t *p_samples; /* point into p_output */
  46.     unsigned int i_samples; /* number of buffered samples available */
  47. };
  48. /* FIXME : check supported configurations */
  49. /* channel configuration */
  50. static unsigned int pi_channels_maps[7] =
  51. {
  52.     0,
  53.     AOUT_CHAN_CENTER,
  54.     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
  55.     AOUT_CHAN_CENTER | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
  56.     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT,
  57.     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT,
  58.     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE
  59. };
  60. /*****************************************************************************
  61.  * Local prototypes
  62.  *****************************************************************************/
  63. static int  OpenDecoder   ( vlc_object_t * );
  64. static void CloseDecoder  ( vlc_object_t * );
  65. static aout_buffer_t *DecodeFrame  ( decoder_t *, block_t ** );
  66. /*****************************************************************************
  67.  * Module descriptor
  68.  *****************************************************************************/
  69. vlc_module_begin();
  70.     set_category( CAT_INPUT );
  71.     set_subcategory( SUBCAT_INPUT_ACODEC );
  72.     set_description( _("WMA v1/v2 fixed point audio decoder") );
  73.     set_capability( "decoder", 50 );
  74.     add_shortcut( "wmafixed" )
  75.     set_callbacks( OpenDecoder, CloseDecoder );
  76. vlc_module_end();
  77. /*****************************************************************************
  78.  * SplitBuffer: Needed because aout really doesn't like big audio chunk and
  79.  * wma produces easily > 30000 samples...
  80.  *****************************************************************************/
  81. static aout_buffer_t *SplitBuffer( decoder_t *p_dec )
  82. {
  83.     decoder_sys_t *p_sys = p_dec->p_sys;
  84.     unsigned int i_samples = __MIN( p_sys->i_samples, 2048 );
  85.     aout_buffer_t *p_buffer;
  86.     if( i_samples == 0 ) return NULL;
  87.     if( !( p_buffer = p_dec->pf_aout_buffer_new( p_dec, i_samples ) ) )
  88.         return NULL;
  89.     p_buffer->start_date = aout_DateGet( &p_sys->end_date );
  90.     p_buffer->end_date = aout_DateIncrement( &p_sys->end_date, i_samples );
  91.     memcpy( p_buffer->p_buffer, p_sys->p_samples, p_buffer->i_nb_bytes );
  92.     p_sys->p_samples += p_buffer->i_nb_bytes;
  93.     p_sys->i_samples -= i_samples;
  94.     return p_buffer;
  95. }
  96. /*****************************************************************************
  97.  * OpenDecoder: probe the decoder and return score
  98.  *****************************************************************************/
  99. static int OpenDecoder( vlc_object_t *p_this )
  100. {
  101.     decoder_t *p_dec = (decoder_t*)p_this;
  102.     decoder_sys_t *p_sys;
  103.     if( p_dec->fmt_in.i_codec != VLC_FOURCC('w','m','a','1') &&
  104.         p_dec->fmt_in.i_codec != VLC_FOURCC('W','M','A','1') &&
  105.         p_dec->fmt_in.i_codec != VLC_FOURCC('w','m','a','2') &&
  106.         p_dec->fmt_in.i_codec != VLC_FOURCC('W','M','A','2') )
  107.     {
  108.         return VLC_EGENERIC;
  109.     }
  110.     /* Allocate the memory needed to store the decoder's structure */
  111.     p_dec->p_sys = p_sys = (decoder_sys_t *)malloc(sizeof(decoder_sys_t));
  112.     if( !p_sys )
  113.         return VLC_ENOMEM;
  114.     memset( p_sys, 0, sizeof( decoder_sys_t ) );
  115.     /* Date */
  116.     aout_DateInit( &p_sys->end_date, p_dec->fmt_in.audio.i_rate );
  117.     /* Set output properties */
  118.     p_dec->fmt_out.i_cat = AUDIO_ES;
  119.     p_dec->fmt_out.i_codec = VLC_FOURCC('f','i','3','2');
  120.     p_dec->fmt_out.audio.i_bitspersample = p_dec->fmt_in.audio.i_bitspersample;
  121.     p_dec->fmt_out.audio.i_rate = p_dec->fmt_in.audio.i_rate;
  122.     p_dec->fmt_out.audio.i_channels = p_dec->fmt_in.audio.i_channels;
  123.     assert( p_dec->fmt_out.audio.i_channels <
  124.         ( sizeof( pi_channels_maps ) / sizeof( pi_channels_maps[0] ) ) );
  125.     p_dec->fmt_out.audio.i_original_channels =
  126.         p_dec->fmt_out.audio.i_physical_channels =
  127.             pi_channels_maps[p_dec->fmt_out.audio.i_channels];
  128.     /* aout core assumes this number is not 0 and uses it in divisions */
  129.     assert( p_dec->fmt_out.audio.i_physical_channels != 0 );
  130.     asf_waveformatex_t wfx;
  131.     wfx.rate = p_dec->fmt_in.audio.i_rate;
  132.     wfx.bitrate = p_dec->fmt_in.i_bitrate;
  133.     wfx.channels = p_dec->fmt_in.audio.i_channels;
  134.     wfx.blockalign = p_dec->fmt_in.audio.i_blockalign;
  135.     wfx.bitspersample = p_dec->fmt_in.audio.i_bitspersample;
  136.     msg_Dbg( p_dec, "samplerate %d bitrate %d channels %d align %d bps %d",
  137.         wfx.rate, wfx.bitrate, wfx.channels, wfx.blockalign,
  138.         wfx.bitspersample );
  139.     if( p_dec->fmt_in.i_codec == VLC_FOURCC('w','m','a','1')
  140.         || p_dec->fmt_in.i_codec == VLC_FOURCC('W','M','A','1') )
  141.         wfx.codec_id = ASF_CODEC_ID_WMAV1;
  142.     else if( p_dec->fmt_in.i_codec == VLC_FOURCC('W','M','A','2')
  143.         || p_dec->fmt_in.i_codec == VLC_FOURCC('w','m','a','2') )
  144.         wfx.codec_id = ASF_CODEC_ID_WMAV2;
  145.     wfx.datalen = p_dec->fmt_in.i_extra;
  146.     if( wfx.datalen > 6 ) wfx.datalen = 6;
  147.     if( wfx.datalen > 0 )
  148.         memcpy( wfx.data, p_dec->fmt_in.p_extra, wfx.datalen );
  149.     /* Init codec */
  150.     if( wma_decode_init(&p_sys->wmadec, &wfx ) < 0 )
  151.     {
  152.         msg_Err( p_dec, "codec init failed" );
  153.         free( p_sys );
  154.         return VLC_EGENERIC;
  155.     }
  156.     /* Set callback */
  157.     p_dec->pf_decode_audio = DecodeFrame;
  158.     return VLC_SUCCESS;
  159. }
  160. /*****************************************************************************
  161.  * DecodeFrame: decodes a wma frame.
  162.  *****************************************************************************/
  163. static aout_buffer_t *DecodeFrame( decoder_t *p_dec, block_t **pp_block )
  164. {
  165.     decoder_sys_t *p_sys = p_dec->p_sys;
  166.     block_t       *p_block;
  167.     aout_buffer_t *p_aout_buffer = NULL;
  168. #ifdef NDEBUG
  169.     mtime_t start = mdate(); /* for statistics */
  170. #endif
  171.     if( !pp_block || !*pp_block ) return NULL;
  172.     p_block = *pp_block;
  173.     if( p_block->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
  174.     {
  175.         aout_DateSet( &p_sys->end_date, 0 );
  176.         block_Release( p_block );
  177.         *pp_block = NULL;
  178.         return NULL;
  179.     }
  180.     if( p_block->i_buffer <= 0 )
  181.     {
  182.         /* we already decoded the samples, just feed a few to aout */
  183.         if( p_sys->i_samples )
  184.             p_aout_buffer = SplitBuffer( p_dec );
  185.         if( !p_sys->i_samples )
  186.         {   /* we need to decode new samples now */
  187.             free( p_sys->p_output );
  188.             p_sys->p_output = NULL;
  189.             block_Release( p_block );
  190.             *pp_block = NULL;
  191.         }
  192.         return p_aout_buffer;
  193.     }
  194.     /* Date management */
  195.     if( p_block->i_pts > 0 &&
  196.         p_block->i_pts != aout_DateGet( &p_sys->end_date ) )
  197.     {
  198.         aout_DateSet( &p_sys->end_date, p_block->i_pts );
  199.         /* don't reuse the same pts */
  200.         p_block->i_pts = 0;
  201.     }
  202.     else if( !aout_DateGet( &p_sys->end_date ) )
  203.     {
  204.         /* We've just started the stream, wait for the first PTS. */
  205.         block_Release( p_block );
  206.         return NULL;
  207.     }
  208.     if( wma_decode_superframe_init( &p_sys->wmadec, p_block->p_buffer,
  209.             p_block->i_buffer ) == 0 )
  210.     {
  211.         msg_Err( p_dec, "failed initializing wmafixed decoder" );
  212.         block_Release( p_block );
  213.         *pp_block = NULL;
  214.         return NULL;
  215.     }
  216.     if( p_sys->wmadec.nb_frames <= 0 )
  217.     {
  218.         msg_Err( p_dec, "can not decode, invalid ASF packet ?" );
  219.         block_Release( p_block );
  220.         *pp_block = NULL;
  221.         return NULL;
  222.     }
  223.     /* worst case */
  224.     size_t i_buffer = BLOCK_MAX_SIZE * MAX_CHANNELS * p_sys->wmadec.nb_frames;
  225.     if( p_sys->p_output )
  226.         free( p_sys->p_output );
  227.     p_sys->p_output = malloc(i_buffer * sizeof(int32_t) );
  228.     p_sys->p_samples = (int8_t*)p_sys->p_output;
  229.     if( !p_sys->p_output )
  230.     {
  231.         /* OOM, will try a bit later if VLC hasn't been killed */
  232.         block_Release( p_block );
  233.         return NULL;
  234.     }
  235.     p_sys->i_samples = 0;
  236.     for( int i = 0 ; i < p_sys->wmadec.nb_frames; i++ )
  237.     {
  238.         int i_samples = 0;
  239.         i_samples = wma_decode_superframe_frame( &p_sys->wmadec,
  240.                  p_sys->p_output + p_sys->i_samples * p_sys->wmadec.nb_channels,
  241.                  p_block->p_buffer, p_block->i_buffer );
  242.         if( i_samples < 0 )
  243.         {
  244.             msg_Warn( p_dec,
  245.                 "wma_decode_superframe_frame() failed for frame %d", i );
  246.             free( p_sys->p_output );
  247.             p_sys->p_output = NULL;
  248.             return NULL;
  249.         }
  250.         p_sys->i_samples += i_samples; /* advance in the samples buffer */
  251.     }
  252.     p_block->i_buffer = 0; /* this block has been decoded */
  253.     for( size_t s = 0 ; s < i_buffer; s++ )
  254.         p_sys->p_output[s] >>= 2; /* Q30 -> Q28 translation */
  255.     p_aout_buffer = SplitBuffer( p_dec );
  256.     assert( p_aout_buffer );
  257. #ifdef NDEBUG
  258.     msg_Dbg( p_dec, "%s took %"PRIi64" us",__func__,mdate()-start);
  259. #endif
  260.     return p_aout_buffer;
  261. }
  262. /*****************************************************************************
  263.  * CloseDecoder : wma decoder destruction
  264.  *****************************************************************************/
  265. static void CloseDecoder( vlc_object_t *p_this )
  266. {
  267.     decoder_sys_t *p_sys = ((decoder_t*)p_this)->p_sys;
  268.     free( p_sys->p_output );
  269.     free( p_sys );
  270. }