Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  wav.c   Sprache: C

 

/*****************************************************************************
 * wav.c : wav file input module for vlc
 *****************************************************************************
 * Copyright (C) 2001-2008 VLC authors and VideoLAN
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/


/*****************************************************************************
 * Preamble
 *****************************************************************************/


#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <assert.h>
#include <limits.h>

#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_demux.h>
#include <vlc_aout.h>
#include <vlc_codecs.h>

#include "windows_audio_commons.h"

#define WAV_CHAN_MAX 32
static_assert( INPUT_CHAN_MAX >= WAV_CHAN_MAX, "channel count mismatch" );

typedef struct
{
    es_format_t     fmt;
    es_out_id_t     *p_es;

    uint64_t        i_data_pos;
    uint64_t        i_data_size;

    unsigned int    i_frame_size;
    unsigned int    i_frame_samples;

    date_t          pts;

    uint8_t i_chans_to_reorder;            /* do we need channel reordering */
    uint8_t pi_chan_table[AOUT_CHAN_MAX];
} demux_sys_t;

enum wav_chunk_id {
    wav_chunk_id_data,
    wav_chunk_id_ds64,
    wav_chunk_id_fmt,
};

static const struct wav_chunk_id_key
{
    enum wav_chunk_id id;
    char key[5];
} wav_chunk_id_key_list[] =  {
    /* Alphabetical order */
    { wav_chunk_id_data, "data" },
    { wav_chunk_id_ds64, "ds64" },
    { wav_chunk_id_fmt,  "fmt " },
};
static const size_t wav_chunk_id_key_count = ARRAY_SIZE(wav_chunk_id_key_list);

static int
wav_chunk_CompareCb(const void *a, const void *b)
{
    const struct wav_chunk_id_key *id = b;
    return memcmp(a, id->key, 4);
}

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 = vlc_stream_Tell( p_demux->s );
    unsigned int i_read_size = p_sys->i_frame_size;
    uint32_t i_read_samples = p_sys->i_frame_samples;


    if( p_sys->i_data_size > 0 )
    {
        int64_t i_end = p_sys->i_data_pos + p_sys->i_data_size;
        if ( i_pos >= i_end )
            return VLC_DEMUXER_EOF;  /* EOF */

        /* Don't read past data chunk boundary */
        if ( i_end < i_pos + i_read_size )
        {
            i_read_size = i_end - i_pos;
            i_read_samples = ( p_sys->i_frame_size - i_read_size )
                           * p_sys->i_frame_samples / p_sys->i_frame_size;
        }
    }

    if( ( p_block = vlc_stream_Block( p_demux->s, i_read_size ) ) == NULL )
    {
        msg_Warn( p_demux, "cannot read data" );
        return VLC_DEMUXER_EOF;
    }

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

    /* set PCR */
    es_out_SetPCR( p_demux->out, 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->i_chans_to_reorder,
                             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, i_read_samples );

    return VLC_DEMUXER_SUCCESS;
}

static int Control( demux_t *p_demux, int i_query, va_list args )
{
    demux_sys_t *p_sys  = p_demux->p_sys;
    int64_t i_end = -1;

    if( p_sys->i_data_size > 0 )
        i_end = p_sys->i_data_pos + p_sys->i_data_size;

    int ret = demux_vaControlHelper( p_demux->s, p_sys->i_data_pos, i_end,
                                     p_sys->fmt.i_bitrate,
                                     p_sys->fmt.audio.i_blockalign,
                                     i_query, args );
    if( ret != VLC_SUCCESS )
        return ret;

    /* Update the date to the new seek point */
    switch( i_query )
    {
        case DEMUX_SET_POSITION:
        case DEMUX_SET_TIME:
        {
            uint64_t ofs = vlc_stream_Tell( p_demux->s );
            if( unlikely( ofs < p_sys->i_data_pos ) )
                return VLC_SUCCESS;

            ofs -= p_sys->i_data_pos;
            vlc_tick_t pts = VLC_TICK_0 +
                vlc_tick_from_samples( ofs * 8, p_sys->fmt.i_bitrate );
            date_Set( &p_sys->pts, pts );
            break;
        }
        default:
            break;
    }
    return VLC_SUCCESS;
}

