Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/VLC/modules/demux/   (VLC Media Plyer ©)  Datei vom 23.9.2026 mit Größe 15 kB image not shown  

Quelle  aiff.c   Sprache: C

 

/*****************************************************************************
 * aiff.c: Audio Interchange File Format demuxer
 *****************************************************************************
 * Copyright (C) 2004-2007 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 <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_demux.h>
#include <vlc_aout.h>
#include <vlc_meta.h>
#include <limits.h>
#include <stdint.h>

#include "mp4/coreaudio.h"

/* TODO:
 *  - ...
 */


/*****************************************************************************
 * Module descriptor
 *****************************************************************************/

static int  Open    ( vlc_object_t * );
static void Close   ( vlc_object_t * );

vlc_module_begin ()
    set_subcategory( SUBCAT_INPUT_DEMUX )
    set_description( N_("AIFF demuxer" ) )
    set_capability( "demux", 10 )
    set_callbacks( Open, Close )
    add_shortcut( "aiff" )
    add_file_extension("aiff")
vlc_module_end ()

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/


typedef struct
{
    es_out_id_t *es;
    unsigned int i_rate;

    /* real data start */
    uint64_t    i_ssnd_start;
    uint64_t    i_ssnd_end;

    unsigned    i_ssnd_fsize;

    vlc_tick_t  i_time;

    uint8_t     i_chans_to_reorder;
    uint8_t     pi_chan_table[AOUT_CHAN_MAX];
    vlc_meta_t  *p_meta;
    vlc_fourcc_t audio_fourcc;
} demux_sys_t;

static int Demux  ( demux_t *p_demux );
static int Control( demux_t *p_demux, int i_query, va_list args );

/* GetF80BE: read a 80 bits float in big endian */
static unsigned int GetF80BE( const uint8_t p[10] )
{
    unsigned int i_mantissa = GetDWBE( &p[2] );
    int          i_exp = 30 - p[1];
    unsigned int i_last = 0;

    while( i_exp-- > 0 )
    {
        i_last = i_mantissa;
        i_mantissa >>= 1;
    }
    if( i_last&0x01 )
    {
        i_mantissa++;
    }
    return i_mantissa;
}

/*****************************************************************************
 * ReadTextChunk: reads aiff text chunks - name, author, copyright, annotation
 *****************************************************************************/

static int ReadTextChunk( demux_t *p_demux,  uint64_t i_chunk_size, uint32_t i_data_size )
{
    demux_sys_t *p_sys = p_demux->p_sys;
    const uint8_t *p_peek;

    if ( i_data_size >= UINT32_MAX )
        return VLC_ENOMEM;

    ssize_t ret = vlc_stream_Peek( p_demux->s, &p_peek, i_chunk_size );
    if( ret == -1 || (size_t) ret != i_chunk_size )
        return VLC_EGENERIC;

    static const struct {
        const char  chunk_id[4];
        int         i_meta;
    } p_dsc[4] = {
        { {'N', 'A', 'M', 'E'}, vlc_meta_Title },
        { {'A', 'U', 'T', 'H'}, vlc_meta_Artist },
        { {'(', 'c', ')', ' '}, vlc_meta_Copyright },
        { {'A', 'N', 'N', 'O'}, vlc_meta_Description }
    };

    for( size_t i = 0; i < ARRAY_SIZE( p_dsc ); i++ )
    {
        if( memcmp(p_peek, p_dsc[i].chunk_id, 4) )
            continue;

        char *psz_value = malloc( i_data_size + 1 );

        if( unlikely(psz_value == NULL) )
            return VLC_ENOMEM;

        if( !p_sys->p_meta )
        {
            p_sys->p_meta = vlc_meta_New();
            if( unlikely(p_sys->p_meta == NULL) )
            {
                free( psz_value );
                return VLC_ENOMEM;
            }
        }

        memcpy( psz_value, (char*)&p_peek[8], i_data_size );
        psz_value[i_data_size] = '\0';
        vlc_meta_Set( p_sys->p_meta, p_dsc[i].i_meta, psz_value );
        free( psz_value );

        return VLC_SUCCESS;
    }

    return VLC_EGENERIC;
}

