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

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * output.c : internal management of output streams for the audio output
  3.  *****************************************************************************
  4.  * Copyright (C) 2002-2004 VideoLAN
  5.  * $Id: output.c 8485 2004-08-21 13:54:36Z asmax $
  6.  *
  7.  * Authors: Christophe Massiot <massiot@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. #include <stdlib.h>                            /* calloc(), malloc(), free() */
  27. #include <string.h>
  28. #include <vlc/vlc.h>
  29. #include "audio_output.h"
  30. #include "aout_internal.h"
  31. /*****************************************************************************
  32.  * aout_OutputNew : allocate a new output and rework the filter pipeline
  33.  *****************************************************************************
  34.  * This function is entered with the mixer lock.
  35.  *****************************************************************************/
  36. int aout_OutputNew( aout_instance_t * p_aout,
  37.                     audio_sample_format_t * p_format )
  38. {
  39.     /* Retrieve user defaults. */
  40.     int i_rate = config_GetInt( p_aout, "aout-rate" );
  41.     vlc_value_t val, text;
  42.     /* kludge to avoid a fpu error when rate is 0... */
  43.     if( i_rate == 0 ) i_rate = -1;
  44.     memcpy( &p_aout->output.output, p_format, sizeof(audio_sample_format_t) );
  45.     if ( i_rate != -1 )
  46.         p_aout->output.output.i_rate = i_rate;
  47.     aout_FormatPrepare( &p_aout->output.output );
  48.     vlc_mutex_lock( &p_aout->output_fifo_lock );
  49.     /* Find the best output plug-in. */
  50.     p_aout->output.p_module = module_Need( p_aout, "audio output", "$aout", 0);
  51.     if ( p_aout->output.p_module == NULL )
  52.     {
  53.         msg_Err( p_aout, "no suitable aout module" );
  54.         vlc_mutex_unlock( &p_aout->output_fifo_lock );
  55.         return -1;
  56.     }
  57.     if ( var_Type( p_aout, "audio-channels" ) ==
  58.              (VLC_VAR_INTEGER | VLC_VAR_HASCHOICE) )
  59.     {
  60.         /* The user may have selected a different channels configuration. */
  61.         var_Get( p_aout, "audio-channels", &val );
  62.         if ( val.i_int == AOUT_VAR_CHAN_RSTEREO )
  63.         {
  64.             p_aout->output.output.i_original_channels |=
  65.                                         AOUT_CHAN_REVERSESTEREO;
  66.         }
  67.         else if ( val.i_int == AOUT_VAR_CHAN_STEREO )
  68.         {
  69.             p_aout->output.output.i_original_channels =
  70.                 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
  71.         }
  72.         else if ( val.i_int == AOUT_VAR_CHAN_LEFT )
  73.         {
  74.             p_aout->output.output.i_original_channels = AOUT_CHAN_LEFT;
  75.         }
  76.         else if ( val.i_int == AOUT_VAR_CHAN_RIGHT )
  77.         {
  78.             p_aout->output.output.i_original_channels = AOUT_CHAN_RIGHT;
  79.         }
  80.         else if ( val.i_int == AOUT_VAR_CHAN_DOLBYS )
  81.         {
  82.             p_aout->output.output.i_original_channels
  83.                 = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_DOLBYSTEREO;
  84.         }
  85.     }
  86.     else if ( p_aout->output.output.i_physical_channels == AOUT_CHAN_CENTER
  87.               && (p_aout->output.output.i_original_channels
  88.                    & AOUT_CHAN_PHYSMASK) == (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT) )
  89.     {
  90.         /* Mono - create the audio-channels variable. */
  91.         var_Create( p_aout, "audio-channels",
  92.                     VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
  93.         text.psz_string = _("Audio Channels");
  94.         var_Change( p_aout, "audio-channels", VLC_VAR_SETTEXT, &text, NULL );
  95.         val.i_int = AOUT_VAR_CHAN_STEREO; text.psz_string = _("Stereo");
  96.         var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
  97.         val.i_int = AOUT_VAR_CHAN_LEFT; text.psz_string = _("Left");
  98.         var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
  99.         val.i_int = AOUT_VAR_CHAN_RIGHT; text.psz_string = _("Right");
  100.         var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
  101.         if ( p_aout->output.output.i_original_channels & AOUT_CHAN_DUALMONO )
  102.         {
  103.             /* Go directly to the left channel. */
  104.             p_aout->output.output.i_original_channels = AOUT_CHAN_LEFT;
  105.             val.i_int = AOUT_VAR_CHAN_LEFT;
  106.             var_Set( p_aout, "audio-channels", val );
  107.         }
  108.         var_AddCallback( p_aout, "audio-channels", aout_ChannelsRestart,
  109.                          NULL );
  110.     }
  111.     else if ( p_aout->output.output.i_physical_channels ==
  112.                (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)
  113.                 && (p_aout->output.output.i_original_channels &
  114.                      (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)) )
  115.     {
  116.         /* Stereo - create the audio-channels variable. */
  117.         var_Create( p_aout, "audio-channels",
  118.                     VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
  119.         text.psz_string = _("Audio Channels");
  120.         var_Change( p_aout, "audio-channels", VLC_VAR_SETTEXT, &text, NULL );
  121.         if ( p_aout->output.output.i_original_channels & AOUT_CHAN_DOLBYSTEREO )
  122.         {
  123.             val.i_int = AOUT_VAR_CHAN_DOLBYS;
  124.             text.psz_string = _("Dolby Surround");
  125.         }
  126.         else
  127.         {
  128.             val.i_int = AOUT_VAR_CHAN_STEREO;
  129.             text.psz_string = _("Stereo");
  130.         }
  131.         var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
  132.         val.i_int = AOUT_VAR_CHAN_LEFT; text.psz_string = _("Left");
  133.         var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
  134.         val.i_int = AOUT_VAR_CHAN_RIGHT; text.psz_string = _("Right");
  135.         var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
  136.         val.i_int = AOUT_VAR_CHAN_RSTEREO; text.psz_string=_("Reverse stereo");
  137.         var_Change( p_aout, "audio-channels", VLC_VAR_ADDCHOICE, &val, &text );
  138.         if ( p_aout->output.output.i_original_channels & AOUT_CHAN_DUALMONO )
  139.         {
  140.             /* Go directly to the left channel. */
  141.             p_aout->output.output.i_original_channels = AOUT_CHAN_LEFT;
  142.             val.i_int = AOUT_VAR_CHAN_LEFT;
  143.             var_Set( p_aout, "audio-channels", val );
  144.         }
  145.         var_AddCallback( p_aout, "audio-channels", aout_ChannelsRestart,
  146.                          NULL );
  147.     }
  148.     val.b_bool = VLC_TRUE;
  149.     var_Set( p_aout, "intf-change", val );
  150.     aout_FormatPrepare( &p_aout->output.output );
  151.     /* Prepare FIFO. */
  152.     aout_FifoInit( p_aout, &p_aout->output.fifo,
  153.                    p_aout->output.output.i_rate );
  154.     vlc_mutex_unlock( &p_aout->output_fifo_lock );
  155.     aout_FormatPrint( p_aout, "output", &p_aout->output.output );
  156.     /* Calculate the resulting mixer output format. */
  157.     memcpy( &p_aout->mixer.mixer, &p_aout->output.output,
  158.             sizeof(audio_sample_format_t) );
  159.     if ( !AOUT_FMT_NON_LINEAR(&p_aout->output.output) )
  160.     {
  161.         /* Non-S/PDIF mixer only deals with float32 or fixed32. */
  162.         p_aout->mixer.mixer.i_format
  163.                      = (p_aout->p_libvlc->i_cpu & CPU_CAPABILITY_FPU) ?
  164.                         VLC_FOURCC('f','l','3','2') :
  165.                         VLC_FOURCC('f','i','3','2');
  166.         aout_FormatPrepare( &p_aout->mixer.mixer );
  167.     }
  168.     else
  169.     {
  170.         p_aout->mixer.mixer.i_format = p_format->i_format;
  171.     }
  172.     aout_FormatPrint( p_aout, "mixer", &p_aout->output.output );
  173.     /* Create filters. */
  174.     if ( aout_FiltersCreatePipeline( p_aout, p_aout->output.pp_filters,
  175.                                      &p_aout->output.i_nb_filters,
  176.                                      &p_aout->mixer.mixer,
  177.                                      &p_aout->output.output ) < 0 )
  178.     {
  179.         msg_Err( p_aout, "couldn't set an output pipeline" );
  180.         module_Unneed( p_aout, p_aout->output.p_module );
  181.         return -1;
  182.     }
  183.     /* Prepare hints for the buffer allocator. */
  184.     p_aout->mixer.output_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
  185.     p_aout->mixer.output_alloc.i_bytes_per_sec
  186.                         = p_aout->mixer.mixer.i_bytes_per_frame
  187.                            * p_aout->mixer.mixer.i_rate
  188.                            / p_aout->mixer.mixer.i_frame_length;
  189.     aout_FiltersHintBuffers( p_aout, p_aout->output.pp_filters,
  190.                              p_aout->output.i_nb_filters,
  191.                              &p_aout->mixer.output_alloc );
  192.     p_aout->output.b_error = 0;
  193.     return 0;
  194. }
  195. /*****************************************************************************
  196.  * aout_OutputDelete : delete the output
  197.  *****************************************************************************
  198.  * This function is entered with the mixer lock.
  199.  *****************************************************************************/
  200. void aout_OutputDelete( aout_instance_t * p_aout )
  201. {
  202.     if ( p_aout->output.b_error )
  203.     {
  204.         return;
  205.     }
  206.     module_Unneed( p_aout, p_aout->output.p_module );
  207.     aout_FiltersDestroyPipeline( p_aout, p_aout->output.pp_filters,
  208.                                  p_aout->output.i_nb_filters );
  209.     aout_FifoDestroy( p_aout, &p_aout->output.fifo );
  210.     p_aout->output.b_error = VLC_TRUE;
  211. }
  212. /*****************************************************************************
  213.  * aout_OutputPlay : play a buffer
  214.  *****************************************************************************
  215.  * This function is entered with the mixer lock.
  216.  *****************************************************************************/
  217. void aout_OutputPlay( aout_instance_t * p_aout, aout_buffer_t * p_buffer )
  218. {
  219.     aout_FiltersPlay( p_aout, p_aout->output.pp_filters,
  220.                       p_aout->output.i_nb_filters,
  221.                       &p_buffer );
  222.     if( p_buffer->i_nb_bytes == 0 )
  223.     {
  224.         aout_BufferFree( p_buffer );
  225.         return;
  226.     }
  227.     vlc_mutex_lock( &p_aout->output_fifo_lock );
  228.     aout_FifoPush( p_aout, &p_aout->output.fifo, p_buffer );
  229.     p_aout->output.pf_play( p_aout );
  230.     vlc_mutex_unlock( &p_aout->output_fifo_lock );
  231. }
  232. /*****************************************************************************
  233.  * aout_OutputNextBuffer : give the audio output plug-in the right buffer
  234.  *****************************************************************************
  235.  * If b_can_sleek is 1, the aout core functions won't try to resample
  236.  * new buffers to catch up - that is we suppose that the output plug-in can
  237.  * compensate it by itself. S/PDIF outputs should always set b_can_sleek = 1.
  238.  * This function is entered with no lock at all :-).
  239.  *****************************************************************************/
  240. aout_buffer_t * aout_OutputNextBuffer( aout_instance_t * p_aout,
  241.                                        mtime_t start_date,
  242.                                        vlc_bool_t b_can_sleek )
  243. {
  244.     aout_buffer_t * p_buffer;
  245.     vlc_mutex_lock( &p_aout->output_fifo_lock );
  246.     p_buffer = p_aout->output.fifo.p_first;
  247.     while ( p_buffer && p_buffer->start_date < mdate() - AOUT_PTS_TOLERANCE )
  248.     {
  249.         msg_Dbg( p_aout, "audio output is too slow ("I64Fd"), "
  250.                  "trashing "I64Fd"us", mdate() - p_buffer->start_date,
  251.                  p_buffer->end_date - p_buffer->start_date );
  252.         p_buffer = p_buffer->p_next;
  253.         aout_BufferFree( p_aout->output.fifo.p_first );
  254.         p_aout->output.fifo.p_first = p_buffer;
  255.     }
  256.     if ( p_buffer == NULL )
  257.     {
  258.         p_aout->output.fifo.pp_last = &p_aout->output.fifo.p_first;
  259. #if 0 /* This is bad because the audio output might just be trying to fill
  260.        * in it's internal buffers. And anyway, it's up to the audio output
  261.        * to deal with this kind of starvation. */
  262.         /* Set date to 0, to allow the mixer to send a new buffer ASAP */
  263.         aout_FifoSet( p_aout, &p_aout->output.fifo, 0 );
  264.         if ( !p_aout->output.b_starving )
  265.             msg_Dbg( p_aout,
  266.                  "audio output is starving (no input), playing silence" );
  267.         p_aout->output.b_starving = 1;
  268. #endif
  269.         vlc_mutex_unlock( &p_aout->output_fifo_lock );
  270.         return NULL;
  271.     }
  272.     /* Here we suppose that all buffers have the same duration - this is
  273.      * generally true, and anyway if it's wrong it won't be a disaster.
  274.      */
  275.     if ( p_buffer->start_date > start_date
  276.                          + (p_buffer->end_date - p_buffer->start_date) )
  277.     /*
  278.      *                   + AOUT_PTS_TOLERANCE )
  279.      * There is no reason to want that, it just worsen the scheduling of
  280.      * an audio sample after an output starvation (ie. on start or on resume)
  281.      * --Gibalou
  282.      */
  283.     {
  284.         vlc_mutex_unlock( &p_aout->output_fifo_lock );
  285.         if ( !p_aout->output.b_starving )
  286.             msg_Dbg( p_aout, "audio output is starving ("I64Fd"), "
  287.                      "playing silence", p_buffer->start_date - start_date );
  288.         p_aout->output.b_starving = 1;
  289.         return NULL;
  290.     }
  291.     p_aout->output.b_starving = 0;
  292.     if ( !b_can_sleek &&
  293.           ( (p_buffer->start_date - start_date > AOUT_PTS_TOLERANCE)
  294.              || (start_date - p_buffer->start_date > AOUT_PTS_TOLERANCE) ) )
  295.     {
  296.         /* Try to compensate the drift by doing some resampling. */
  297.         int i;
  298.         mtime_t difference = start_date - p_buffer->start_date;
  299.         msg_Warn( p_aout, "output date isn't PTS date, requesting "
  300.                   "resampling ("I64Fd")", difference );
  301.         vlc_mutex_lock( &p_aout->input_fifos_lock );
  302.         for ( i = 0; i < p_aout->i_nb_inputs; i++ )
  303.         {
  304.             aout_fifo_t * p_fifo = &p_aout->pp_inputs[i]->fifo;
  305.             aout_FifoMoveDates( p_aout, p_fifo, difference );
  306.         }
  307.         aout_FifoMoveDates( p_aout, &p_aout->output.fifo, difference );
  308.         vlc_mutex_unlock( &p_aout->input_fifos_lock );
  309.     }
  310.     p_aout->output.fifo.p_first = p_buffer->p_next;
  311.     if ( p_buffer->p_next == NULL )
  312.     {
  313.         p_aout->output.fifo.pp_last = &p_aout->output.fifo.p_first;
  314.     }
  315.     vlc_mutex_unlock( &p_aout->output_fifo_lock );
  316.     return p_buffer;
  317. }