📄 flac.c
字号:
else if( i_query == DEMUX_GET_LENGTH ) { int64_t *pi64 = (int64_t*)va_arg( args, int64_t * ); *pi64 = ControlGetLength( p_demux ); return VLC_SUCCESS; } else if( i_query == DEMUX_SET_TIME ) { int64_t i_time = (int64_t)va_arg( args, int64_t ); return ControlSetTime( p_demux, i_time ); } else if( i_query == DEMUX_SET_POSITION ) { const double f = (double)va_arg( args, double ); int64_t i_time = f * ControlGetLength( p_demux ); return ControlSetTime( p_demux, i_time ); } else if( i_query == DEMUX_GET_TIME ) { int64_t *pi64 = (int64_t*)va_arg( args, int64_t * ); *pi64 = ControlGetTime( p_demux ); return VLC_SUCCESS; } else if( i_query == DEMUX_GET_POSITION ) { double *pf = (double*)va_arg( args, double * ); const int64_t i_length = ControlGetLength(p_demux); if( i_length > 0 ) *pf = (double)ControlGetTime(p_demux) / (double)i_length; else *pf= 0.0; return VLC_SUCCESS; } else if( i_query == DEMUX_GET_ATTACHMENTS ) { input_attachment_t ***ppp_attach = (input_attachment_t***)va_arg( args, input_attachment_t*** ); int *pi_int = (int*)va_arg( args, int * ); int i; if( p_sys->i_attachments <= 0 ) return VLC_EGENERIC; *pi_int = p_sys->i_attachments;; *ppp_attach = malloc( sizeof(input_attachment_t**) * p_sys->i_attachments ); for( i = 0; i < p_sys->i_attachments; i++ ) (*ppp_attach)[i] = vlc_input_attachment_Duplicate( p_sys->attachments[i] ); return VLC_SUCCESS; } return demux_vaControlHelper( p_demux->s, p_sys->i_data_pos, -1, 8*0, 1, i_query, args );}enum{ META_STREAMINFO = 0, META_SEEKTABLE = 3, META_COMMENT = 4, META_PICTURE = 6,};static inline int Get24bBE( const uint8_t *p ){ return (p[0] << 16)|(p[1] << 8)|(p[2]);}static void ParseStreamInfo( int *pi_rate, int64_t *pi_count, uint8_t *p_data );static void ParseSeekTable( demux_t *p_demux, const uint8_t *p_data, int i_data, int i_sample_rate );static void ParseComment( demux_t *, const uint8_t *p_data, int i_data );static void ParsePicture( demux_t *, const uint8_t *p_data, int i_data );static int ReadMeta( demux_t *p_demux, uint8_t **pp_streaminfo, int *pi_streaminfo ){ demux_sys_t *p_sys = p_demux->p_sys; int i_peek; const uint8_t *p_peek; bool b_last; int i_sample_rate; int64_t i_sample_count; seekpoint_t *s; /* Read STREAMINFO */ i_peek = stream_Peek( p_demux->s, &p_peek, 8 ); if( (p_peek[4] & 0x7F) != META_STREAMINFO ) { msg_Err( p_demux, "this isn't a STREAMINFO metadata block" ); return VLC_EGENERIC; } if( Get24bBE(&p_peek[5]) != (STREAMINFO_SIZE - 4) ) { msg_Err( p_demux, "invalid size for a STREAMINFO metadata block" ); return VLC_EGENERIC; } *pi_streaminfo = 4 + STREAMINFO_SIZE; *pp_streaminfo = malloc( 4 + STREAMINFO_SIZE ); if( *pp_streaminfo == NULL ) return VLC_EGENERIC; if( stream_Read( p_demux->s, *pp_streaminfo, 4+STREAMINFO_SIZE ) != 4+STREAMINFO_SIZE ) { msg_Err( p_demux, "failed to read STREAMINFO metadata block" ); free( *pp_streaminfo ); return VLC_EGENERIC; } /* */ ParseStreamInfo( &i_sample_rate, &i_sample_count, *pp_streaminfo ); if( i_sample_rate > 0 ) p_sys->i_length = i_sample_count * INT64_C(1000000)/i_sample_rate; /* Be sure we have seekpoint 0 */ s = vlc_seekpoint_New(); s->i_time_offset = 0; s->i_byte_offset = 0; TAB_APPEND( p_sys->i_seekpoint, p_sys->seekpoint, s ); b_last = (*pp_streaminfo)[4]&0x80; while( !b_last ) { int i_len; int i_type; i_peek = stream_Peek( p_demux->s, &p_peek, 4 ); if( i_peek < 4 ) break; b_last = p_peek[0]&0x80; i_type = p_peek[0]&0x7f; i_len = Get24bBE( &p_peek[1] ); if( i_type == META_SEEKTABLE ) { i_peek = stream_Peek( p_demux->s, &p_peek, 4+i_len ); if( i_peek == 4+i_len ) ParseSeekTable( p_demux, p_peek, i_peek, i_sample_rate ); } else if( i_type == META_COMMENT ) { i_peek = stream_Peek( p_demux->s, &p_peek, 4+i_len ); if( i_peek == 4+i_len ) ParseComment( p_demux, p_peek, i_peek ); } else if( i_type == META_PICTURE ) { i_peek = stream_Peek( p_demux->s, &p_peek, 4+i_len ); if( i_peek == 4+i_len ) ParsePicture( p_demux, p_peek, i_peek ); } if( stream_Read( p_demux->s, NULL, 4+i_len ) < 4+i_len ) break; } /* */ p_sys->i_data_pos = stream_Tell( p_demux->s ); return VLC_SUCCESS;}static void ParseStreamInfo( int *pi_rate, int64_t *pi_count, uint8_t *p_data ){ const int i_skip = 4+4; *pi_rate = GetDWBE(&p_data[i_skip+4+6]) >> 12; *pi_count = GetQWBE(&p_data[i_skip+4+6]) & ((INT64_C(1)<<36)-1);}static void ParseSeekTable( demux_t *p_demux, const uint8_t *p_data, int i_data, int i_sample_rate ){ demux_sys_t *p_sys = p_demux->p_sys; seekpoint_t *s; int i; if( i_sample_rate <= 0 ) return; /* */ for( i = 0; i < (i_data-4)/18; i++ ) { const int64_t i_sample = GetQWBE( &p_data[4+18*i+0] ); int j; if( i_sample < 0 || i_sample >= INT64_MAX ) continue; s = vlc_seekpoint_New(); s->i_time_offset = i_sample * INT64_C(1000000)/i_sample_rate; s->i_byte_offset = GetQWBE( &p_data[4+18*i+8] ); /* Check for duplicate entry */ for( j = 0; j < p_sys->i_seekpoint; j++ ) { if( p_sys->seekpoint[j]->i_time_offset == s->i_time_offset || p_sys->seekpoint[j]->i_byte_offset == s->i_byte_offset ) { vlc_seekpoint_Delete( s ); s = NULL; break; } } if( s ) { TAB_APPEND( p_sys->i_seekpoint, p_sys->seekpoint, s ); } } /* TODO sort it by size and remove wrong seek entry (time not increasing) */}#define RM(x) do { i_data -= (x); p_data += (x); } while(0)static void ParseComment( demux_t *p_demux, const uint8_t *p_data, int i_data ){ demux_sys_t *p_sys = p_demux->p_sys; int n; int i_comment; if( i_data < 8 ) return; RM(4); 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 ); msg_Dbg( p_demux, "FLAC: COMMENT vendor length=%d vendor=%s\n", n, psz_vendor ); free( psz_vendor ); }#endif RM(n); if( i_data < 4 ) return; i_comment = GetDWLE(p_data); RM(4); if( i_comment <= 0 ) return; p_sys->p_meta = vlc_meta_New(); for( ; i_comment > 0; i_comment-- ) { char *psz; if( i_data < 4 ) break; n = GetDWLE(p_data); RM(4); if( n > i_data ) break; if( n <= 0 ) continue; psz = strndup( (const char*)p_data, n ); RM(n); EnsureUTF8( psz );#define IF_EXTRACT(txt,var) \ if( !strncasecmp(psz, txt, strlen(txt)) ) \ { \ const char *oldval = vlc_meta_Get( p_sys->p_meta, vlc_meta_ ## var ); \ if( oldval ) \ { \ char * newval; \ if( asprintf( &newval, "%s,%s", oldval, &psz[strlen(txt)] ) == -1 ) \ newval = NULL; \ vlc_meta_Set( p_sys->p_meta, vlc_meta_ ## var, newval ); \ free( newval ); \ } \ else \ vlc_meta_Set( p_sys->p_meta, vlc_meta_ ## var, &psz[strlen(txt)] ); \ } IF_EXTRACT("TITLE=", Title ) else IF_EXTRACT("ALBUM=", Album ) else IF_EXTRACT("TRACKNUMBER=", TrackNumber ) else IF_EXTRACT("ARTIST=", Artist ) else IF_EXTRACT("COPYRIGHT=", Copyright ) else IF_EXTRACT("DESCRIPTION=", Description ) else IF_EXTRACT("GENRE=", Genre ) else IF_EXTRACT("DATE=", Date ) else if( strchr( psz, '=' ) ) { /* generic (PERFORMER/LICENSE/ORGANIZATION/LOCATION/CONTACT/ISRC, * undocumented tags and replay gain ) */ char *p = strchr( psz, '=' ); *p++ = '\0'; vlc_meta_AddExtra( p_sys->p_meta, psz, p ); }#undef IF_EXTRACT free( psz ); }#undef RM}static void ParsePicture( demux_t *p_demux, const uint8_t *p_data, int i_data ){ static const int pi_cover_score[] = { 0, /* other */ 2, 1, /* icons */ 10, /* front cover */ 9, /* back cover */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, /* movie/video screen capture */ 0, 7, /* Illustration */ 8, /* Band/Artist logotype */ 0, /* Publisher/Studio */ }; demux_sys_t *p_sys = p_demux->p_sys; int i_type; int i_len; char *psz_mime = NULL; char *psz_description = NULL; input_attachment_t *p_attachment; char psz_name[128]; if( i_data < 4 + 3*4 ) return;#define RM(x) do { i_data -= (x); p_data += (x); } while(0) RM(4); i_type = GetDWBE( p_data ); RM(4); i_len = GetDWBE( p_data ); RM(4); if( i_len < 0 || i_data < i_len + 4 ) goto error; psz_mime = strndup( (const char*)p_data, i_len ); RM(i_len); i_len = GetDWBE( p_data ); RM(4); if( i_len < 0 || i_data < i_len + 4*4 + 4) goto error; psz_description = strndup( (const char*)p_data, i_len ); RM(i_len); EnsureUTF8( psz_description ); RM(4*4); i_len = GetDWBE( p_data ); RM(4); if( i_len < 0 || i_len > i_data ) goto error; msg_Dbg( p_demux, "FLAC: Picture type=%d mime=%s description='%s' file length=%d", i_type, psz_mime, psz_description, i_len ); snprintf( psz_name, sizeof(psz_name), "picture%d", p_sys->i_attachments ); if( !strcasecmp( psz_mime, "image/jpeg" ) ) strcat( psz_name, ".jpg" ); else if( !strcasecmp( psz_mime, "image/png" ) ) strcat( psz_name, ".png" ); p_attachment = vlc_input_attachment_New( psz_name, psz_mime, psz_description, p_data, i_data ); TAB_APPEND( p_sys->i_attachments, p_sys->attachments, p_attachment ); if( i_type >= 0 && (unsigned int)i_type < sizeof(pi_cover_score)/sizeof(pi_cover_score[0]) && p_sys->i_cover_score < pi_cover_score[i_type] ) { p_sys->i_cover_idx = p_sys->i_attachments-1; p_sys->i_cover_score = pi_cover_score[i_type]; }error: free( psz_mime ); free( psz_description );}#undef RM
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -