Esempio n. 1
0
void
ca_Play(audio_output_t * p_aout, block_t * p_block)
{
    struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;

    /* Do the channel reordering */
    if (p_sys->chans_to_reorder)
       aout_ChannelReorder(p_block->p_buffer, p_block->i_buffer,
                           p_sys->chans_to_reorder, p_sys->chan_table,
                           VLC_CODEC_FL32);

    /* move data to buffer */
    while (!TPCircularBufferProduceBytes(&p_sys->circular_buffer,
                                         p_block->p_buffer, p_block->i_buffer))
    {
        if (atomic_load_explicit(&p_sys->b_paused, memory_order_relaxed))
        {
            msg_Warn(p_aout, "dropping block because the circular buffer is "
                     "full and paused");
            break;
        }

        /* Try to play what we can */
        int32_t i_avalaible_bytes;
        TPCircularBufferHead(&p_sys->circular_buffer, &i_avalaible_bytes);
        assert(i_avalaible_bytes >= 0);
        if (unlikely((size_t) i_avalaible_bytes >= p_block->i_buffer))
            continue;

        bool ret =
            TPCircularBufferProduceBytes(&p_sys->circular_buffer,
                                         p_block->p_buffer, i_avalaible_bytes);
        assert(ret == true);
        p_block->p_buffer += i_avalaible_bytes;
        p_block->i_buffer -= i_avalaible_bytes;

        /* Wait for the render buffer to play the remaining data */
        const mtime_t i_frame_us =
            FramesToUs(p_sys, BytesToFrames(p_sys, p_block->i_buffer));
        msleep(i_frame_us / 2);
    }

    unsigned i_underrun_size = atomic_exchange(&p_sys->i_underrun_size, 0);
    if (i_underrun_size > 0)
        msg_Warn(p_aout, "underrun of %u bytes", i_underrun_size);

    block_Release(p_block);
}
Esempio n. 2
0
/* This routine will be called by the PortAudio engine when audio is needed.
 * It may called at interrupt level on some machines so don't do anything
 * that could mess up the system like calling malloc() or free().
 */
static int paCallback( const void *inputBuffer, void *outputBuffer,
                       unsigned long framesPerBuffer,
                       const PaStreamCallbackTimeInfo *paDate,
                       PaStreamCallbackFlags statusFlags, void *p_cookie )
{
    VLC_UNUSED( inputBuffer ); VLC_UNUSED( statusFlags );

    struct aout_sys_t *p_sys = (struct aout_sys_t*) p_cookie;
    aout_instance_t   *p_aout = p_sys->p_aout;
    aout_buffer_t     *p_buffer;
    mtime_t out_date;

    out_date = mdate() + (mtime_t) ( 1000000 *
        ( paDate->outputBufferDacTime - paDate->currentTime ) );
    p_buffer = aout_OutputNextBuffer( p_aout, out_date, true );

    if ( p_buffer != NULL )
    {
        if( p_sys->b_chan_reorder )
        {
            /* Do the channel reordering here */
            aout_ChannelReorder( p_buffer->p_buffer, p_buffer->i_nb_bytes,
                                 p_sys->i_channels, p_sys->pi_chan_table,
                                 p_sys->i_bits_per_sample );
        }
        vlc_memcpy( outputBuffer, p_buffer->p_buffer,
                    framesPerBuffer * p_sys->i_sample_size );
        /* aout_BufferFree may be dangereous here, but then so is
         * aout_OutputNextBuffer (calls aout_BufferFree internally).
         * one solution would be to link the no longer useful buffers
         * in a second fifo (in aout_OutputNextBuffer too) and to
         * wait until we are in Play to do the actual free.
         */
        aout_BufferFree( p_buffer );
    }
    else
        /* Audio output buffer shortage -> stop the fill process and wait */
    {
        vlc_memset( outputBuffer, 0, framesPerBuffer * p_sys->i_sample_size );
    }
    return 0;
}
Esempio n. 3
0
File: wav.c Progetto: Tilka/vlc
/*****************************************************************************
 * Demux: read packet and send them to decoders
 *****************************************************************************
 * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
 *****************************************************************************/