/*****************************************************************************
 * Open
 *****************************************************************************/

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;

    if( vlc_stream_Peek( p_demux->s, &p_peek, 12 ) < 12 )
        return VLC_EGENERIC;
    if( memcmp( p_peek, "FORM", 4 ) || memcmp( &p_peek[8], "AIFF", 4 ) )
        return VLC_EGENERIC;

    bool b_canseek = false;
    vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_canseek );
    if (!b_canseek)
    {
        msg_Err( p_demux, "AIFF parsing requires seeking" );
        return VLC_EGENERIC;
    }

    /* skip aiff header */
    if( vlc_stream_Read( p_demux->s, NULL, 12 ) != 12 )
        return VLC_EGENERIC;

    p_sys = vlc_obj_calloc( p_this, 1, sizeof( *p_sys ) );

    if( unlikely(p_sys == NULL) )
        return VLC_ENOMEM;

    p_demux->p_sys = p_sys;

    p_sys->i_time = 0;
    p_sys->i_chans_to_reorder = 0;

    es_format_t fmt;
    es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC( 't', 'w', 'o', 's' ) );

    const uint32_t *pi_channels_in = NULL;
    uint64_t i_ssnd_pos = UINT64_C(-1);
    uint32_t i_ssnd_size = 0;
    uint32_t i_ssnd_offset = 0;

    for( ;; )
    {
        if( vlc_stream_Peek( p_demux->s, &p_peek, 8 ) < 8 )
            break;

        uint32_t i_data_size = GetDWBE( &p_peek[4] );
        uint64_t i_chunk_size = UINT64_C( 8 ) + i_data_size + ( i_data_size & 1 );

        msg_Dbg( p_demux, "chunk fcc=%4.4s size=%" PRIu64 " data_size=%" PRIu32,
            p_peek, i_chunk_size, i_data_size );

        if( !memcmp( p_peek, "COMM", 4 ) )
        {
            if( vlc_stream_Peek( p_demux->s, &p_peek, 18+8 ) < 18+8 )
                goto error;

            uint16_t channels = GetWBE( &p_peek[8] );
            if (channels > 32)
            {
                msg_Err( p_demux, "Unsupported number of channels %" PRIu16, channels );
                goto error;
            }
            fmt.audio.i_channels = channels;
            fmt.audio.i_bitspersample = GetWBE( &p_peek[14] );
            fmt.audio.i_rate = p_sys->i_rate = GetF80BE( &p_peek[16] );

            msg_Dbg( p_demux, "COMM: channels=%" PRIu16 " samples_frames=%d bits=%u rate=%u",
                     channels, GetDWBE( &p_peek[10] ), fmt.audio.i_bitspersample,
                     fmt.audio.i_rate );
        }
        else if( !memcmp( p_peek, "SSND", 4 ) )
        {
            if( vlc_stream_Peek( p_demux->s, &p_peek, 8+8 ) < 8+8 )
                goto error;

            i_ssnd_pos = vlc_stream_Tell( p_demux->s );
            i_ssnd_size = i_data_size;
            i_ssnd_offset = GetDWBE( &p_peek[8] );
            uint32_t i_ssnd_blocksize = GetDWBE( &p_peek[12] );

            msg_Dbg( p_demux, "SSND: (offset=%" PRIu32 " blocksize=%" PRIu32 ")",
                     i_ssnd_offset, i_ssnd_blocksize );
        }
        else if( !memcmp( p_peek, "CHAN", 4 ) && i_chunk_size > 8 + 12 )
        {
            ssize_t ret = vlc_stream_Peek( p_demux->s, &p_peek, i_chunk_size );
            if( ret == -1 || (size_t) ret != i_chunk_size )
                goto error;

            struct CoreAudio_layout_s layout;
            layout.i_channels_layout_tag = GetDWBE( &p_peek[8] );
            layout.i_channels_bitmap = GetDWBE( &p_peek[8+4] );
            layout.i_channels_description_count = GetDWBE( &p_peek[8+8] );
            /* TODO: handle CoreAudio_layout_s.p_descriptions */

            if ( CoreAudio_Layout_to_vlc( &layout,
                                          &fmt.audio.i_physical_channels,
                                          &fmt.audio.i_channels,
                                          &pi_channels_in ) != VLC_SUCCESS )
                msg_Warn( p_demux, "discarding chan mapping" );
        }
        else
        {
            int i_ret = ReadTextChunk( p_demux, i_chunk_size, i_data_size );

            if( unlikely(i_ret == VLC_ENOMEM) )
                goto error;
        }

        /* consume chunk data */
        for( ssize_t i_req; i_chunk_size; i_chunk_size -= i_req )
        {
#if SSIZE_MAX < UINT64_MAX
            i_req = __MIN( SSIZE_MAX, i_chunk_size );
#else
            i_req = i_chunk_size;
#endif
            if( vlc_stream_Read( p_demux->s, NULL, i_req ) != i_req )
            {
                msg_Warn( p_demux, "incomplete file" );
                goto error;
            }
        }
    }

    if ( i_ssnd_pos == UINT64_C(-1) )
    {
        msg_Err( p_demux, "Missing SSND chunk" );
        goto error;
    }

    if( pi_channels_in != NULL )
    {
        p_sys->i_chans_to_reorder =
            aout_CheckChannelReorder( pi_channels_in, NULL,
                                      fmt.audio.i_physical_channels,
                                      p_sys->pi_chan_table ) > 0;
        p_sys->audio_fourcc =
            vlc_fourcc_GetCodecAudio( fmt.i_codec,
                                      fmt.audio.i_bitspersample );
        if( p_sys->audio_fourcc == 0 )
            p_sys->i_chans_to_reorder = 0;
    }

    p_sys->i_ssnd_start = i_ssnd_pos + 16 + i_ssnd_offset;
    p_sys->i_ssnd_end   = p_sys->i_ssnd_start + i_ssnd_size;

    p_sys->i_ssnd_fsize = fmt.audio.i_channels *
                          ((fmt.audio.i_bitspersample + 7) / 8);

    if( p_sys->i_ssnd_fsize == 0 || p_sys->i_rate == 0 )
    {
        msg_Err( p_demux, "invalid audio parameters" );
        goto error;
    }

    if( i_ssnd_size == 0 )
    {
        /* unknown */
        p_sys->i_ssnd_end = 0;
    }

    /* seek into SSND chunk */
    if( vlc_stream_Seek( p_demux->s, p_sys->i_ssnd_start ) )
    {
        msg_Err( p_demux, "cannot seek to data chunk" );
        goto error;
    }

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

    p_demux->pf_demux = Demux;
    p_demux->pf_control = Control;

    return VLC_SUCCESS;