static int ChunkSkip( demux_t *p_demux, uint32_t i_size )
{
    i_size += i_size & 1;

    if( unlikely( i_size >= 65536 ) )
    {
        /* Arbitrary size where a seek should be performed instead of skipping
         * by reading NULL. Non data chunks are generally smaller than this.
         * This seek may be used to skip the data chunk if there is an other
         * chunk after it (unlikely). */

        return vlc_stream_Seek( p_demux->s,
                                vlc_stream_Tell( p_demux->s ) + i_size );
    }

    return vlc_stream_Read( p_demux->s, NULL, i_size ) != i_size ? VLC_EGENERIC : VLC_SUCCESS;
}

static int ChunkGetNext( demux_t *p_demux, enum wav_chunk_id *p_id,
                         uint32_t *pi_size )
{
#ifndef NDEBUG
    /* assert that keys are in alphabetical order */
    for( size_t i = 0; i < wav_chunk_id_key_count - 1; ++i )
        assert( strcmp( wav_chunk_id_key_list[i].key,
                        wav_chunk_id_key_list[i + 1].key ) < 0 );
#endif

    for( ;; )
    {
        const uint8_t *p_peek;
        if( vlc_stream_Peek( p_demux->s, &p_peek, 8 ) < 8 )
            return VLC_EGENERIC;

        const struct wav_chunk_id_key *id =
            bsearch( p_peek, wav_chunk_id_key_list, wav_chunk_id_key_count,
                     sizeof(*wav_chunk_id_key_list), wav_chunk_CompareCb );
        uint32_t i_size = GetDWLE( p_peek + 4 );

        if( id == NULL )
        {
            msg_Warn( p_demux, "unknown chunk '%4.4s' of size: %u",
                      p_peek, i_size );

            if( vlc_stream_Read( p_demux->s, NULL, 8 ) != 8 )
                return VLC_EGENERIC;

            if( ChunkSkip( p_demux, i_size ) != VLC_SUCCESS )
                return VLC_EGENERIC;
            continue;
        }

        if( vlc_stream_Read( p_demux->s, NULL, 8 ) != 8 )
            return VLC_EGENERIC;

        *p_id = id->id;
        *pi_size = i_size;

        return VLC_SUCCESS;
    }
}

static int FrameInfo_PCM( unsigned int *pi_size, unsigned *pi_samples,
                          const es_format_t *p_fmt )
{
    int i_bytes;

    if( p_fmt->audio.i_rate > 352800
     || p_fmt->audio.i_bitspersample > 64
     || p_fmt->audio.i_channels > WAV_CHAN_MAX )
        return VLC_EGENERIC;

    /* read samples for 50ms of */
    *pi_samples = __MAX( p_fmt->audio.i_rate / 20, 1 );

    i_bytes = *pi_samples * p_fmt->audio.i_channels *
        ( (p_fmt->audio.i_bitspersample + 7) / 8 );

    if( p_fmt->audio.i_blockalign > 0 )
    {
        const int i_modulo = i_bytes % p_fmt->audio.i_blockalign;
        if( i_modulo > 0 )
            i_bytes += p_fmt->audio.i_blockalign - i_modulo;
    }

    *pi_size = i_bytes;
    return VLC_SUCCESS;
}

static int FrameInfo_MS_ADPCM( unsigned int *pi_size, unsigned *pi_samples,
                               const es_format_t *p_fmt )
{
    if( p_fmt->audio.i_channels == 0 )
        return VLC_EGENERIC;

    if( p_fmt->audio.i_blockalign < 7 * p_fmt->audio.i_channels )
        return VLC_EGENERIC;

    *pi_samples = 2 + 2 * ( p_fmt->audio.i_blockalign -
        7 * p_fmt->audio.i_channels ) / p_fmt->audio.i_channels;
    *pi_size = p_fmt->audio.i_blockalign;

    return VLC_SUCCESS;
}

