예제 #1
0
파일: dec.c 프로젝트: Jobq/vlc-mdc
/*****************************************************************************
 * aout_DecPlay : filter & mix the decoded buffer
 *****************************************************************************/
int aout_DecPlay (audio_output_t *p_aout, block_t *p_buffer, int i_input_rate)
{
    aout_owner_t *owner = aout_owner (p_aout);
    aout_input_t *input;

    assert( i_input_rate >= INPUT_RATE_DEFAULT / AOUT_MAX_INPUT_RATE &&
            i_input_rate <= INPUT_RATE_DEFAULT * AOUT_MAX_INPUT_RATE );
    assert( p_buffer->i_pts > 0 );

    p_buffer->i_length = (mtime_t)p_buffer->i_nb_samples * 1000000
                                / owner->input_format.i_rate;

    aout_lock( p_aout );
    aout_CheckRestart( p_aout );

    input = owner->input;
    if (unlikely(input == NULL)) /* can happen due to restart */
    {
        aout_unlock( p_aout );
        aout_BufferFree( p_buffer );
        return -1;
    }

    /* Input */
    p_buffer = aout_InputPlay (p_aout, input, p_buffer, i_input_rate,
                               &owner->sync.date);
    if( p_buffer != NULL )
    {
        date_Increment (&owner->sync.date, p_buffer->i_nb_samples);

        /* Mixer */
        if (owner->volume.mixer != NULL)
        {
            float amp = owner->volume.multiplier
                      * vlc_atomic_getf (&owner->gain.multiplier);
            aout_MixerRun (owner->volume.mixer, p_buffer, amp);
        }

        /* Output */
        aout_OutputPlay( p_aout, p_buffer );
    }

    aout_unlock( p_aout );
#ifdef __unix__
    sched_yield();
#endif
    return 0;
}
예제 #2
0
/**
 * Stops all plugins involved in the audio output.
 */
void aout_Shutdown (audio_output_t *p_aout)
{
    aout_owner_t *owner = aout_owner (p_aout);
    aout_input_t *input;
    struct audio_mixer *mixer;

    aout_lock( p_aout );
    /* Remove the input. */
    input = owner->input;
    if (likely(input != NULL))
        aout_InputDelete (p_aout, input);
    owner->input = NULL;

    mixer = owner->volume.mixer;
    owner->volume.mixer = NULL;

    var_DelCallback (p_aout, "audio-replay-gain-mode",
                     ReplayGainCallback, owner);

    aout_OutputDelete( p_aout );
    var_Destroy( p_aout, "audio-device" );
    var_Destroy( p_aout, "audio-channels" );

    aout_unlock( p_aout );

    aout_MixerDelete (mixer);
    free (input);
}
예제 #3
0
void aout_DecFlush (audio_output_t *aout)
{
    aout_owner_t *owner = aout_owner (aout);

    aout_lock (aout);
    date_Set (&owner->sync.date, VLC_TS_INVALID);
    aout_OutputFlush (aout, false);
    aout_unlock (aout);
}
예제 #4
0
파일: dec.c 프로젝트: ares89/vlc
/*****************************************************************************
 * aout_DecPlay : filter & mix the decoded buffer
 *****************************************************************************/