error:
    Close( p_this );
    return VLC_EGENERIC;
}

/*****************************************************************************
 * Demux:
 *****************************************************************************/

static int Demux( demux_t *p_demux )
{
    demux_sys_t *p_sys = p_demux->p_sys;
    uint64_t    i_tell = vlc_stream_Tell( p_demux->s );

    block_t     *p_block;
    size_t      i_read;

    if( p_sys->i_ssnd_end != 0 && i_tell >= p_sys->i_ssnd_end )
    {
        /* EOF */
        return VLC_DEMUXER_EOF;
    }

    /* Set PCR */
    es_out_SetPCR( p_demux->out, VLC_TICK_0 + p_sys->i_time);

    /* we will read 100ms at once */
    i_read = p_sys->i_ssnd_fsize * ( p_sys->i_rate / 10 );
    if( p_sys->i_ssnd_end != 0 && p_sys->i_ssnd_end > i_tell && p_sys->i_ssnd_end - i_tell < i_read )
    {
        i_read = p_sys->i_ssnd_end - i_tell;
    }
    if( ( p_block = vlc_stream_Block( p_demux->s, i_read ) ) == NULL )
    {
        return VLC_DEMUXER_EOF;
    }

    p_block->i_dts =
    p_block->i_pts = VLC_TICK_0 + p_sys->i_time;

    p_sys->i_time += vlc_tick_from_samples(p_block->i_buffer,
                                           p_sys->i_ssnd_fsize) /
                     p_sys->i_rate;

    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->audio_fourcc );
    /* */
    es_out_Send( p_demux->out, p_sys->es, p_block );
    return VLC_DEMUXER_SUCCESS;
}