static int Demux( demux_t *p_demux )
{
    demux_sys_t *p_sys = p_demux->p_sys;
    block_t     *p_block;
    const int64_t i_pos = stream_Tell( p_demux->s );

    if( p_sys->i_data_size > 0 &&
            i_pos >= p_sys->i_data_pos + p_sys->i_data_size )
    {
        /* EOF */
        return 0;
    }

    if( ( p_block = stream_Block( p_demux->s, p_sys->i_frame_size ) ) == NULL )
    {
        msg_Warn( p_demux, "cannot read data" );
        return 0;
    }

    p_block->i_dts =
        p_block->i_pts = VLC_TS_0 + date_Get( &p_sys->pts );

    /* set PCR */
    es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block->i_pts );

    /* Do the channel reordering */
    if( p_sys->i_chans_to_reorder )
        aout_ChannelReorder( p_block->p_buffer, p_block->i_buffer,
                             p_sys->fmt.audio.i_channels,
                             p_sys->pi_chan_table, p_sys->fmt.i_codec );

    es_out_Send( p_demux->out, p_sys->p_es, p_block );

    date_Increment( &p_sys->pts, p_sys->i_frame_samples );

    return 1;
}
Esempio n. 4
0
/* This routine will be called by the PortAudio engine when audio is needed.
 * It may called at interrupt level on some machines so don't do anything
 * that could mess up the system like calling malloc() or free().
 */
static int paCallback( const void *inputBuffer, void *outputBuffer,
                       unsigned long framesPerBuffer,
                       const PaStreamCallbackTimeInfo *paDate,
                       PaStreamCallbackFlags statusFlags, void *p_cookie )
{
    VLC_UNUSED( inputBuffer ); VLC_UNUSED( statusFlags );

    struct aout_sys_t *p_sys = (struct aout_sys_t*) p_cookie;
    audio_output_t   *p_aout = p_sys->p_aout;
    aout_buffer_t     *p_buffer;
    mtime_t out_date;

    out_date = mdate() + (mtime_t) ( 1000000 *
        ( paDate->outputBufferDacTime - paDate->currentTime ) );
    p_buffer = aout_PacketNext( p_aout, out_date );

    if ( p_buffer != NULL )
    {
        if( p_sys->b_chan_reorder )
        {
            /* Do the channel reordering here */
            aout_ChannelReorder( p_buffer->p_buffer, p_buffer->i_buffer,
                                 p_sys->i_channels, p_sys->pi_chan_table,
                                 p_sys->i_bits_per_sample );
        }
        vlc_memcpy( outputBuffer, p_buffer->p_buffer,
                    framesPerBuffer * p_sys->i_sample_size );
        aout_BufferFree( p_buffer );
    }
    else
        /* Audio output buffer shortage -> stop the fill process and wait */
    {
        vlc_memset( outputBuffer, 0, framesPerBuffer * p_sys->i_sample_size );
    }
    return 0;
}
Esempio n. 5
0
/*****************************************************************************
 * DecodeFrame: decodes an lpcm frame.
 ****************************************************************************
 * Beware, this function must be fed with complete frames (PES packet).
 *****************************************************************************/
