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

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * lpcm.c: lpcm decoder/packetizer module
  3.  *****************************************************************************
  4.  * Copyright (C) 1999-2003 VideoLAN
  5.  * $Id: lpcm.c 6961 2004-03-05 17:34:23Z sam $
  6.  *
  7.  * Authors: Samuel Hocevar <sam@zoy.org>
  8.  *          Henri Fallon <henri@videolan.org>
  9.  *          Christophe Massiot <massiot@via.ecp.fr>
  10.  *          Gildas Bazin <gbazin@netcourrier.com>
  11.  *
  12.  * This program is free software; you can redistribute it and/or modify
  13.  * it under the terms of the GNU General Public License as published by
  14.  * the Free Software Foundation; either version 2 of the License, or
  15.  * (at your option) any later version.
  16.  *
  17.  * This program is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  * GNU General Public License for more details.
  21.  *
  22.  * You should have received a copy of the GNU General Public License
  23.  * along with this program; if not, write to the Free Software
  24.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  25.  *****************************************************************************/
  26. /*****************************************************************************
  27.  * Preamble
  28.  *****************************************************************************/
  29. #include <vlc/vlc.h>
  30. #include <vlc/decoder.h>
  31. /*****************************************************************************
  32.  * decoder_sys_t : lpcm decoder descriptor
  33.  *****************************************************************************/
  34. struct decoder_sys_t
  35. {
  36.     /* Module mode */
  37.     vlc_bool_t b_packetizer;
  38.     /*
  39.      * Output properties
  40.      */
  41.     audio_date_t end_date;
  42. };
  43. /*
  44.  * LPCM header :
  45.  * - PES header
  46.  * - private stream ID (16 bits) == 0xA0 -> not in the bitstream
  47.  *
  48.  * - frame number (8 bits)
  49.  * - unknown (16 bits) == 0x0003 ?
  50.  * - unknown (4 bits)
  51.  * - current frame (4 bits)
  52.  * - unknown (2 bits)
  53.  * - frequency (2 bits) 0 == 48 kHz, 1 == 32 kHz, 2 == ?, 3 == ?
  54.  * - unknown (1 bit)
  55.  * - number of channels - 1 (3 bits) 1 == 2 channels
  56.  * - start code (8 bits) == 0x80
  57.  */
  58. #define LPCM_HEADER_LEN 6
  59. /*****************************************************************************
  60.  * Local prototypes
  61.  *****************************************************************************/
  62. static int  OpenDecoder   ( vlc_object_t * );
  63. static int  OpenPacketizer( vlc_object_t * );
  64. static void CloseDecoder  ( vlc_object_t * );
  65. static void *DecodeFrame  ( decoder_t *, block_t ** );
  66. /*****************************************************************************
  67.  * Module descriptor
  68.  *****************************************************************************/
  69. vlc_module_begin();
  70.     set_description( _("Linear PCM audio decoder") );
  71.     set_capability( "decoder", 100 );
  72.     set_callbacks( OpenDecoder, CloseDecoder );
  73.     add_submodule();
  74.     set_description( _("Linear PCM audio packetizer") );
  75.     set_capability( "packetizer", 100 );
  76.     set_callbacks( OpenPacketizer, CloseDecoder );
  77. vlc_module_end();
  78. /*****************************************************************************
  79.  * OpenDecoder: probe the decoder and return score
  80.  *****************************************************************************/
  81. static int OpenDecoder( vlc_object_t *p_this )
  82. {
  83.     decoder_t *p_dec = (decoder_t*)p_this;
  84.     decoder_sys_t *p_sys;
  85.     if( p_dec->fmt_in.i_codec != VLC_FOURCC('l','p','c','m')
  86.          && p_dec->fmt_in.i_codec != VLC_FOURCC('l','p','c','b') )
  87.     {   
  88.         return VLC_EGENERIC;
  89.     }
  90.     /* Allocate the memory needed to store the decoder's structure */
  91.     if( ( p_dec->p_sys = p_sys =
  92.           (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
  93.     {
  94.         msg_Err( p_dec, "out of memory" );
  95.         return VLC_EGENERIC;
  96.     }
  97.     /* Misc init */
  98.     p_sys->b_packetizer = VLC_FALSE;
  99.     aout_DateSet( &p_sys->end_date, 0 );
  100.     /* Set output properties */
  101.     p_dec->fmt_out.i_cat = AUDIO_ES;
  102.     p_dec->fmt_out.i_codec = VLC_FOURCC('s','1','6','b');
  103.     /* Set callback */
  104.     p_dec->pf_decode_audio = (aout_buffer_t *(*)(decoder_t *, block_t **))
  105.         DecodeFrame;
  106.     p_dec->pf_packetize    = (block_t *(*)(decoder_t *, block_t **))
  107.         DecodeFrame;
  108.     return VLC_SUCCESS;
  109. }
  110. static int OpenPacketizer( vlc_object_t *p_this )
  111. {
  112.     decoder_t *p_dec = (decoder_t*)p_this;
  113.     int i_ret = OpenDecoder( p_this );
  114.     if( i_ret != VLC_SUCCESS ) return i_ret;
  115.     p_dec->p_sys->b_packetizer = VLC_TRUE;
  116.     p_dec->fmt_out.i_codec = VLC_FOURCC('l','p','c','m');
  117.     return i_ret;
  118. }
  119. /*****************************************************************************
  120.  * DecodeFrame: decodes an lpcm frame.
  121.  ****************************************************************************
  122.  * Beware, this function must be fed with complete frames (PES packet).
  123.  *****************************************************************************/
  124. static void *DecodeFrame( decoder_t *p_dec, block_t **pp_block )
  125. {
  126.     decoder_sys_t *p_sys = p_dec->p_sys;
  127.     block_t       *p_block;
  128.     unsigned int  i_rate = 0, i_original_channels = 0, i_channels = 0;
  129.     int           i_frame_length;
  130.     uint8_t       i_header;
  131.     if( !pp_block || !*pp_block ) return NULL;
  132.     p_block = *pp_block;
  133.     *pp_block = NULL; /* So the packet doesn't get re-sent */
  134.     /* Date management */
  135.     if( p_block->i_pts > 0 &&
  136.         p_block->i_pts != aout_DateGet( &p_sys->end_date ) )
  137.     {
  138.         aout_DateSet( &p_sys->end_date, p_block->i_pts );
  139.     }
  140.     if( !aout_DateGet( &p_sys->end_date ) )
  141.     {
  142.         /* We've just started the stream, wait for the first PTS. */
  143.         block_Release( p_block );
  144.         return NULL;
  145.     }
  146.     if( p_block->i_buffer <= LPCM_HEADER_LEN )
  147.     {
  148.         msg_Err(p_dec, "frame is too short");
  149.         block_Release( p_block );
  150.         return NULL;
  151.     }
  152.     i_header = p_block->p_buffer[4];
  153.     switch ( (i_header >> 4) & 0x3 )
  154.     {
  155.     case 0:
  156.         i_rate = 48000;
  157.         break;
  158.     case 1:
  159.         i_rate = 96000;
  160.         break;
  161.     case 2:
  162.         i_rate = 44100;
  163.         break;
  164.     case 3:
  165.         i_rate = 32000;
  166.         break;
  167.     }
  168.     i_channels = (i_header & 0x7);
  169.     switch ( i_channels )
  170.     {
  171.     case 0:
  172.         i_original_channels = AOUT_CHAN_CENTER;
  173.         break;
  174.     case 1:
  175.         i_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
  176.         break;
  177.     case 2:
  178.         /* This is unsure. */
  179.         i_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_LFE;
  180.         break;
  181.     case 3:
  182.         i_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
  183.                                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
  184.         break;
  185.     case 4:
  186.         /* This is unsure. */
  187.         i_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
  188.                                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
  189.                                | AOUT_CHAN_LFE;
  190.         break;
  191.     case 5:
  192.         i_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
  193.                                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
  194.                                | AOUT_CHAN_CENTER | AOUT_CHAN_LFE;
  195.         break;
  196.     case 6:
  197.         i_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
  198.                                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
  199.                                | AOUT_CHAN_CENTER | AOUT_CHAN_MIDDLELEFT
  200.                                | AOUT_CHAN_MIDDLERIGHT;
  201.         break;
  202.     case 7:
  203.         i_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
  204.                                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
  205.                                | AOUT_CHAN_CENTER | AOUT_CHAN_MIDDLELEFT
  206.                                | AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_LFE;
  207.         break;
  208.     }
  209.     /* Check frame sync and drop it. */
  210.     if( p_block->p_buffer[5] != 0x80 )
  211.     {
  212.         msg_Warn( p_dec, "no frame sync" );
  213.         block_Release( p_block );
  214.         return NULL;
  215.     }
  216.     /* Set output properties */
  217.     if( p_dec->fmt_out.audio.i_rate != i_rate )
  218.     {
  219.         aout_DateInit( &p_sys->end_date, i_rate );
  220.         aout_DateSet( &p_sys->end_date, p_block->i_pts );
  221.     }
  222.     p_dec->fmt_out.audio.i_rate = i_rate;
  223.     p_dec->fmt_out.audio.i_channels = i_channels + 1;
  224.     p_dec->fmt_out.audio.i_original_channels = i_original_channels;
  225.     p_dec->fmt_out.audio.i_physical_channels
  226.         = i_original_channels & AOUT_CHAN_PHYSMASK;
  227.     i_frame_length = (p_block->i_buffer - LPCM_HEADER_LEN) /
  228.         ( p_dec->fmt_out.audio.i_channels * 2 );
  229.     if( p_sys->b_packetizer )
  230.     {
  231.         p_block->i_pts = p_block->i_dts = aout_DateGet( &p_sys->end_date );
  232.         p_block->i_length =
  233.             aout_DateIncrement( &p_sys->end_date, i_frame_length ) -
  234.             p_block->i_pts;
  235.         /* Just pass on the incoming frame */
  236.         return p_block;
  237.     }
  238.     else
  239.     {
  240.         aout_buffer_t *p_aout_buffer;
  241.         p_aout_buffer = p_dec->pf_aout_buffer_new( p_dec, i_frame_length );
  242.         if( p_aout_buffer == NULL ) return NULL;
  243.         p_aout_buffer->start_date = aout_DateGet( &p_sys->end_date );
  244.         p_aout_buffer->end_date =
  245.             aout_DateIncrement( &p_sys->end_date, i_frame_length );
  246.         memcpy( p_aout_buffer->p_buffer,
  247.                 p_block->p_buffer + LPCM_HEADER_LEN,
  248.                 p_block->i_buffer - LPCM_HEADER_LEN );
  249.         block_Release( p_block );
  250.         return p_aout_buffer;
  251.     }
  252. }
  253. /*****************************************************************************
  254.  * CloseDecoder : lpcm decoder destruction
  255.  *****************************************************************************/
  256. static void CloseDecoder( vlc_object_t *p_this )
  257. {
  258.     decoder_t *p_dec = (decoder_t*)p_this;
  259.     free( p_dec->p_sys );
  260. }