static int FrameInfo_IMA_ADPCM( unsigned int *pi_size, unsigned *pi_samples,
                                const es_format_t *p_fmt )
{
    if( p_fmt->audio.i_channels == 0 )
        return VLC_EGENERIC;

    if( p_fmt->audio.i_blockalign < 4 * p_fmt->audio.i_channels )
        return VLC_EGENERIC;

    *pi_samples = 2 * ( p_fmt->audio.i_blockalign -
        4 * p_fmt->audio.i_channels ) / p_fmt->audio.i_channels;
    *pi_size = p_fmt->audio.i_blockalign;

    return VLC_SUCCESS;
}

static int FrameInfo_Creative_ADPCM( unsigned int *pi_size, unsigned *pi_samples,
                                     const es_format_t *p_fmt )
{
    if( p_fmt->audio.i_channels == 0 )
        return VLC_EGENERIC;

    /* 4 bits / sample */
    *pi_samples = p_fmt->audio.i_blockalign * 2 / p_fmt->audio.i_channels;
    *pi_size = p_fmt->audio.i_blockalign;

    return VLC_SUCCESS;
}

static int FrameInfo_MSGSM( unsigned int *pi_size, unsigned *pi_samples,
                            const es_format_t *p_fmt )
{
    if( p_fmt->i_bitrate <= 0 )
        return VLC_EGENERIC;

    *pi_samples = ( p_fmt->audio.i_blockalign * p_fmt->audio.i_rate * 8)
                    / p_fmt->i_bitrate;
    *pi_size = p_fmt->audio.i_blockalign;

    return VLC_SUCCESS;
}
static void Close ( vlc_object_t * p_this )
{
    demux_t     *p_demux = (demux_t*)p_this;
    demux_sys_t *p_sys   = p_demux->p_sys;

    es_format_Clean( &p_sys->fmt );
    free( p_sys );
}

static int ChunkParseDS64( demux_t *p_demux, uint32_t i_size )
{
    demux_sys_t *p_sys = p_demux->p_sys;
    const uint8_t *p_peek;

    if( i_size < 24 )
    {
        msg_Err( p_demux, "invalid 'ds64' chunk" );
        return VLC_EGENERIC;
    }

    if( vlc_stream_Peek( p_demux->s, &p_peek, 24 ) < 24 )
        return VLC_EGENERIC;

    p_sys->i_data_size = GetQWLE( &p_peek[8] );

    return ChunkSkip( p_demux, i_size );
}

static void InitFmt( demux_t *p_demux )
{
    demux_sys_t *p_sys = p_demux->p_sys;

    es_format_Init( &p_sys->fmt, AUDIO_ES, 0 );
    p_sys->i_frame_size = 0;
    p_sys->i_frame_samples = 0;
    p_sys->i_chans_to_reorder = 0;
}

