From 4966f4213e530d6cf47012766360262e17dc69d6 Mon Sep 17 00:00:00 2001 From: Ron Pedde Date: Sun, 16 Sep 2007 02:03:25 +0000 Subject: [PATCH] Fold the mp4 scanner into the aac scanner, fix the playlist issue, and the aac metadata parsing issue --- src/Makefile.am | 2 +- src/io.c | 15 ++- src/mp3-scanner.c | 71 ++++++---- src/os-unix.c | 2 +- src/scan-aac.c | 128 +++++++++++++----- src/scan-mp4.c | 332 ---------------------------------------------- 6 files changed, 149 insertions(+), 401 deletions(-) delete mode 100644 src/scan-mp4.c diff --git a/src/Makefile.am b/src/Makefile.am index d84d3ca0..cf980f87 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -65,7 +65,7 @@ mt_daapd_SOURCES = main.c daapd.h rend.h webserver.c \ webserver.h configfile.c configfile.h err.c err.h restart.c restart.h \ mp3-scanner.h mp3-scanner.c rend-unix.h \ db-generic.c db-generic.h ff-plugins.c ff-plugins.h \ - rxml.c rxml.h redblack.c redblack.h scan-mp3.c scan-mp4.c scan-aif.c \ + rxml.c rxml.h redblack.c redblack.h scan-mp3.c scan-aif.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 \ os.h ll.c ll.h conf.c conf.h compat.c compat.h util.c util.h \ diff --git a/src/io.c b/src/io.c index e7725672..f9531e90 100644 --- a/src/io.c +++ b/src/io.c @@ -916,17 +916,22 @@ int io_readline_timeout(IO_PRIVHANDLE *phandle, unsigned char *buf, return TRUE; } if((!ascii) || (to_read != '\r')) { - numread += to_read; - if(buf[numread-1] == '\n') { - buf[numread] = '\0'; /* retain the CR */ - *len = numread+1; + if(buf[numread] == '\n') { + buf[numread+1] = '\0'; /* retain the CR */ + *len = numread + 1; return TRUE; } + numread++; } + } else { } } - return FALSE; + buf[numread-1] = '\0'; + *len = numread-1; + + io_err_printf(IO_LOG_LOG,"Buffer too small in io_readline_timeout()\n"); + return TRUE; } /** diff --git a/src/mp3-scanner.c b/src/mp3-scanner.c index 3e34e07c..fecd8660 100644 --- a/src/mp3-scanner.c +++ b/src/mp3-scanner.c @@ -64,6 +64,7 @@ typedef struct { int (*scanner)(char* file, MP3FILE* pmp3); char *type; /* daap.songformat */ char *codectype; /* song.codectype */ + int has_video; /* hack hack hack */ char *description; /* daap.songdescription */ } TAGHANDLER; @@ -107,7 +108,6 @@ 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); extern int scan_get_aifinfo(char *filename, MP3FILE *pmp3); /* playlist scanners */ @@ -136,31 +136,33 @@ static int scan_static_playlist(char *path); * This system is broken, and won't work with something like a .cue file */ static TAGHANDLER taghandlers[] = { - { "aac", scan_get_aacinfo, "m4a", "mp4a", "AAC audio file" }, - { "mp4", scan_get_aacinfo, "m4a", "mp4a", "AAC audio file" }, - { "m4b", scan_get_aacinfo, "m4a", "mp4a", "Protected AAC audio file" }, - { "m4a", scan_get_aacinfo, "m4a", "mp4a", "AAC audio file" }, - { "m4p", scan_get_aacinfo, "m4p", "mp4a", "AAC audio file" }, - { "mp3", scan_get_mp3info, "mp3", "mpeg", "MPEG audio file" }, - { "wav", scan_get_wavinfo, "wav", "wav", "WAV audio file" }, - { "aif", scan_get_aifinfo, "aif", "aif", "AIFF audio file" }, - { "aiff",scan_get_aifinfo, "aif", "aif", "AIFF audio file" }, - { "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" }, - { "mp4", scan_get_mp4info, "m4v", "mp4v", "MPEG-4 video file" }, + { "aac", scan_get_aacinfo, "m4a", "mp4a", 0, "AAC audio file" }, + { "mp4", scan_get_aacinfo, "m4a", "mp4a", 0, "AAC audio file" }, + { "m4b", scan_get_aacinfo, "m4a", "mp4a", 0, "Protected AAC audio file" }, + { "m4a", scan_get_aacinfo, "m4a", "mp4a", 0, "AAC audio file" }, + { "m4p", scan_get_aacinfo, "m4p", "mp4a", 0, "AAC audio file" }, + { "mp3", scan_get_mp3info, "mp3", "mpeg", 0, "MPEG audio file" }, + { "wav", scan_get_wavinfo, "wav", "wav", 0, "WAV audio file" }, + { "aif", scan_get_aifinfo, "aif", "aif", 0, "AIFF audio file" }, + { "aiff",scan_get_aifinfo, "aif", "aif", 0, "AIFF audio file" }, + { "wma", scan_get_wmainfo, "wma", "wma", 0, "WMA audio file" }, + { "url", scan_get_urlinfo, "pls", NULL, 0, "Playlist URL" }, + { "pls", scan_get_urlinfo, "pls", NULL, 0, "Playlist URL" }, + { "m4v", scan_get_aacinfo, "m4v", "mp4v", 1, "MPEG-4 video file" }, + { "mp4", scan_get_aacinfo, "m4v", "mp4v", 1, "MPEG-4 video file" }, + { "mov", scan_get_aacinfo, "m4v", "mp4v", 1, "MPEG-4 video file" }, + { "mpeg4", scan_get_aacinfo, "m4v", "mp4v", 1, "MPEG-4 video file" }, #ifdef OGGVORBIS - { "ogg", scan_get_ogginfo, "ogg", "ogg", "Ogg Vorbis audio file" }, + { "ogg", scan_get_ogginfo, "ogg", "ogg", 0, "Ogg Vorbis audio file" }, #endif #ifdef FLAC - { "flac", scan_get_flacinfo, "flac","flac", "FLAC audio file" }, - { "fla", scan_get_flacinfo, "flac","flac", "FLAC audio file" }, + { "flac", scan_get_flacinfo, "flac","flac", 0, "FLAC audio file" }, + { "fla", scan_get_flacinfo, "flac","flac", 0, "FLAC audio file" }, #endif #ifdef MUSEPACK - { "mpc", scan_get_mpcinfo, "mpc", "mpc", "Musepack audio file" }, - { "mpp", scan_get_mpcinfo, "mpc", "mpc", "Musepack audio file" }, - { "mp+", scan_get_mpcinfo, "mpc", "mpc", "Musepack audio file" }, + { "mpc", scan_get_mpcinfo, "mpc", "mpc", 0, "Musepack audio file" }, + { "mpp", scan_get_mpcinfo, "mpc", "mpc", 0, "Musepack audio file" }, + { "mp+", scan_get_mpcinfo, "mpc", "mpc", 0, "Musepack audio file" }, #endif { NULL, NULL, NULL, NULL, NULL } }; @@ -512,8 +514,6 @@ int scan_static_playlist(char *path) { continue; } - // FIXME - should chomp trailing comments - ptr = linebuffer; while(*ptr) { if((*ptr == '/') || (*ptr == '\\')) @@ -522,6 +522,7 @@ int scan_static_playlist(char *path) { } // otherwise, assume it is a path + // FIXME: Fixups for an absolute path without a drive letter if((linebuffer[0] == PATHSEP) || (linebuffer[1] == ':')) { strcpy(file_path,linebuffer); } else { @@ -544,8 +545,12 @@ int scan_static_playlist(char *path) { free(perr); } - len = strlen(linebuffer); + len = sizeof(linebuffer); } + if(!len) + DPRINTF(L_SCAN,E_LOG,"Error reading playlist: %s\n",io_errstr(hfile)); + else + DPRINTF(L_SCAN,E_LOG,"Finished processing playlist. Len: %d\n",len); io_close(hfile); } @@ -762,18 +767,30 @@ int scan_freetags(MP3FILE *pmp3) { /** - * Dispatch to actual file info handlers + * Dispatch to actual file info handlers. In addition (and this + * is kinda hackish, it pokes has_video into the file if it's marked + * as having video in the taghandler. This should really be done in + * the metainfo parser, but it's easier to hack m4v up here and leverage + * the existing aac parser than add video handling to the parser. + * anyone know an easy way to tell if a mpeg4 file has a video stream + * or not? * * @param file file to read file metainfo for * @param pmp3 struct to stuff with info gleaned */ int scan_get_info(char *file, MP3FILE *pmp3) { TAGHANDLER *hdl; + int retval; /* dispatch to appropriate tag handler */ hdl = scan_gethandler(pmp3->type); - if(hdl && hdl->scanner) - return hdl->scanner(file,pmp3); + if(hdl && hdl->scanner) { + retval = hdl->scanner(file,pmp3); + if(retval && hdl->has_video) { + pmp3->has_video = 1; + } + return retval; + } return TRUE; } diff --git a/src/os-unix.c b/src/os-unix.c index 48cedaad..4b957b76 100644 --- a/src/os-unix.c +++ b/src/os-unix.c @@ -470,7 +470,7 @@ void *os_loadlib(char **pe, char *path) { void *os_libfunc(char **pe, void *handle, char *function) { void *retval; - if(!(retval = dlsym(handle,function))) + if((!(retval = dlsym(handle,function))) && (pe)) *pe = strdup(dlerror()); return retval; diff --git a/src/scan-aac.c b/src/scan-aac.c index fa9b71bb..010e9ba3 100644 --- a/src/scan-aac.c +++ b/src/scan-aac.c @@ -79,7 +79,9 @@ uint64_t scan_aac_drilltoatom(IOHANDLE hfile,char *atom_path, DPRINTF(E_SPAM,L_SCAN,"Searching for %s\n",atom_path); + // FIXME: cache io_size for static files io_size(hfile, &file_size); + io_setpos(hfile,0,SEEK_SET); end_p = atom_path; while (*end_p != '\0') { @@ -98,7 +100,7 @@ uint64_t scan_aac_drilltoatom(IOHANDLE hfile,char *atom_path, if (atom_offset == -1) { return -1; } - + io_getpos(hfile,&pos); DPRINTF(E_SPAM,L_SCAN,"Found %s atom at off %lld.\n", atom_name, pos - 8); @@ -137,25 +139,32 @@ uint64_t scan_aac_drilltoatom(IOHANDLE hfile,char *atom_path, * @param atom_size this will hold the size of the atom found */ uint64_t scan_aac_findatom(IOHANDLE hfile, uint64_t max_offset, - char *which_atom, unsigned int *atom_size) { + char *which_atom, unsigned int *atom_size) { uint64_t current_offset=0; - int size; + uint32_t size; char atom[4]; uint32_t bytes_read; while(current_offset < max_offset) { - bytes_read = sizeof(int); - if(!io_read(hfile,(unsigned char *)&size,&bytes_read) || (!bytes_read)) + bytes_read = sizeof(uint32_t); + if(!io_read(hfile,(unsigned char *)&size,&bytes_read) || (!bytes_read)) { + DPRINTF(E_LOG,L_SCAN,"Error parsing file: %s\n",io_errstr(hfile)); return -1; - + } + size=ntohl(size); - if(size <= 7) /* something not right */ + if(size <= 7) { /* something not right */ + DPRINTF(E_LOG,L_SCAN,"Bad aac file: atom length too short searching for %s\n", + which_atom); return -1; + } bytes_read = 4; - if(!io_read(hfile,(unsigned char *)atom,&bytes_read) || (!bytes_read)) + if(!io_read(hfile,(unsigned char *)atom,&bytes_read) || (!bytes_read)) { + DPRINTF(E_LOG,L_SCAN,"Error parsing file: %s\n",io_errstr(hfile)); return -1; + } if(strncasecmp(atom,which_atom,4) == 0) { *atom_size=size; @@ -166,6 +175,7 @@ uint64_t scan_aac_findatom(IOHANDLE hfile, uint64_t max_offset, current_offset+=size; } + DPRINTF(E_SPAM,L_SCAN,"Couldn't find atom %s as requested\n",which_atom); return -1; } @@ -183,19 +193,19 @@ int scan_get_aacinfo(char *filename, MP3FILE *pmp3) { unsigned int atom_length; long current_offset=0; - int current_size; + uint32_t 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; + uint32_t sample_size; + uint32_t samples; + uint32_t bit_rate; int ms; unsigned char buffer[2]; - int time = 0; + uint32_t time = 0; hfile = io_new(); @@ -213,20 +223,30 @@ int scan_get_aacinfo(char *filename, MP3FILE *pmp3) { if(atom_offset != -1) { /* found the tag section - need to walk through now */ while(current_offset < (uint64_t)atom_length) { - bytes_read = sizeof(int); - if(!io_read(hfile,(unsigned char *)¤t_size,&bytes_read) || !bytes_read) - break; + bytes_read = sizeof(uint32_t); + if(!io_read(hfile,(unsigned char *)¤t_size,&bytes_read) || !bytes_read) { + DPRINTF(E_LOG,L_SCAN,"Error reading mp4 atoms: %s\n",io_errstr(hfile)); + io_dispose(hfile); + return FALSE; + } current_size=ntohl(current_size); DPRINTF(E_SPAM,L_SCAN,"Current size: %d\n",current_size); - if(current_size <= 7) /* something not right */ - break; + if(current_size <= 7) { /* something not right */ + DPRINTF(E_LOG,L_SCAN,"mp4 atom too small. Bad aac tags?\n"); + io_dispose(hfile); + return FALSE; + } + bytes_read = 4; - if(!io_read(hfile,(unsigned char *)current_atom,&bytes_read) || !bytes_read) - break; + if(!io_read(hfile,(unsigned char *)current_atom,&bytes_read) || !bytes_read) { + DPRINTF(E_LOG,L_SCAN,"Error reading mp4 atoms: %s\n",io_errstr(hfile)); + io_dispose(hfile); + return FALSE; + } DPRINTF(E_SPAM,L_SCAN,"Current Atom: %c%c%c%c\n", current_atom[0],current_atom[1],current_atom[2], @@ -235,17 +255,23 @@ int scan_get_aacinfo(char *filename, MP3FILE *pmp3) { if(current_size > 4096) { /* Does this break anything? */ /* too big! cover art, maybe? */ io_setpos(hfile,current_size - 8, SEEK_CUR); + DPRINTF(E_SPAM,L_SCAN,"Atom too big... skipping\n"); } else { len=current_size-7; /* for ill-formed too-short tags */ - if(len < 22) + if(len < 22) { len=22; + } current_data=(char*)malloc(len); /* extra byte */ memset(current_data,0x00,len); bytes_read = current_size - 8; - if(!io_read(hfile,(unsigned char *)current_data,&bytes_read) || (!bytes_read)) - break; + if(!io_read(hfile,(unsigned char *)current_data,&bytes_read) || (!bytes_read)) { + DPRINTF(E_LOG,L_SCAN,"Error reading mp4 data: %s\n",io_errstr(hfile)); + free(current_data); + io_dispose(hfile); + return FALSE; + } if(!memcmp(current_atom,"\xA9" "nam",4)) { /* Song name */ pmp3->title=strdup((char*)¤t_data[16]); @@ -303,8 +329,8 @@ int scan_get_aacinfo(char *filename, MP3FILE *pmp3) { } free(current_data); - current_offset+=current_size; } + current_offset+=current_size; } } @@ -314,21 +340,43 @@ int scan_get_aacinfo(char *filename, MP3FILE *pmp3) { io_setpos(hfile,4,SEEK_CUR); /* FIXME: error handling */ - bytes_read = sizeof(int); - io_read(hfile,(unsigned char *)&time, &bytes_read); + bytes_read = sizeof(uint32_t); + if(!io_read(hfile,(unsigned char *)&time, &bytes_read)) { + DPRINTF(E_LOG,L_SCAN,"Error reading time from moov:mvhd: %s\n", + io_errstr(hfile)); + io_dispose(hfile); + return FALSE; + } time = ntohl(time); pmp3->time_added = (int)scan_aac_mac_to_unix_time(time); - bytes_read = sizeof(int); - io_read(hfile,(unsigned char *)&time, &bytes_read); + bytes_read = sizeof(uint32_t); + if(!io_read(hfile,(unsigned char *)&time, &bytes_read)) { + DPRINTF(E_LOG,L_SCAN,"Error reading time from moov:mvhd: %s\n", + io_errstr(hfile)); + io_dispose(hfile); + return FALSE; + } + time = ntohl(time); pmp3->time_modified = (int)scan_aac_mac_to_unix_time(time); - bytes_read = sizeof(int); - io_read(hfile,(unsigned char *)&sample_size,&bytes_read); - bytes_read = sizeof(int); - io_read(hfile,(unsigned char*)&samples, &bytes_read); + bytes_read = sizeof(uint32_t); + if(!io_read(hfile,(unsigned char *)&sample_size,&bytes_read)) { + DPRINTF(E_LOG,L_SCAN,"Error reading sample_size from moov:mvhd: %s\n", + io_errstr(hfile)); + io_dispose(hfile); + return FALSE; + } + + bytes_read = sizeof(uint32_t); + if(!io_read(hfile,(unsigned char*)&samples, &bytes_read)) { + DPRINTF(E_LOG,L_SCAN,"Error reading samples from moov:mvhd: %s\n", + io_errstr(hfile)); + io_dispose(hfile); + return FALSE; + } sample_size=ntohl(sample_size); samples=ntohl(samples); @@ -341,7 +389,7 @@ int scan_get_aacinfo(char *filename, MP3FILE *pmp3) { } /* DWB: use ms time instead of sec */ - pmp3->song_length=(int)((samples * ms) / sample_size); + pmp3->song_length=(uint32_t)((samples * ms) / sample_size); DPRINTF(E_DBG,L_SCAN,"Song length: %d seconds\n", pmp3->song_length / 1000); } @@ -380,7 +428,12 @@ int scan_get_aacinfo(char *filename, MP3FILE *pmp3) { * "reserved") though the timescale in the 'mdhd' atom is 4. Not sure * how this is dealt with when sample rate goes higher than 64K. */ bytes_read = 2; - io_read(hfile, (unsigned char *)buffer, &bytes_read); + if(!io_read(hfile, (unsigned char *)buffer, &bytes_read)) { + DPRINTF(E_LOG,L_SCAN,"Error reading timescale from drms atom: %s\n", + io_errstr(hfile)); + io_dispose(hfile); + return FALSE; + } pmp3->samplerate = (buffer[0] << 8) | (buffer[1]); @@ -401,7 +454,12 @@ int scan_get_aacinfo(char *filename, MP3FILE *pmp3) { io_setpos(hfile, atom_offset + 22, SEEK_CUR); bytes_read = sizeof(unsigned int); - io_read(hfile, (unsigned char *)&bit_rate, &bytes_read); + if(!io_read(hfile, (unsigned char *)&bit_rate, &bytes_read)) { + DPRINTF(E_LOG,L_SCAN,"Error reading bitrate from esds: %s\n", + io_errstr(hfile)); + io_dispose(hfile); + return FALSE; + } pmp3->bitrate = ntohl(bit_rate) / 1000; DPRINTF(E_DBG,L_SCAN,"esds bitrate: %d\n",pmp3->bitrate); diff --git a/src/scan-mp4.c b/src/scan-mp4.c deleted file mode 100644 index cf78b104..00000000 --- a/src/scan-mp4.c +++ /dev/null @@ -1,332 +0,0 @@ -/* - * $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 -#ifdef HAVE_SYS_TIME_H -#include -#endif - -#ifndef WIN32 -#include -#endif - -#include "daapd.h" -#include "err.h" -#include "io.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) { - IOHANDLE hfile; - uint64_t atom_offset; - unsigned int atom_length; - - uint64_t current_offset=0; - uint64_t file_pos; - uint32_t read_size; - - uint32_t 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(!(hfile = io_new())) { - DPRINTF(E_LOG,L_SCAN,"Cannot create file handle\n"); - return FALSE; - } - - if(!io_open(hfile,"file://%U",filename)) { - DPRINTF(E_INF,L_SCAN,"Cannot open file %s for reading: %s\n", - filename,io_errstr(hfile)); - io_dispose(hfile); - return FALSE; - } - - atom_offset=scan_aac_drilltoatom(hfile, "moov:udta:meta:ilst", &atom_length); - if(atom_offset != -1) { - /* found the tag section - need to walk through now */ - - while(current_offset < (long) atom_length) { - read_size = sizeof(uint32_t); - if(!io_read(hfile,(unsigned char *)¤t_size,&read_size) || (read_size != sizeof(uint32_t))) { - io_close(hfile); - io_dispose(hfile); - return FALSE; - } - - DPRINTF(E_SPAM,L_SCAN,"Current size: %d\n",current_size); - - current_size=ntohl(current_size); - - if(current_size <= 7) /* something not right */ - break; - - read_size = 4; - if(!io_read(hfile,(unsigned char *)¤t_atom,&read_size) || (read_size != 4)) { - io_close(hfile); - io_dispose(hfile); - return FALSE; - } - - DPRINTF(E_SPAM,L_SCAN,"Current Atom: %c%c%c%c\n", - current_atom[0],current_atom[1],current_atom[2], - current_atom[3]); - - if(current_size > 4096) { /* Does this break anything? */ - /* too big! cover art, maybe? */ - io_setpos(hfile, current_size - 8, SEEK_CUR); - } else { - 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); - - read_size = current_size - 8; - if(!io_read(hfile,(unsigned char *)current_data,&read_size) || (current_size != 8)) { - io_close(hfile); - io_dispose(hfile); - return FALSE; - } - - 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(hfile, "moov:mvhd", &atom_length); - if(atom_offset != -1) { - io_setpos(hfile,4,SEEK_CUR); - - read_size = sizeof(int); - if(!io_read(hfile,(unsigned char *)&time, &read_size) || (read_size != sizeof(int))) { - io_dispose(hfile); - return FALSE; - } - - time = ntohl(time); - pmp3->time_added = (int) scan_aac_mac_to_unix_time(time); - - read_size = sizeof(int); - if(!io_read(hfile,(unsigned char *)&time, &read_size) || (read_size != sizeof(int))) { - io_dispose(hfile); - return FALSE; - } - - time = ntohl(time); - pmp3->time_modified = (int) scan_aac_mac_to_unix_time(time); - - read_size = sizeof(int); - if(!io_read(hfile,(unsigned char *)&sample_size, &read_size) || (read_size != sizeof(int))) { - io_dispose(hfile); - return FALSE; - } - - read_size = sizeof(int); - if(!io_read(hfile,(unsigned char *)&samples, &read_size) || (read_size != sizeof(int))) { - io_dispose(hfile); - return FALSE; - } - - 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(hfile, - "moov:trak:mdia:minf:stbl:stsd:mp4a", - &atom_length); - if(atom_offset == -1) { - atom_offset=scan_aac_drilltoatom(hfile, - "moov:trak:mdia:minf:stbl:stsd:drms", - &atom_length); - } - - if (atom_offset != -1) { - io_setpos(hfile, 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. */ - read_size = 2; - if(!io_read(hfile,(unsigned char *)&buffer,&read_size) || (read_size != 2)) { - io_dispose(hfile); - return FALSE; - } - - pmp3->samplerate = (buffer[0] << 8) | (buffer[1]); - - /* Seek to end of atom. */ - io_setpos(hfile,2,SEEK_CUR); - - /* Get the bit rate from the 'esds' atom. We are already positioned - in the parent atom so just scan ahead. */ - io_getpos(hfile,&file_pos); - atom_offset = scan_aac_findatom(hfile, - atom_length-(file_pos-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. - */ - io_setpos(hfile, atom_offset + 22, SEEK_CUR); - - read_size = sizeof(unsigned int); - if(!io_read(hfile,(unsigned char *)&bit_rate, &read_size) || (read_size != sizeof(unsigned int))) { - io_dispose(hfile); - return FALSE; - } - - 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(hfile,"mdat",&atom_length); - if ((atom_offset != -1) && (pmp3->song_length > 1000)) { - pmp3->bitrate = atom_length / ((pmp3->song_length / 1000) * 128); - } - } - - io_dispose(hfile); - - pmp3->has_video=1; - - return TRUE; /* we'll return as much as we got. */ -}