static block_t *DecodeFrame( decoder_t *p_dec, block_t **pp_block )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    block_t       *p_block;
    unsigned int  i_rate = 0, i_original_channels = 0, i_channels = 0, i_bits = 0;
    int           i_frame_length;

    if( !pp_block || !*pp_block ) return NULL;

    p_block = *pp_block;
    *pp_block = NULL; /* So the packet doesn't get re-sent */

    /* Date management */
    if( p_block->i_pts > VLC_TS_INVALID &&
        p_block->i_pts != date_Get( &p_sys->end_date ) )
    {
        date_Set( &p_sys->end_date, p_block->i_pts );
    }

    if( !date_Get( &p_sys->end_date ) )
    {
        /* We've just started the stream, wait for the first PTS. */
        block_Release( p_block );
        return NULL;
    }

    if( p_block->i_buffer <= p_sys->i_header_size )
    {
        msg_Err(p_dec, "frame is too short");
        block_Release( p_block );
        return NULL;
    }

    int i_ret;
    unsigned i_channels_padding = 0;
    unsigned i_padding = 0;
    aob_group_t p_aob_group[2];
    switch( p_sys->i_type )
    {
    case LPCM_VOB:
        i_ret = VobHeader( &i_rate, &i_channels, &i_original_channels, &i_bits,
                           p_block->p_buffer );
        break;
    case LPCM_AOB:
        i_ret = AobHeader( &i_rate, &i_channels, &i_original_channels, &i_bits, &i_padding,
                           p_aob_group,
                           p_block->p_buffer );
        break;
    case LPCM_BD:
        i_ret = BdHeader( p_sys, &i_rate, &i_channels, &i_channels_padding, &i_original_channels, &i_bits,
                          p_block->p_buffer );
        break;
    default:
        abort();
    }

    if( i_ret || p_block->i_buffer <= p_sys->i_header_size + i_padding )
    {
        msg_Warn( p_dec, "no frame sync or too small frame" );
        block_Release( p_block );
        return NULL;
    }

    /* Set output properties */
    if( p_dec->fmt_out.audio.i_rate != i_rate )
    {
        date_Init( &p_sys->end_date, i_rate, 1 );
        date_Set( &p_sys->end_date, p_block->i_pts );
    }
    p_dec->fmt_out.audio.i_rate = i_rate;
    p_dec->fmt_out.audio.i_channels = i_channels;
    p_dec->fmt_out.audio.i_original_channels = i_original_channels;
    p_dec->fmt_out.audio.i_physical_channels = i_original_channels;

    i_frame_length = (p_block->i_buffer - p_sys->i_header_size - i_padding) /
                     (i_channels + i_channels_padding) * 8 / i_bits;

    if( p_sys->b_packetizer )
    {
        p_block->i_pts = p_block->i_dts = date_Get( &p_sys->end_date );
        p_block->i_length =
            date_Increment( &p_sys->end_date, i_frame_length ) -
            p_block->i_pts;

        /* Just pass on the incoming frame */
        return p_block;
    }
    else
    {
        /* */
        if( i_bits == 16 )
        {
            p_dec->fmt_out.i_codec = VLC_CODEC_S16N;
            p_dec->fmt_out.audio.i_bitspersample = 16;
        }
        else
        {
            p_dec->fmt_out.i_codec = VLC_CODEC_S32N;
            p_dec->fmt_out.audio.i_bitspersample = 32;
        }

        /* */
        block_t *p_aout_buffer;
        p_aout_buffer = decoder_NewAudioBuffer( p_dec, i_frame_length );
        if( !p_aout_buffer )
            return NULL;

        p_aout_buffer->i_pts = date_Get( &p_sys->end_date );
        p_aout_buffer->i_length =
            date_Increment( &p_sys->end_date, i_frame_length )
            - p_aout_buffer->i_pts;

        p_block->p_buffer += p_sys->i_header_size + i_padding;
        p_block->i_buffer -= p_sys->i_header_size + i_padding;

        if( p_sys->i_chans_to_reorder )
        {
            aout_ChannelReorder( p_block->p_buffer, p_block->i_buffer,
                                 p_sys->i_chans_to_reorder, p_sys->pi_chan_table,
                                 p_dec->fmt_out.i_codec );
        }

        switch( p_sys->i_type )
        {
        case LPCM_VOB:
            VobExtract( p_aout_buffer, p_block, i_bits );
            break;
        case LPCM_AOB:
            AobExtract( p_aout_buffer, p_block, i_bits, p_aob_group );
            break;
        default:
            assert(0);
        case LPCM_BD:
            BdExtract( p_aout_buffer, p_block, i_frame_length, i_channels, i_channels_padding, i_bits );
            break;
        }

        block_Release( p_block );
        return p_aout_buffer;
    }
}
Esempio n. 6
0
/**
 * Fills in one of the DirectSound frame buffers.
 *
 * @return VLC_SUCCESS on success.
 */
