Exemplo n.º 1
0
static block_t *Filter(filter_t *filter, block_t *block)
{
    filter_sys_t *sys = filter->p_sys;

    if (sys->pre)
        sys->pre(block);

    for (int i = 0; i < 2; i++) {
        if (sys->directs[i]) {
            block = sys->directs[i](filter, block);
        } else if (sys->indirects[i]) {
            int dst_size = sys->indirects_ratio[i][1] *
                           (block->i_buffer / sys->indirects_ratio[i][0]);
            block_t *out = filter_NewAudioBuffer(filter, dst_size);
            if (!out) {
                block_Release(block);
                return NULL;
            }
            out->i_nb_samples = block->i_nb_samples;
            out->i_dts        = block->i_dts;
            out->i_pts        = block->i_pts;
            out->i_length     = block->i_length;

            sys->indirects[i](out, block);

            block_Release(block);
            block = out;
        }
    }

    if (sys->post)
        sys->post(block);
    return block;
}
Exemplo n.º 2
0
static block_t *Convert( filter_t *p_filter, block_t *p_block )
{
    if( !p_block || !p_block->i_nb_samples )
    {
        if( p_block )
            block_Release( p_block );
        return NULL;
    }

    size_t i_out_size = p_block->i_nb_samples *
      p_filter->fmt_out.audio.i_bitspersample *
        p_filter->fmt_out.audio.i_channels / 8;

    block_t *p_out = filter_NewAudioBuffer( p_filter, i_out_size );
    if( !p_out )
    {
        msg_Warn( p_filter, "can't get output buffer" );
        block_Release( p_block );
        return NULL;
    }

    p_out->i_nb_samples = p_block->i_nb_samples;
    p_out->i_dts = p_block->i_dts;
    p_out->i_pts = p_block->i_pts;
    p_out->i_length = p_block->i_length;

    DoWork( p_filter, p_block, p_out );

    block_Release( p_block );

    return p_out;
}
Exemplo n.º 3
0
/*****************************************************************************
 * DoWork: convert a buffer
 *****************************************************************************/
static block_t *DoWork( filter_t * p_filter, block_t *p_in_buf )
{
    /* AC3 is natively big endian. Most SPDIF devices have the native
     * endianness of the computer system.
     * On Mac OS X however, little endian devices are also common.
     */
    static const uint8_t p_sync_le[6] = { 0x72, 0xF8, 0x1F, 0x4E, 0x01, 0x00 };
    static const uint8_t p_sync_be[6] = { 0xF8, 0x72, 0x4E, 0x1F, 0x00, 0x01 };
    uint16_t i_frame_size = p_in_buf->i_buffer / 2;
    uint8_t * p_in = p_in_buf->p_buffer;

    block_t *p_out_buf = filter_NewAudioBuffer( p_filter, AOUT_SPDIF_SIZE );
    if( !p_out_buf )
        goto out;
    uint8_t * p_out = p_out_buf->p_buffer;

    /* Copy the S/PDIF headers. */
    if( p_filter->fmt_out.audio.i_format == VLC_CODEC_SPDIFB )
    {
        vlc_memcpy( p_out, p_sync_be, 6 );
        p_out[4] = p_in[5] & 0x7; /* bsmod */
        SetWBE( p_out + 6, i_frame_size << 4 );
        vlc_memcpy( &p_out[8], p_in, i_frame_size * 2 );
    }
    else
    {
        vlc_memcpy( p_out, p_sync_le, 6 );
        p_out[5] = p_in[5] & 0x7; /* bsmod */
        SetWLE( p_out + 6, i_frame_size << 4 );
        swab( p_in, &p_out[8], i_frame_size * 2 );
    }
    vlc_memset( p_out + 8 + i_frame_size * 2, 0,
                AOUT_SPDIF_SIZE - i_frame_size * 2 - 8 );

    p_out_buf->i_dts = p_in_buf->i_dts;
    p_out_buf->i_pts = p_in_buf->i_pts;
    p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
    p_out_buf->i_buffer = AOUT_SPDIF_SIZE;
out:
    block_Release( p_in_buf );
    return p_out_buf;
}
Exemplo n.º 4
0
/*****************************************************************************
 * DoWork: filter wrapper for transform_buffer
 *****************************************************************************/
