Beispiel #1
0
/*****************************************************************************
 * ParseTheoraComments:
 *****************************************************************************/
static void ParseTheoraComments( decoder_t *p_dec )
{
    char *psz_name, *psz_value, *psz_comment;
    int i = 0;

    while ( i < p_dec->p_sys->tc.comments )
    {
        psz_comment = strdup( p_dec->p_sys->tc.user_comments[i] );
        if( !psz_comment )
            break;
        psz_name = psz_comment;
        psz_value = strchr( psz_comment, '=' );
        if( psz_value )
        {
            *psz_value = '\0';
            psz_value++;

            if( !p_dec->p_description )
                p_dec->p_description = vlc_meta_New();
            if( p_dec->p_description )
                vlc_meta_AddExtra( p_dec->p_description, psz_name, psz_value );
        }
        free( psz_comment );
        i++;
    }
}
Beispiel #2
0
static void ParseSpeexComments( decoder_t *p_dec, ogg_packet *p_oggpacket )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    const SpeexMode *p_mode;

    assert( p_sys->p_header->mode < SPEEX_NB_MODES );

    p_mode = speex_mode_list[p_sys->p_header->mode];
    assert( p_mode != NULL );

    if( !p_dec->p_description )
    {
        p_dec->p_description = vlc_meta_New();
        if( !p_dec->p_description )
            return;
    }

    /* */
    char *psz_mode;
    if( asprintf( &psz_mode, "%s%s", p_mode->modeName, p_sys->p_header->vbr ? " VBR" : "" ) >= 0 )
    {
        vlc_meta_AddExtra( p_dec->p_description, _("Mode"), psz_mode );
        free( psz_mode );
    }

    /* TODO: finish comments parsing */
    VLC_UNUSED( p_oggpacket );
}
Beispiel #3
0
static int vlclua_input_item_set_meta( lua_State *L )
{
    input_item_t *p_item = vlclua_input_item_get_internal( L );
    lua_settop( L, 1 + 2 ); // two arguments
    const char *psz_name = luaL_checkstring( L, 2 ),
               *psz_value = luaL_checkstring( L, 3 );

#define META_TYPE( n, s ) { s, vlc_meta_ ## n },
    static const struct
    {
        const char psz_name[15];
        unsigned char type;
    } pp_meta_types[] = {
        META_TYPE( Title, "title" )
        META_TYPE( Artist, "artist" )
        META_TYPE( Genre, "genre" )
        META_TYPE( Copyright, "copyright" )
        META_TYPE( Album, "album" )
        META_TYPE( TrackNumber, "track_number" )
        META_TYPE( Description, "description" )
        META_TYPE( Rating, "rating" )
        META_TYPE( Date, "date" )
        META_TYPE( Setting, "setting" )
        META_TYPE( URL, "url" )
        META_TYPE( Language, "language" )
        META_TYPE( NowPlaying, "now_playing" )
        META_TYPE( ESNowPlaying, "now_playing" )
        META_TYPE( Publisher, "publisher" )
        META_TYPE( EncodedBy, "encoded_by" )
        META_TYPE( ArtworkURL, "artwork_url" )
        META_TYPE( TrackID, "track_id" )
        META_TYPE( TrackTotal, "track_total" )
        META_TYPE( Director, "director" )
        META_TYPE( Season, "season" )
        META_TYPE( Episode, "episode" )
        META_TYPE( ShowName, "show_name" )
        META_TYPE( Actors, "actors" )
    };
#undef META_TYPE

    static_assert( sizeof(pp_meta_types)
                      == VLC_META_TYPE_COUNT * sizeof(pp_meta_types[0]),
                   "Inconsistent meta data types" );
    vlc_meta_type_t type = vlc_meta_Title;
    for( unsigned i = 0; i < VLC_META_TYPE_COUNT; i++ )
    {
        if( !strcasecmp( pp_meta_types[i].psz_name, psz_name ) )
        {
            type = pp_meta_types[i].type;
            input_item_SetMeta( p_item, type, psz_value );
            return 1;
        }
    }

    vlc_meta_AddExtra( p_item->p_meta, psz_name, psz_value );
    return 1;
}
Beispiel #4
0
/*****************************************************************************
 * ParseTheoraComments:
 *****************************************************************************/
static void ParseTheoraComments( decoder_t *p_dec )
{
    char *psz_name, *psz_value, *psz_comment;
    int i = 0;

    decoder_sys_t *p_sys = p_dec->p_sys;

    /* Regarding the th_comment structure: */

    /* The metadata is stored as a series of (tag, value) pairs, in
       length-encoded string vectors. The first occurrence of the '='
       character delimits the tag and value. A particular tag may
       occur more than once, and order is significant. The character
       set encoding for the strings is always UTF-8, but the tag names
       are limited to ASCII, and treated as case-insensitive. See the
       Theora specification, Section 6.3.3 for details. */

    /* In filling in this structure, th_decode_headerin() will
       null-terminate the user_comment strings for safety. However,
       the bitstream format itself treats them as 8-bit clean vectors,
       possibly containing null characters, and so the length array
       should be treated as their authoritative length. */
    while ( i < p_sys->tc.comments )
    {
        int clen = p_sys->tc.comment_lengths[i];
        if ( clen <= 0 || clen >= INT_MAX ) { i++; continue; }
        psz_comment = (char *)malloc( clen + 1 );
        if( !psz_comment )
            break;
        memcpy( (void*)psz_comment, (void*)p_sys->tc.user_comments[i], clen + 1 );
        psz_name = psz_comment;
        psz_value = strchr( psz_comment, '=' );
        if( psz_value )
        {
            *psz_value = '\0';
            psz_value++;

            if( !p_dec->p_description )
                p_dec->p_description = vlc_meta_New();
            /* TODO:  Since psz_value can contain NULLs see if there is an
             * instance where we need to preserve the full length of this string */
            if( p_dec->p_description )
                vlc_meta_AddExtra( p_dec->p_description, psz_name, psz_value );
        }
        free( psz_comment );
        i++;
    }
}
Beispiel #5
0
static void fill_metas_with_results( fingerprint_request_t *p_r, acoustid_fingerprint_t *p_f )
{
    for( unsigned int i=0 ; i < p_f->results.count; i++ )
    {
        acoustid_result_t *p_result = & p_f->results.p_results[ i ];
        for ( unsigned int j=0 ; j < p_result->recordings.count; j++ )
        {
            musicbrainz_recording_t *p_record = & p_result->recordings.p_recordings[ j ];
            vlc_meta_t *p_meta = vlc_meta_New();
            if ( p_meta )
            {
                vlc_meta_Set( p_meta, vlc_meta_Title, p_record->psz_title );
                vlc_meta_Set( p_meta, vlc_meta_Artist, p_record->psz_artist );
                vlc_meta_AddExtra( p_meta, "musicbrainz-id", p_record->s_musicbrainz_id );
                vlc_array_append( & p_r->results.metas_array, p_meta );
            }
        }
    }
}
Beispiel #6
0
void vlclua_read_custom_meta_data( vlc_object_t *p_this, lua_State *L,
                                     input_item_t *p_input )
{
    /* Lock the input item and create the meta table if needed */
    vlc_mutex_lock( &p_input->lock );

    if( !p_input->p_meta )
        p_input->p_meta = vlc_meta_New();

    /* ... item */
    lua_getfield( L, -1, "meta" );
    /* ... item meta */
    if( lua_istable( L, -1 ) )
    {
        lua_pushnil( L );
        /* ... item meta nil */
        while( lua_next( L, -2 ) )
        {
            /* ... item meta key value */
            if( !lua_isstring( L, -2 ) || !lua_isstring( L, -1 ) )
            {
                msg_Err( p_this, "'meta' keys and values must be strings");
                lua_pop( L, 1 ); /* pop "value" */
                continue;
            }
            const char *psz_key = lua_tostring( L, -2 );
            const char *psz_value = lua_tostring( L, -1 );

            vlc_meta_AddExtra( p_input->p_meta, psz_key, psz_value );

            lua_pop( L, 1 ); /* pop "value" */
        }
    }
    lua_pop( L, 1 ); /* pop "meta" */
    /* ... item -> back to original stack */

    vlc_mutex_unlock( &p_input->lock );
}
Beispiel #7
0
/*****************************************************************************
 * Import meta data
 *****************************************************************************/
