/***************************************************************************** * InformationCreate: *****************************************************************************/ void matroska_segment_c::InformationCreate( ) { if( !sys.meta ) sys.meta = vlc_meta_New(); if( psz_title ) { vlc_meta_SetTitle( sys.meta, psz_title ); } }
static int Control (demux_t *demux, int query, va_list args) { demux_sys_t *sys = demux->p_sys; switch (query) { case DEMUX_GET_TIME : { int64_t *v = va_arg (args, int64_t*); *v = sys->player->time() * sys->player->timebase() * (CLOCK_FREQ / 100); return VLC_SUCCESS; } case DEMUX_GET_META : { vlc_meta_t *p_meta = va_arg (args, vlc_meta_t *); /* These are specified in the sid tune class as 0 = Title, 1 = Artist, 2 = Copyright/Publisher */ vlc_meta_SetTitle( p_meta, sys->tuneInfo.infoString[0] ); vlc_meta_SetArtist( p_meta, sys->tuneInfo.infoString[1] ); vlc_meta_SetCopyright( p_meta, sys->tuneInfo.infoString[2] ); return VLC_SUCCESS; } case DEMUX_GET_TITLE_INFO : if ( sys->tuneInfo.songs > 1 ) { input_title_t ***ppp_title = va_arg (args, input_title_t ***); int *pi_int = va_arg( args, int* ); *pi_int = sys->tuneInfo.songs; *ppp_title = (input_title_t**) malloc( sizeof (input_title_t*) * sys->tuneInfo.songs); for( int i = 0; i < sys->tuneInfo.songs; i++ ) { (*ppp_title)[i] = vlc_input_title_New(); } return VLC_SUCCESS; } return VLC_EGENERIC; case DEMUX_SET_TITLE : { int i_idx = va_arg (args, int); sys->tune->selectSong (i_idx+1); bool result = (sys->player->load (sys->tune) >=0 ); if (!result) return VLC_EGENERIC; demux->info.i_title = i_idx; demux->info.i_update = INPUT_UPDATE_TITLE; msg_Dbg( demux, "set song %i", i_idx); return VLC_SUCCESS; } }
/***************************************************************************** * 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 ); }
static int CdTextParse( vlc_meta_t ***ppp_tracks, int *pi_tracks, const uint8_t *p_buffer, int i_buffer ) { char *pppsz_info[128][0x10]; int i_track_last = -1; if( i_buffer < 4 ) return -1; memset( pppsz_info, 0, sizeof(pppsz_info) ); for( int i = 0; i < (i_buffer-4)/18; i++ ) { const uint8_t *p_block = &p_buffer[4 + 18*i]; char psz_text[12+1]; const int i_pack_type = p_block[0]; if( i_pack_type < 0x80 || i_pack_type > 0x8f ) continue; const int i_track_number = (p_block[1] >> 0)&0x7f; const int i_extension_flag = ( p_block[1] >> 7)& 0x01; if( i_extension_flag ) continue; //const int i_sequence_number = p_block[2]; //const int i_charater_position = (p_block[3] >> 0) &0x0f; //const int i_block_number = (p_block[3] >> 4) &0x07; /* TODO unicode support * I need a sample */ //const int i_unicode = ( p_block[3] >> 7)&0x01; //const int i_crc = (p_block[4+12] << 8) | (p_block[4+13] << 0); /* */ memcpy( psz_text, &p_block[4], 12 ); psz_text[12] = '\0'; /* */ int i_track = i_track_number; char *psz_track = &psz_text[0]; while( i_track <= 127 && psz_track < &psz_text[12] ) { //fprintf( stderr, "t=%d psz_track=%p end=%p", i_track, (void *)psz_track, (void *)&psz_text[12] ); if( *psz_track ) { astrcat( &pppsz_info[i_track][i_pack_type-0x80], psz_track ); i_track_last = __MAX( i_track_last, i_track ); } i_track++; psz_track += 1 + strlen(psz_track); } } if( i_track_last < 0 ) return -1; vlc_meta_t **pp_tracks = calloc( i_track_last+1, sizeof(*pp_tracks) ); if( !pp_tracks ) goto exit; for( int j = 0; j < 0x10; j++ ) { for( int i = 0; i <= i_track_last; i++ ) { /* */ if( pppsz_info[i][j] ) EnsureUTF8( pppsz_info[i][j] ); /* */ const char *psz_default = pppsz_info[0][j]; const char *psz_value = pppsz_info[i][j]; if( !psz_value && !psz_default ) continue; vlc_meta_t *p_track = pp_tracks[i]; if( !p_track ) { p_track = pp_tracks[i] = vlc_meta_New(); if( !p_track ) continue; } switch( j ) { case 0x00: /* Album/Title */ if( i == 0 ) { vlc_meta_SetAlbum( p_track, psz_value ); } else { if( psz_value ) vlc_meta_SetTitle( p_track, psz_value ); if( psz_default ) vlc_meta_SetAlbum( p_track, psz_default ); } break; case 0x01: /* Performer */ vlc_meta_SetArtist( p_track, psz_value ? psz_value : psz_default ); break; case 0x05: /* Messages */ vlc_meta_SetDescription( p_track, psz_value ? psz_value : psz_default ); break; case 0x07: /* Genre */ vlc_meta_SetGenre( p_track, psz_value ? psz_value : psz_default ); break; /* FIXME unsupported: * 0x02: songwriter * 0x03: composer * 0x04: arrenger * 0x06: disc id */ } } } /* */ exit: for( int j = 0; j < 0x10; j++ ) for( int i = 0; i <= i_track_last; i++ ) free( pppsz_info[i][j] ); *ppp_tracks = pp_tracks; *pi_tracks = i_track_last+1; return pp_tracks ? 0 : -1; }
/***************************************************************************** * 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; } }
/***************************************************************************** * 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 }
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--; } }