static block_t *DoWork( filter_t * p_filter, block_t * p_in_buf )
{
    filter_sys_t *p = p_filter->p_sys;

    if( p_filter->fmt_in.audio.i_rate == p->sample_rate )
        return p_in_buf;

    double scale = p_filter->fmt_in.audio.i_rate / (double)p->sample_rate;
    if( scale != p->scale ) {
      p->scale = scale;
      p->bytes_stride_scaled  = p->bytes_stride * p->scale;
      p->frames_stride_scaled = p->bytes_stride_scaled / p->bytes_per_frame;
      p->bytes_to_slide = 0;
      msg_Dbg( p_filter, "%.3f scale, %.3f stride_in, %i stride_out",
               p->scale,
               p->frames_stride_scaled,
               (int)( p->bytes_stride / p->bytes_per_frame ) );
    }

    size_t i_outsize = calculate_output_buffer_size ( p_filter, p_in_buf->i_buffer );
    block_t *p_out_buf = filter_NewAudioBuffer( p_filter, i_outsize );
    if( p_out_buf == NULL )
        return NULL;

    size_t bytes_out = transform_buffer( p_filter,
        p_in_buf->p_buffer, p_in_buf->i_buffer,
        p_out_buf->p_buffer );

    p_out_buf->i_buffer     = bytes_out;
    p_out_buf->i_nb_samples = bytes_out / p->bytes_per_frame;
    p_out_buf->i_dts        = p_in_buf->i_dts;
    p_out_buf->i_pts        = p_in_buf->i_pts;
    p_out_buf->i_length     = p_in_buf->i_length;

    block_Release( p_in_buf );
    return p_out_buf;
}
Exemplo n.º 5
0
Arquivo: remap.c Projeto: Mettbrot/vlc
/*****************************************************************************
 * Remap:
 *****************************************************************************/
static block_t *Remap( filter_t *p_filter, block_t *p_block )
{
    filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
    if( !p_block || !p_block->i_nb_samples )
    {
        if( p_block )
            block_Release( p_block );
        return NULL;
    }

    size_t i_out_size = p_block->i_nb_samples *
        p_filter->fmt_out.audio.i_bytes_per_frame;

    block_t *p_out = filter_NewAudioBuffer( p_filter, i_out_size );
    if( !p_out )
    {
        msg_Warn( p_filter, "can't get output buffer" );
        block_Release( p_block );
        return NULL;
    }
    p_out->i_nb_samples = p_block->i_nb_samples;
    p_out->i_dts = p_block->i_dts;
    p_out->i_pts = p_block->i_pts;
    p_out->i_length = p_block->i_length;

    memset( p_out->p_buffer, 0, i_out_size );

    p_sys->pf_remap( p_filter,
                (const void *)p_block->p_buffer, (void *)p_out->p_buffer,
                p_block->i_nb_samples,
                p_filter->fmt_in.audio.i_channels,
                p_filter->fmt_out.audio.i_channels );

    block_Release( p_block );

    return p_out;
}
Exemplo n.º 6
0
/*****************************************************************************
 * DoWork: convert a buffer
 *****************************************************************************/
static block_t *DoWork( filter_t * p_filter, block_t * p_in_buf )
{
    int i_input_nb = aout_FormatNbChannels( &p_filter->fmt_in.audio );
    int i_output_nb = aout_FormatNbChannels( &p_filter->fmt_out.audio );

    block_t *p_out_buf;
    if( i_input_nb >= i_output_nb )
    {
        p_out_buf = p_in_buf; /* mix in place */
        p_out_buf->i_buffer = p_in_buf->i_buffer / i_input_nb * i_output_nb;
    }
    else
    {
        p_out_buf = filter_NewAudioBuffer( p_filter,
                              p_in_buf->i_buffer / i_input_nb * i_output_nb );
        if( !p_out_buf )
            goto out;
        p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
        p_out_buf->i_dts        = p_in_buf->i_dts;
        p_out_buf->i_pts        = p_in_buf->i_pts;
        p_out_buf->i_length     = p_in_buf->i_length;
    }

    float * p_dest = (float *)p_out_buf->p_buffer;
    const float * p_src = (float *)p_in_buf->p_buffer;

    if ( (p_filter->fmt_out.audio.i_original_channels & AOUT_CHAN_PHYSMASK)
                != (p_filter->fmt_in.audio.i_original_channels & AOUT_CHAN_PHYSMASK)
           && (p_filter->fmt_in.audio.i_original_channels & AOUT_CHAN_PHYSMASK)
                == (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT) )
    {
        int i;
        /* This is a bit special. */
        if ( !(p_filter->fmt_out.audio.i_original_channels & AOUT_CHAN_LEFT) )
        {
            p_src++;
        }
        if ( p_filter->fmt_out.audio.i_physical_channels == AOUT_CHAN_CENTER )
        {
            /* Mono mode */
            for ( i = p_in_buf->i_nb_samples; i--; )
            {
                *p_dest = *p_src;
                p_dest++;
                p_src += 2;
            }
        }
        else
        {
            /* Fake-stereo mode */
            for ( i = p_in_buf->i_nb_samples; i--; )
            {
                *p_dest = *p_src;
                p_dest++;
                *p_dest = *p_src;
                p_dest++;
                p_src += 2;
            }
        }
    }
    else if ( p_filter->fmt_out.audio.i_original_channels
                                    & AOUT_CHAN_REVERSESTEREO )
    {
        /* Reverse-stereo mode */
        int i;
        for ( i = p_in_buf->i_nb_samples; i--; )
        {
            float i_tmp = p_src[0];
            p_dest[0] = p_src[1];
            p_dest[1] = i_tmp;

            p_dest += 2;
            p_src += 2;
        }
    }
    else
    {
        SparseCopy( p_dest, p_src, p_in_buf->i_nb_samples, i_output_nb,
                    i_input_nb );
    }
out:
    if( p_in_buf != p_out_buf )
        block_Release( p_in_buf );
    return p_out_buf;
}
Exemplo n.º 7
0
/*****************************************************************************
 * DoWork: convert a buffer
 *****************************************************************************/
