Skip to content

Commit 83cab25

Browse files
marconeAndroid (Google) Code Review
authored andcommitted
Merge "Further speed up playlist processing" into jb-dev
2 parents 1fa1de5 + 0b71839 commit 83cab25

File tree

1 file changed

+85
-96
lines changed

1 file changed

+85
-96
lines changed

media/java/android/media/MediaScanner.java

Lines changed: 85 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,16 @@
3131
import android.mtp.MtpConstants;
3232
import android.net.Uri;
3333
import android.os.Environment;
34-
import android.os.Process;
3534
import android.os.RemoteException;
3635
import android.os.SystemProperties;
3736
import android.provider.MediaStore;
38-
import android.provider.MediaStore.Files.FileColumns;
39-
import android.provider.Settings;
4037
import android.provider.MediaStore.Audio;
38+
import android.provider.MediaStore.Audio.Playlists;
4139
import android.provider.MediaStore.Files;
40+
import android.provider.MediaStore.Files.FileColumns;
4241
import android.provider.MediaStore.Images;
4342
import android.provider.MediaStore.Video;
44-
import android.provider.MediaStore.Audio.Playlists;
43+
import android.provider.Settings;
4544
import android.sax.Element;
4645
import android.sax.ElementListener;
4746
import android.sax.RootElement;
@@ -56,10 +55,8 @@
5655
import java.io.IOException;
5756
import java.io.InputStreamReader;
5857
import java.util.ArrayList;
59-
import java.util.HashMap;
6058
import java.util.HashSet;
6159
import java.util.Iterator;
62-
import java.util.LinkedHashMap;
6360
import java.util.Locale;
6461

6562
import libcore.io.ErrnoException;
@@ -372,6 +369,14 @@ public String toString() {
372369
}
373370
}
374371

372+
private static class PlaylistEntry {
373+
String path;
374+
long bestmatchid;
375+
int bestmatchlevel;
376+
}
377+
378+
private ArrayList<PlaylistEntry> mPlaylistEntries = new ArrayList<PlaylistEntry>();
379+
375380
private MediaInserter mMediaInserter;
376381

377382
private ArrayList<FileEntry> mPlayLists;
@@ -1492,93 +1497,83 @@ private int matchPaths(String path1, String path2) {
14921497
return result;
14931498
}
14941499