static int ChunkParseFmt( demux_t *p_demux, uint32_t i_size )
{
    demux_sys_t *p_sys = p_demux->p_sys;
    WAVEFORMATEXTENSIBLE *p_wf_ext = NULL;
    WAVEFORMATEX         *p_wf = NULL;
    const char *psz_name;
    unsigned int i_extended;

    i_size += 2;
    if( i_size < sizeof( WAVEFORMATEX ) || i_size > (sizeof( WAVEFORMATEX ) + UINT16_MAX ) )
    {
        msg_Err( p_demux, "invalid 'fmt ' chunk of size %" PRIu32, i_size );
        goto error;
    }

    /* load waveformatex */
    p_wf_ext = malloc( i_size );
    if( unlikely( !p_wf_ext ) )
         goto error;

    p_wf         = &p_wf_ext->Format;
    p_wf->cbSize = 0;
    i_size      -= 2;
    if( vlc_stream_Read( p_demux->s, p_wf, i_size ) != (int)i_size ||
        ( ( i_size & 1 ) && vlc_stream_Read( p_demux->s, NULL, 1 ) != 1 ) )
    {
        msg_Err( p_demux, "cannot load 'fmt ' chunk" );
        goto error;
    }

    wf_tag_to_fourcc( GetWLE( &p_wf->wFormatTag ), &p_sys->fmt.i_codec,
                      &psz_name );
    p_sys->fmt.audio.i_channels      = GetWLE ( &p_wf->nChannels );
    p_sys->fmt.audio.i_rate          = GetDWLE( &p_wf->nSamplesPerSec );
    p_sys->fmt.audio.i_blockalign    = GetWLE( &p_wf->nBlockAlign );
    p_sys->fmt.i_bitrate             = GetDWLE( &p_wf->nAvgBytesPerSec ) * 8;
    p_sys->fmt.audio.i_bitspersample = GetWLE( &p_wf->wBitsPerSample );
    if( i_size >= sizeof(WAVEFORMATEX) )
        p_sys->fmt.i_extra = __MIN( GetWLE( &p_wf->cbSize ), i_size - sizeof(WAVEFORMATEX) );
    i_extended = 0;

    unsigned i_channel_mask = 0;
    /* Handle new WAVE_FORMAT_EXTENSIBLE wav files */
    /* see the following link for more information:
     * http://www.microsoft.com/whdc/device/audio/multichaud.mspx#EFAA */

    if( GetWLE( &p_wf->wFormatTag ) == WAVE_FORMAT_EXTENSIBLE &&
        i_size >= sizeof( WAVEFORMATEXTENSIBLE ) &&
        ( p_sys->fmt.i_extra + sizeof( WAVEFORMATEX )
            >= sizeof( WAVEFORMATEXTENSIBLE ) ) )
    {
        unsigned dwChannelMask;
        GUID guid_subformat;

        guid_subformat = p_wf_ext->SubFormat;
        guid_subformat.Data1 = GetDWLE( &p_wf_ext->SubFormat.Data1 );
        guid_subformat.Data2 = GetWLE( &p_wf_ext->SubFormat.Data2 );
        guid_subformat.Data3 = GetWLE( &p_wf_ext->SubFormat.Data3 );

        sf_tag_to_fourcc( &guid_subformat, &p_sys->fmt.i_codec, &psz_name );

        msg_Dbg( p_demux, "extensible format guid " GUID_FMT, GUID_PRINT(guid_subformat) );

        i_extended = sizeof( WAVEFORMATEXTENSIBLE ) - sizeof( WAVEFORMATEX );
        p_sys->fmt.i_extra -= i_extended;

        dwChannelMask = GetDWLE( &p_wf_ext->dwChannelMask );
        if( dwChannelMask )
        {
            int i_match = 0;
            i_channel_mask = getChannelMask( &dwChannelMask, p_sys->fmt.audio.i_channels, &i_match );
            if( dwChannelMask )
                msg_Warn( p_demux, "Some channels are unrecognized or uselessly specified (0x%x)", dwChannelMask );
            if( i_match < p_sys->fmt.audio.i_channels )
            {
                int i_missing = p_sys->fmt.audio.i_channels - i_match;
                msg_Warn( p_demux, "Trying to fill up unspecified position for %d channels", p_sys->fmt.audio.i_channels - i_match );

                static const uint32_t pi_pair[] = { AOUT_CHAN_REARLEFT|AOUT_CHAN_REARRIGHT,
                                                    AOUT_CHAN_MIDDLELEFT|AOUT_CHAN_MIDDLERIGHT,
                                                    AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT };
                /* FIXME: Unused yet
                static const uint32_t pi_center[] = { AOUT_CHAN_REARCENTER,
                                                      0,
                                                      AOUT_CHAN_CENTER }; */


                /* Try to complete with pair */
                for( unsigned i = 0; i < ARRAY_SIZE(pi_pair); i++ )
                {
                    if( i_missing >= 2 && !(i_channel_mask & pi_pair[i] ) )
                    {
                        i_missing -= 2;
                        i_channel_mask |= pi_pair[i];
                    }
                }
                /* Well fill up with what we can */
                for( unsigned i = 0; pi_channels_aout[i] && i_missing > 0; i++ )
                {
                    if( !( i_channel_mask & pi_channels_aout[i] ) )
                    {
                        i_channel_mask |= pi_channels_aout[i];
                        i_missing--;
                    }
                }

                if( i_missing > 0 )
                {
                    msg_Err( p_demux, "Invalid/unsupported channel mask" );
                    i_channel_mask = 0;
                }
            }
        }
    }
    if( i_channel_mask == 0 && p_sys->fmt.audio.i_channels > 2
     && p_sys->fmt.audio.i_channels <= AOUT_CHAN_MAX )
    {
        /* A dwChannelMask of 0 tells the audio device to render the first
         * channel to the first port on the device, the second channel to the
         * second port on the device, and so on. pi_default_channels is
         * different than pi_channels_aout. Indeed FLC/FRC must be treated a
         * SL/SR in that case. See "Default Channel Ordering" and "Details
         * about dwChannelMask" from msdn */


        static const uint32_t pi_default_channels[] = {
            AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_CENTER,
            AOUT_CHAN_LFE, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
            AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT, AOUT_CHAN_REARCENTER };

        for( unsigned i = 0; i < p_sys->fmt.audio.i_channels &&
             i < ARRAY_SIZE(pi_default_channels);
             i++ )
            i_channel_mask |= pi_default_channels[i];
    }

    if( i_channel_mask )
    {
        if( p_sys->fmt.i_codec == VLC_FOURCC('a','r','a','w') ||
            p_sys->fmt.i_codec == VLC_FOURCC('a','f','l','t') )
            p_sys->i_chans_to_reorder =
                aout_CheckChannelReorder( pi_channels_aout, NULL,
                                          i_channel_mask,
                                          p_sys->pi_chan_table );

        msg_Dbg( p_demux, "channel mask: %x, reordering: %u",
                 i_channel_mask, p_sys->i_chans_to_reorder );
    }

    p_sys->fmt.audio.i_physical_channels = i_channel_mask;

    if( p_sys->fmt.i_extra > 0 )
    {
        p_sys->fmt.p_extra = malloc( p_sys->fmt.i_extra );
        if( unlikely(!p_sys->fmt.p_extra) )
        {
            p_sys->fmt.i_extra = 0;
            goto error;
        }
        memcpy( p_sys->fmt.p_extra, (uint8_t *)p_wf + sizeof( WAVEFORMATEX ) + i_extended,
                p_sys->fmt.i_extra );
    }

    msg_Dbg( p_demux, "format: 0x%4.4x, fourcc: %4.4s, channels: %d, "
             "freq: %u Hz, bitrate: %uKo/s, blockalign: %d, bits/samples: %d, "
             "extra size: %zu",
             GetWLE( &p_wf->wFormatTag ), (char *)&p_sys->fmt.i_codec,
             p_sys->fmt.audio.i_channels, p_sys->fmt.audio.i_rate,
             p_sys->fmt.i_bitrate / 8 / 1024, p_sys->fmt.audio.i_blockalign,
             p_sys->fmt.audio.i_bitspersample, p_sys->fmt.i_extra );

    free( p_wf );
    p_wf = NULL;

    switch( p_sys->fmt.i_codec )
    {
    case VLC_FOURCC( 'a', 'r', 'a', 'w' ):
    case VLC_FOURCC( 'a', 'f', 'l', 't' ):
    case VLC_FOURCC( 'u', 'l', 'a', 'w' ):
    case VLC_CODEC_ALAW:
    case VLC_CODEC_MULAW:
        if( FrameInfo_PCM( &p_sys->i_frame_size, &p_sys->i_frame_samples,
                           &p_sys->fmt ) )
            goto error;
        p_sys->fmt.i_codec =
            vlc_fourcc_GetCodecAudio( p_sys->fmt.i_codec,
                                      p_sys->fmt.audio.i_bitspersample );
        if( p_sys->fmt.i_codec == 0 ) {
            msg_Err( p_demux, "Unrecognized codec" );
            goto error;
        }
        break;
    case VLC_CODEC_ADPCM_MS:
    /* FIXME not sure at all FIXME */
    case VLC_FOURCC( 'm', 's', 0x00, 0x61 ):
    case VLC_FOURCC( 'm', 's', 0x00, 0x62 ):
        if( FrameInfo_MS_ADPCM( &p_sys->i_frame_size, &p_sys->i_frame_samples,
                                &p_sys->fmt ) )
            goto error;
        break;
    case VLC_CODEC_ADPCM_IMA_WAV:
        if( FrameInfo_IMA_ADPCM( &p_sys->i_frame_size, &p_sys->i_frame_samples,
                                 &p_sys->fmt ) )
            goto error;
        break;
    case VLC_CODEC_ADPCM_CREATIVE:
        if( FrameInfo_Creative_ADPCM( &p_sys->i_frame_size, &p_sys->i_frame_samples,
                                      &p_sys->fmt ) )
            goto error;
        break;
    case VLC_CODEC_MPGA:
    case VLC_CODEC_A52:
        /* FIXME set end of area FIXME */
        goto error;
    case VLC_CODEC_GSM_MS:
    case VLC_CODEC_ADPCM_G726:
    case VLC_CODEC_TRUESPEECH:
    case VLC_CODEC_ATRAC3P:
    case VLC_CODEC_ATRAC3:
    case VLC_CODEC_DFPWM:
    case VLC_CODEC_G723_1:
    case VLC_CODEC_WMA2:
        if( FrameInfo_MSGSM( &p_sys->i_frame_size, &p_sys->i_frame_samples,
                             &p_sys->fmt ) )
            goto error;
        break;
    default:
        msg_Err( p_demux, "unsupported codec (%4.4s)",
                 (char*)&p_sys->fmt.i_codec );
        goto error;
    }

    if( p_sys->i_frame_size == 0 || p_sys->i_frame_samples == 0 )
    {
        msg_Dbg( p_demux, "invalid frame size: 0 0" );
        goto error;
    }
    if( p_sys->fmt.audio.i_rate == 0 )
    {
        msg_Dbg( p_demux, "invalid sample rate: 0" );
        goto error;
    }

    msg_Dbg( p_demux, "found %s audio format", psz_name );

    return VLC_SUCCESS;

error:
    es_format_Clean( &p_sys->fmt );
    InitFmt( p_demux );
    free( p_wf );
    return VLC_EGENERIC;
}