static block_t *DoWork( filter_t * p_filter, block_t * p_in_buf )
{
    uint32_t i_ac5_spdif_type = 0;
    uint16_t i_fz = p_in_buf->i_nb_samples * 4;
    uint16_t i_frame, i_length = p_in_buf->i_buffer;
    static const uint8_t p_sync_le[6] = { 0x72, 0xF8, 0x1F, 0x4E, 0x00, 0x00 };
    static const uint8_t p_sync_be[6] = { 0xF8, 0x72, 0x4E, 0x1F, 0x00, 0x00 };

    if( p_in_buf->i_buffer != p_filter->p_sys->i_frame_size )
    {
        /* Frame size changed, reset everything */
        msg_Warn( p_filter, "Frame size changed from %zu to %zu, "
                          "resetting everything.",
                  p_filter->p_sys->i_frame_size, p_in_buf->i_buffer );

        p_filter->p_sys->i_frame_size = p_in_buf->i_buffer;
        p_filter->p_sys->p_buf = xrealloc( p_filter->p_sys->p_buf,
                                                  p_in_buf->i_buffer * 3 );
        p_filter->p_sys->i_frames = 0;
    }

    /* Backup frame */
    /* TODO: keeping the blocks in a list would save one memcpy */
    memcpy( p_filter->p_sys->p_buf + p_in_buf->i_buffer *
                  p_filter->p_sys->i_frames,
                p_in_buf->p_buffer, p_in_buf->i_buffer );

    p_filter->p_sys->i_frames++;

    if( p_filter->p_sys->i_frames < 3 )
    {
        if( p_filter->p_sys->i_frames == 1 )
            /* We'll need the starting date */
            p_filter->p_sys->start_date = p_in_buf->i_pts;

        /* Not enough data */
        block_Release( p_in_buf );
        return NULL;
    }

    p_filter->p_sys->i_frames = 0;
    block_t *p_out_buf = filter_NewAudioBuffer( p_filter,
                                                12 * p_in_buf->i_nb_samples );
    if( !p_out_buf )
        goto out;

    for( i_frame = 0; i_frame < 3; i_frame++ )
    {
        uint16_t i_length_padded = i_length;
        uint8_t * p_out = p_out_buf->p_buffer + (i_frame * i_fz);
        uint8_t * p_in = p_filter->p_sys->p_buf + (i_frame * i_length);

        switch( p_in_buf->i_nb_samples )
        {
            case  512: i_ac5_spdif_type = 0x0B; break;
            case 1024: i_ac5_spdif_type = 0x0C; break;
            case 2048: i_ac5_spdif_type = 0x0D; break;
        }

        /* Copy the S/PDIF headers. */
        if( p_filter->fmt_out.audio.i_format == VLC_CODEC_SPDIFB )
        {
            memcpy( p_out, p_sync_be, 6 );
            p_out[5] = i_ac5_spdif_type;
            SetWBE( p_out + 6, i_length << 3 );
        }
        else
        {
            memcpy( p_out, p_sync_le, 6 );
            p_out[4] = i_ac5_spdif_type;
            SetWLE( p_out + 6, i_length << 3 );
        }

        if( ( (p_in[0] == 0x1F || p_in[0] == 0x7F) && p_filter->fmt_out.audio.i_format == VLC_CODEC_SPDIFL ) ||
            ( (p_in[0] == 0xFF || p_in[0] == 0xFE) && p_filter->fmt_out.audio.i_format == VLC_CODEC_SPDIFB ) )
        {
            /* We are dealing with a big endian bitstream and a little endian output
             * or a little endian bitstream and a big endian output.
             * Byteswap the stream */
            swab( p_in, p_out + 8, i_length );

            /* If i_length is odd, we have to adjust swapping a bit.. */
            if( i_length & 1 )
            {
                p_out[8+i_length-1] = 0;
                p_out[8+i_length] = p_in[i_length-1];
                i_length_padded++;
            }
        }
        else
        {
            memcpy( p_out + 8, p_in, i_length );
        }

        if( i_fz > i_length + 8 )
        {
            memset( p_out + 8 + i_length_padded, 0,
                        i_fz - i_length_padded - 8 );
        }
    }

    p_out_buf->i_pts = p_filter->p_sys->start_date;
    p_out_buf->i_nb_samples = p_in_buf->i_nb_samples * 3;
    p_out_buf->i_buffer = p_out_buf->i_nb_samples * 4;
out:
    block_Release( p_in_buf );
    return p_out_buf;
}
Exemplo n.º 8
0
/*****************************************************************************
 * Resample: convert a buffer
 *****************************************************************************/