/*****************************************************************************
 * Close: frees unused data
 *****************************************************************************/

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;

    if( p_sys->p_meta )
        vlc_meta_Delete( p_sys->p_meta );
}

/*****************************************************************************
 * Control:
 *****************************************************************************/

static int Control( demux_t *p_demux, int i_query, va_list args )
{
    demux_sys_t *p_sys = p_demux->p_sys;
    double f, *pf;

    switch( i_query )
    {
        case DEMUX_CAN_SEEK:
            return vlc_stream_vaControl( p_demux->s, i_query, args );

        case DEMUX_GET_POSITION:
        {
            uint64_t i_start = p_sys->i_ssnd_start;
            uint64_t i_end   = p_sys->i_ssnd_end != 0 ? p_sys->i_ssnd_end : stream_Size( p_demux->s );
            uint64_t i_tell  = vlc_stream_Tell( p_demux->s );

            pf = va_arg( args, double * );

            if( i_start < i_end && i_start <= i_tell )
            {
                *pf = (double)(i_tell - i_start)/(double)(i_end - i_start);
                return VLC_SUCCESS;
            }
            return VLC_EGENERIC;
        }

        case DEMUX_SET_POSITION:
        {
            uint64_t i_start = p_sys->i_ssnd_start;
            uint64_t i_end  = p_sys->i_ssnd_end != 0 ? p_sys->i_ssnd_end : stream_Size( p_demux->s );

            f = va_arg( args, double );

            if( i_start < i_end )
            {
                unsigned i_frame = (f * ( i_end - i_start )) / p_sys->i_ssnd_fsize;
                uint64_t i_new   = i_start + i_frame * p_sys->i_ssnd_fsize;

                if( vlc_stream_Seek( p_demux->s, i_new ) )
                {
                    return VLC_EGENERIC;
                }
                p_sys->i_time = vlc_tick_from_samples( i_frame, p_sys->i_rate );
                return VLC_SUCCESS;
            }
            return VLC_EGENERIC;
        }

        case DEMUX_GET_TIME:
            *va_arg( args, vlc_tick_t * ) = p_sys->i_time;
            return VLC_SUCCESS;

        case DEMUX_GET_LENGTH:
        {
            uint64_t i_end  = p_sys->i_ssnd_end != 0 ? p_sys->i_ssnd_end : stream_Size( p_demux->s );

            if( p_sys->i_ssnd_start < i_end )
            {
                *va_arg( args, vlc_tick_t * ) =
                    vlc_tick_from_samples( i_end - p_sys->i_ssnd_start, p_sys->i_ssnd_fsize) / p_sys->i_rate;
                return VLC_SUCCESS;
            }
            return VLC_EGENERIC;
        }
        case DEMUX_GET_META:
        {
            vlc_meta_t *p_meta = va_arg( args, vlc_meta_t * );
            if( !p_sys->p_meta )
                return VLC_EGENERIC;
            vlc_meta_Merge( p_meta, p_sys->p_meta );
            return VLC_SUCCESS;
        }

        case DEMUX_SET_TIME:
        case DEMUX_GET_FPS:
            return VLC_EGENERIC;

        case DEMUX_CAN_PAUSE:
        case DEMUX_SET_PAUSE_STATE:
        case DEMUX_CAN_CONTROL_PACE:
        case DEMUX_GET_PTS_DELAY:
             return demux_vaControlHelper( p_demux->s, 0, -1, 0, 1, i_query, args );

        default:
            return VLC_EGENERIC;
    }
}

Messung
CHZG
839610093

¤ Dauer der Verarbeitung: 0.7 Sekunden  ¤

*© 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.