mirror of
https://github.com/owntone/owntone-server.git
synced 2025-02-24 11:59:16 -05:00
Add video support for m4v files
This commit is contained in:
parent
7b6560c651
commit
8dfea7dee3
@ -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 \
|
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 \
|
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 \
|
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 \
|
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 \
|
smart-parser.c smart-parser.h xml-rpc.c xml-rpc.h \
|
||||||
$(PRENDSRC) $(ORENDSRC) $(HRENDSRC) $(OGGVORBISSRC) $(FLACSRC) \
|
$(PRENDSRC) $(ORENDSRC) $(HRENDSRC) $(OGGVORBISSRC) $(FLACSRC) \
|
||||||
|
@ -214,6 +214,7 @@ DAAP_ITEMS taglist[] = {
|
|||||||
{ 0x0C, "arif", "daap.resolveinfo" },
|
{ 0x0C, "arif", "daap.resolveinfo" },
|
||||||
{ 0x05, "aeNV", "com.apple.itunes.norm-volume" },
|
{ 0x05, "aeNV", "com.apple.itunes.norm-volume" },
|
||||||
{ 0x01, "aeSP", "com.apple.itunes.smart-playlist" },
|
{ 0x01, "aeSP", "com.apple.itunes.smart-playlist" },
|
||||||
|
|
||||||
/* iTunes 4.5+ */
|
/* iTunes 4.5+ */
|
||||||
{ 0x01, "msas", "dmap.authenticationschemes" },
|
{ 0x01, "msas", "dmap.authenticationschemes" },
|
||||||
{ 0x05, "ascd", "daap.songcodectype" },
|
{ 0x05, "ascd", "daap.songcodectype" },
|
||||||
@ -227,6 +228,13 @@ DAAP_ITEMS taglist[] = {
|
|||||||
{ 0x05, "aeSI", "com.apple.iTunes.itms-songid" },
|
{ 0x05, "aeSI", "com.apple.iTunes.itms-songid" },
|
||||||
{ 0x05, "aeSF", "com.apple.iTunes.itms-storefrontid" },
|
{ 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 */
|
/* mt-daapd specific */
|
||||||
{ 0x09, "MSPS", "org.mt-daapd.smart-playlist-spec" },
|
{ 0x09, "MSPS", "org.mt-daapd.smart-playlist-spec" },
|
||||||
{ 0x01, "MPTY", "org.mt-daapd.playlist-type" },
|
{ 0x01, "MPTY", "org.mt-daapd.playlist-type" },
|
||||||
@ -235,6 +243,7 @@ DAAP_ITEMS taglist[] = {
|
|||||||
{ 0x0C, "MDPR", "org.mt-daapd.delplaylist" },
|
{ 0x0C, "MDPR", "org.mt-daapd.delplaylist" },
|
||||||
{ 0x0C, "MDPI", "org.mt-daapd.delplaylistitem" },
|
{ 0x0C, "MDPI", "org.mt-daapd.delplaylistitem" },
|
||||||
{ 0x0C, "MEPR", "org.mt-daapd.editplaylist" },
|
{ 0x0C, "MEPR", "org.mt-daapd.editplaylist" },
|
||||||
|
|
||||||
{ 0x00, NULL, NULL }
|
{ 0x00, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -276,6 +285,7 @@ static METAMAP db_metamap[] = {
|
|||||||
{ "daap.songtracknumber", metaSongTrackNumber },
|
{ "daap.songtracknumber", metaSongTrackNumber },
|
||||||
{ "daap.songuserrating", metaSongUserRating },
|
{ "daap.songuserrating", metaSongUserRating },
|
||||||
{ "daap.songyear", metaSongYear },
|
{ "daap.songyear", metaSongYear },
|
||||||
|
|
||||||
/* iTunes 4.5+ (forgot exactly when) */
|
/* iTunes 4.5+ (forgot exactly when) */
|
||||||
{ "daap.songcodectype", metaSongCodecType },
|
{ "daap.songcodectype", metaSongCodecType },
|
||||||
{ "daap.songcodecsubtype", metaSongCodecSubType },
|
{ "daap.songcodecsubtype", metaSongCodecSubType },
|
||||||
@ -287,9 +297,18 @@ static METAMAP db_metamap[] = {
|
|||||||
{ "com.apple.itunes.itms-genreid", metaItmsGenreId },
|
{ "com.apple.itunes.itms-genreid", metaItmsGenreId },
|
||||||
{ "com.apple.itunes.itms-storefrontid",metaItmsStorefrontId },
|
{ "com.apple.itunes.itms-storefrontid",metaItmsStorefrontId },
|
||||||
{ "com.apple.itunes.smart-playlist", metaItunesSmartPlaylist },
|
{ "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 */
|
/* mt-daapd specific */
|
||||||
{ "org.mt-daapd.smart-playlist-spec", metaMPlaylistSpec },
|
{ "org.mt-daapd.smart-playlist-spec", metaMPlaylistSpec },
|
||||||
{ "org.mt-daapd.playlist-type", metaMPlaylistType },
|
{ "org.mt-daapd.playlist-type", metaMPlaylistType },
|
||||||
|
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -78,6 +78,13 @@ typedef enum {
|
|||||||
metaItmsStorefrontId,
|
metaItmsStorefrontId,
|
||||||
metaItunesSmartPlaylist,
|
metaItunesSmartPlaylist,
|
||||||
|
|
||||||
|
/* iTunes 5.0 + */
|
||||||
|
metaSongContentRating,
|
||||||
|
metaHasChildContainers,
|
||||||
|
|
||||||
|
/* iTunes 6.0.2+ */
|
||||||
|
metaItunesHasVideo,
|
||||||
|
|
||||||
/* mt-daapd specific */
|
/* mt-daapd specific */
|
||||||
metaMPlaylistSpec,
|
metaMPlaylistSpec,
|
||||||
metaMPlaylistType
|
metaMPlaylistType
|
||||||
|
@ -64,13 +64,14 @@ static int db_sqlite2_in_enum=0;
|
|||||||
|
|
||||||
static char db_sqlite2_path[PATH_MAX + 1];
|
static char db_sqlite2_path[PATH_MAX + 1];
|
||||||
|
|
||||||
#define DB_SQLITE2_VERSION 8
|
#define DB_SQLITE2_VERSION 9
|
||||||
|
|
||||||
|
|
||||||
/* Forwards */
|
/* Forwards */
|
||||||
void db_sqlite2_lock(void);
|
void db_sqlite2_lock(void);
|
||||||
void db_sqlite2_unlock(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
|
* 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,"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;
|
db_sqlite2_reload=1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -381,6 +384,7 @@ int db_sqlite2_event(int event_type) {
|
|||||||
"id from playlists)");
|
"id from playlists)");
|
||||||
db_sqlite2_exec(NULL,E_FATAL,"drop table plupdated");
|
db_sqlite2_exec(NULL,E_FATAL,"drop table plupdated");
|
||||||
}
|
}
|
||||||
|
db_sqlite2_reload=0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -401,7 +405,7 @@ int db_sqlite2_insert_id(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char *db_sqlite2_initial =
|
char *db_sqlite2_initial1 =
|
||||||
"create table songs (\n"
|
"create table songs (\n"
|
||||||
" id INTEGER PRIMARY KEY NOT NULL,\n"
|
" id INTEGER PRIMARY KEY NOT NULL,\n"
|
||||||
" path VARCHAR(4096) UNIQUE NOT NULL,\n"
|
" path VARCHAR(4096) UNIQUE NOT NULL,\n"
|
||||||
@ -441,18 +445,23 @@ char *db_sqlite2_initial =
|
|||||||
" sample_count INTEGER DEFAULT 0,\n"
|
" sample_count INTEGER DEFAULT 0,\n"
|
||||||
" force_update INTEGER DEFAULT 0,\n"
|
" force_update INTEGER DEFAULT 0,\n"
|
||||||
" codectype VARCHAR(5) DEFAULT NULL,\n"
|
" codectype VARCHAR(5) DEFAULT NULL,\n"
|
||||||
" idx INTEGER NOT NULL\n"
|
" idx INTEGER NOT NULL,\n"
|
||||||
");\n"
|
" has_video INTEGER DEFAULT 0,\n"
|
||||||
"create table config (\n"
|
" contentrating INTEGER DEFAULT 0\n"
|
||||||
" term VARCHAR(255) NOT NULL,\n"
|
|
||||||
" subterm VARCHAR(255) DEFAULT NULL,\n"
|
|
||||||
" value VARCHAR(1024) NOT NULL\n"
|
|
||||||
");\n"
|
");\n"
|
||||||
"create table playlistitems (\n"
|
"create table playlistitems (\n"
|
||||||
" id INTEGER PRIMARY KEY NOT NULL,\n"
|
" id INTEGER PRIMARY KEY NOT NULL,\n"
|
||||||
" playlistid INTEGER NOT NULL,\n"
|
" playlistid INTEGER NOT NULL,\n"
|
||||||
" songid INTEGER NOT NULL\n"
|
" songid INTEGER NOT NULL\n"
|
||||||
");\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"
|
"create table playlists (\n"
|
||||||
" id INTEGER PRIMARY KEY NOT NULL,\n"
|
" id INTEGER PRIMARY KEY NOT NULL,\n"
|
||||||
" title VARCHAR(255) NOT NULL,\n"
|
" title VARCHAR(255) NOT NULL,\n"
|
||||||
@ -463,7 +472,6 @@ char *db_sqlite2_initial =
|
|||||||
" path VARCHAR(4096),\n"
|
" path VARCHAR(4096),\n"
|
||||||
" idx INTEGER NOT NULL\n"
|
" idx INTEGER NOT NULL\n"
|
||||||
");\n"
|
");\n"
|
||||||
"insert into config values ('version','','8');\n"
|
|
||||||
"insert into playlists values (1,'Library',1,0,'1',0,'',0);\n";
|
"insert into playlists values (1,'Library',1,0,'1',0,'',0);\n";
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,13 +65,14 @@ static char **db_sqlite3_row = NULL;
|
|||||||
|
|
||||||
static char db_sqlite3_path[PATH_MAX + 1];
|
static char db_sqlite3_path[PATH_MAX + 1];
|
||||||
|
|
||||||
#define DB_SQLITE3_VERSION 8
|
#define DB_SQLITE3_VERSION 9
|
||||||
|
|
||||||
|
|
||||||
/* Forwards */
|
/* Forwards */
|
||||||
void db_sqlite3_lock(void);
|
void db_sqlite3_lock(void);
|
||||||
void db_sqlite3_unlock(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
|
* 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,"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;
|
db_sqlite3_reload=1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -402,6 +404,7 @@ int db_sqlite3_event(int event_type) {
|
|||||||
"id from playlists)");
|
"id from playlists)");
|
||||||
db_sqlite3_exec(NULL,E_FATAL,"drop table plupdated");
|
db_sqlite3_exec(NULL,E_FATAL,"drop table plupdated");
|
||||||
}
|
}
|
||||||
|
db_sqlite3_reload=0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -423,7 +426,7 @@ int db_sqlite3_insert_id(void) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
char *db_sqlite3_initial =
|
char *db_sqlite3_initial1 =
|
||||||
"create table songs (\n"
|
"create table songs (\n"
|
||||||
" id INTEGER PRIMARY KEY NOT NULL,\n"
|
" id INTEGER PRIMARY KEY NOT NULL,\n"
|
||||||
" path VARCHAR(4096) UNIQUE NOT NULL,\n"
|
" path VARCHAR(4096) UNIQUE NOT NULL,\n"
|
||||||
@ -463,18 +466,23 @@ char *db_sqlite3_initial =
|
|||||||
" sample_count INTEGER DEFAULT 0,\n"
|
" sample_count INTEGER DEFAULT 0,\n"
|
||||||
" force_update INTEGER DEFAULT 0,\n"
|
" force_update INTEGER DEFAULT 0,\n"
|
||||||
" codectype VARCHAR(5) DEFAULT NULL,\n"
|
" codectype VARCHAR(5) DEFAULT NULL,\n"
|
||||||
" idx INTEGER NOT NULL\n"
|
" idx INTEGER NOT NULL,\n"
|
||||||
");\n"
|
" has_video INTEGER DEFAULT 0,\n"
|
||||||
"create table config (\n"
|
" contentrating INTEGER DEFAULT 0\n"
|
||||||
" term VARCHAR(255) NOT NULL,\n"
|
|
||||||
" subterm VARCHAR(255) DEFAULT NULL,\n"
|
|
||||||
" value VARCHAR(1024) NOT NULL\n"
|
|
||||||
");\n"
|
");\n"
|
||||||
"create table playlistitems (\n"
|
"create table playlistitems (\n"
|
||||||
" id INTEGER PRIMARY KEY NOT NULL,\n"
|
" id INTEGER PRIMARY KEY NOT NULL,\n"
|
||||||
" playlistid INTEGER NOT NULL,\n"
|
" playlistid INTEGER NOT NULL,\n"
|
||||||
" songid INTEGER NOT NULL\n"
|
" songid INTEGER NOT NULL\n"
|
||||||
");\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"
|
"create table playlists (\n"
|
||||||
" id INTEGER PRIMARY KEY NOT NULL,\n"
|
" id INTEGER PRIMARY KEY NOT NULL,\n"
|
||||||
" title VARCHAR(255) NOT NULL,\n"
|
" title VARCHAR(255) NOT NULL,\n"
|
||||||
@ -485,7 +493,6 @@ char *db_sqlite3_initial =
|
|||||||
" path VARCHAR(4096),\n"
|
" path VARCHAR(4096),\n"
|
||||||
" idx INTEGER NOT NULL\n"
|
" idx INTEGER NOT NULL\n"
|
||||||
");\n"
|
");\n"
|
||||||
"insert into config values ('version','','8');\n"
|
|
||||||
"insert into playlists values (1,'Library',1,0,'1',0,'',0);\n";
|
"insert into playlists values (1,'Library',1,0,'1',0,'',0);\n";
|
||||||
|
|
||||||
|
|
||||||
|
23
src/db-sql.c
23
src/db-sql.c
@ -661,7 +661,9 @@ int db_sql_add(char **pe, MP3FILE *pmp3, int *id) {
|
|||||||
"%d," // sample_count
|
"%d," // sample_count
|
||||||
"0," // force_update
|
"0," // force_update
|
||||||
"'%q'," // codectype
|
"'%q'," // codectype
|
||||||
"%d)", // index
|
"%d," // index
|
||||||
|
"%d," // has_video
|
||||||
|
"%d)", // contentrating
|
||||||
STR(pmp3->path),
|
STR(pmp3->path),
|
||||||
STR(pmp3->fname),
|
STR(pmp3->fname),
|
||||||
STR(pmp3->title),
|
STR(pmp3->title),
|
||||||
@ -697,7 +699,9 @@ int db_sql_add(char **pe, MP3FILE *pmp3, int *id) {
|
|||||||
pmp3->disabled,
|
pmp3->disabled,
|
||||||
pmp3->sample_count,
|
pmp3->sample_count,
|
||||||
STR(pmp3->codectype),
|
STR(pmp3->codectype),
|
||||||
pmp3->index);
|
pmp3->index,
|
||||||
|
pmp3->has_video,
|
||||||
|
pmp3->contentrating);
|
||||||
|
|
||||||
if(err != DB_E_SUCCESS)
|
if(err != DB_E_SUCCESS)
|
||||||
DPRINTF(E_FATAL,L_DB,"Error inserting file %s in database\n",pmp3->fname);
|
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);
|
pmp3->db_timestamp = (int)time(NULL);
|
||||||
|
|
||||||
|
/* FIXME: this should update all fields */
|
||||||
err=db_sql_exec_fn(pe,E_LOG,"UPDATE songs SET "
|
err=db_sql_exec_fn(pe,E_LOG,"UPDATE songs SET "
|
||||||
"title='%q'," // title
|
"title='%q'," // title
|
||||||
"artist='%q'," // artist
|
"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))
|
if(ISSTR(valarray[37]) && db_wantsmeta(pinfo->meta, metaSongCodecType))
|
||||||
/* ascd */
|
/* ascd */
|
||||||
size += 12;
|
size += 12;
|
||||||
|
|
||||||
|
if(db_wantsmeta(pinfo->meta,metaSongContentRating))
|
||||||
|
/* ascr */
|
||||||
|
size += 9;
|
||||||
|
if(db_wantsmeta(pinfo->meta,metaItunesHasVideo))
|
||||||
|
/* aeHV */
|
||||||
|
size += 9;
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
break;
|
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);
|
current += db_dmap_add_literal(current,"ascd",valarray[37],4);
|
||||||
if(db_wantsmeta(pinfo->meta, metaContainerItemId))
|
if(db_wantsmeta(pinfo->meta, metaContainerItemId))
|
||||||
current += db_dmap_add_int(current,"mcti",atoi(valarray[0]));
|
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;
|
return 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1532,6 +1549,8 @@ void db_sql_build_mp3file(SQL_ROW valarray, MP3FILE *pmp3) {
|
|||||||
pmp3->force_update=db_sql_atoi(valarray[36]);
|
pmp3->force_update=db_sql_atoi(valarray[36]);
|
||||||
pmp3->codectype=db_sql_strdup(valarray[37]);
|
pmp3->codectype=db_sql_strdup(valarray[37]);
|
||||||
pmp3->index=db_sql_atoi(valarray[38]);
|
pmp3->index=db_sql_atoi(valarray[38]);
|
||||||
|
pmp3->has_video=db_sql_atoi(valarray[39]);
|
||||||
|
pmp3->contentrating=db_sql_atoi(valarray[40]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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_wavinfo(char *filename, MP3FILE *pmp3);
|
||||||
extern int scan_get_urlinfo(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_mp3info(char *filename, MP3FILE *pmp3);
|
||||||
|
extern int scan_get_mp4info(char *filename, MP3FILE *pmp3);
|
||||||
|
|
||||||
/* playlist scanners */
|
/* playlist scanners */
|
||||||
extern int scan_xml_playlist(char *filename);
|
extern int scan_xml_playlist(char *filename);
|
||||||
@ -135,6 +136,7 @@ static TAGHANDLER taghandlers[] = {
|
|||||||
{ "wma", scan_get_wmainfo, "wma", "wma", "WMA audio file" },
|
{ "wma", scan_get_wmainfo, "wma", "wma", "WMA audio file" },
|
||||||
{ "url", scan_get_urlinfo, "pls", NULL, "Playlist URL" },
|
{ "url", scan_get_urlinfo, "pls", NULL, "Playlist URL" },
|
||||||
{ "pls", 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
|
#ifdef OGGVORBIS
|
||||||
{ "ogg", scan_get_ogginfo, "ogg", "ogg", "Ogg Vorbis audio file" },
|
{ "ogg", scan_get_ogginfo, "ogg", "ogg", "Ogg Vorbis audio file" },
|
||||||
#endif
|
#endif
|
||||||
|
@ -71,6 +71,12 @@ typedef struct tag_mp3file {
|
|||||||
int force_update;
|
int force_update;
|
||||||
int sample_count;
|
int sample_count;
|
||||||
char compilation;
|
char compilation;
|
||||||
|
|
||||||
|
/* iTunes 5+ */
|
||||||
|
int contentrating;
|
||||||
|
|
||||||
|
/* iTunes 6.0.2 */
|
||||||
|
int has_video;
|
||||||
} MP3FILE;
|
} MP3FILE;
|
||||||
|
|
||||||
typedef struct tag_m3ufile {
|
typedef struct tag_m3ufile {
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
#include "scan-aac.h"
|
#include "scan-aac.h"
|
||||||
|
|
||||||
/* Forwards */
|
/* 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)
|
* Convert mac time to unix time (different epochs)
|
||||||
|
258
src/scan-mp4.c
Normal file
258
src/scan-mp4.c
Normal file
@ -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 <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#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. */
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user