From 8dfea7dee3958ebce161f68200927ca172963456 Mon Sep 17 00:00:00 2001 From: Ron Pedde Date: Thu, 12 Jan 2006 08:10:48 +0000 Subject: [PATCH] Add video support for m4v files --- src/Makefile.am | 2 +- src/db-generic.c | 19 ++++ src/db-generic.h | 7 ++ src/db-sql-sqlite2.c | 30 +++-- src/db-sql-sqlite3.c | 29 +++-- src/db-sql.c | 25 ++++- src/mp3-scanner.c | 2 + src/mp3-scanner.h | 6 + src/scan-aac.c | 2 +- src/scan-mp4.c | 258 +++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 353 insertions(+), 27 deletions(-) create mode 100644 src/scan-mp4.c diff --git a/src/Makefile.am b/src/Makefile.am index c447dd6b..7399bc34 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -49,7 +49,7 @@ mt_daapd_SOURCES = main.c daapd.h rend.h uici.c uici.h webserver.c \ mp3-scanner.h mp3-scanner.c rend-unix.h strcasestr.c strcasestr.h \ strsep.c dynamic-art.c dynamic-art.h query.c query.h ssc.c ssc.h \ db-generic.c db-generic.h dispatch.c dispatch.h \ - rxml.c rxml.h redblack.c redblack.h scan-mp3.c \ + rxml.c rxml.h redblack.c redblack.h scan-mp3.c scan-mp4.c \ scan-xml.c scan-wma.c scan-aac.c scan-aac.h scan-wav.c scan-url.c \ smart-parser.c smart-parser.h xml-rpc.c xml-rpc.h \ $(PRENDSRC) $(ORENDSRC) $(HRENDSRC) $(OGGVORBISSRC) $(FLACSRC) \ diff --git a/src/db-generic.c b/src/db-generic.c index 6812899e..81753ee2 100644 --- a/src/db-generic.c +++ b/src/db-generic.c @@ -214,6 +214,7 @@ DAAP_ITEMS taglist[] = { { 0x0C, "arif", "daap.resolveinfo" }, { 0x05, "aeNV", "com.apple.itunes.norm-volume" }, { 0x01, "aeSP", "com.apple.itunes.smart-playlist" }, + /* iTunes 4.5+ */ { 0x01, "msas", "dmap.authenticationschemes" }, { 0x05, "ascd", "daap.songcodectype" }, @@ -227,6 +228,13 @@ DAAP_ITEMS taglist[] = { { 0x05, "aeSI", "com.apple.iTunes.itms-songid" }, { 0x05, "aeSF", "com.apple.iTunes.itms-storefrontid" }, + /* iTunes 5.0+ */ + { 0x01, "ascr", "daap.songcontentrating" }, + { 0x05, "f" "\x8d" "ch", "dmap.haschildcontainers" }, /* wtf - content codes says it's 1 */ + + /* iTunes 6.0.2+ */ + { 0x01, "aeHV", "com.apple.itunes.has-video" }, + /* mt-daapd specific */ { 0x09, "MSPS", "org.mt-daapd.smart-playlist-spec" }, { 0x01, "MPTY", "org.mt-daapd.playlist-type" }, @@ -235,6 +243,7 @@ DAAP_ITEMS taglist[] = { { 0x0C, "MDPR", "org.mt-daapd.delplaylist" }, { 0x0C, "MDPI", "org.mt-daapd.delplaylistitem" }, { 0x0C, "MEPR", "org.mt-daapd.editplaylist" }, + { 0x00, NULL, NULL } }; @@ -276,6 +285,7 @@ static METAMAP db_metamap[] = { { "daap.songtracknumber", metaSongTrackNumber }, { "daap.songuserrating", metaSongUserRating }, { "daap.songyear", metaSongYear }, + /* iTunes 4.5+ (forgot exactly when) */ { "daap.songcodectype", metaSongCodecType }, { "daap.songcodecsubtype", metaSongCodecSubType }, @@ -287,9 +297,18 @@ static METAMAP db_metamap[] = { { "com.apple.itunes.itms-genreid", metaItmsGenreId }, { "com.apple.itunes.itms-storefrontid",metaItmsStorefrontId }, { "com.apple.itunes.smart-playlist", metaItunesSmartPlaylist }, + + /* iTunes 5.0+ */ + { "daap.songcontentrating", metaSongContentRating }, + { "dmap.haschildcontainers", metaHasChildContainers }, + + /* iTunes 6.0.2+ */ + { "com.apple.itunes.has-video", metaItunesHasVideo }, + /* mt-daapd specific */ { "org.mt-daapd.smart-playlist-spec", metaMPlaylistSpec }, { "org.mt-daapd.playlist-type", metaMPlaylistType }, + { 0, 0 } }; diff --git a/src/db-generic.h b/src/db-generic.h index 539449e3..334cfdec 100644 --- a/src/db-generic.h +++ b/src/db-generic.h @@ -77,6 +77,13 @@ typedef enum { metaItmsGenreId, metaItmsStorefrontId, metaItunesSmartPlaylist, + + /* iTunes 5.0 + */ + metaSongContentRating, + metaHasChildContainers, + + /* iTunes 6.0.2+ */ + metaItunesHasVideo, /* mt-daapd specific */ metaMPlaylistSpec, diff --git a/src/db-sql-sqlite2.c b/src/db-sql-sqlite2.c index c5c464ac..47f2907b 100644 --- a/src/db-sql-sqlite2.c +++ b/src/db-sql-sqlite2.c @@ -64,13 +64,14 @@ static int db_sqlite2_in_enum=0; static char db_sqlite2_path[PATH_MAX + 1]; -#define DB_SQLITE2_VERSION 8 +#define DB_SQLITE2_VERSION 9 /* Forwards */ void db_sqlite2_lock(void); void db_sqlite2_unlock(void); -extern char *db_sqlite2_initial; +extern char *db_sqlite2_initial1; +extern char *db_sqlite2_initial2; /** * lock the db_mutex @@ -331,7 +332,9 @@ int db_sqlite2_event(int event_type) { db_sqlite2_exec(NULL,E_DBG,"vacuum"); - db_sqlite2_exec(NULL,E_DBG,db_sqlite2_initial); + db_sqlite2_exec(NULL,E_DBG,db_sqlite2_initial1); + db_sqlite2_exec(NULL,E_DBG,db_sqlite2_initial2); + db_sqlite2_reload=1; break; @@ -381,6 +384,7 @@ int db_sqlite2_event(int event_type) { "id from playlists)"); db_sqlite2_exec(NULL,E_FATAL,"drop table plupdated"); } + db_sqlite2_reload=0; break; default: @@ -401,7 +405,7 @@ int db_sqlite2_insert_id(void) { } -char *db_sqlite2_initial = +char *db_sqlite2_initial1 = "create table songs (\n" " id INTEGER PRIMARY KEY NOT NULL,\n" " path VARCHAR(4096) UNIQUE NOT NULL,\n" @@ -441,18 +445,23 @@ char *db_sqlite2_initial = " sample_count INTEGER DEFAULT 0,\n" " force_update INTEGER DEFAULT 0,\n" " codectype VARCHAR(5) DEFAULT NULL,\n" -" idx INTEGER NOT NULL\n" -");\n" -"create table config (\n" -" term VARCHAR(255) NOT NULL,\n" -" subterm VARCHAR(255) DEFAULT NULL,\n" -" value VARCHAR(1024) NOT NULL\n" +" idx INTEGER NOT NULL,\n" +" has_video INTEGER DEFAULT 0,\n" +" contentrating INTEGER DEFAULT 0\n" ");\n" "create table playlistitems (\n" " id INTEGER PRIMARY KEY NOT NULL,\n" " playlistid INTEGER NOT NULL,\n" " songid INTEGER NOT NULL\n" ");\n" +"create table config (\n" +" term VARCHAR(255) NOT NULL,\n" +" subterm VARCHAR(255) DEFAULT NULL,\n" +" value VARCHAR(1024) NOT NULL\n" +");\n" +"insert into config values ('version','','9');\n"; + +char *db_sqlite2_initial2 = "create table playlists (\n" " id INTEGER PRIMARY KEY NOT NULL,\n" " title VARCHAR(255) NOT NULL,\n" @@ -463,7 +472,6 @@ char *db_sqlite2_initial = " path VARCHAR(4096),\n" " idx INTEGER NOT NULL\n" ");\n" -"insert into config values ('version','','8');\n" "insert into playlists values (1,'Library',1,0,'1',0,'',0);\n"; diff --git a/src/db-sql-sqlite3.c b/src/db-sql-sqlite3.c index d744566a..15f6deb0 100644 --- a/src/db-sql-sqlite3.c +++ b/src/db-sql-sqlite3.c @@ -65,13 +65,14 @@ static char **db_sqlite3_row = NULL; static char db_sqlite3_path[PATH_MAX + 1]; -#define DB_SQLITE3_VERSION 8 +#define DB_SQLITE3_VERSION 9 /* Forwards */ void db_sqlite3_lock(void); void db_sqlite3_unlock(void); -extern char *db_sqlite3_initial; +extern char *db_sqlite3_initial1; +extern char *db_sqlite3_initial2; /** * lock the db_mutex @@ -352,7 +353,8 @@ int db_sqlite3_event(int event_type) { db_sqlite3_exec(NULL,E_DBG,"vacuum"); - db_sqlite3_exec(NULL,E_DBG,db_sqlite3_initial); + db_sqlite3_exec(NULL,E_DBG,db_sqlite3_initial1); + db_sqlite3_exec(NULL,E_DBG,db_sqlite3_initial2); db_sqlite3_reload=1; break; @@ -402,6 +404,7 @@ int db_sqlite3_event(int event_type) { "id from playlists)"); db_sqlite3_exec(NULL,E_FATAL,"drop table plupdated"); } + db_sqlite3_reload=0; break; default: @@ -423,7 +426,7 @@ int db_sqlite3_insert_id(void) { -char *db_sqlite3_initial = +char *db_sqlite3_initial1 = "create table songs (\n" " id INTEGER PRIMARY KEY NOT NULL,\n" " path VARCHAR(4096) UNIQUE NOT NULL,\n" @@ -463,18 +466,23 @@ char *db_sqlite3_initial = " sample_count INTEGER DEFAULT 0,\n" " force_update INTEGER DEFAULT 0,\n" " codectype VARCHAR(5) DEFAULT NULL,\n" -" idx INTEGER NOT NULL\n" -");\n" -"create table config (\n" -" term VARCHAR(255) NOT NULL,\n" -" subterm VARCHAR(255) DEFAULT NULL,\n" -" value VARCHAR(1024) NOT NULL\n" +" idx INTEGER NOT NULL,\n" +" has_video INTEGER DEFAULT 0,\n" +" contentrating INTEGER DEFAULT 0\n" ");\n" "create table playlistitems (\n" " id INTEGER PRIMARY KEY NOT NULL,\n" " playlistid INTEGER NOT NULL,\n" " songid INTEGER NOT NULL\n" ");\n" +"create table config (\n" +" term VARCHAR(255) NOT NULL,\n" +" subterm VARCHAR(255) DEFAULT NULL,\n" +" value VARCHAR(1024) NOT NULL\n" +");\n" +"insert into config values ('version','','9');\n"; + +char *db_sqlite3_initial2 = "create table playlists (\n" " id INTEGER PRIMARY KEY NOT NULL,\n" " title VARCHAR(255) NOT NULL,\n" @@ -485,7 +493,6 @@ char *db_sqlite3_initial = " path VARCHAR(4096),\n" " idx INTEGER NOT NULL\n" ");\n" -"insert into config values ('version','','8');\n" "insert into playlists values (1,'Library',1,0,'1',0,'',0);\n"; diff --git a/src/db-sql.c b/src/db-sql.c index 77a32c1b..4183c563 100644 --- a/src/db-sql.c +++ b/src/db-sql.c @@ -623,7 +623,7 @@ int db_sql_add(char **pe, MP3FILE *pmp3, int *id) { pmp3->time_played=0; err=db_sql_exec_fn(pe,E_DBG,"INSERT INTO songs VALUES " - "(NULL," // id + "(NULL," // id "'%q'," // path "'%q'," // fname "'%q'," // title @@ -661,7 +661,9 @@ int db_sql_add(char **pe, MP3FILE *pmp3, int *id) { "%d," // sample_count "0," // force_update "'%q'," // codectype - "%d)", // index + "%d," // index + "%d," // has_video + "%d)", // contentrating STR(pmp3->path), STR(pmp3->fname), STR(pmp3->title), @@ -697,7 +699,9 @@ int db_sql_add(char **pe, MP3FILE *pmp3, int *id) { pmp3->disabled, pmp3->sample_count, STR(pmp3->codectype), - pmp3->index); + pmp3->index, + pmp3->has_video, + pmp3->contentrating); if(err != DB_E_SUCCESS) DPRINTF(E_FATAL,L_DB,"Error inserting file %s in database\n",pmp3->fname); @@ -731,6 +735,7 @@ int db_sql_update(char **pe, MP3FILE *pmp3, int *id) { pmp3->db_timestamp = (int)time(NULL); + /* FIXME: this should update all fields */ err=db_sql_exec_fn(pe,E_LOG,"UPDATE songs SET " "title='%q'," // title "artist='%q'," // artist @@ -1327,6 +1332,14 @@ int db_sql_get_size(DBQUERYINFO *pinfo, SQL_ROW valarray) { if(ISSTR(valarray[37]) && db_wantsmeta(pinfo->meta, metaSongCodecType)) /* ascd */ size += 12; + + if(db_wantsmeta(pinfo->meta,metaSongContentRating)) + /* ascr */ + size += 9; + if(db_wantsmeta(pinfo->meta,metaItunesHasVideo)) + /* aeHV */ + size += 9; + return size; break; @@ -1460,6 +1473,10 @@ int db_sql_build_dmap(DBQUERYINFO *pinfo, char **valarray, unsigned char *presul current += db_dmap_add_literal(current,"ascd",valarray[37],4); if(db_wantsmeta(pinfo->meta, metaContainerItemId)) current += db_dmap_add_int(current,"mcti",atoi(valarray[0])); + if(db_wantsmeta(pinfo->meta, metaItunesHasVideo)) + current += db_dmap_add_char(current,"aeHV",atoi(valarray[39])); + if(db_wantsmeta(pinfo->meta, metaSongContentRating)) + current += db_dmap_add_char(current,"ascr",atoi(valarray[40])); return 0; break; @@ -1532,6 +1549,8 @@ void db_sql_build_mp3file(SQL_ROW valarray, MP3FILE *pmp3) { pmp3->force_update=db_sql_atoi(valarray[36]); pmp3->codectype=db_sql_strdup(valarray[37]); pmp3->index=db_sql_atoi(valarray[38]); + pmp3->has_video=db_sql_atoi(valarray[39]); + pmp3->contentrating=db_sql_atoi(valarray[40]); } /** diff --git a/src/mp3-scanner.c b/src/mp3-scanner.c index b97a5d6e..5452eb0f 100644 --- a/src/mp3-scanner.c +++ b/src/mp3-scanner.c @@ -99,6 +99,7 @@ extern int scan_get_aacinfo(char *filename, MP3FILE *pmp3); extern int scan_get_wavinfo(char *filename, MP3FILE *pmp3); extern int scan_get_urlinfo(char *filename, MP3FILE *pmp3); extern int scan_get_mp3info(char *filename, MP3FILE *pmp3); +extern int scan_get_mp4info(char *filename, MP3FILE *pmp3); /* playlist scanners */ extern int scan_xml_playlist(char *filename); @@ -135,6 +136,7 @@ static TAGHANDLER taghandlers[] = { { "wma", scan_get_wmainfo, "wma", "wma", "WMA audio file" }, { "url", scan_get_urlinfo, "pls", NULL, "Playlist URL" }, { "pls", scan_get_urlinfo, "pls", NULL, "Playlist URL" }, + { "m4v", scan_get_mp4info, "m4v", "mp4v", "MPEG-4 video file" }, #ifdef OGGVORBIS { "ogg", scan_get_ogginfo, "ogg", "ogg", "Ogg Vorbis audio file" }, #endif diff --git a/src/mp3-scanner.h b/src/mp3-scanner.h index e29faeec..454bb7c3 100644 --- a/src/mp3-scanner.h +++ b/src/mp3-scanner.h @@ -71,6 +71,12 @@ typedef struct tag_mp3file { int force_update; int sample_count; char compilation; + + /* iTunes 5+ */ + int contentrating; + + /* iTunes 6.0.2 */ + int has_video; } MP3FILE; typedef struct tag_m3ufile { diff --git a/src/scan-aac.c b/src/scan-aac.c index 49961679..463bd8a9 100644 --- a/src/scan-aac.c +++ b/src/scan-aac.c @@ -33,7 +33,7 @@ #include "scan-aac.h" /* Forwards */ -static time_t scan_aac_mac_to_unix_time(int t); +time_t scan_aac_mac_to_unix_time(int t); /** * Convert mac time to unix time (different epochs) diff --git a/src/scan-mp4.c b/src/scan-mp4.c new file mode 100644 index 00000000..d95ef326 --- /dev/null +++ b/src/scan-mp4.c @@ -0,0 +1,258 @@ +/* + * $Id$ + * + * Copyright (C) 2003 Ron Pedde (ron@pedde.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "err.h" +#include "mp3-scanner.h" +#include "scan-aac.h" + +/* Forwards */ +extern time_t scan_aac_mac_to_unix_time(int t); + + +/* FIXME: This is really just a copy of scan-aac.c + * there should really be some mpeg4-specific stuff in here, + * but this seems to do a fair job. Should check it against + * .mov files. + */ + +/** + * main mp4 scanning routing. + * + * @param filename file to scan + * @param pmp3 pointer to the MP3FILE to fill with data + * @returns FALSE if file should not be added to database, TRUE otherwise + */ +int scan_get_mp4info(char *filename, MP3FILE *pmp3) { + FILE *fin; + long atom_offset; + unsigned int atom_length; + + long current_offset=0; + int current_size; + char current_atom[4]; + char *current_data; + unsigned short us_data; + int genre; + int len; + + int sample_size; + int samples; + unsigned int bit_rate; + int ms; + unsigned char buffer[2]; + int time = 0; + + + if(!(fin=fopen(filename,"rb"))) { + DPRINTF(E_INF,L_SCAN,"Cannot open file %s for reading\n",filename); + return FALSE; + } + + fseek(fin,0,SEEK_END); + pmp3->file_size = ftell(fin); + fseek(fin,0,SEEK_SET); + + + atom_offset=scan_aac_drilltoatom(fin, "moov:udta:meta: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 <= 7) /* something not right */ + break; + + if(fread(current_atom,1,4,fin) != 4) + break; + + len=current_size-7; /* for ill-formed too-short tags */ + if(len < 22) + len=22; + + current_data=(char*)malloc(len); /* extra byte */ + memset(current_data,0x00,len); + + 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" "cmt",4)) { + pmp3->comment=strdup((char*)¤t_data[16]); + } else if(!memcmp(current_atom,"\xA9" "wrt",4)) { + pmp3->composer=strdup((char*)¤t_data[16]); + } else if(!memcmp(current_atom,"\xA9" "grp",4)) { + pmp3->grouping=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,"tmpo",4)) { + us_data=*((unsigned short *)¤t_data[16]); + us_data=ntohs(us_data); + pmp3->bpm=us_data; + } else if(!memcmp(current_atom,"trkn",4)) { + us_data=*((unsigned short *)¤t_data[18]); + us_data=ntohs(us_data); + + pmp3->track=us_data; + + us_data=*((unsigned short *)¤t_data[20]); + us_data=ntohs(us_data); + + pmp3->total_tracks=us_data; + } else if(!memcmp(current_atom,"disk",4)) { + us_data=*((unsigned short *)¤t_data[18]); + us_data=ntohs(us_data); + + pmp3->disc=us_data; + + us_data=*((unsigned short *)¤t_data[20]); + us_data=ntohs(us_data); + + pmp3->total_discs=us_data; + } else if(!memcmp(current_atom,"\xA9" "day",4)) { + pmp3->year=atoi((char*)¤t_data[16]); + } else if(!memcmp(current_atom,"gnre",4)) { + genre=(int)(*((char*)¤t_data[17])); + genre--; + + if((genre < 0) || (genre > WINAMP_GENRE_UNKNOWN)) + genre=WINAMP_GENRE_UNKNOWN; + + pmp3->genre=strdup(scan_winamp_genre[genre]); + } else if (!memcmp(current_atom, "cpil", 4)) { + pmp3->compilation = current_data[16]; + } + + free(current_data); + current_offset+=current_size; + } + } + + /* got the tag info, now let's get bitrate, etc */ + atom_offset = scan_aac_drilltoatom(fin, "moov:mvhd", &atom_length); + if(atom_offset != -1) { + fseek(fin, 4, SEEK_CUR); + fread((void *)&time, sizeof(int), 1, fin); + time = ntohl(time); + pmp3->time_added = scan_aac_mac_to_unix_time(time); + + fread((void *)&time, sizeof(int), 1, fin); + time = ntohl(time); + pmp3->time_modified = scan_aac_mac_to_unix_time(time); + fread((void*)&sample_size,1,sizeof(int),fin); + fread((void*)&samples,1,sizeof(int),fin); + + sample_size=ntohl(sample_size); + samples=ntohl(samples); + + /* avoid overflowing on large sample_sizes (90000) */ + ms=1000; + while((ms > 9) && (!(sample_size % 10))) { + sample_size /= 10; + ms /= 10; + } + + /* DWB: use ms time instead of sec */ + pmp3->song_length=(int)((samples * ms) / sample_size); + DPRINTF(E_DBG,L_SCAN,"Song length: %d seconds\n", + pmp3->song_length / 1000); + } + + pmp3->bitrate = 0; + + /* Get the sample rate from the 'mp4a' atom (timescale). This is also + found in the 'mdhd' atom which is a bit closer but we need to + navigate to the 'mp4a' atom anyways to get to the 'esds' atom. */ + atom_offset=scan_aac_drilltoatom(fin, + "moov:trak:mdia:minf:stbl:stsd:mp4a", + &atom_length); + if (atom_offset != -1) { + fseek(fin, atom_offset + 32, SEEK_SET); + + /* Timescale here seems to be 2 bytes here (the 2 bytes before it are + * "reserved") though the timescale in the 'mdhd' atom is 4. Not sure + * how this is dealt with when sample rate goes higher than 64K. */ + fread(buffer, sizeof(unsigned char), 2, fin); + + pmp3->samplerate = (buffer[0] << 8) | (buffer[1]); + + /* Seek to end of atom. */ + fseek(fin, 2, SEEK_CUR); + + /* Get the bit rate from the 'esds' atom. We are already positioned + in the parent atom so just scan ahead. */ + atom_offset = scan_aac_findatom(fin, + atom_length-(ftell(fin)-atom_offset), + "esds", &atom_length); + + if (atom_offset != -1) { + /* Roku Soundbridge seems to believe anything above 320K is + * an ALAC encoded m4a. We'll lie on their behalf. + */ + fseek(fin, atom_offset + 22, SEEK_CUR); + fread((void *)&bit_rate, sizeof(unsigned int), 1, fin); + pmp3->bitrate = ntohl(bit_rate) / 1000; + DPRINTF(E_DBG,L_SCAN,"esds bitrate: %d\n",pmp3->bitrate); + + if(pmp3->bitrate > 320) { + pmp3->bitrate = 320; + } + } else { + DPRINTF(E_DBG,L_SCAN, "Couldn't find 'esds' atom for bit rate.\n"); + } + } else { + DPRINTF(E_DBG,L_SCAN, "Couldn't find 'mp4a' atom for sample rate.\n"); + } + + /* Fallback if we can't find the info in the atoms. */ + if (pmp3->bitrate == 0) { + /* calculate bitrate from song length... Kinda cheesy */ + DPRINTF(E_DBG,L_SCAN, "Guesstimating bit rate.\n"); + atom_offset=scan_aac_drilltoatom(fin,"mdat",&atom_length); + if ((atom_offset != -1) && (pmp3->song_length)) { + pmp3->bitrate = atom_length / ((pmp3->song_length / 1000) * 128); + } + } + + fclose(fin); + + pmp3->has_video=1; + + return TRUE; /* we'll return as much as we got. */ +}