static int Open( vlc_object_t * p_this )
{
    demux_t     *p_demux = (demux_t*)p_this;
    demux_sys_t *p_sys;

    const uint8_t *p_peek;
    bool           b_is_rf64;
    uint32_t       i_size;

    /* Is it a wav file ? */
    if( vlc_stream_Peek( p_demux->s, &p_peek, 12 ) < 12 )
        return VLC_EGENERIC;

    b_is_rf64 = ( memcmp( p_peek, "RF64", 4 ) == 0 );
    if( ( !b_is_rf64 && memcmp( p_peek, "RIFF", 4 ) ) ||
          memcmp( &p_peek[8], "WAVE", 4 ) )
    {
        return VLC_EGENERIC;
    }

    p_demux->pf_demux     = Demux;
    p_demux->pf_control   = Control;
    p_demux->p_sys        = p_sys = malloc( sizeof( *p_sys ) );
    if( unlikely(!p_sys) )
        return VLC_ENOMEM;

    p_sys->p_es           = NULL;
    p_sys->i_data_pos = p_sys->i_data_size = 0;
    InitFmt( p_demux );

    /* skip riff header */
    if( vlc_stream_Read( p_demux->s, NULL, 12 ) != 12 )
        goto error;

    bool eof = false;
    enum wav_chunk_id id;
    while( !eof && ( ChunkGetNext( p_demux, &id, &i_size ) ) == VLC_SUCCESS )
    {
        if( i_size == 0 )
        {
            msg_Err( p_demux, "invalid chunk with a size 0");
            goto error;
        }

        switch( id )
        {
            case wav_chunk_id_data:
            {
                uint64_t i_stream_size;
                if( vlc_stream_GetSize( p_demux->s, &i_stream_size ) != VLC_SUCCESS )
                    goto error;
                p_sys->i_data_pos = vlc_stream_Tell( p_demux->s );

                if( !b_is_rf64 && i_stream_size >= i_size + p_sys->i_data_pos )
                    p_sys->i_data_size = i_size;

                if( likely( b_is_rf64
                 || p_sys->i_data_pos + i_size == i_stream_size ) )
                {
                    /* Bypass the final ChunkGetNext() to avoid a read+seek
                     * since this chunk is the last one */

                    eof = true;
                }   /* Unlikely case where there is a chunk after 'data' */
                else if( ChunkSkip( p_demux, i_size ) != VLC_SUCCESS )
                    goto error;
                break;
            }
            case wav_chunk_id_ds64:
                if( b_is_rf64 )
                {
                    if( ChunkParseDS64( p_demux, i_size ) != VLC_SUCCESS )
                        goto error;
                }
                else
                {
                    msg_Err( p_demux, "'ds64' chunk found but format not RF64" );
                    goto error;
                }
                break;
            case wav_chunk_id_fmt:
                if( p_sys->i_frame_samples != 0 )
                {
                    ChunkSkip( p_demux, i_size );
                    msg_Warn( p_demux, "fmt chunk already parsed" );
                    break;
                }
                if( ChunkParseFmt( p_demux, i_size ) != VLC_SUCCESS )
                    goto error;
                break;
        }
    }

    if( p_sys->i_data_pos == 0 || p_sys->i_data_size == 0
     || p_sys->i_frame_samples == 0 )
    {
        msg_Err( p_demux, "'%s' chunk not found",
                 p_sys->i_data_pos == 0 ? "data" :
                 p_sys->i_frame_samples == 0 ? "fmt " :
                 b_is_rf64 ? "ds64" : "data" );
        goto error;
    }

    /* Seek back to data position if needed */
    if( unlikely( vlc_stream_Tell( p_demux->s ) != p_sys->i_data_pos )
     && vlc_stream_Seek( p_demux->s, p_sys->i_data_pos ) != VLC_SUCCESS )
        goto error;

    if( p_sys->fmt.i_bitrate <= 0 )
    {
        p_sys->fmt.i_bitrate = (int64_t)p_sys->i_frame_size *
            p_sys->fmt.audio.i_rate * 8 / p_sys->i_frame_samples;
    }

    p_sys->fmt.i_id = 0;
    p_sys->p_es = es_out_Add( p_demux->out, &p_sys->fmt );
    if( unlikely(p_sys->p_es == NULL) )
        goto error;

    date_Init( &p_sys->pts, p_sys->fmt.audio.i_rate, 1 );
    date_Set( &p_sys->pts, VLC_TICK_0 );

    return VLC_SUCCESS;

error:
    es_format_Clean( &p_sys->fmt );
    free( p_sys );
    return VLC_EGENERIC;
}

vlc_module_begin ()
    set_description( N_("WAV demuxer") )
    set_subcategory( SUBCAT_INPUT_DEMUX )
    set_capability( "demux", 142 )
    set_callbacks( Open, Close )
vlc_module_end ()

Messung
CHZG
839610093

¤ Dauer der Verarbeitung: 0.4 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104856
#Domains=417320