static HRESULT FillBuffer( vlc_object_t *obj, aout_stream_sys_t *p_sys,
                           block_t *p_buffer )
{
    size_t towrite = (p_buffer != NULL) ? p_buffer->i_buffer : DS_BUF_SIZE;
    void *p_write_position, *p_wrap_around;
    unsigned long l_bytes1, l_bytes2;
    HRESULT dsresult;

    vlc_mutex_lock( &p_sys->lock );

    /* Before copying anything, we have to lock the buffer */
    dsresult = IDirectSoundBuffer_Lock(
           p_sys->p_dsbuffer,    /* DS buffer */
           p_sys->i_write,       /* Start offset */
           towrite,                /* Number of bytes */
           &p_write_position,    /* Address of lock start */
           &l_bytes1,            /* Count of bytes locked before wrap around */
           &p_wrap_around,       /* Buffer address (if wrap around) */
           &l_bytes2,            /* Count of bytes after wrap around */
           0 );                  /* Flags: DSBLOCK_FROMWRITECURSOR is buggy */
    if( dsresult == DSERR_BUFFERLOST )
    {
        IDirectSoundBuffer_Restore( p_sys->p_dsbuffer );
        dsresult = IDirectSoundBuffer_Lock(
                               p_sys->p_dsbuffer,
                               p_sys->i_write,
                               towrite,
                               &p_write_position,
                               &l_bytes1,
                               &p_wrap_around,
                               &l_bytes2,
                               0 );
    }
    if( dsresult != DS_OK )
    {
        msg_Warn( obj, "cannot lock buffer" );
        if( p_buffer != NULL )
            block_Release( p_buffer );
        vlc_mutex_unlock( &p_sys->lock );
        return dsresult;
    }

    if( p_buffer == NULL )
    {
        memset( p_write_position, 0, l_bytes1 );
        memset( p_wrap_around, 0, l_bytes2 );
    }
    else
    {
        if( p_sys->chans_to_reorder ) /* Do the channel reordering here */
            aout_ChannelReorder( p_buffer->p_buffer, p_buffer->i_buffer,
                                 p_sys->chans_to_reorder, p_sys->chan_table,
                                 p_sys->format );

        memcpy( p_write_position, p_buffer->p_buffer, l_bytes1 );
        if( p_wrap_around && l_bytes2 )
            memcpy( p_wrap_around, p_buffer->p_buffer + l_bytes1, l_bytes2 );

        if( unlikely( ( l_bytes1 + l_bytes2 ) < p_buffer->i_buffer ) )
            msg_Err( obj, "Buffer overrun");

        block_Release( p_buffer );
    }

    /* Now the data has been copied, unlock the buffer */
    IDirectSoundBuffer_Unlock( p_sys->p_dsbuffer, p_write_position, l_bytes1,
                               p_wrap_around, l_bytes2 );

    p_sys->i_write += towrite;
    p_sys->i_write %= DS_BUF_SIZE;
    p_sys->i_data += towrite;
    vlc_mutex_unlock( &p_sys->lock );

    return DS_OK;
}
Esempio n. 7
0
/*****************************************************************************
 * WaveOutThread: this thread will capture play notification events. 
 *****************************************************************************
 * We use this thread to feed new audio samples to the sound card because
 * we are not authorized to use waveOutWrite() directly in the waveout
 * callback.
 *****************************************************************************/
static void WaveOutThread( notification_thread_t *p_notif )
{
    aout_instance_t *p_aout = p_notif->p_aout;
    aout_sys_t *p_sys = p_aout->output.p_sys;
    aout_buffer_t *p_buffer = NULL;
    WAVEHDR *p_waveheader = p_sys->waveheader;
    int i, i_queued_frames;
    vlc_bool_t b_sleek;

    /* We don't want any resampling when using S/PDIF */
    b_sleek = p_aout->output.output.i_format == VLC_FOURCC('s','p','d','i');

    while( 1 )
    {
        WaitForSingleObject( p_sys->event, INFINITE );

        /* Cleanup and find out the current latency */
        i_queued_frames = 0;
        for( i = 0; i < FRAMES_NUM; i++ )
        {
            if( (p_waveheader[i].dwFlags & WHDR_DONE) &&
                p_waveheader[i].dwUser )
            {
                /* Unprepare and free the buffers which has just been played */
                waveOutUnprepareHeader( p_sys->h_waveout, &p_waveheader[i],
                                        sizeof(WAVEHDR) );

                if( p_waveheader[i].dwUser != 1 )
                    aout_BufferFree( (aout_buffer_t *)p_waveheader[i].dwUser );

                p_waveheader[i].dwUser = 0;
            }

            /* Check if frame buf is available */
            if( !(p_waveheader[i].dwFlags & WHDR_DONE) )
            {
                i_queued_frames++;
            }
        }

        if( p_aout->b_die ) return;

        /* Try to fill in as many frame buffers as possible */
        for( i = 0; i < FRAMES_NUM; i++ )
        {
            /* Check if frame buf is available */
            if( p_waveheader[i].dwFlags & WHDR_DONE )
            {
                /* Take into account the latency */
                p_buffer = aout_OutputNextBuffer( p_aout,
                    mdate() + 1000000 * i_queued_frames /
                    p_aout->output.output.i_rate * p_aout->output.i_nb_samples,
                    b_sleek );

                if( !p_buffer && i_queued_frames )
                {
                    /* We aren't late so no need to play a blank sample */
                    break;
                }

                /* Do the channel reordering */
                if( p_buffer && p_sys->b_chan_reorder )
                {
                    aout_ChannelReorder( p_buffer->p_buffer,
                        p_buffer->i_nb_bytes,
                        p_sys->waveformat.Format.nChannels,
                        p_sys->pi_chan_table,
                        p_sys->waveformat.Format.wBitsPerSample );
                }

                PlayWaveOut( p_aout, p_sys->h_waveout,
                             &p_waveheader[i], p_buffer );

                i_queued_frames++;
            }
        }
    }
}