static block_t *Resample( filter_t * p_filter, block_t * p_in_buf )
{
    if( !p_in_buf || !p_in_buf->i_nb_samples )
    {
        if( p_in_buf )
            block_Release( p_in_buf );
        return NULL;
    }

    filter_sys_t *p_sys = p_filter->p_sys;
    unsigned int i_out_rate = p_filter->fmt_out.audio.i_rate;
    int i_nb_channels = aout_FormatNbChannels( &p_filter->fmt_in.audio );

    /* Check if we really need to run the resampler */
    if( i_out_rate == p_filter->fmt_in.audio.i_rate )
    {
        if( !(p_in_buf->i_flags & BLOCK_FLAG_DISCONTINUITY) &&
            p_sys->i_old_wing )
        {
            /* output the whole thing with the samples from last time */
            p_in_buf = block_Realloc( p_in_buf,
                p_sys->i_old_wing * p_filter->fmt_in.audio.i_bytes_per_frame,
                p_in_buf->i_buffer );
            if( !p_in_buf )
                return NULL;
            memcpy( p_in_buf->p_buffer, p_sys->p_buf +
                    i_nb_channels * p_sys->i_old_wing,
                    p_sys->i_old_wing *
                    p_filter->fmt_in.audio.i_bytes_per_frame );

            p_in_buf->i_nb_samples += p_sys->i_old_wing;

            p_in_buf->i_pts = date_Get( &p_sys->end_date );
            p_in_buf->i_length =
                date_Increment( &p_sys->end_date,
                                p_in_buf->i_nb_samples ) - p_in_buf->i_pts;
        }
        p_sys->i_old_wing = 0;
        p_sys->b_first = true;
        return p_in_buf;
    }

    unsigned i_bytes_per_frame = p_filter->fmt_out.audio.i_channels *
                                 p_filter->fmt_out.audio.i_bitspersample / 8;
    size_t i_out_size = i_bytes_per_frame * ( 1 + ( p_in_buf->i_nb_samples *
              p_filter->fmt_out.audio.i_rate / p_filter->fmt_in.audio.i_rate) )
            + p_filter->p_sys->i_buf_size;
    block_t *p_out_buf = filter_NewAudioBuffer( p_filter, i_out_size );
    if( !p_out_buf )
    {
        block_Release( p_in_buf );
        return NULL;
    }

    if( (p_in_buf->i_flags & BLOCK_FLAG_DISCONTINUITY) || p_sys->b_first )
    {
        /* Continuity in sound samples has been broken, we'd better reset
         * everything. */
        p_out_buf->i_flags |= BLOCK_FLAG_DISCONTINUITY;
        p_sys->i_remainder = 0;
        date_Init( &p_sys->end_date, i_out_rate, 1 );
        date_Set( &p_sys->end_date, p_in_buf->i_pts );
        p_sys->d_old_factor = 1;
        p_sys->i_old_wing   = 0;
        p_sys->b_first = false;
    }

    size_t i_in_nb = p_in_buf->i_nb_samples;
    size_t i_in, i_out = 0;
    double d_factor, d_scale_factor, d_old_scale_factor;
    size_t i_filter_wing;

#if 0
    msg_Err( p_filter, "old rate: %i, old factor: %f, old wing: %i, i_in: %i",
             p_sys->i_old_rate, p_sys->d_old_factor,
             p_sys->i_old_wing, i_in_nb );
#endif

    /* Same format in and out... */
    assert( p_filter->fmt_in.audio.i_bytes_per_frame == i_bytes_per_frame );

    /* Prepare the source buffer */
    if( p_sys->i_old_wing )
    {   /* Copy all our samples in p_in_buf */
        /* Normally, there should be enough room for the old wing in the
         * buffer head room. Otherwise, we need to copy memory anyway. */
        p_in_buf = block_Realloc( p_in_buf,
                                  p_sys->i_old_wing * 2 * i_bytes_per_frame,
                                  p_in_buf->i_buffer );
        if( unlikely(p_in_buf == NULL) )
            return NULL;
        memcpy( p_in_buf->p_buffer, p_sys->p_buf,
                p_sys->i_old_wing * 2 * i_bytes_per_frame );
    }
    i_in_nb += (p_sys->i_old_wing * 2);
    float *p_in = (float *)p_in_buf->p_buffer;
    const float *p_in_orig = p_in;

    /* Make sure the output buffer is reset */
    memset( p_out_buf->p_buffer, 0, p_out_buf->i_buffer );

    /* Calculate the new length of the filter wing */
    d_factor = (double)i_out_rate / p_filter->fmt_in.audio.i_rate;
    i_filter_wing = ((SMALL_FILTER_NMULT+1)/2.0) * __MAX(1.0,1.0/d_factor) + 1;

    /* Account for increased filter gain when using factors less than 1 */
    d_old_scale_factor = SMALL_FILTER_SCALE *
        p_sys->d_old_factor + 0.5;
    d_scale_factor = SMALL_FILTER_SCALE * d_factor + 0.5;

    /* Apply the old rate until we have enough samples for the new one */
    i_in = p_sys->i_old_wing;
    p_in += p_sys->i_old_wing * i_nb_channels;

    size_t i_old_in_end = 0;
    if( p_sys->i_old_wing <= i_in_nb )
        i_old_in_end = __MIN( i_filter_wing, i_in_nb - p_sys->i_old_wing );

    ResampleFloat( p_filter,
                   &p_out_buf, &i_out, &p_in,
                   i_in, i_old_in_end,
                   p_sys->d_old_factor, true,
                   i_nb_channels, i_bytes_per_frame );
    i_in = __MAX( i_in, i_old_in_end );

    /* Apply the new rate for the rest of the samples */
    if( i_in < i_in_nb - i_filter_wing )
    {
        p_sys->d_old_factor = d_factor;
        p_sys->i_old_wing   = i_filter_wing;
    }
    if( p_out_buf )
    {
        ResampleFloat( p_filter,
                       &p_out_buf, &i_out, &p_in,
                       i_in, i_in_nb - i_filter_wing,
                       d_factor, false,
                       i_nb_channels, i_bytes_per_frame );

        /* Finalize aout buffer */
        p_out_buf->i_nb_samples = i_out;
        p_out_buf->i_dts =
        p_out_buf->i_pts = date_Get( &p_sys->end_date );
        p_out_buf->i_length = date_Increment( &p_sys->end_date,
                                      p_out_buf->i_nb_samples ) - p_out_buf->i_pts;

        p_out_buf->i_buffer = p_out_buf->i_nb_samples *
            i_nb_channels * sizeof(int32_t);
    }

    /* Buffer i_filter_wing * 2 samples for next time */
    if( p_sys->i_old_wing )
    {
        size_t newsize = p_sys->i_old_wing * 2 * i_bytes_per_frame;
        if( newsize > p_sys->i_buf_size )
        {
            free( p_sys->p_buf );
            p_sys->p_buf = malloc( newsize );
            if( p_sys->p_buf != NULL )
                p_sys->i_buf_size = newsize;
            else
            {
                p_sys->i_buf_size = p_sys->i_old_wing = 0; /* oops! */
                block_Release( p_in_buf );
                return p_out_buf;
            }
        }
        memcpy( p_sys->p_buf,
                p_in_orig + (i_in_nb - 2 * p_sys->i_old_wing) *
                i_nb_channels, (2 * p_sys->i_old_wing) *
                p_filter->fmt_in.audio.i_bytes_per_frame );
    }

#if 0
    msg_Err( p_filter, "p_out size: %i, nb bytes out: %i", p_out_buf->i_buffer,
             i_out * p_filter->fmt_in.audio.i_bytes_per_frame );
#endif

    block_Release( p_in_buf );
    return p_out_buf;
}
Exemplo n.º 9
0
/*****************************************************************************
 * Resample: convert a buffer
 *****************************************************************************/