static void ImportMeta( access_t *p_access )
{
    access_sys_t *p_sys = p_access->p_sys;

    FILE *infofile = OpenRelativeFile( p_access, "info" );
    if( !infofile )
        return;

    vlc_meta_t *p_meta = vlc_meta_New();
    p_sys->p_meta = p_meta;
    if( !p_meta )
    {
        fclose( infofile );
        return;
    }

    char *line = NULL;
    size_t line_len;
    char *psz_title = NULL, *psz_smalltext = NULL, *psz_date = NULL;

    while( ReadLine( &line, &line_len, infofile ) )
    {
        if( !isalpha( (unsigned char)line[0] ) || line[1] != ' ' )
            continue;

        char tag = line[0];
        char *text = line + 2;

        if( tag == 'C' )
        {
            char *psz_name = strchr( text, ' ' );
            if( psz_name )
            {
                *psz_name = '\0';
                vlc_meta_AddExtra( p_meta, "Channel", psz_name + 1 );
            }
            vlc_meta_AddExtra( p_meta, "Transponder", text );
        }

        else if( tag == 'E' )
        {
            unsigned i_id, i_start, i_length;
            if( sscanf( text, "%u %u %u", &i_id, &i_start, &i_length ) == 3 )
            {
                char str[50];
                struct tm tm;
                time_t start = i_start;
                localtime_r( &start, &tm );

                /* TODO: locale */
                strftime( str, sizeof(str), "%Y-%m-%d %H:%M", &tm );
                vlc_meta_AddExtra( p_meta, "Date", str );
                free( psz_date );
                psz_date = strdup( str );

                /* display in minutes */
                i_length = ( i_length + 59 ) / 60;
                snprintf( str, sizeof(str), "%u:%02u", i_length / 60, i_length % 60 );
                vlc_meta_AddExtra( p_meta, "Duration", str );
            }
        }

        else if( tag == 'T' )
        {
            free( psz_title );
            psz_title = strdup( text );
            vlc_meta_AddExtra( p_meta, "Title", text );
        }

        else if( tag == 'S' )
        {
            free( psz_smalltext );
            psz_smalltext = strdup( text );
            vlc_meta_AddExtra( p_meta, "Info", text );
        }

        else if( tag == 'D' )
        {
            for( char *p = text; *p; ++p )
            {
                if( *p == '|' )
                    *p = '\n';
            }
            vlc_meta_SetDescription( p_meta, text );
        }

        /* FPS are required to convert between timestamps and frames */
        else if( tag == 'F' )
        {
            float fps = atof( text );
            if( fps >= 1 )
                p_sys->fps = fps;
            vlc_meta_AddExtra( p_meta, "Frame Rate", text );
        }

        else if( tag == 'P' )
        {
            vlc_meta_AddExtra( p_meta, "Priority", text );
        }

        else if( tag == 'L' )
        {
            vlc_meta_AddExtra( p_meta, "Lifetime", text );
        }
    }

    /* create a meaningful title */
    int i_len = 10 +
        ( psz_title ? strlen( psz_title ) : 0 ) +
        ( psz_smalltext ? strlen( psz_smalltext ) : 0 ) +
        ( psz_date ? strlen( psz_date ) : 0 );
    char *psz_display = malloc( i_len );

    if( psz_display )
    {
        *psz_display = '\0';
        if( psz_title )
            strcat( psz_display, psz_title );
        if( psz_title && psz_smalltext )
            strcat( psz_display, " - " );
        if( psz_smalltext )
            strcat( psz_display, psz_smalltext );
        if( ( psz_title || psz_smalltext ) && psz_date )
        {
            strcat( psz_display, " (" );
            strcat( psz_display, psz_date );
            strcat( psz_display, ")" );
        }
        if( *psz_display )
            vlc_meta_SetTitle( p_meta, psz_display );
    }

    free( psz_display );
    free( psz_title );
    free( psz_smalltext );
    free( psz_date );

    fclose( infofile );
}
Beispiel #8
0
bool matroska_segment_c::ParseSimpleTags( SimpleTag* pout_simple, KaxTagSimple *tag, int target_type )
{
    EbmlParser eparser ( &es, tag, &sys.demuxer, var_InheritBool( &sys.demuxer, "mkv-use-dummy" ) );
    EbmlElement *el;
    size_t max_size = tag->GetSize();
    size_t size = 0;

    if( !sys.meta )
        sys.meta = vlc_meta_New();

    msg_Dbg( &sys.demuxer, "|   + Simple Tag ");
    try
    {
        while( ( el = eparser.Get() ) != NULL && size < max_size)
        {
            if( unlikely( !el->ValidateSize() ) )
            {
                msg_Err( &sys.demuxer, "Error %s too big ignoring the tag", typeid(*el).name() );
                delete ep;
                return false;
            }
            if( MKV_CHECKED_PTR_DECL ( ktn_ptr, KaxTagName, el ) )
            {
                ktn_ptr->ReadData( es.I_O(), SCOPE_ALL_DATA );
                pout_simple->tag_name = UTFstring( *ktn_ptr ).GetUTF8().c_str();
            }
            else if( MKV_CHECKED_PTR_DECL ( kts_ptr, KaxTagString, el ) )
            {
                kts_ptr->ReadData( es.I_O(), SCOPE_ALL_DATA );
                pout_simple->value = UTFstring( *kts_ptr ).GetUTF8().c_str();
            }
            else if(  MKV_CHECKED_PTR_DECL ( ktl_ptr, KaxTagLangue, el ) )
            {
                ktl_ptr->ReadData( es.I_O(), SCOPE_ALL_DATA );
                pout_simple->lang = *ktl_ptr;
            }
            else if(  MKV_CHECKED_PTR_DECL ( ktd_ptr, KaxTagDefault, el ) )
            {
                VLC_UNUSED(ktd_ptr); // TODO: we do not care about this value, but maybe we should?
            }
            /*Tags can be nested*/
            else if( MKV_CHECKED_PTR_DECL ( kts_ptr, KaxTagSimple, el) )
            {
                SimpleTag st; // ParseSimpleTags will write to this variable
                              // the SimpleTag is valid if ParseSimpleTags returns `true`

                if (ParseSimpleTags( &st, kts_ptr, target_type )) {
                  pout_simple->sub_tags.push_back( st );
                }
            }
            /*TODO Handle binary tags*/
            size += el->HeadSize() + el->GetSize();
        }
    }
    catch(...)
    {
        msg_Err( &sys.demuxer, "Error while reading Tag ");
        delete ep;
        return false;
    }

    if( pout_simple->tag_name.empty() )
    {
        msg_Warn( &sys.demuxer, "Invalid MKV SimpleTag found.");
        return false;
    }
    for( int i = 0; metadata_map[i].key; i++ )
    {
        if( pout_simple->tag_name == metadata_map[i].key &&
            (metadata_map[i].target_type == 0 || target_type == metadata_map[i].target_type ) )
        {
            vlc_meta_Set( sys.meta, metadata_map[i].type, pout_simple->value.c_str () );
            msg_Dbg( &sys.demuxer, "|   |   + Meta %s: %s", pout_simple->tag_name.c_str (), pout_simple->value.c_str ());
            goto done;
        }
    }
    msg_Dbg( &sys.demuxer, "|   |   + Meta %s: %s", pout_simple->tag_name.c_str (), pout_simple->value.c_str ());
    vlc_meta_AddExtra( sys.meta, pout_simple->tag_name.c_str (), pout_simple->value.c_str ());
done:
    return true;
}
Beispiel #9
0
/*****************************************************************************
 * ParseVorbisComments
 *****************************************************************************/
