mirror of
https://github.com/owntone/owntone-server.git
synced 2025-04-01 18:21:31 -04:00
First pass at .m4a support
This commit is contained in:
parent
d6ce8bf570
commit
7df7ce5c83
@ -2,6 +2,13 @@
|
|||||||
* $Id$
|
* $Id$
|
||||||
* Implementation file for mp3 scanner and monitor
|
* Implementation file for mp3 scanner and monitor
|
||||||
*
|
*
|
||||||
|
* Ironically, this now scans file types other than mp3 files,
|
||||||
|
* but the name is the same for historical purposes, not to mention
|
||||||
|
* the fact that sf.net makes it virtually impossible to manage a cvs
|
||||||
|
* root reasonably. Perhaps one day soon they will move to subversion.
|
||||||
|
*
|
||||||
|
* /me crosses his fingers
|
||||||
|
*
|
||||||
* Copyright (C) 2003 Ron Pedde (ron@pedde.com)
|
* Copyright (C) 2003 Ron Pedde (ron@pedde.com)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@ -221,6 +228,8 @@ char *scan_winamp_genre[] = {
|
|||||||
*/
|
*/
|
||||||
int scan_foreground(char *path);
|
int scan_foreground(char *path);
|
||||||
int scan_gettags(char *file, MP3FILE *pmp3);
|
int scan_gettags(char *file, MP3FILE *pmp3);
|
||||||
|
int scan_get_mp3tags(char *file, MP3FILE *pmp3);
|
||||||
|
int scan_get_aactags(char *file, MP3FILE *pmp3);
|
||||||
int scan_getfileinfo(char *file, MP3FILE *pmp3);
|
int scan_getfileinfo(char *file, MP3FILE *pmp3);
|
||||||
int scan_freetags(MP3FILE *pmp3);
|
int scan_freetags(MP3FILE *pmp3);
|
||||||
void scan_static_playlist(char *path, struct dirent *pde, struct stat *psb);
|
void scan_static_playlist(char *path, struct dirent *pde, struct stat *psb);
|
||||||
@ -412,6 +421,139 @@ void scan_music_file(char *path, struct dirent *pde, struct stat *psb) {
|
|||||||
scan_freetags(&mp3file);
|
scan_freetags(&mp3file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* scan_aac_findatom
|
||||||
|
*
|
||||||
|
* Find an AAC atom
|
||||||
|
*/
|
||||||
|
long scan_aac_findatom(FILE *fin, long max_offset, char *which_atom, int *atom_size) {
|
||||||
|
long current_offset=0;
|
||||||
|
int size;
|
||||||
|
char atom[4];
|
||||||
|
|
||||||
|
while(current_offset < max_offset) {
|
||||||
|
if(fread((void*)&size,1,sizeof(int),fin) != sizeof(int))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
size=ntohl(size);
|
||||||
|
|
||||||
|
if(size < 0) /* something not right */
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if(fread(atom,1,4,fin) != 4)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if(strncasecmp(atom,which_atom,4) == 0) {
|
||||||
|
*atom_size=size;
|
||||||
|
return current_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(fin,size-8,SEEK_CUR);
|
||||||
|
current_offset+=size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* scan_get_aactags
|
||||||
|
*
|
||||||
|
* Get tags from an AAC (m4a) file
|
||||||
|
*/
|
||||||
|
int scan_get_aactags(char *file, MP3FILE *pmp3) {
|
||||||
|
FILE *fin;
|
||||||
|
long atom_offset;
|
||||||
|
int atom_length;
|
||||||
|
long file_size;
|
||||||
|
|
||||||
|
long current_offset=0;
|
||||||
|
int current_size;
|
||||||
|
char current_atom[4];
|
||||||
|
char *current_data;
|
||||||
|
unsigned short us_data;
|
||||||
|
|
||||||
|
if(!(fin=fopen(file,"rb"))) {
|
||||||
|
DPRINTF(ERR_INFO,"Cannot open file %s for reading\n",file);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(fin,0,SEEK_END);
|
||||||
|
file_size=ftell(fin);
|
||||||
|
fseek(fin,0,SEEK_SET);
|
||||||
|
|
||||||
|
atom_offset=scan_aac_findatom(fin,file_size,"moov",&atom_length);
|
||||||
|
if(atom_offset != -1) {
|
||||||
|
atom_offset=scan_aac_findatom(fin,atom_length - 8,"udta",&atom_length);
|
||||||
|
if(atom_offset != -1) {
|
||||||
|
atom_offset=scan_aac_findatom(fin,atom_length - 8, "meta", &atom_length);
|
||||||
|
if(atom_offset != -1) {
|
||||||
|
fseek(fin,4,SEEK_CUR); /* ???? */
|
||||||
|
atom_offset=scan_aac_findatom(fin, atom_length - 8, "ilst", &atom_length);
|
||||||
|
if(atom_offset != -1) {
|
||||||
|
/* found the tag section - need to walk through now */
|
||||||
|
|
||||||
|
while(current_offset < atom_length) {
|
||||||
|
if(fread((void*)¤t_size,1,sizeof(int),fin) != sizeof(int))
|
||||||
|
break;
|
||||||
|
|
||||||
|
current_size=ntohl(current_size);
|
||||||
|
|
||||||
|
if(current_size < 0) /* something not right */
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(fread(current_atom,1,4,fin) != 4)
|
||||||
|
break;
|
||||||
|
|
||||||
|
current_data=(char*)malloc(current_size - 7); /* extra byte */
|
||||||
|
memset(current_data,0x00,current_size - 7);
|
||||||
|
|
||||||
|
if(fread(current_data,1,current_size-8,fin) != current_size-8)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(!memcmp(current_atom,"\xA9" "nam",4)) { /* Song name */
|
||||||
|
pmp3->title=strdup((char*)¤t_data[16]);
|
||||||
|
} else if(!memcmp(current_atom,"\xA9" "ART",4)) {
|
||||||
|
pmp3->artist=strdup((char*)¤t_data[16]);
|
||||||
|
} else if(!memcmp(current_atom,"\xA9" "alb",4)) {
|
||||||
|
pmp3->album=strdup((char*)¤t_data[16]);
|
||||||
|
} else if(!memcmp(current_atom,"\xA9" "gen",4)) {
|
||||||
|
/* can this be a winamp genre??? */
|
||||||
|
pmp3->genre=strdup((char*)¤t_data[16]);
|
||||||
|
} else if(!memcmp(current_atom,"trkn",4)) {
|
||||||
|
us_data=*((unsigned short *)¤t_data[18]);
|
||||||
|
us_data=htons(us_data);
|
||||||
|
|
||||||
|
pmp3->track=us_data;
|
||||||
|
|
||||||
|
us_data=*((unsigned short *)¤t_data[20]);
|
||||||
|
us_data=htons(us_data);
|
||||||
|
|
||||||
|
pmp3->total_tracks=us_data;
|
||||||
|
} else if(!memcmp(current_atom,"disk",4)) {
|
||||||
|
us_data=*((unsigned short *)¤t_data[18]);
|
||||||
|
us_data=htons(us_data);
|
||||||
|
|
||||||
|
pmp3->disc=us_data;
|
||||||
|
|
||||||
|
us_data=*((unsigned short *)¤t_data[20]);
|
||||||
|
us_data=htons(us_data);
|
||||||
|
|
||||||
|
pmp3->total_discs=us_data;
|
||||||
|
} else if(!memcmp(current_atom,"\xA9" "day",4)) {
|
||||||
|
pmp3->year=atoi((char*)¤t_data[16]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(current_data);
|
||||||
|
current_offset+=current_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fin);
|
||||||
|
return 0; /* we'll return as much as we got. */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -420,6 +562,32 @@ void scan_music_file(char *path, struct dirent *pde, struct stat *psb) {
|
|||||||
* Scan an mp3 file for id3 tags using libid3tag
|
* Scan an mp3 file for id3 tags using libid3tag
|
||||||
*/
|
*/
|
||||||
int scan_gettags(char *file, MP3FILE *pmp3) {
|
int scan_gettags(char *file, MP3FILE *pmp3) {
|
||||||
|
/* dispatch to appropriate tag handler */
|
||||||
|
|
||||||
|
/* perhaps it would be better to just blindly try each
|
||||||
|
* in turn, just in case the extensions are wrong/lying
|
||||||
|
*/
|
||||||
|
|
||||||
|
if(!strcasecmp(pmp3->type,".aac"))
|
||||||
|
return scan_get_aactags(file,pmp3);
|
||||||
|
|
||||||
|
if(!strcasecmp(pmp3->type,".m4a"))
|
||||||
|
return scan_get_aactags(file,pmp3);
|
||||||
|
|
||||||
|
/* should handle mp3 in the same way */
|
||||||
|
if(!strcasecmp(pmp3->type,".mp3"))
|
||||||
|
return scan_get_mp3tags(file,pmp3);
|
||||||
|
|
||||||
|
/* maybe this is an extension that we've manually
|
||||||
|
* specified in the config file, but don't know how
|
||||||
|
* to extract tags from. Ogg, maybe.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int scan_get_mp3tags(char *file, MP3FILE *pmp3) {
|
||||||
struct id3_file *pid3file;
|
struct id3_file *pid3file;
|
||||||
struct id3_tag *pid3tag;
|
struct id3_tag *pid3tag;
|
||||||
struct id3_frame *pid3frame;
|
struct id3_frame *pid3frame;
|
||||||
@ -433,6 +601,9 @@ int scan_gettags(char *file, MP3FILE *pmp3) {
|
|||||||
id3_ucs4_t const *native_text;
|
id3_ucs4_t const *native_text;
|
||||||
char *tmp;
|
char *tmp;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if(strcasecmp(pmp3->type,".mp3")) /* can't get tags for non-mp3 */
|
if(strcasecmp(pmp3->type,".mp3")) /* can't get tags for non-mp3 */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -638,7 +809,8 @@ int scan_getfileinfo(char *file, MP3FILE *pmp3) {
|
|||||||
|
|
||||||
/* guesstimate the file length */
|
/* guesstimate the file length */
|
||||||
time_seconds = ((int)(file_size * 8)) / (bitrate * 1024);
|
time_seconds = ((int)(file_size * 8)) / (bitrate * 1024);
|
||||||
pmp3->song_length=time_seconds;
|
if(!pmp3->song_length) /* could have gotten it from the tag */
|
||||||
|
pmp3->song_length=time_seconds;
|
||||||
} else {
|
} else {
|
||||||
/* should really scan forward to next sync frame */
|
/* should really scan forward to next sync frame */
|
||||||
fclose(infile);
|
fclose(infile);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user