id3tag.c

来自「VLC Player Source Code」· C语言 代码 · 共 521 行 · 第 1/2 页

C
521
字号
    /* is it the header */    if( flags & (1<<29) )        return i_body + ( (flags&(1<<30)) ? APE_TAG_HEADERSIZE : 0 );    /* it is the footer */    return i_body + ( (flags&(1<<31)) ? APE_TAG_HEADERSIZE : 0 );}static void ParseAPEvXTag( demux_t *p_demux, const uint8_t *p_data, int i_data ){    demux_meta_t     *p_demux_meta = (demux_meta_t*)p_demux->p_private;    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--;    }}/***************************************************************************** * CheckFooter: check for ID3/APE at the end of the file * CheckHeader: check for ID3/APE at the begining of the file *****************************************************************************/static void CheckFooter( demux_t *p_demux ){    const int64_t i_pos = stream_Size( p_demux->s );    const size_t i_peek = 128+APE_TAG_HEADERSIZE;    const uint8_t *p_peek;    const uint8_t *p_peek_id3;    int64_t i_id3v2_pos = -1;    int64_t i_apevx_pos = -1;    int i_id3v2_size;    int i_apevx_size;    size_t i_id3v1_size;    if( i_pos < i_peek )        return;    if( stream_Seek( p_demux->s, i_pos - i_peek ) )        return;    if( stream_Peek( p_demux->s, &p_peek, i_peek ) < i_peek )        return;    p_peek_id3 = &p_peek[APE_TAG_HEADERSIZE];    /* Check/Parse ID3v1 */    i_id3v1_size = id3_tag_query( p_peek_id3, ID3_TAG_QUERYSIZE );    if( i_id3v1_size == 128 )    {        msg_Dbg( p_demux, "found ID3v1 tag" );        ParseID3Tag( p_demux, p_peek_id3, i_id3v1_size );    }    /* Compute ID3v2 position */    i_id3v2_size = -id3_tag_query( &p_peek_id3[128-ID3_TAG_QUERYSIZE], ID3_TAG_QUERYSIZE );    if( i_id3v2_size > 0 )        i_id3v2_pos = i_pos - i_id3v2_size;    /* Compute APE2v2 position */    i_apevx_size = GetAPEvXSize( &p_peek[128+0], APE_TAG_HEADERSIZE );    if( i_apevx_size > 0 )    {        i_apevx_pos = i_pos - i_apevx_size;    }    else if( i_id3v1_size > 0 )    {        /* it can be before ID3v1 */        i_apevx_size = GetAPEvXSize( p_peek, APE_TAG_HEADERSIZE );        if( i_apevx_size > 0 )            i_apevx_pos = i_pos - 128 - i_apevx_size;    }    if( i_id3v2_pos > 0 && i_apevx_pos > 0 )    {        msg_Warn( p_demux,                  "Both ID3v2 and APEv1/2 at the end of file, ignoring APEv1/2" );        i_apevx_pos = -1;    }    /* Parse ID3v2.4 */    if( i_id3v2_pos > 0 )    {        if( !stream_Seek( p_demux->s, i_id3v2_pos ) &&            stream_Peek( p_demux->s, &p_peek, i_id3v2_size ) == i_id3v2_size )        {            msg_Dbg( p_demux, "found ID3v2 tag at end of file" );            ParseID3Tag( p_demux, p_peek, i_id3v2_size );        }    }    /* Parse APEv1/2 */    if( i_apevx_pos > 0 )    {        if( !stream_Seek( p_demux->s, i_apevx_pos ) &&            stream_Peek( p_demux->s, &p_peek, i_apevx_size ) == i_apevx_size )        {            msg_Dbg( p_demux, "found APEvx tag at end of file" );            ParseAPEvXTag( p_demux, p_peek, i_apevx_size );        }    }}static void CheckHeader( demux_t *p_demux ){    const uint8_t *p_peek;    int i_size;    if( stream_Seek( p_demux->s, 0 ) )        return;    /* Test ID3v2 first */    if( stream_Peek( p_demux->s, &p_peek, ID3_TAG_QUERYSIZE ) != ID3_TAG_QUERYSIZE )        return;    i_size = id3_tag_query( p_peek, ID3_TAG_QUERYSIZE );    if( i_size > 0 &&        stream_Peek( p_demux->s, &p_peek, i_size ) == i_size )    {        msg_Dbg( p_demux, "found ID3v2 tag" );        ParseID3Tag( p_demux, p_peek, i_size );        return;    }    /* Test APEv1 */    if( stream_Peek( p_demux->s, &p_peek, APE_TAG_HEADERSIZE ) != APE_TAG_HEADERSIZE )        return;    i_size = GetAPEvXSize( p_peek, APE_TAG_HEADERSIZE );    if( i_size > 0 &&        stream_Peek( p_demux->s, &p_peek, i_size ) == i_size )    {        msg_Dbg( p_demux, "found APEv1/2 tag" );        ParseAPEvXTag( p_demux, p_peek, i_size );    }}/***************************************************************************** * ParseTags: check if ID3/APE tags at common locations. ****************************************************************************/static int ParseTags( vlc_object_t *p_this ){    demux_t      *p_demux = (demux_t *)p_this;    demux_meta_t *p_demux_meta = (demux_meta_t*)p_demux->p_private;    bool    b_seekable;    int64_t       i_init;    msg_Dbg( p_demux, "checking for ID3v1/2 and APEv1/2 tags" );    stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &b_seekable );    if( !b_seekable )        return VLC_EGENERIC;    i_init = stream_Tell( p_demux->s );    TAB_INIT( p_demux_meta->i_attachments, p_demux_meta->attachments );    p_demux_meta->p_meta = NULL;    /* */    CheckFooter( p_demux );    /* */    CheckHeader( p_demux );    /* Restore position     *  Demuxer will not see tags at the start as src/input/demux.c skips it     *  for them     */    stream_Seek( p_demux->s, i_init );    if( !p_demux_meta->p_meta && p_demux_meta->i_attachments <= 0 )        return VLC_EGENERIC;    return VLC_SUCCESS;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?