static void ParseVorbisComments( decoder_t *p_dec )
{
    char *psz_name, *psz_value, *psz_comment;
    int i = 0;

    while( i < p_dec->p_sys->vc.comments )
    {
        psz_comment = strdup( p_dec->p_sys->vc.user_comments[i] );
        if( !psz_comment )
            break;
        psz_name = psz_comment;
        psz_value = strchr( psz_comment, '=' );
        /* Don't add empty values */
        if( psz_value && psz_value[1] != '\0')
        {
            *psz_value = '\0';
            psz_value++;

            if( !strcasecmp( psz_name, "REPLAYGAIN_TRACK_GAIN" ) ||
                    !strcasecmp( psz_name, "RG_RADIO" ) )
            {
                audio_replay_gain_t *r = &p_dec->fmt_out.audio_replay_gain;

                r->pb_gain[AUDIO_REPLAY_GAIN_TRACK] = true;
                r->pf_gain[AUDIO_REPLAY_GAIN_TRACK] = us_atof( psz_value );
            }
            else if( !strcasecmp( psz_name, "REPLAYGAIN_TRACK_PEAK" ) ||
                     !strcasecmp( psz_name, "RG_PEAK" ) )
            {
                audio_replay_gain_t *r = &p_dec->fmt_out.audio_replay_gain;

                r->pb_peak[AUDIO_REPLAY_GAIN_TRACK] = true;
                r->pf_peak[AUDIO_REPLAY_GAIN_TRACK] = us_atof( psz_value );
            }
            else if( !strcasecmp( psz_name, "REPLAYGAIN_ALBUM_GAIN" ) ||
                     !strcasecmp( psz_name, "RG_AUDIOPHILE" ) )
            {
                audio_replay_gain_t *r = &p_dec->fmt_out.audio_replay_gain;

                r->pb_gain[AUDIO_REPLAY_GAIN_ALBUM] = true;
                r->pf_gain[AUDIO_REPLAY_GAIN_ALBUM] = us_atof( psz_value );
            }
            else if( !strcasecmp( psz_name, "REPLAYGAIN_ALBUM_PEAK" ) )
            {
                audio_replay_gain_t *r = &p_dec->fmt_out.audio_replay_gain;

                r->pb_peak[AUDIO_REPLAY_GAIN_ALBUM] = true;
                r->pf_peak[AUDIO_REPLAY_GAIN_ALBUM] = us_atof( psz_value );
            }
            else if( !strcasecmp( psz_name, "METADATA_BLOCK_PICTURE" ) )
            {   /* Do nothing, for now */
            }
            else
            {
                if( !p_dec->p_description )
                    p_dec->p_description = vlc_meta_New();
                if( p_dec->p_description )
                    vlc_meta_AddExtra( p_dec->p_description, psz_name, psz_value );
            }

        }
        free( psz_comment );
        i++;
    }
}
Beispiel #10
0
/*****************************************************************************
 * DecodeBlock:
 *****************************************************************************/