int aout_DecPlay (audio_output_t *aout, block_t *block, int input_rate)
{
    aout_owner_t *owner = aout_owner (aout);

    assert (input_rate >= INPUT_RATE_DEFAULT / AOUT_MAX_INPUT_RATE);
    assert (input_rate <= INPUT_RATE_DEFAULT * AOUT_MAX_INPUT_RATE);
    assert (block->i_pts >= VLC_TS_0);

    block->i_length = CLOCK_FREQ * block->i_nb_samples
                                 / owner->input_format.i_rate;

    aout_lock (aout);
    if (unlikely(aout_CheckReady (aout)))
        goto drop; /* Pipeline is unrecoverably broken :-( */

    const mtime_t now = mdate (), advance = block->i_pts - now;
    if (advance < -AOUT_MAX_PTS_DELAY)
    {   /* Late buffer can be caused by bugs in the decoder, by scheduling
         * latency spikes (excessive load, SIGSTOP, etc.) or if buffering is
         * insufficient. We assume the PTS is wrong and play the buffer anyway:
         * Hopefully video has encountered a similar PTS problem as audio. */
        msg_Warn (aout, "buffer too late (%"PRId64" us): dropped", advance);
        goto drop;
    }
    if (advance > AOUT_MAX_ADVANCE_TIME)
    {   /* Early buffers can only be caused by bugs in the decoder. */
        msg_Err (aout, "buffer too early (%"PRId64" us): dropped", advance);
        goto drop;
    }
    if (block->i_flags & BLOCK_FLAG_DISCONTINUITY)
        owner->sync.discontinuity = true;

    block = aout_FiltersPlay (aout, block, input_rate);
    if (block == NULL)
        goto lost;

    /* Software volume */
    aout_volume_Amplify (owner->volume, block);

    /* Drift correction */
    aout_DecSynchronize (aout, block->i_pts, input_rate);

    /* Output */
    owner->sync.end = block->i_pts + block->i_length + 1;
    owner->sync.discontinuity = false;
    aout_OutputPlay (aout, block);
out:
    aout_unlock (aout);
    return 0;
drop:
    owner->sync.discontinuity = true;
    block_Release (block);
lost:
    atomic_fetch_add(&owner->buffers_lost, 1);
    goto out;
}
예제 #5
0
void aout_DecChangePause (audio_output_t *aout, bool paused, mtime_t date)
{
    aout_owner_t *owner = aout_owner (aout);

    aout_lock (aout);
    /* XXX: Should the date be offset by the pause duration instead? */
    date_Set (&owner->sync.date, VLC_TS_INVALID);
    aout_OutputPause (aout, paused, date);
    aout_unlock (aout);
}
예제 #6
0
파일: output.c 프로젝트: ares89/vlc
/**
 * Sets the audio output stream mute flag.
 * \return 0 on success, -1 on failure.
 */
int aout_MuteSet (audio_output_t *aout, bool mute)
{
    int ret = -1;

    aout_lock (aout);
    if (aout->mute_set != NULL)
        ret = aout->mute_set (aout, mute);
    aout_unlock (aout);
    return ret;
}
예제 #7
0
파일: output.c 프로젝트: ares89/vlc
/**
 * Enumerates possible audio output devices.
 *
 * The function will heap-allocate two tables of heap-allocated strings;
 * the caller is responsible for freeing all strings and both tables.
 *
 * \param ids pointer to a table of device identifiers [OUT]
 * \param names pointer to a table of device human-readable descriptions [OUT]
 * \return the number of devices, or negative on error.
 * \note In case of error, *ids and *names are undefined.
 */
int aout_DevicesList (audio_output_t *aout, char ***ids, char ***names)
{
    int ret = -1;

    aout_lock (aout);
    if (aout->device_enum != NULL)
        ret = aout->device_enum (aout, ids, names);
    aout_unlock (aout);
    return ret;
}
예제 #8
0
파일: dec.c 프로젝트: ares89/vlc
void aout_DecFlush (audio_output_t *aout)
{
    aout_owner_t *owner = aout_owner (aout);

    aout_lock (aout);
    owner->sync.end = VLC_TS_INVALID;
    if (owner->mixer_format.i_format)
        aout_OutputFlush (aout, false);
    aout_unlock (aout);
}
예제 #9
0
파일: output.c 프로젝트: ares89/vlc
/**
 * Selects an audio output device.
 * \param id device ID to select, or NULL for the default device
 * \return zero on success, non-zero on error.
 */
int aout_DeviceSet (audio_output_t *aout, const char *id)
{
    int ret = -1;

    aout_lock (aout);
    if (aout->device_select != NULL)
        ret = aout->device_select (aout, id);
    aout_unlock (aout);
    return ret;
}
예제 #10
0
파일: output.c 프로젝트: ares89/vlc
/**
 * Sets the volume of the audio output stream.
 * \note The mute status is not changed.
 * \return 0 on success, -1 on failure.
 */
int aout_VolumeSet (audio_output_t *aout, float vol)
{
    int ret = -1;

    aout_lock (aout);
    if (aout->volume_set != NULL)
        ret = aout->volume_set (aout, vol);
    aout_unlock (aout);
    return ret;
}
예제 #11
0
파일: dec.c 프로젝트: ares89/vlc
/**
 * Stops all plugins involved in the audio output.
 */
void aout_DecDelete (audio_output_t *aout)
{
    aout_owner_t *owner = aout_owner (aout);

    aout_lock (aout);
    if (owner->mixer_format.i_format)
    {
        aout_FiltersDelete (aout);
        aout_OutputDelete (aout);
    }
    aout_volume_Delete (owner->volume);
    aout_unlock (aout);
    var_Destroy (aout, "stereo-mode");
}
예제 #12
0
파일: dec.c 프로젝트: ares89/vlc
void aout_DecChangePause (audio_output_t *aout, bool paused, mtime_t date)
{
    aout_owner_t *owner = aout_owner (aout);

    aout_lock (aout);
    if (owner->sync.end != VLC_TS_INVALID)
    {
        if (paused)
            owner->sync.end -= date;
        else
            owner->sync.end += date;
    }
    if (owner->mixer_format.i_format)
        aout_OutputPause (aout, paused, date);
    aout_unlock (aout);
}
예제 #13
0
파일: output.c 프로젝트: ares89/vlc
/**
 * Deinitializes an audio output module and destroys an audio output object.
 */
void aout_Destroy (audio_output_t *aout)
{
    aout_owner_t *owner = aout_owner (aout);

    aout_lock (aout);
    module_unneed (aout, owner->module);
    /* Protect against late call from intf.c */
    aout->volume_set = NULL;
    aout->mute_set = NULL;
    aout_unlock (aout);

    var_DelCallback (aout, "mute", var_Copy, aout->p_parent);
    var_SetFloat (aout, "volume", -1.f);
    var_DelCallback (aout, "volume", var_Copy, aout->p_parent);
    vlc_object_release (aout);
}
예제 #14
0
파일: dec.c 프로젝트: ares89/vlc
bool aout_DecIsEmpty (audio_output_t *aout)
{
    aout_owner_t *owner = aout_owner (aout);
    mtime_t now = mdate ();
    bool empty = true;

    aout_lock (aout);
    if (owner->sync.end != VLC_TS_INVALID)
        empty = owner->sync.end <= now;
    if (empty && owner->mixer_format.i_format)
        /* The last PTS has elapsed already. So the underlying audio output
         * buffer should be empty or almost. Thus draining should be fast
         * and will not block the caller too long. */
        aout_OutputFlush (aout, true);
    aout_unlock (aout);
    return empty;
}
예제 #15
0
bool aout_DecIsEmpty (audio_output_t *aout)
{
    aout_owner_t *owner = aout_owner (aout);
    mtime_t end_date, now = mdate ();
    bool empty;

    aout_lock (aout);
    end_date = date_Get (&owner->sync.date);
    empty = end_date == VLC_TS_INVALID || end_date <= now;
    if (empty)
        /* The last PTS has elapsed already. So the underlying audio output
         * buffer should be empty or almost. Thus draining should be fast
         * and will not block the caller too long. */
        aout_OutputFlush (aout, true);
    aout_unlock (aout);
    return empty;
}
예제 #16
0
int aout_DecGetResetLost (audio_output_t *aout)
{
    aout_owner_t *owner = aout_owner (aout);
    aout_input_t *input = owner->input;
    int val;

    aout_lock (aout);
    if (likely(input != NULL))
    {
        val = input->i_buffer_lost;
        input->i_buffer_lost = 0;
    }
    else
        val = 0; /* if aout_CheckRestart() failed */
    aout_unlock (aout);

    return val;
}
예제 #17
0
파일: dec.c 프로젝트: ares89/vlc
/**
 * Creates an audio output
 */
int aout_DecNew( audio_output_t *p_aout,
                 const audio_sample_format_t *p_format,
                 const audio_replay_gain_t *p_replay_gain,
                 const aout_request_vout_t *p_request_vout )
{
    /* Sanitize audio format */
    if( p_format->i_channels != aout_FormatNbChannels( p_format ) )
    {
        msg_Err( p_aout, "incompatible audio channels count with layout mask" );
        return -1;
    }

    if( p_format->i_rate > 192000 )
    {
        msg_Err( p_aout, "excessive audio sample frequency (%u)",
                 p_format->i_rate );
        return -1;
    }
    if( p_format->i_rate < 4000 )
    {
        msg_Err( p_aout, "too low audio sample frequency (%u)",
                 p_format->i_rate );
        return -1;
    }

    aout_owner_t *owner = aout_owner(p_aout);

    /* TODO: reduce lock scope depending on decoder's real need */
    aout_lock( p_aout );

    var_Destroy( p_aout, "stereo-mode" );

    /* Create the audio output stream */
    owner->volume = aout_volume_New (p_aout, p_replay_gain);

    atomic_store (&owner->restart, 0);
    owner->input_format = *p_format;
    owner->mixer_format = owner->input_format;

    if (aout_OutputNew (p_aout, &owner->mixer_format))
        goto error;
    aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format);

    /* Create the audio filtering "input" pipeline */
    if (aout_FiltersNew (p_aout, p_format, &owner->mixer_format,
                         p_request_vout))
    {
        aout_OutputDelete (p_aout);
error:
        aout_volume_Delete (owner->volume);
        aout_unlock (p_aout);
        return -1;
    }

    owner->sync.end = VLC_TS_INVALID;
    owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
    owner->sync.discontinuity = true;
    aout_unlock( p_aout );

    atomic_init (&owner->buffers_lost, 0);
    return 0;
}
예제 #18
0
/**
 * Creates an audio output
 */