static block_t *Resample( filter_t * p_filter, block_t * p_in_buf )
{
    if( !p_in_buf || !p_in_buf->i_nb_samples )
    {
        if( p_in_buf )
            block_Release( p_in_buf );
        return NULL;
    }

    filter_sys_t *p_sys = p_filter->p_sys;
    unsigned int i_out_rate = p_filter->fmt_out.audio.i_rate;
    int i_nb_channels = aout_FormatNbChannels( &p_filter->fmt_in.audio );

    /* Check if we really need to run the resampler */
    if( i_out_rate == p_filter->fmt_in.audio.i_rate )
    {
        if( !(p_in_buf->i_flags & BLOCK_FLAG_DISCONTINUITY) &&
            p_sys->i_old_wing )
        {
            /* output the whole thing with the samples from last time */
            p_in_buf = block_Realloc( p_in_buf,
                p_sys->i_old_wing * p_filter->fmt_in.audio.i_bytes_per_frame,
                p_in_buf->i_buffer );
            if( !p_in_buf )
                return NULL;
            memcpy( p_in_buf->p_buffer, p_sys->p_buf +
                    i_nb_channels * p_sys->i_old_wing,
                    p_sys->i_old_wing *
                    p_filter->fmt_in.audio.i_bytes_per_frame );

            p_in_buf->i_nb_samples += p_sys->i_old_wing;

            p_in_buf->i_pts = date_Get( &p_sys->end_date );
            p_in_buf->i_length =
                date_Increment( &p_sys->end_date,
                                p_in_buf->i_nb_samples ) - p_in_buf->i_pts;
        }
        p_sys->i_old_wing = 0;
        p_sys->b_first = true;
        return p_in_buf;
    }

    unsigned i_bytes_per_frame = p_filter->fmt_out.audio.i_channels *
                                 p_filter->fmt_out.audio.i_bitspersample / 8;
    size_t i_out_size = i_bytes_per_frame * ( 1 + ( p_in_buf->i_nb_samples *
              p_filter->fmt_out.audio.i_rate / p_filter->fmt_in.audio.i_rate) )
            + p_filter->p_sys->i_buf_size;
    block_t *p_out_buf = filter_NewAudioBuffer( p_filter, i_out_size );
    if( !p_out_buf )
        return NULL;
    float *p_out = (float *)p_out_buf->p_buffer;

    if( (p_in_buf->i_flags & BLOCK_FLAG_DISCONTINUITY) || p_sys->b_first )
    {
        /* Continuity in sound samples has been broken, we'd better reset
         * everything. */
        p_out_buf->i_flags |= BLOCK_FLAG_DISCONTINUITY;
        p_sys->i_remainder = 0;
        date_Init( &p_sys->end_date, i_out_rate, 1 );
        date_Set( &p_sys->end_date, p_in_buf->i_pts );
        p_sys->d_old_factor = 1;
        p_sys->i_old_wing   = 0;
        p_sys->b_first = false;
    }

    int i_in_nb = p_in_buf->i_nb_samples;
    int i_in, i_out = 0;
    double d_factor, d_scale_factor, d_old_scale_factor;
    int i_filter_wing;

#if 0
    msg_Err( p_filter, "old rate: %i, old factor: %f, old wing: %i, i_in: %i",
             p_sys->i_old_rate, p_sys->d_old_factor,
             p_sys->i_old_wing, i_in_nb );
#endif

    /* Prepare the source buffer */
    i_in_nb += (p_sys->i_old_wing * 2);

    float p_in_orig[i_in_nb * p_filter->fmt_in.audio.i_bytes_per_frame / 4],
         *p_in = p_in_orig;

    /* Copy all our samples in p_in */
    if( p_sys->i_old_wing )
    {
        vlc_memcpy( p_in, p_sys->p_buf,
                    p_sys->i_old_wing * 2 *
                      p_filter->fmt_in.audio.i_bytes_per_frame );
    }
    /* XXX: why i_nb_channels instead of i_bytes_per_frame??? */
    vlc_memcpy( p_in + p_sys->i_old_wing * 2 * i_nb_channels,
                p_in_buf->p_buffer,
                p_in_buf->i_nb_samples * p_filter->fmt_in.audio.i_bytes_per_frame );
    block_Release( p_in_buf );

    /* Make sure the output buffer is reset */
    memset( p_out, 0, p_out_buf->i_buffer );

    /* Calculate the new length of the filter wing */
    d_factor = (double)i_out_rate / p_filter->fmt_in.audio.i_rate;
    i_filter_wing = ((SMALL_FILTER_NMULT+1)/2.0) * __MAX(1.0,1.0/d_factor) + 1;

    /* Account for increased filter gain when using factors less than 1 */
    d_old_scale_factor = SMALL_FILTER_SCALE *
        p_sys->d_old_factor + 0.5;
    d_scale_factor = SMALL_FILTER_SCALE * d_factor + 0.5;

    /* Apply the old rate until we have enough samples for the new one */
    i_in = p_sys->i_old_wing;
    p_in += p_sys->i_old_wing * i_nb_channels;
    for( ; i_in < i_filter_wing &&
           (i_in + p_sys->i_old_wing) < i_in_nb; i_in++ )
    {
        if( p_sys->d_old_factor == 1 )
        {
            /* Just copy the samples */
            memcpy( p_out, p_in,
                    p_filter->fmt_in.audio.i_bytes_per_frame );
            p_in += i_nb_channels;
            p_out += i_nb_channels;
            i_out++;
            continue;
        }

        while( p_sys->i_remainder < p_filter->fmt_out.audio.i_rate )
        {

            if( p_sys->d_old_factor >= 1 )
            {
                /* FilterFloatUP() is faster if we can use it */

                /* Perform left-wing inner product */
                FilterFloatUP( SMALL_FILTER_FLOAT_IMP, SMALL_FILTER_FLOAT_IMPD,
                               SMALL_FILTER_NWING, p_in, p_out,
                               p_sys->i_remainder,
                               p_filter->fmt_out.audio.i_rate,
                               -1, i_nb_channels );
                /* Perform right-wing inner product */
                FilterFloatUP( SMALL_FILTER_FLOAT_IMP, SMALL_FILTER_FLOAT_IMPD,
                               SMALL_FILTER_NWING, p_in + i_nb_channels, p_out,
                               p_filter->fmt_out.audio.i_rate -
                               p_sys->i_remainder,
                               p_filter->fmt_out.audio.i_rate,
                               1, i_nb_channels );

#if 0
                /* Normalize for unity filter gain */
                for( i = 0; i < i_nb_channels; i++ )
                {
                    *(p_out+i) *= d_old_scale_factor;
                }
#endif

                /* Sanity check */
                if( p_out_buf->i_buffer/p_filter->fmt_in.audio.i_bytes_per_frame
                    <= (unsigned int)i_out+1 )
                {
                    p_out += i_nb_channels;
                    i_out++;
                    p_sys->i_remainder += p_filter->fmt_in.audio.i_rate;
                    break;
                }
            }
            else
            {
                /* Perform left-wing inner product */
                FilterFloatUD( SMALL_FILTER_FLOAT_IMP, SMALL_FILTER_FLOAT_IMPD,
                               SMALL_FILTER_NWING, p_in, p_out,
                               p_sys->i_remainder,
                               p_filter->fmt_out.audio.i_rate, p_filter->fmt_in.audio.i_rate,
                               -1, i_nb_channels );
                /* Perform right-wing inner product */
                FilterFloatUD( SMALL_FILTER_FLOAT_IMP, SMALL_FILTER_FLOAT_IMPD,
                               SMALL_FILTER_NWING, p_in + i_nb_channels, p_out,
                               p_filter->fmt_out.audio.i_rate -
                               p_sys->i_remainder,
                               p_filter->fmt_out.audio.i_rate, p_filter->fmt_in.audio.i_rate,
                               1, i_nb_channels );
            }

            p_out += i_nb_channels;
            i_out++;

            p_sys->i_remainder += p_filter->fmt_in.audio.i_rate;
        }

        p_in += i_nb_channels;
        p_sys->i_remainder -= p_filter->fmt_out.audio.i_rate;
    }

    /* Apply the new rate for the rest of the samples */
    if( i_in < i_in_nb - i_filter_wing )
    {
        p_sys->d_old_factor = d_factor;
        p_sys->i_old_wing   = i_filter_wing;
    }
    for( ; i_in < i_in_nb - i_filter_wing; i_in++ )
    {
        while( p_sys->i_remainder < p_filter->fmt_out.audio.i_rate )
        {

            if( d_factor >= 1 )
            {
                /* FilterFloatUP() is faster if we can use it */

                /* Perform left-wing inner product */
                FilterFloatUP( SMALL_FILTER_FLOAT_IMP, SMALL_FILTER_FLOAT_IMPD,
                               SMALL_FILTER_NWING, p_in, p_out,
                               p_sys->i_remainder,
                               p_filter->fmt_out.audio.i_rate,
                               -1, i_nb_channels );

                /* Perform right-wing inner product */
                FilterFloatUP( SMALL_FILTER_FLOAT_IMP, SMALL_FILTER_FLOAT_IMPD,
                               SMALL_FILTER_NWING, p_in + i_nb_channels, p_out,
                               p_filter->fmt_out.audio.i_rate -
                               p_sys->i_remainder,
                               p_filter->fmt_out.audio.i_rate,
                               1, i_nb_channels );

#if 0
                /* Normalize for unity filter gain */
                for( int i = 0; i < i_nb_channels; i++ )
                {
                    *(p_out+i) *= d_old_scale_factor;
                }
#endif
                /* Sanity check */
                if( p_out_buf->i_buffer/p_filter->fmt_in.audio.i_bytes_per_frame
                    <= (unsigned int)i_out+1 )
                {
                    p_out += i_nb_channels;
                    i_out++;
                    p_sys->i_remainder += p_filter->fmt_in.audio.i_rate;
                    break;
                }
            }
            else
            {
                /* Perform left-wing inner product */
                FilterFloatUD( SMALL_FILTER_FLOAT_IMP, SMALL_FILTER_FLOAT_IMPD,
                               SMALL_FILTER_NWING, p_in, p_out,
                               p_sys->i_remainder,
                               p_filter->fmt_out.audio.i_rate, p_filter->fmt_in.audio.i_rate,
                               -1, i_nb_channels );
                /* Perform right-wing inner product */
                FilterFloatUD( SMALL_FILTER_FLOAT_IMP, SMALL_FILTER_FLOAT_IMPD,
                               SMALL_FILTER_NWING, p_in + i_nb_channels, p_out,
                               p_filter->fmt_out.audio.i_rate -
                               p_sys->i_remainder,
                               p_filter->fmt_out.audio.i_rate, p_filter->fmt_in.audio.i_rate,
                               1, i_nb_channels );
            }

            p_out += i_nb_channels;
            i_out++;

            p_sys->i_remainder += p_filter->fmt_in.audio.i_rate;
        }

        p_in += i_nb_channels;
        p_sys->i_remainder -= p_filter->fmt_out.audio.i_rate;
    }

    /* Finalize aout buffer */
    p_out_buf->i_nb_samples = i_out;
    p_out_buf->i_pts = date_Get( &p_sys->end_date );
    p_out_buf->i_length = date_Increment( &p_sys->end_date,
                                  p_out_buf->i_nb_samples ) - p_out_buf->i_pts;

    p_out_buf->i_buffer = p_out_buf->i_nb_samples *
        i_nb_channels * sizeof(int32_t);

    /* Buffer i_filter_wing * 2 samples for next time */
    if( p_sys->i_old_wing )
    {
        size_t newsize = p_sys->i_old_wing * 2
                         * p_filter->fmt_in.audio.i_bytes_per_frame;
        if( newsize > p_sys->i_buf_size )
        {
            free( p_sys->p_buf );
            p_sys->p_buf = malloc( newsize );
            if( p_sys->p_buf != NULL )
                p_sys->i_buf_size = newsize;
            else
            {
                p_sys->i_buf_size = p_sys->i_old_wing = 0; /* oops! */
                return p_out_buf;
            }
        }
        memcpy( p_sys->p_buf,
                p_in_orig + (i_in_nb - 2 * p_sys->i_old_wing) *
                i_nb_channels, (2 * p_sys->i_old_wing) *
                p_filter->fmt_in.audio.i_bytes_per_frame );
    }

#if 0
    msg_Err( p_filter, "p_out size: %i, nb bytes out: %i", p_out_buf->i_buffer,
             i_out * p_filter->fmt_in.audio.i_bytes_per_frame );
#endif

    return p_out_buf;
}