static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    block_t *p_block;

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

    p_block = *pp_block;

    if( p_block->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
    {
        block_Release( p_block );
        return NULL;
    }

    /* Remove ADTS header if we have decoder specific config */
    if( p_dec->fmt_in.i_extra && p_block->i_buffer > 7 )
    {
        if( p_block->p_buffer[0] == 0xff &&
            ( p_block->p_buffer[1] & 0xf0 ) == 0xf0 ) /* syncword */
        {   /* ADTS header present */
            size_t i_header_size; /* 7 bytes (+ 2 bytes for crc) */
            i_header_size = 7 + ( ( p_block->p_buffer[1] & 0x01 ) ? 0 : 2 );
            /* FIXME: multiple blocks per frame */
            if( p_block->i_buffer > i_header_size )
            {
                p_block->p_buffer += i_header_size;
                p_block->i_buffer -= i_header_size;
            }
        }
    }

    /* Append the block to the temporary buffer */
    if( p_sys->i_buffer_size < p_sys->i_buffer + p_block->i_buffer )
    {
        size_t  i_buffer_size = p_sys->i_buffer + p_block->i_buffer;
        uint8_t *p_buffer     = realloc( p_sys->p_buffer, i_buffer_size );
        if( p_buffer )
        {
            p_sys->i_buffer_size = i_buffer_size;
            p_sys->p_buffer      = p_buffer;
        }
        else
        {
            p_block->i_buffer = 0;
        }
    }

    if( p_block->i_buffer > 0 )
    {
        memcpy( &p_sys->p_buffer[p_sys->i_buffer],
                     p_block->p_buffer, p_block->i_buffer );
        p_sys->i_buffer += p_block->i_buffer;
        p_block->i_buffer = 0;
    }

    if( p_dec->fmt_out.audio.i_rate == 0 && p_dec->fmt_in.i_extra > 0 )
    {
        /* We have a decoder config so init the handle */
        unsigned long i_rate;
        unsigned char i_channels;

        if( faacDecInit2( p_sys->hfaad, p_dec->fmt_in.p_extra,
                          p_dec->fmt_in.i_extra,
                          &i_rate, &i_channels ) >= 0 )
        {
            p_dec->fmt_out.audio.i_rate = i_rate;
            p_dec->fmt_out.audio.i_channels = i_channels;
            p_dec->fmt_out.audio.i_physical_channels
                = p_dec->fmt_out.audio.i_original_channels
                = pi_channels_guessed[i_channels];

            date_Init( &p_sys->date, i_rate, 1 );
        }
    }

    if( p_dec->fmt_out.audio.i_rate == 0 && p_sys->i_buffer )
    {
        unsigned long i_rate;
        unsigned char i_channels;

        /* Init faad with the first frame */
        if( faacDecInit( p_sys->hfaad,
                         p_sys->p_buffer, p_sys->i_buffer,
                         &i_rate, &i_channels ) < 0 )
        {
            block_Release( p_block );
            return NULL;
        }

        p_dec->fmt_out.audio.i_rate = i_rate;
        p_dec->fmt_out.audio.i_channels = i_channels;
        p_dec->fmt_out.audio.i_physical_channels
            = p_dec->fmt_out.audio.i_original_channels
            = pi_channels_guessed[i_channels];
        date_Init( &p_sys->date, i_rate, 1 );
    }

    if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != date_Get( &p_sys->date ) )
    {
        date_Set( &p_sys->date, p_block->i_pts );
    }
    else if( !date_Get( &p_sys->date ) )
    {
        /* We've just started the stream, wait for the first PTS. */
        block_Release( p_block );
        p_sys->i_buffer = 0;
        return NULL;
    }

    /* Decode all data */
    if( p_sys->i_buffer )
    {
        void *samples;
        faacDecFrameInfo frame;
        block_t *p_out;

        samples = faacDecDecode( p_sys->hfaad, &frame,
                                 p_sys->p_buffer, p_sys->i_buffer );

        if( frame.error > 0 )
        {
            msg_Warn( p_dec, "%s", faacDecGetErrorMessage( frame.error ) );

            if( frame.error == 21 || frame.error == 12 )
            {
                /*
                 * Once an "Unexpected channel configuration change"
                 * or a "Invalid number of channels" error
                 * occurs, it will occurs afterwards, and we got no sound.
                 * Reinitialization of the decoder is required.
                 */
                unsigned long i_rate;
                unsigned char i_channels;
                faacDecHandle *hfaad;
                faacDecConfiguration *cfg,*oldcfg;

                oldcfg = faacDecGetCurrentConfiguration( p_sys->hfaad );
                hfaad = faacDecOpen();
                cfg = faacDecGetCurrentConfiguration( hfaad );
                if( oldcfg->defSampleRate )
                    cfg->defSampleRate = oldcfg->defSampleRate;
                cfg->defObjectType = oldcfg->defObjectType;
                cfg->outputFormat = oldcfg->outputFormat;
                faacDecSetConfiguration( hfaad, cfg );

                if( faacDecInit( hfaad, p_sys->p_buffer, p_sys->i_buffer,
                                &i_rate,&i_channels ) < 0 )
                {
                    /* reinitialization failed */
                    faacDecClose( hfaad );
                    faacDecSetConfiguration( p_sys->hfaad, oldcfg );
                }
                else
                {
                    faacDecClose( p_sys->hfaad );
                    p_sys->hfaad = hfaad;
                    p_dec->fmt_out.audio.i_rate = i_rate;
                    p_dec->fmt_out.audio.i_channels = i_channels;
                    p_dec->fmt_out.audio.i_physical_channels
                        = p_dec->fmt_out.audio.i_original_channels
                        = pi_channels_guessed[i_channels];
                    date_Init( &p_sys->date, i_rate, 1 );
                }
            }

            /* Flush the buffer */
            p_sys->i_buffer = 0;
            block_Release( p_block );
            return NULL;
        }

        if( frame.channels <= 0 || frame.channels > 8 || frame.channels == 7 )
        {
            msg_Warn( p_dec, "invalid channels count: %i", frame.channels );

            /* Flush the buffer */
            p_sys->i_buffer -= frame.bytesconsumed;
            if( p_sys->i_buffer > 0 )
            {
                memmove( p_sys->p_buffer,&p_sys->p_buffer[frame.bytesconsumed],
                         p_sys->i_buffer );
            }
            block_Release( p_block );
            return NULL;
        }

        if( frame.samples <= 0 )
        {
            msg_Warn( p_dec, "decoded zero sample" );

            /* Flush the buffer */
            p_sys->i_buffer -= frame.bytesconsumed;
            if( p_sys->i_buffer > 0 )
            {
                memmove( p_sys->p_buffer,&p_sys->p_buffer[frame.bytesconsumed],
                         p_sys->i_buffer );
            }
            block_Release( p_block );
            return NULL;
        }

        /* We decoded a valid frame */
        if( p_dec->fmt_out.audio.i_rate != frame.samplerate )
        {
            date_Init( &p_sys->date, frame.samplerate, 1 );
            date_Set( &p_sys->date, p_block->i_pts );
        }
        p_block->i_pts = VLC_TS_INVALID;  /* PTS is valid only once */

        p_dec->fmt_out.audio.i_rate = frame.samplerate;
        p_dec->fmt_out.audio.i_channels = frame.channels;

        /* Adjust stream info when dealing with SBR/PS */
        bool b_sbr = (frame.sbr == 1) || (frame.sbr == 2);
        if( p_sys->b_sbr != b_sbr || p_sys->b_ps != frame.ps )
        {
            const char *psz_ext = (b_sbr && frame.ps) ? "SBR+PS" :
                                    b_sbr ? "SBR" : "PS";

            msg_Dbg( p_dec, "AAC %s (channels: %u, samplerate: %lu)",
                    psz_ext, frame.channels, frame.samplerate );

            if( !p_dec->p_description )
                p_dec->p_description = vlc_meta_New();
            if( p_dec->p_description )
                vlc_meta_AddExtra( p_dec->p_description, _("AAC extension"), psz_ext );

            p_sys->b_sbr = b_sbr;
            p_sys->b_ps = frame.ps;
        }

        /* Convert frame.channel_position to our own channel values */
        p_dec->fmt_out.audio.i_physical_channels = 0;
        const uint32_t nbChannels = frame.channels;
        unsigned j;
        for( unsigned i = 0; i < nbChannels; i++ )
        {
            /* Find the channel code */
            for( j = 0; j < MAX_CHANNEL_POSITIONS; j++ )
            {
                if( frame.channel_position[i] == pi_channels_in[j] )
                    break;
            }
            if( j >= MAX_CHANNEL_POSITIONS )
            {
                msg_Warn( p_dec, "unknown channel ordering" );
                /* Invent something */
                j = i;
            }
            /* */
            p_sys->pi_channel_positions[i] = pi_channels_out[j];
            if( p_dec->fmt_out.audio.i_physical_channels & pi_channels_out[j] )
                frame.channels--; /* We loose a duplicated channel */
            else
                p_dec->fmt_out.audio.i_physical_channels |= pi_channels_out[j];
        }
        if ( nbChannels != frame.channels )
        {
            p_dec->fmt_out.audio.i_physical_channels
                = p_dec->fmt_out.audio.i_original_channels
                = pi_channels_guessed[nbChannels];
        }
        else
        {
            p_dec->fmt_out.audio.i_original_channels =
                p_dec->fmt_out.audio.i_physical_channels;
        }
        p_dec->fmt_out.audio.i_channels = nbChannels;
        p_out = decoder_NewAudioBuffer( p_dec, frame.samples / nbChannels );
        if( p_out == NULL )
        {
            p_sys->i_buffer = 0;
            block_Release( p_block );
            return NULL;
        }

        p_out->i_pts = date_Get( &p_sys->date );
        p_out->i_length = date_Increment( &p_sys->date,
                                          frame.samples / nbChannels )
                          - p_out->i_pts;

        DoReordering( (uint32_t *)p_out->p_buffer, samples,
                      frame.samples / nbChannels, nbChannels,
                      p_sys->pi_channel_positions );

        p_sys->i_buffer -= frame.bytesconsumed;
        if( p_sys->i_buffer > 0 )
        {
            memmove( p_sys->p_buffer, &p_sys->p_buffer[frame.bytesconsumed],
                     p_sys->i_buffer );
        }

        return p_out;
    }

    block_Release( p_block );
    return NULL;
}
Beispiel #11
0
/*****************************************************************************
 * 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;
    vlc_tick_t i64;
    vlc_tick_t *pi64;

    switch( i_query )
    {
    case DEMUX_CAN_SEEK:
        *va_arg( args, bool * ) = true;
        return VLC_SUCCESS;

    case DEMUX_GET_POSITION:
        pf = va_arg( args, double* );
        if( p_sys->i_length > 0 )
        {
            double current = date_Get( &p_sys->pts ) - VLC_TICK_0;
            double length = p_sys->i_length;
            *pf = current / length;
            return VLC_SUCCESS;
        }
        return VLC_EGENERIC;

    case DEMUX_SET_POSITION:
        f = va_arg( args, double );

        i64 = f * p_sys->i_length;
        if( i64 >= 0 && i64 <= p_sys->i_length )
        {
            ModPlug_Seek( p_sys->f, MS_FROM_VLC_TICK(i64) );
            date_Set( &p_sys->pts, VLC_TICK_0 + i64 );

            return VLC_SUCCESS;
        }
        return VLC_EGENERIC;

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

    case DEMUX_GET_LENGTH:
        pi64 = va_arg( args, vlc_tick_t * );
        *pi64 = p_sys->i_length;
        return VLC_SUCCESS;

    case DEMUX_SET_TIME:
        i64 = va_arg( args, vlc_tick_t );

        if( likely(i64 >= 0) && i64 <= p_sys->i_length )
        {
            ModPlug_Seek( p_sys->f, MS_FROM_VLC_TICK( i64 ) );
            date_Set( &p_sys->pts, VLC_TICK_0 + i64 );

            return VLC_SUCCESS;
        }
        return VLC_EGENERIC;

    case DEMUX_HAS_UNSUPPORTED_META:
    {
        bool *pb_bool = va_arg( args, bool* );
        *pb_bool = false; /* FIXME I am not sure of this one */
        return VLC_SUCCESS;
    }
    case DEMUX_GET_META:
    {
        vlc_meta_t *p_meta = va_arg( args, vlc_meta_t * );
        unsigned i_num_samples = ModPlug_NumSamples( p_sys->f ),
                 i_num_instruments = ModPlug_NumInstruments( p_sys->f );
        unsigned i_num_patterns = ModPlug_NumPatterns( p_sys->f ),
                 i_num_channels = ModPlug_NumChannels( p_sys->f );
        //      unsigned modType = ModPlug_GetModuleType( p_sys->f );

        char psz_temp[2048]; /* 32 * 240 max, but only need start  */
        char *psz_module_info, *psz_instrument_info;
        unsigned i_temp_index = 0;
        const char *psz_name = ModPlug_GetName( p_sys->f );
        if( psz_name && *psz_name && IsUTF8( psz_name ) )
            vlc_meta_SetTitle( p_meta, psz_name );

        /* Comment field from artist - not in every type of MOD */
        psz_name = ModPlug_GetMessage( p_sys->f );
        if( psz_name && *psz_name && IsUTF8( psz_name ) )
            vlc_meta_SetDescription( p_meta, psz_name );

        /* Instruments only in newer MODs - so don't show if 0 */
        if( asprintf( &psz_instrument_info, ", %i Instruments",
                      i_num_instruments ) >= 0 )
        {
            if( asprintf( &psz_module_info,
                          "%i Channels, %i Patterns\n"
                          "%i Samples%s\n",
                          i_num_channels, i_num_patterns, i_num_samples,
                          ( i_num_instruments ? psz_instrument_info : "" ) ) >= 0 )
            {
                vlc_meta_AddExtra( p_meta, "Module Information",
                                   psz_module_info );
                free( psz_module_info );
            }

            free( psz_instrument_info );
        }

        /* Make list of instruments (XM, IT, etc) */
        if( i_num_instruments )
        {
            i_temp_index = 0;
            for( unsigned i = 0; i < i_num_instruments && i_temp_index < sizeof(psz_temp); i++ )
            {
                char lBuffer[33];
                ModPlug_InstrumentName( p_sys->f, i, lBuffer );
                if ( !lBuffer[0] || !IsUTF8( lBuffer ) ) continue;
                i_temp_index += snprintf( &psz_temp[i_temp_index], sizeof(psz_temp) - i_temp_index, "%s\n", lBuffer );
            }

            vlc_meta_AddExtra( p_meta, "Instruments", psz_temp );
        }

        /* Make list of samples */
        for( unsigned int i = 0; i < i_num_samples && i_temp_index < sizeof(psz_temp); i++ )
        {
            char psz_buffer[33];
            ModPlug_SampleName( p_sys->f, i, psz_buffer );
            if ( !psz_buffer[0] || !IsUTF8( psz_buffer ) ) continue;
            i_temp_index += snprintf( &psz_temp[i_temp_index], sizeof(psz_temp) - i_temp_index, "%s\n", psz_buffer );
        }

        vlc_meta_AddExtra( p_meta, "Samples", psz_temp );

        return VLC_SUCCESS;
    }

    case DEMUX_GET_FPS: /* meaningless */
        return VLC_EGENERIC;

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

    default:
        return VLC_EGENERIC;

    }
}
Beispiel #12
0
Datei: faad.c Projekt: Kafay/vlc
/*****************************************************************************
 * DecodeBlock:
 *****************************************************************************/