1495-
private boolean addPlayListEntry(String entry, String playListDirectory,
1496-
Uri uri, ContentValues values, int index, Cursor fileList) {
1500+
private boolean matchEntries(long rowId, String data) {
1501+
1502+
int len = mPlaylistEntries.size();
1503+
boolean done = true;
1504+
for (int i = 0; i < len; i++) {
1505+
PlaylistEntry entry = mPlaylistEntries.get(i);
1506+
if (entry.bestmatchlevel == Integer.MAX_VALUE) {
1507+
continue; // this entry has been matched already
1508+
}
1509+
done = false;
1510+
if (data.equalsIgnoreCase(entry.path)) {
1511+
entry.bestmatchid = rowId;
1512+
entry.bestmatchlevel = Integer.MAX_VALUE;
1513+
continue; // no need for path matching
1514+
}
1515+
1516+
int matchLength = matchPaths(data, entry.path);
1517+
if (matchLength > entry.bestmatchlevel) {
1518+
entry.bestmatchid = rowId;
1519+
entry.bestmatchlevel = matchLength;
1520+
}
1521+
}
1522+
return done;
1523+
}
14971524

1525+
private void cachePlaylistEntry(String line, String playListDirectory) {
1526+
PlaylistEntry entry = new PlaylistEntry();
14981527
// watch for trailing whitespace
1499-
int entryLength = entry.length();
1500-
while (entryLength > 0 && Character.isWhitespace(entry.charAt(entryLength - 1))) entryLength--;
1528+
int entryLength = line.length();
1529+
while (entryLength > 0 && Character.isWhitespace(line.charAt(entryLength - 1))) entryLength--;
15011530
// path should be longer than 3 characters.
15021531
// avoid index out of bounds errors below by returning here.
1503-
if (entryLength < 3) return false;
1504-
if (entryLength < entry.length()) entry = entry.substring(0, entryLength);
1532+
if (entryLength < 3) return;
1533+
if (entryLength < line.length()) line = line.substring(0, entryLength);
15051534

15061535
// does entry appear to be an absolute path?
15071536
// look for Unix or DOS absolute paths
1508-
char ch1 = entry.charAt(0);
1537+
char ch1 = line.charAt(0);
15091538
boolean fullPath = (ch1 == '/' ||
1510-
(Character.isLetter(ch1) && entry.charAt(1) == ':' && entry.charAt(2) == '\\'));
1539+
(Character.isLetter(ch1) && line.charAt(1) == ':' && line.charAt(2) == '\\'));
15111540
// if we have a relative path, combine entry with playListDirectory
15121541
if (!fullPath)
1513-
entry = playListDirectory + entry;
1514-
1542+
line = playListDirectory + line;
1543+
entry.path = line;
15151544
//FIXME - should we look for "../" within the path?
15161545

1517-
// best matching MediaFile for the play list entry
1518-
FileEntry bestMatch = null;
1519-
1520-
// number of rightmost file/directory names for bestMatch
1521-
int bestMatchLength = 0;
1522-
1523-
if (fileList != null) {
1524-
int count = fileList.getCount();
1525-
// Backing up a little in the cursor helps when the files in the
1526-
// playlist are not in the same order as they are in the database
1527-
// but are still close.
1528-
fileList.move(-1000);
1529-
while(--count >= 0) {
1530-
if (!fileList.moveToNext()) {
1531-
fileList.moveToFirst();
1532-
}
1533-
long rowId = fileList.getLong(FILES_PRESCAN_ID_COLUMN_INDEX);
1534-
String path = fileList.getString(FILES_PRESCAN_PATH_COLUMN_INDEX);
1535-
int format = fileList.getInt(FILES_PRESCAN_FORMAT_COLUMN_INDEX);
1536-
long lastModified = fileList.getLong(FILES_PRESCAN_DATE_MODIFIED_COLUMN_INDEX);
1537-
1538-
if (path.equalsIgnoreCase(entry)) {
1539-
bestMatch = new FileEntry(rowId, path, lastModified, format);
1540-
break; // don't bother continuing search
1541-
}
1546+
mPlaylistEntries.add(entry);
1547+
}
15421548

1543-
int matchLength = matchPaths(path, entry);
1544-
if (matchLength > bestMatchLength) {
1545-
bestMatch = new FileEntry(rowId, path, lastModified, format);
1546-
bestMatchLength = matchLength;
1547-
}
1549+
private void processCachedPlaylist(Cursor fileList, ContentValues values, Uri playlistUri) {
1550+
fileList.moveToPosition(-1);
1551+
while (fileList.moveToNext()) {
1552+
long rowId = fileList.getLong(FILES_PRESCAN_ID_COLUMN_INDEX);
1553+
String data = fileList.getString(FILES_PRESCAN_PATH_COLUMN_INDEX);
1554+
if (matchEntries(rowId, data)) {
1555+
break;
15481556
}
15491557
}
15501558

1551-
if (bestMatch == null) {
1552-
return false;
1553-
}
1554-
1555-
try {
1556-
// check rowid is set. Rowid may be missing if it is inserted by bulkInsert().
1557-
if (bestMatch.mRowId == 0) {
1558-
Cursor c = mMediaProvider.query(mAudioUri, ID_PROJECTION,
1559-
MediaStore.Files.FileColumns.DATA + "=?",
1560-
new String[] { bestMatch.mPath }, null, null);
1561-
if (c != null) {
1562-
if (c.moveToNext()) {
1563-
bestMatch.mRowId = c.getLong(0);
1564-
}
1565-
c.close();
1566-
}
1567-
if (bestMatch.mRowId == 0) {
1568-
return false;
1559+
int len = mPlaylistEntries.size();
1560+
int index = 0;
1561+
for (int i = 0; i < len; i++) {
1562+
PlaylistEntry entry = mPlaylistEntries.get(i);
1563+
if (entry.bestmatchlevel > 0) {
1564+
try {
1565+
values.clear();
1566+
values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, Integer.valueOf(index));
1567+
values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, Long.valueOf(entry.bestmatchid));
1568+
mMediaProvider.insert(playlistUri, values);
1569+
index++;
1570+
} catch (RemoteException e) {
1571+
Log.e(TAG, "RemoteException in MediaScanner.processCachedPlaylist()", e);
1572+
return;
15691573
}
15701574
}
1571-
// OK, now we are ready to add this to the database
1572-
values.clear();
1573-
values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, Integer.valueOf(index));
1574-
values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, Long.valueOf(bestMatch.mRowId));
1575-
mMediaProvider.insert(uri, values);
1576-
} catch (RemoteException e) {
1577-
Log.e(TAG, "RemoteException in MediaScanner.addPlayListEntry()", e);
1578-
return false;
15791575
}
1580-
1581-
return true;
1576+
mPlaylistEntries.clear();
15821577
}
15831578

15841579
private void processM3uPlayList(String path, String playListDirectory, Uri uri,
@@ -1590,16 +1585,16 @@ private void processM3uPlayList(String path, String playListDirectory, Uri uri,
15901585
reader = new BufferedReader(
15911586
new InputStreamReader(new FileInputStream(f)), 8192);
15921587
String line = reader.readLine();
1593-
int index = 0;
1588+
mPlaylistEntries.clear();
15941589
while (line != null) {
15951590
// ignore comment lines, which begin with '#'
15961591
if (line.length() > 0 && line.charAt(0) != '#') {
1597-
values.clear();
1598-
if (addPlayListEntry(line, playListDirectory, uri, values, index, fileList))
1599-
index++;
1592+
cachePlaylistEntry(line, playListDirectory);
16001593
}
16011594
line = reader.readLine();
16021595
}
1596+
1597+
processCachedPlaylist(fileList, values, uri);
16031598
}
16041599
} catch (IOException e) {
16051600
Log.e(TAG, "IOException in MediaScanner.processM3uPlayList()", e);
@@ -1622,20 +1617,19 @@ private void processPlsPlayList(String path, String playListDirectory, Uri uri,
16221617
reader = new BufferedReader(
16231618
new InputStreamReader(new FileInputStream(f)), 8192);
16241619
String line = reader.readLine();
1625-
int index = 0;
1620+
mPlaylistEntries.clear();
16261621
while (line != null) {
16271622
// ignore comment lines, which begin with '#'
16281623
if (line.startsWith("File")) {
16291624
int equals = line.indexOf('=');
16301625
if (equals > 0) {
1631-
values.clear();
1632-
if (addPlayListEntry(line.substring(equals + 1), playListDirectory,
1633-
uri, values, index, fileList))
1634-
index++;
1626+
cachePlaylistEntry(line, playListDirectory);
16351627
}
16361628
}
16371629
line = reader.readLine();
16381630
}
1631+
1632+
processCachedPlaylist(fileList, values, uri);
16391633
}
16401634
} catch (IOException e) {
16411635
Log.e(TAG, "IOException in MediaScanner.processPlsPlayList()", e);
@@ -1653,15 +1647,9 @@ class WplHandler implements ElementListener {
16531647

16541648
final ContentHandler handler;
16551649
String playListDirectory;
1656-
Uri uri;
1657-
Cursor fileList;
1658-
ContentValues values = new ContentValues();
1659-
int index = 0;
16601650

16611651
public WplHandler(String playListDirectory, Uri uri, Cursor fileList) {
16621652
this.playListDirectory = playListDirectory;
1663-
this.uri = uri;
1664-
this.fileList = fileList;
16651653

16661654
RootElement root = new RootElement("smil");
16671655
Element body = root.getChild("body");
@@ -1676,13 +1664,11 @@ public WplHandler(String playListDirectory, Uri uri, Cursor fileList) {
16761664
public void start(Attributes attributes) {
16771665
String path = attributes.getValue("", "src");
16781666
if (path != null) {
1679-
values.clear();
1680-
if (addPlayListEntry(path, playListDirectory, uri, values, index, fileList)) {
1681-
index++;
1682-
}
1667+
cachePlaylistEntry(path, playListDirectory);
16831668
}
16841669
}
16851670

1671+
@Override
16861672
public void end() {
16871673
}
16881674

@@ -1692,15 +1678,18 @@ ContentHandler getContentHandler() {
16921678
}
16931679

16941680
private void processWplPlayList(String path, String playListDirectory, Uri uri,
1695-
Cursor fileList) {
1681+
ContentValues values, Cursor fileList) {
16961682
FileInputStream fis = null;
16971683
try {
16981684
File f = new File(path);
16991685
if (f.exists()) {
17001686
fis = new FileInputStream(f);
17011687

1688+
mPlaylistEntries.clear();
17021689
Xml.parse(fis, Xml.findEncodingByName("UTF-8"),
17031690
new WplHandler(playListDirectory, uri, fileList).getContentHandler());
1691+
1692+
processCachedPlaylist(fileList, values, uri);
17041693
}
17051694
} catch (SAXException e) {
17061695
e.printStackTrace();
@@ -1762,7 +1751,7 @@ private void processPlayList(FileEntry entry, Cursor fileList) throws RemoteExce
17621751
} else if (fileType == MediaFile.FILE_TYPE_PLS) {
17631752
processPlsPlayList(path, playListDirectory, membersUri, values, fileList);
17641753
} else if (fileType == MediaFile.FILE_TYPE_WPL) {
1765-
processWplPlayList(path, playListDirectory, membersUri, fileList);
1754+
processWplPlayList(path, playListDirectory, membersUri, values, fileList);
17661755
}
17671756
}
17681757

@@ -1800,7 +1789,7 @@ private void processPlayLists() throws RemoteException {
18001789
private native final void native_finalize();
18011790

18021791
/**
1803-
* Releases resouces associated with this MediaScanner object.
1792+
* Releases resources associated with this MediaScanner object.
18041793
* It is considered good practice to call this method when
18051794
* one is done using the MediaScanner object. After this method
18061795
* is called, the MediaScanner object can no longer be used.

0 commit comments

Comments
 (0)