summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Marco Nelissen <marcone@google.com> 2012-03-23 16:04:58 -0700
committer Marco Nelissen <marcone@google.com> 2012-03-23 16:37:50 -0700
commitc164faa8314c110d417b653b9926de4803bb2dda (patch)
tree35cb3ae226e1b663d07e710fa2205339268432e5
parentda9deca7bab75f39a236d04b9e43d9da833ce4a0 (diff)
Speed up playlist processing
The recent removal of the cache from MediaScanner (commit 58ef68905d67e356eb) slowed down processing of playlists, in some cases significantly, due to every line in a playlist prompting a query that looped over the entire audio table. With this change, the query is only done once instead of for every line, and the code starts iterating over the Cursor starting near the point of the last match, instead of from the start. The latter is especially helpful when the entire query result is too large to fit in a CursorWindow, since it reduces the number of times that sqlite has to perform an offset query under the hood to refil the window. Change-Id: I9fea990b3b8c86571384de2122708fb7e809c355
-rw-r--r--media/java/android/media/MediaScanner.java92
1 files changed, 58 insertions, 34 deletions
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index a08d6c37e1a4..a8144a783937 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -1396,6 +1396,7 @@ public class MediaScanner
}
mMtpObjectHandle = objectHandle;
+ Cursor fileList = null;
try {
if (MediaFile.isPlayListFileType(fileType)) {
// build file cache so we can look up tracks in the playlist
@@ -1403,7 +1404,9 @@ public class MediaScanner
FileEntry entry = makeEntryFor(path);
if (entry != null) {
- processPlayList(entry);
+ fileList = mMediaProvider.query(mFilesUri, FILES_PRESCAN_PROJECTION,
+ null, null, null, null);
+ processPlayList(entry, fileList);
}
} else {
// MTP will create a file entry for us so we don't want to do it in prescan
@@ -1417,6 +1420,9 @@ public class MediaScanner
Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e);
} finally {
mMtpObjectHandle = 0;
+ if (fileList != null) {
+ fileList.close();
+ }
}
}
@@ -1479,7 +1485,7 @@ public class MediaScanner
}
private boolean addPlayListEntry(String entry, String playListDirectory,
- Uri uri, ContentValues values, int index) {
+ Uri uri, ContentValues values, int index, Cursor fileList) {
// watch for trailing whitespace
int entryLength = entry.length();
@@ -1506,19 +1512,20 @@ public class MediaScanner
// number of rightmost file/directory names for bestMatch
int bestMatchLength = 0;
- Cursor c = null;
- try {
- c = mMediaProvider.query(mFilesUri, FILES_PRESCAN_PROJECTION,
- null, null, null, null);
- } catch (RemoteException e1) {
- }
-
- if (c != null) {
- while (c.moveToNext()) {
- long rowId = c.getLong(FILES_PRESCAN_ID_COLUMN_INDEX);
- String path = c.getString(FILES_PRESCAN_PATH_COLUMN_INDEX);
- int format = c.getInt(FILES_PRESCAN_FORMAT_COLUMN_INDEX);
- long lastModified = c.getLong(FILES_PRESCAN_DATE_MODIFIED_COLUMN_INDEX);
+ if (fileList != null) {
+ int count = fileList.getCount();
+ // Backing up a little in the cursor helps when the files in the
+ // playlist are not in the same order as they are in the database
+ // but are still close.
+ fileList.move(-1000);
+ while(--count >= 0) {
+ if (!fileList.moveToNext()) {
+ fileList.moveToFirst();
+ }
+ long rowId = fileList.getLong(FILES_PRESCAN_ID_COLUMN_INDEX);
+ String path = fileList.getString(FILES_PRESCAN_PATH_COLUMN_INDEX);
+ int format = fileList.getInt(FILES_PRESCAN_FORMAT_COLUMN_INDEX);
+ long lastModified = fileList.getLong(FILES_PRESCAN_DATE_MODIFIED_COLUMN_INDEX);
if (path.equalsIgnoreCase(entry)) {
bestMatch = new FileEntry(rowId, path, lastModified, format);
@@ -1531,7 +1538,6 @@ public class MediaScanner
bestMatchLength = matchLength;
}
}
- c.close();
}
if (bestMatch == null) {
@@ -1541,7 +1547,7 @@ public class MediaScanner
try {
// check rowid is set. Rowid may be missing if it is inserted by bulkInsert().
if (bestMatch.mRowId == 0) {
- c = mMediaProvider.query(mAudioUri, ID_PROJECTION,
+ Cursor c = mMediaProvider.query(mAudioUri, ID_PROJECTION,
MediaStore.Files.FileColumns.DATA + "=?",
new String[] { bestMatch.mPath }, null, null);
if (c != null) {
@@ -1567,7 +1573,8 @@ public class MediaScanner
return true;
}
- private void processM3uPlayList(String path, String playListDirectory, Uri uri, ContentValues values) {
+ private void processM3uPlayList(String path, String playListDirectory, Uri uri,
+ ContentValues values, Cursor fileList) {
BufferedReader reader = null;
try {
File f = new File(path);
@@ -1580,7 +1587,7 @@ public class MediaScanner
// ignore comment lines, which begin with '#'
if (line.length() > 0 && line.charAt(0) != '#') {
values.clear();
- if (addPlayListEntry(line, playListDirectory, uri, values, index))
+ if (addPlayListEntry(line, playListDirectory, uri, values, index, fileList))
index++;
}
line = reader.readLine();
@@ -1598,7 +1605,8 @@ public class MediaScanner
}
}
- private void processPlsPlayList(String path, String playListDirectory, Uri uri, ContentValues values) {
+ private void processPlsPlayList(String path, String playListDirectory, Uri uri,
+ ContentValues values, Cursor fileList) {
BufferedReader reader = null;
try {
File f = new File(path);
@@ -1613,7 +1621,8 @@ public class MediaScanner
int equals = line.indexOf('=');
if (equals > 0) {
values.clear();
- if (addPlayListEntry(line.substring(equals + 1), playListDirectory, uri, values, index))
+ if (addPlayListEntry(line.substring(equals + 1), playListDirectory,
+ uri, values, index, fileList))
index++;
}
}
@@ -1637,12 +1646,14 @@ public class MediaScanner
final ContentHandler handler;
String playListDirectory;
Uri uri;
+ Cursor fileList;
ContentValues values = new ContentValues();
int index = 0;
- public WplHandler(String playListDirectory, Uri uri) {
+ public WplHandler(String playListDirectory, Uri uri, Cursor fileList) {
this.playListDirectory = playListDirectory;
this.uri = uri;
+ this.fileList = fileList;
RootElement root = new RootElement("smil");
Element body = root.getChild("body");
@@ -1653,11 +1664,12 @@ public class MediaScanner
this.handler = root.getContentHandler();
}
+ @Override
public void start(Attributes attributes) {
String path = attributes.getValue("", "src");
if (path != null) {
values.clear();
- if (addPlayListEntry(path, playListDirectory, uri, values, index)) {
+ if (addPlayListEntry(path, playListDirectory, uri, values, index, fileList)) {
index++;
}
}
@@ -1671,14 +1683,16 @@ public class MediaScanner
}
}
- private void processWplPlayList(String path, String playListDirectory, Uri uri) {
+ private void processWplPlayList(String path, String playListDirectory, Uri uri,
+ Cursor fileList) {
FileInputStream fis = null;
try {
File f = new File(path);
if (f.exists()) {
fis = new FileInputStream(f);
- Xml.parse(fis, Xml.findEncodingByName("UTF-8"), new WplHandler(playListDirectory, uri).getContentHandler());
+ Xml.parse(fis, Xml.findEncodingByName("UTF-8"),
+ new WplHandler(playListDirectory, uri, fileList).getContentHandler());
}
} catch (SAXException e) {
e.printStackTrace();
@@ -1694,7 +1708,7 @@ public class MediaScanner
}
}
- private void processPlayList(FileEntry entry) throws RemoteException {
+ private void processPlayList(FileEntry entry, Cursor fileList) throws RemoteException {
String path = entry.mPath;
ContentValues values = new ContentValues();
int lastSlash = path.lastIndexOf('/');
@@ -1736,21 +1750,31 @@ public class MediaScanner
int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType);
if (fileType == MediaFile.FILE_TYPE_M3U) {
- processM3uPlayList(path, playListDirectory, membersUri, values);
+ processM3uPlayList(path, playListDirectory, membersUri, values, fileList);
} else if (fileType == MediaFile.FILE_TYPE_PLS) {
- processPlsPlayList(path, playListDirectory, membersUri, values);
+ processPlsPlayList(path, playListDirectory, membersUri, values, fileList);
} else if (fileType == MediaFile.FILE_TYPE_WPL) {
- processWplPlayList(path, playListDirectory, membersUri);
+ processWplPlayList(path, playListDirectory, membersUri, fileList);
}
}
private void processPlayLists() throws RemoteException {
Iterator<FileEntry> iterator = mPlayLists.iterator();
- while (iterator.hasNext()) {
- FileEntry entry = iterator.next();
- // only process playlist files if they are new or have been modified since the last scan
- if (entry.mLastModifiedChanged) {
- processPlayList(entry);
+ Cursor fileList = null;
+ try {
+ fileList = mMediaProvider.query(mFilesUri, FILES_PRESCAN_PROJECTION,
+ null, null, null, null);
+ while (iterator.hasNext()) {
+ FileEntry entry = iterator.next();
+ // only process playlist files if they are new or have been modified since the last scan
+ if (entry.mLastModifiedChanged) {
+ processPlayList(entry, fileList);
+ }
+ }
+ } catch (RemoteException e1) {
+ } finally {
+ if (fileList != null) {
+ fileList.close();
}
}
}