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 + -
显示快捷键?