static aout_buffer_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    block_t *p_block;

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

    p_block = *pp_block;

    if( p_block->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
    {
        block_Release( p_block );
        return NULL;
    }

    /* Remove ADTS header if we have decoder specific config */
    if( p_dec->fmt_in.i_extra && p_block->i_buffer > 7 )
    {
        if( p_block->p_buffer[0] == 0xff &&
            ( p_block->p_buffer[1] & 0xf0 ) == 0xf0 ) /* syncword */
        {   /* ADTS header present */
            size_t i_header_size; /* 7 bytes (+ 2 bytes for crc) */
            i_header_size = 7 + ( ( p_block->p_buffer[1] & 0x01 ) ? 0 : 2 );
            /* FIXME: multiple blocks per frame */
            if( p_block->i_buffer > i_header_size )
            {
                vlc_memcpy( p_block->p_buffer,
                            p_block->p_buffer + i_header_size,
                            p_block->i_buffer - i_header_size );
                p_block->i_buffer -= i_header_size;
            }
        }
    }

    /* Append the block to the temporary buffer */
    if( p_sys->i_buffer_size < p_sys->i_buffer + p_block->i_buffer )
    {
        p_sys->i_buffer_size = p_sys->i_buffer + p_block->i_buffer;
        p_sys->p_buffer = realloc( p_sys->p_buffer, p_sys->i_buffer_size );
    }

    if( p_block->i_buffer > 0 )
    {
        vlc_memcpy( &p_sys->p_buffer[p_sys->i_buffer],
                     p_block->p_buffer, p_block->i_buffer );
        p_sys->i_buffer += p_block->i_buffer;
        p_block->i_buffer = 0;
    }

    if( p_dec->fmt_out.audio.i_rate == 0 && p_dec->fmt_in.i_extra > 0 )
    {
        /* We have a decoder config so init the handle */
        unsigned long i_rate;
        unsigned char i_channels;

        if( faacDecInit2( p_sys->hfaad, p_dec->fmt_in.p_extra,
                          p_dec->fmt_in.i_extra,
                          &i_rate, &i_channels ) >= 0 )
        {
            p_dec->fmt_out.audio.i_rate = i_rate;
            p_dec->fmt_out.audio.i_channels = i_channels;
            p_dec->fmt_out.audio.i_physical_channels
                = p_dec->fmt_out.audio.i_original_channels
                = pi_channels_guessed[i_channels];

            aout_DateInit( &p_sys->date, i_rate );
        }
    }

    if( p_dec->fmt_out.audio.i_rate == 0 && p_sys->i_buffer )
    {
        unsigned long i_rate;
        unsigned char i_channels;

        /* Init faad with the first frame */
        if( faacDecInit( p_sys->hfaad,
                         p_sys->p_buffer, p_sys->i_buffer,
                         &i_rate, &i_channels ) < 0 )
        {
            block_Release( p_block );
            return NULL;
        }

        p_dec->fmt_out.audio.i_rate = i_rate;
        p_dec->fmt_out.audio.i_channels = i_channels;
        p_dec->fmt_out.audio.i_physical_channels
            = p_dec->fmt_out.audio.i_original_channels
            = pi_channels_guessed[i_channels];
        aout_DateInit( &p_sys->date, i_rate );
    }

    if( p_block->i_pts != 0 && p_block->i_pts != aout_DateGet( &p_sys->date ) )
    {
        aout_DateSet( &p_sys->date, p_block->i_pts );
    }
    else if( !aout_DateGet( &p_sys->date ) )
    {
        /* We've just started the stream, wait for the first PTS. */
        block_Release( p_block );
        p_sys->i_buffer = 0;
        return NULL;
    }

    /* Decode all data */
    if( p_sys->i_buffer )
    {
        void *samples;
        faacDecFrameInfo frame;
        aout_buffer_t *p_out;
        int i, j;

        samples = faacDecDecode( p_sys->hfaad, &frame,
                                 p_sys->p_buffer, p_sys->i_buffer );

        if( frame.error > 0 )
        {
            msg_Warn( p_dec, "%s", faacDecGetErrorMessage( frame.error ) );

            /* Flush the buffer */
            p_sys->i_buffer = 0;
            block_Release( p_block );
            return NULL;
        }

        if( frame.channels <= 0 || frame.channels > 8 || frame.channels == 7 )
        {
            msg_Warn( p_dec, "invalid channels count: %i", frame.channels );

            /* Flush the buffer */
            p_sys->i_buffer -= frame.bytesconsumed;
            if( p_sys->i_buffer > 0 )
            {
                memmove( p_sys->p_buffer,&p_sys->p_buffer[frame.bytesconsumed],
                         p_sys->i_buffer );
            }
            block_Release( p_block );
            return NULL;
        }

        if( frame.samples <= 0 )
        {
            msg_Warn( p_dec, "decoded zero sample" );

            /* Flush the buffer */
            p_sys->i_buffer -= frame.bytesconsumed;
            if( p_sys->i_buffer > 0 )
            {
                memmove( p_sys->p_buffer,&p_sys->p_buffer[frame.bytesconsumed],
                         p_sys->i_buffer );
            }
            block_Release( p_block );
            return NULL;
        }

        /* We decoded a valid frame */
        if( p_dec->fmt_out.audio.i_rate != frame.samplerate )
        {
            aout_DateInit( &p_sys->date, frame.samplerate );
            aout_DateSet( &p_sys->date, p_block->i_pts );
        }
        p_block->i_pts = 0;  /* PTS is valid only once */

        p_dec->fmt_out.audio.i_rate = frame.samplerate;
        p_dec->fmt_out.audio.i_channels = frame.channels;
        p_dec->fmt_out.audio.i_physical_channels
            = p_dec->fmt_out.audio.i_original_channels
            = pi_channels_guessed[frame.channels];

        /* Adjust stream info when dealing with SBR/PS */
        if( p_sys->b_sbr != frame.sbr || p_sys->b_ps != frame.ps )
        {
            const char *psz_ext = (frame.sbr && frame.ps) ? "SBR+PS" :
                                    frame.sbr ? "SBR" : "PS";

            msg_Dbg( p_dec, "AAC %s (channels: %u, samplerate: %lu)",
                    psz_ext, frame.channels, frame.samplerate );

            if( !p_dec->p_description )
                p_dec->p_description = vlc_meta_New();
            if( p_dec->p_description )
                vlc_meta_AddExtra( p_dec->p_description, _("AAC extension"), psz_ext );

            p_sys->b_sbr = frame.sbr; p_sys->b_ps = frame.ps;
        }

        /* Convert frame.channel_position to our own channel values */
        p_dec->fmt_out.audio.i_physical_channels = 0;
        for( i = 0; i < frame.channels; i++ )
        {
            /* Find the channel code */
            for( j = 0; j < MAX_CHANNEL_POSITIONS; j++ )
            {
                if( frame.channel_position[i] == pi_channels_in[j] )
                    break;
            }
            if( j >= MAX_CHANNEL_POSITIONS )
            {
                msg_Warn( p_dec, "unknown channel ordering" );
                /* Invent something */
                j = i;
            }
            /* */
            p_sys->pi_channel_positions[i] = pi_channels_out[j];
            if( p_dec->fmt_out.audio.i_physical_channels & pi_channels_out[j] )
                frame.channels--; /* We loose a duplicated channel */
            else
                p_dec->fmt_out.audio.i_physical_channels |= pi_channels_out[j];
        }
        p_dec->fmt_out.audio.i_original_channels =
            p_dec->fmt_out.audio.i_physical_channels;

        p_out = decoder_NewAudioBuffer(p_dec, frame.samples/frame.channels);
        if( p_out == NULL )
        {
            p_sys->i_buffer = 0;
            block_Release( p_block );
            return NULL;
        }

        p_out->start_date = aout_DateGet( &p_sys->date );
        p_out->end_date = aout_DateIncrement( &p_sys->date, frame.samples / frame.channels );

        DoReordering( (uint32_t *)p_out->p_buffer, samples,
                      frame.samples / frame.channels, frame.channels,
                      p_sys->pi_channel_positions );

        p_sys->i_buffer -= frame.bytesconsumed;
        if( p_sys->i_buffer > 0 )
        {
            memmove( p_sys->p_buffer, &p_sys->p_buffer[frame.bytesconsumed],
                     p_sys->i_buffer );
        }

        return p_out;
    }

    block_Release( p_block );
    return NULL;
}
Beispiel #13
0
/*****************************************************************************
 * ParseID3Tag : parse an id3tag into the info structures
 *****************************************************************************/