int aout_DecNew( audio_output_t *p_aout,
                 const audio_sample_format_t *p_format,
                 const audio_replay_gain_t *p_replay_gain,
                 const aout_request_vout_t *p_request_vout )
{
    /* Sanitize audio format */
    if( p_format->i_channels > 32 )
    {
        msg_Err( p_aout, "too many audio channels (%u)",
                 p_format->i_channels );
        return -1;
    }
    if( p_format->i_channels <= 0 )
    {
        msg_Err( p_aout, "no audio channels" );
        return -1;
    }
    if( p_format->i_channels != aout_FormatNbChannels( p_format ) )
    {
        msg_Err( p_aout, "incompatible audio channels count with layout mask" );
        return -1;
    }

    if( p_format->i_rate > 192000 )
    {
        msg_Err( p_aout, "excessive audio sample frequency (%u)",
                 p_format->i_rate );
        return -1;
    }
    if( p_format->i_rate < 4000 )
    {
        msg_Err( p_aout, "too low audio sample frequency (%u)",
                 p_format->i_rate );
        return -1;
    }

    aout_owner_t *owner = aout_owner(p_aout);
#ifdef RECYCLE
    /* Calling decoder is responsible for serializing aout_DecNew() and
     * aout_DecDelete(). So no need to lock to _read_ those properties. */
    if (owner->module != NULL) /* <- output exists */
    {   /* Check if we can recycle the existing output and pipelines */
        if (AOUT_FMTS_IDENTICAL(&owner->input_format, p_format))
            return 0;

        /* TODO? If the new input format is closer to the output format than
         * the old input format was, then the output could be recycled. The
         * input pipeline however would need to be restarted. */

        /* No recycling: delete everything and restart from scratch */
        aout_Shutdown (p_aout);
    }
#endif
    int ret = 0;

    /* TODO: reduce lock scope depending on decoder's real need */
    aout_lock( p_aout );
    assert (owner->module == NULL);

    /* Create the audio output stream */
    var_Destroy( p_aout, "audio-device" );
    var_Destroy( p_aout, "audio-channels" );

    owner->input_format = *p_format;
    vlc_atomic_set (&owner->restart, 0);
    if( aout_OutputNew( p_aout, p_format ) < 0 )
    {
        ret = -1;
        goto error;
    }

    /* Allocate a software mixer */
    assert (owner->volume.mixer == NULL);
    owner->volume.mixer = aout_MixerNew (p_aout, owner->mixer_format.i_format);

    aout_ReplayGainInit (&owner->gain.data, p_replay_gain);
    var_AddCallback (p_aout, "audio-replay-gain-mode",
                     ReplayGainCallback, owner);
    var_TriggerCallback (p_aout, "audio-replay-gain-mode");

    /* Create the audio filtering "input" pipeline */
    date_Init (&owner->sync.date, owner->mixer_format.i_rate, 1);
    date_Set (&owner->sync.date, VLC_TS_INVALID);

    assert (owner->input == NULL);
    owner->input = aout_InputNew (p_aout, p_format, &owner->mixer_format,
                                  p_request_vout);
    if (owner->input == NULL)
    {
        struct audio_mixer *mixer = owner->volume.mixer;

        owner->volume.mixer = NULL;
        aout_OutputDelete (p_aout);
        aout_unlock (p_aout);
        aout_MixerDelete (mixer);
        return -1;
    }
error:
    aout_unlock( p_aout );
    return ret;
}