static void ParseID3Tag( demux_meta_t *p_demux_meta, const uint8_t *p_data, int i_size )
{
    struct id3_tag   *p_id3_tag;
    struct id3_frame *p_frame;
    vlc_meta_t       *p_meta;
    int i;

    p_id3_tag = id3_tag_parse( p_data, i_size );
    if( !p_id3_tag )
        return;

    if( !p_demux_meta->p_meta )
        p_demux_meta->p_meta = vlc_meta_New();
    p_meta = p_demux_meta->p_meta;

#define ID_IS( a ) (!strcmp(  p_frame->id, a ))
#define DESCR_IS( a) strstr( (char*)p_frame->description, a )
#define GET_STRING(frame,fidx) id3_ucs4_latin1duplicate( id3_field_getstring( &(frame)->fields[fidx] ) )

    /* */
    for( i = 0; (p_frame = id3_tag_findframe( p_id3_tag, "UFID", i )) != NULL; i++ )
    {
        const char *psz_owner = id3_field_getlatin1( &p_frame->fields[0] );

        if( !strncmp( psz_owner, "http://musicbrainz.org", 22 ) )
        {
            id3_byte_t const * p_ufid;
            id3_length_t i_ufidlen;

            p_ufid = id3_field_getbinarydata( &p_frame->fields[1], &i_ufidlen );
            char *psz_ufid = strndup( p_ufid, i_ufidlen );

            vlc_meta_SetTrackID( p_meta, psz_ufid );
            free( psz_ufid );
        }
    }

    /* User defined text (TXXX) */
    for( i = 0; (p_frame = id3_tag_findframe( p_id3_tag, "TXXX", i )) != NULL; i++ )
    {
        /* 3 fields: 'encoding', 'description', 'value' */
        char *psz_name = GET_STRING( p_frame, 1 );
        char *psz_value = GET_STRING( p_frame, 2 );

        vlc_meta_AddExtra( p_meta, psz_name, psz_value );
#if 0
        if( !strncmp( psz_name, "MusicBrainz Artist Id", 21 ) )
            vlc_meta_SetArtistID( p_meta, psz_value );
        if( !strncmp( psz_desc, "MusicBrainz Album Id", 20 ) )
            vlc_meta_SetAlbumID( p_meta, psz_value );
#endif
        free( psz_name );
        free( psz_value );
    }

    /* Relative volume adjustment */
    for( i = 0; (p_frame = id3_tag_findframe( p_id3_tag, "RVA2", i )) != NULL; i++ )
    {
        /* 2 fields: 'latin1', 'binary' */
        const char *psz_type = id3_field_getlatin1( &p_frame->fields[0] );
        if( !strcasecmp( psz_type, "track" ) || !strcasecmp( psz_type, "album" ) ||
            !strcasecmp( psz_type, "normalize" ) )
        {
            id3_byte_t const * p_data;
            id3_length_t i_data;

            p_data = id3_field_getbinarydata( &p_frame->fields[1], &i_data );
            while( i_data >= 4 )
            {
                const unsigned int i_peak_size = p_data[3];
                const float f_temp = GetWBE( &p_data[1] );
                const float f_gain = f_temp / 512.0;
                char psz_value[32];

                if( i_data < i_peak_size + 4 )
                    break;
                /* only master volume */
                if( p_data[0] == 0x01 )
                {
                    snprintf( psz_value, sizeof(psz_value), "%f", f_gain );
                    if( !strcasecmp( psz_type, "album" ) )
                        vlc_meta_AddExtra( p_meta, "REPLAYGAIN_ALBUM_GAIN", psz_value );
                    else
                        vlc_meta_AddExtra( p_meta, "REPLAYGAIN_TRACK_GAIN", psz_value );
                    /* XXX I have no idea what peak unit is ... */
                }
                i_data -= 4+i_peak_size;
            }
        }
    }

    /* TODO 'RGAD' if it is used somewhere */

    /* T--- Text informations */
    for( i = 0; (p_frame = id3_tag_findframe( p_id3_tag, "T", i )) != NULL; i++ )
    {
        unsigned i_strings;
 
        /* Special case TXXX is not the same beast */
        if( ID_IS( "TXXX" ) )
            continue;

        i_strings = id3_field_getnstrings( &p_frame->fields[1] );
        while( i_strings > 0 )
        {
            char *psz_temp = id3_ucs4_utf8duplicate(
                id3_field_getstrings( &p_frame->fields[1], --i_strings ) );

            if( ID_IS( ID3_FRAME_GENRE ) )
            {
                char *psz_endptr;
                int i_genre = strtol( psz_temp, &psz_endptr, 10 );

                if( psz_temp != psz_endptr &&
                    i_genre >= 0 && i_genre < NUM_GENRES )
                {
                    vlc_meta_SetGenre( p_meta, ppsz_genres[atoi(psz_temp)]);
                }
                else
                {
                    /* Unknown genre */
                    vlc_meta_SetGenre( p_meta,psz_temp );
                }
            }
            else if( ID_IS( ID3_FRAME_TITLE ) )
            {
                vlc_meta_SetTitle( p_meta, psz_temp );
            }
            else if( ID_IS( ID3_FRAME_ARTIST ) )
            {
                vlc_meta_SetArtist( p_meta, psz_temp );
            }
            else if( ID_IS( ID3_FRAME_YEAR ) )
            {
                vlc_meta_SetDate( p_meta, psz_temp );
            }
            else if( ID_IS( ID3_FRAME_COMMENT ) )
            {
                vlc_meta_SetDescription( p_meta, psz_temp );
            }
            else if( DESCR_IS( "Copyright" ) )
            {
                vlc_meta_SetCopyright( p_meta, psz_temp );
            }
            else if( DESCR_IS( "Publisher" ) )
            {
                vlc_meta_SetPublisher( p_meta, psz_temp );
            }
            else if( DESCR_IS( "Track number/position in set" ) )
            {
                vlc_meta_SetTrackNum( p_meta, psz_temp );
            }
            else if( DESCR_IS( "Album/movie/show title" ) )
            {
                vlc_meta_SetAlbum( p_meta, psz_temp );
            }
            else if( DESCR_IS( "Encoded by" ) )
            {
                vlc_meta_SetEncodedBy( p_meta, psz_temp );
            }
            else if( ID_IS ( "APIC" ) )
            {
                msg_Dbg( p_demux_meta, "** Has APIC **" );
            }
            else if( p_frame->description )
            {
                /* Unhandled meta */
                vlc_meta_AddExtra( p_meta, (char*)p_frame->description, psz_temp );
            }
            free( psz_temp );
        }
    }
    id3_tag_delete( p_id3_tag );
#undef GET_STRING
#undef DESCR_IS
#undef ID_IS
}
Beispiel #14
0
static void ParseAPEvXTag( demux_meta_t *p_demux_meta, const uint8_t *p_data, int i_data )
{
    vlc_meta_t       *p_meta;
    bool b_start;
    bool b_end;
    const uint8_t *p_header = NULL;
    int i_entry;

    if( i_data < APE_TAG_HEADERSIZE )
        return;

    b_start = !strncmp( (char*)&p_data[0], "APETAGEX", 8 );
    b_end = !strncmp( (char*)&p_data[i_data-APE_TAG_HEADERSIZE], "APETAGEX", 8 );
    if( !b_end && !b_start )
        return;

    if( !p_demux_meta->p_meta )
        p_demux_meta->p_meta = vlc_meta_New();
    p_meta = p_demux_meta->p_meta;

    if( b_start )
    {
        p_header = &p_data[0];
        p_data += APE_TAG_HEADERSIZE;
        i_data -= APE_TAG_HEADERSIZE;
    }
    if( b_end )
    {
        p_header = &p_data[i_data-APE_TAG_HEADERSIZE];
        i_data -= APE_TAG_HEADERSIZE;
    }
    if( i_data <= 0 )
        return;

    i_entry = GetDWLE( &p_header[8+4+4] );
    if( i_entry <= 0 )
        return;

    while( i_entry > 0 && i_data >= 10 )
    {
        const int i_size = GetDWLE( &p_data[0] );
        const uint32_t flags = GetDWLE( &p_data[4] );
        char psz_name[256];
        int n;

        strlcpy( psz_name, (char*)&p_data[8], sizeof(psz_name) );
        n = strlen( psz_name );
        if( n <= 0 )
            break;

        p_data += 8+n+1;
        i_data -= 8+n+1;
        if( i_data < i_size )
            break;

        /* Retreive UTF-8 fields only */
        if( ((flags>>1) & 0x03) == 0x00 )
        {
            /* FIXME list are separated by '\0' */
            char *psz_value = strndup( (char*)&p_data[0], i_size );

            EnsureUTF8( psz_name );
            EnsureUTF8( psz_value );
#define IS(s) (!strcasecmp( psz_name, s ) )
            if( IS( "Title" ) )
                vlc_meta_SetTitle( p_meta, psz_value );
            else  if( IS( "Artist" ) )
                vlc_meta_SetArtist( p_meta, psz_value );
            else  if( IS( "Album" ) )
                vlc_meta_SetAlbum( p_meta, psz_value );
            else  if( IS( "Publisher" ) )
                vlc_meta_SetPublisher( p_meta, psz_value );
            else  if( IS( "Track" ) )
            {
                char *p = strchr( psz_value, '/' );
                if( p )
                    *p++ = '\0';
                vlc_meta_SetTrackNum( p_meta, psz_value );
            }
            else  if( IS( "Comment" ) )
                vlc_meta_SetDescription( p_meta, psz_value );
            else  if( IS( "Copyright" ) )
                vlc_meta_SetCopyright( p_meta, psz_value );
            else  if( IS( "Year" ) )
                vlc_meta_SetDate( p_meta, psz_value );
            else  if( IS( "Genre" ) )
                vlc_meta_SetGenre( p_meta, psz_value );
            else  if( IS( "Language" ) )
                vlc_meta_SetLanguage( p_meta, psz_value );
            else
                vlc_meta_AddExtra( p_meta, psz_name, psz_value );
#undef IS
            free( psz_value );
        }

        p_data += i_size;
        i_data -= i_size;
        i_entry--;
    }
}
Beispiel #15
0
void vorbis_ParseComment( es_format_t *p_fmt, vlc_meta_t **pp_meta,
        const uint8_t *p_data, int i_data,
        int *i_attachments, input_attachment_t ***attachments,
        int *i_cover_score, int *i_cover_idx,
        int *i_seekpoint, seekpoint_t ***ppp_seekpoint,
        float (* ppf_replay_gain)[AUDIO_REPLAY_GAIN_MAX],
        float (* ppf_replay_peak)[AUDIO_REPLAY_GAIN_MAX] )
{
    int n;
    int i_comment;

    if( i_data < 8 )
        return;

    n = GetDWLE(p_data); RM(4);
    if( n < 0 || n > i_data )
        return;
#if 0
    if( n > 0 )
    {
        /* TODO report vendor string ? */
        char *psz_vendor = psz_vendor = strndup( p_data, n );
        free( psz_vendor );
    }
#endif
    RM(n);

    if( i_data < 4 )
        return;

    i_comment = GetDWLE(p_data); RM(4);
    if( i_comment <= 0 )
        return;

    /* */
    vlc_meta_t *p_meta = *pp_meta;
    if( !p_meta )
        *pp_meta = p_meta = vlc_meta_New();
    if( !p_meta )
        return;

    /* */
    bool hasTitle        = false;
    bool hasArtist       = false;
    bool hasGenre        = false;
    bool hasCopyright    = false;
    bool hasAlbum        = false;
    bool hasTrackNum     = false;
    bool hasDescription  = false;
    bool hasRating       = false;
    bool hasDate         = false;
    bool hasLanguage     = false;
    bool hasPublisher    = false;
    bool hasEncodedBy    = false;
    bool hasTrackTotal   = false;

    chapters_array_t chapters_array = { 0, NULL };

    for( ; i_comment > 0; i_comment-- )
    {
        char *psz_comment;
        if( i_data < 4 )
            break;
        n = GetDWLE(p_data); RM(4);
        if( n > i_data )
            break;
        if( n <= 0 )
            continue;

        psz_comment = strndup( (const char*)p_data, n );
        RM(n);

        EnsureUTF8( psz_comment );

#define IF_EXTRACT(txt,var) \
    if( !strncasecmp(psz_comment, txt, strlen(txt)) ) \
    { \
        const char *oldval = vlc_meta_Get( p_meta, vlc_meta_ ## var ); \
        if( oldval && has##var) \
        { \
            char * newval; \
            if( asprintf( &newval, "%s,%s", oldval, &psz_comment[strlen(txt)] ) == -1 ) \
                newval = NULL; \
            vlc_meta_Set( p_meta, vlc_meta_ ## var, newval ); \
            free( newval ); \
        } \
        else \
            vlc_meta_Set( p_meta, vlc_meta_ ## var, &psz_comment[strlen(txt)] ); \
        has##var = true; \
    }

#define IF_EXTRACT_ONCE(txt,var) \
    if( !strncasecmp(psz_comment, txt, strlen(txt)) && !has##var ) \
    { \
        vlc_meta_Set( p_meta, vlc_meta_ ## var, &psz_comment[strlen(txt)] ); \
        has##var = true; \
    }

#define IF_EXTRACT_FMT(txt,var,fmt,target) \
    IF_EXTRACT(txt,var)\
    if( fmt && !strncasecmp(psz_comment, txt, strlen(txt)) )\
        {\
            if ( fmt->target ) free( fmt->target );\
            fmt->target = strdup(&psz_comment[strlen(txt)]);\
        }

        IF_EXTRACT("TITLE=", Title )
        else IF_EXTRACT("ARTIST=", Artist )
        else IF_EXTRACT("GENRE=", Genre )
        else IF_EXTRACT("COPYRIGHT=", Copyright )
        else IF_EXTRACT("ALBUM=", Album )
        else if( !hasTrackNum && !strncasecmp(psz_comment, "TRACKNUMBER=", strlen("TRACKNUMBER=" ) ) )
        {
            /* Yeah yeah, such a clever idea, let's put xx/xx inside TRACKNUMBER
             * Oh, and let's not use TRACKTOTAL or TOTALTRACKS... */
            short unsigned u_track, u_total;
            if( sscanf( &psz_comment[strlen("TRACKNUMBER=")], "%hu/%hu", &u_track, &u_total ) == 2 )
            {
                char str[6];
                snprintf(str, 6, "%u", u_track);
                vlc_meta_Set( p_meta, vlc_meta_TrackNumber, str );
                hasTrackNum = true;
                snprintf(str, 6, "%u", u_total);
                vlc_meta_Set( p_meta, vlc_meta_TrackTotal, str );
                hasTrackTotal = true;
            }
            else
            {
                vlc_meta_Set( p_meta, vlc_meta_TrackNumber, &psz_comment[strlen("TRACKNUMBER=")] );
                hasTrackNum = true;
            }
        }
        else IF_EXTRACT_ONCE("TRACKTOTAL=", TrackTotal )
        else IF_EXTRACT_ONCE("TOTALTRACKS=", TrackTotal )
        else IF_EXTRACT("DESCRIPTION=", Description )
        else IF_EXTRACT("COMMENT=", Description )
        else IF_EXTRACT("COMMENTS=", Description )
        else IF_EXTRACT("RATING=", Rating )
        else IF_EXTRACT("DATE=", Date )
        else IF_EXTRACT_FMT("LANGUAGE=", Language, p_fmt, psz_language )
        else IF_EXTRACT("ORGANIZATION=", Publisher )
        else IF_EXTRACT("ENCODER=", EncodedBy )
        else if( !strncasecmp( psz_comment, "METADATA_BLOCK_PICTURE=", strlen("METADATA_BLOCK_PICTURE=")))
        {
            if( attachments == NULL )
                continue;

            uint8_t *p_picture;
            size_t i_size = vlc_b64_decode_binary( &p_picture, &psz_comment[strlen("METADATA_BLOCK_PICTURE=")]);
            input_attachment_t *p_attachment = ParseFlacPicture( p_picture,
                i_size, *i_attachments, i_cover_score, i_cover_idx );
            free( p_picture );
            if( p_attachment )
            {
                TAB_APPEND_CAST( (input_attachment_t**),
                    *i_attachments, *attachments, p_attachment );
            }
        }
        else if ( ppf_replay_gain && ppf_replay_peak && !strncmp(psz_comment, "REPLAYGAIN_", 11) )
        {
            char *p = strchr( psz_comment, '=' );
            if (!p) continue;
            if ( !strncasecmp(psz_comment, "REPLAYGAIN_TRACK_GAIN=", 22) )
            {
                (*ppf_replay_gain)[AUDIO_REPLAY_GAIN_TRACK] = us_atof( ++p );
            }
            else if ( !strncasecmp(psz_comment, "REPLAYGAIN_ALBUM_GAIN=", 22) )
            {
                (*ppf_replay_gain)[AUDIO_REPLAY_GAIN_ALBUM] = us_atof( ++p );
            }
            else if ( !strncasecmp(psz_comment, "REPLAYGAIN_ALBUM_PEAK=", 22) )
            {
                (*ppf_replay_peak)[AUDIO_REPLAY_GAIN_ALBUM] = us_atof( ++p );
            }
            else if ( !strncasecmp(psz_comment, "REPLAYGAIN_TRACK_PEAK=", 22) )
            {
                (*ppf_replay_peak)[AUDIO_REPLAY_GAIN_TRACK] = us_atof( ++p );
            }
        }
        else if( !strncasecmp(psz_comment, "CHAPTER", 7) )
        {
            unsigned int i_chapt;
            seekpoint_t *p_seekpoint = NULL;

            for( int i = 0; psz_comment[i] && psz_comment[i] != '='; i++ )
                if( psz_comment[i] >= 'a' && psz_comment[i] <= 'z' )
                    psz_comment[i] -= 'a' - 'A';

            if( strstr( psz_comment, "NAME=" ) &&
                    sscanf( psz_comment, "CHAPTER%uNAME=", &i_chapt ) == 1 )
            {
                char *p = strchr( psz_comment, '=' );
                p_seekpoint = getChapterEntry( i_chapt, &chapters_array );
                if ( !p || ! p_seekpoint ) continue;
                if ( ! p_seekpoint->psz_name )
                    p_seekpoint->psz_name = strdup( ++p );
            }
            else if( sscanf( psz_comment, "CHAPTER%u=", &i_chapt ) == 1 )
            {
                unsigned int h, m, s, ms;
                char *p = strchr( psz_comment, '=' );
                if( p && sscanf( ++p, "%u:%u:%u.%u", &h, &m, &s, &ms ) == 4 )
                {
                    p_seekpoint = getChapterEntry( i_chapt, &chapters_array );
                    if ( ! p_seekpoint ) continue;
                    p_seekpoint->i_time_offset =
                      (((int64_t)h * 3600 + (int64_t)m * 60 + (int64_t)s) * 1000 + ms) * 1000;
                }
            }
        }
        else if( strchr( psz_comment, '=' ) )
        {
            /* generic (PERFORMER/LICENSE/ORGANIZATION/LOCATION/CONTACT/ISRC,
             * undocumented tags and replay gain ) */
            char *p = strchr( psz_comment, '=' );
            *p++ = '\0';

            for( int i = 0; psz_comment[i]; i++ )
                if( psz_comment[i] >= 'a' && psz_comment[i] <= 'z' )
                    psz_comment[i] -= 'a' - 'A';

            vlc_meta_AddExtra( p_meta, psz_comment, p );
        }
#undef IF_EXTRACT
        free( psz_comment );
    }