Commit a591f30e authored by Edward Wang's avatar Edward Wang

Fully optimize the DirectoryAdapter for performance

parent feb52cc2
......@@ -22,7 +22,9 @@
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <vlc/vlc.h>
#include <vlc_common.h>
......@@ -949,16 +951,19 @@ jint Java_org_videolan_vlc_LibVLC_setSpuTrack(JNIEnv *env, jobject thiz, jint in
return -1;
}
jint Java_org_videolan_vlc_LibVLC_nativeCountDirectoryContents(JNIEnv *env, jobject thiz, jstring path)
void Java_org_videolan_vlc_LibVLC_nativeReadDirectory(JNIEnv *env, jobject thiz, jstring path, jobject arrayList)
{
jboolean isCopy;
/* Get C string */
const char* psz_path = (*env)->GetStringUTFChars(env, path, &isCopy);
jint childrenCount = 0;
DIR* p_dir = opendir(psz_path);
(*env)->ReleaseStringUTFChars(env, path, psz_path);
if(!p_dir)
return 0;
return;
jclass arrayClass = (*env)->FindClass(env, "java/util/ArrayList");
jmethodID methodID = (*env)->GetMethodID(env, arrayClass, "add", "(Ljava/lang/Object;)Z");
struct dirent* p_dirent;
while(1) {
......@@ -970,11 +975,29 @@ jint Java_org_videolan_vlc_LibVLC_nativeCountDirectoryContents(JNIEnv *env, jobj
else if(errno == 0) /* end of stream */
break;
}
childrenCount++;
(*env)->CallBooleanMethod(env, arrayList, methodID, (*env)->NewStringUTF(env, p_dirent->d_name));
}
closedir(p_dir);
}
jboolean Java_org_videolan_vlc_LibVLC_nativeIsPathDirectory(JNIEnv *env, jobject thiz, jstring path)
{
jboolean isCopy;
/* Get C string */
const char* psz_path = (*env)->GetStringUTFChars(env, path, &isCopy);
jboolean isDirectory;
struct stat buf;
if(stat(psz_path, &buf) != 0)
/* couldn't stat */
isDirectory = JNI_FALSE;
else {
if(S_ISDIR(buf.st_mode))
isDirectory = JNI_TRUE;
else
isDirectory = JNI_FALSE;
}
/* Clean up */
(*env)->ReleaseStringUTFChars(env, path, psz_path);
return childrenCount;
return isDirectory;
}
......@@ -20,6 +20,8 @@
package org.videolan.vlc;
import java.util.ArrayList;
import org.videolan.vlc.gui.video.VideoPlayerActivity;
import org.videolan.vlc.LibVlcException;
......@@ -408,7 +410,9 @@ public class LibVLC {
public native String nativeToURI(String path);
public native int nativeCountDirectoryContents(String path);
public native void nativeReadDirectory(String path, ArrayList<String> res);
public native boolean nativeIsPathDirectory(String path);
/**
* Return the length of the stream, in milliseconds
......
......@@ -31,6 +31,7 @@ public class Media implements Comparable<Media> {
public final static String TAG = "VLC/MediaItem";
public final static HashSet<String> EXTENTIONS;
public final static String EXTENTIONS_REGEX;
public final static HashSet<String> FOLDER_BLACKLIST;
static {
......@@ -61,6 +62,16 @@ public class Media implements Comparable<Media> {
EXTENTIONS = new HashSet<String>();
for (String item : extensions)
EXTENTIONS.add(item);
// .+(\.)((?i)(mp3|flac|mp4|ogg|ogv))
StringBuilder sb = new StringBuilder(115);
sb.append(".+(\\.)((?i)(");
sb.append(extensions[0].substring(1));
for(int i = 1; i < extensions.length; i++) {
sb.append('|');
sb.append(extensions[i].substring(1));
}
sb.append("))");
EXTENTIONS_REGEX = sb.toString();
FOLDER_BLACKLIST = new HashSet<String>();
for (String item : folder_blacklist)
FOLDER_BLACKLIST.add(android.os.Environment.getExternalStorageDirectory().getPath() + item);
......
......@@ -21,11 +21,11 @@
package org.videolan.vlc.gui;
import java.io.File;
import java.io.FileFilter;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.regex.Pattern;
import org.videolan.vlc.LibVLC;
import org.videolan.vlc.Media;
......@@ -45,23 +45,8 @@ import android.widget.TextView;
public class DirectoryAdapter extends BaseAdapter {
public final static String TAG = "VLC/DirectoryAdapter";
/**
* Filter: accept only media files and directories
*/
private class AudioDirectoryAdapterFilter implements FileFilter {
@Override
public boolean accept(File f) {
if(f.isHidden())
return false;
if(f.isDirectory() && !Media.FOLDER_BLACKLIST.contains(f.getPath().toLowerCase()))
return true;
for(String ext : Media.EXTENTIONS) {
if(f.getPath().toLowerCase().endsWith(ext))
return true;
}
return false;
}
public static boolean acceptedPath(String f) {
return Pattern.compile(Media.EXTENTIONS_REGEX, Pattern.CASE_INSENSITIVE).matcher(f).matches();
}
/**
......@@ -136,26 +121,47 @@ public class DirectoryAdapter extends BaseAdapter {
ImageView icon;
}
public void populateNode(DirectoryAdapter.Node n, String MRL) {
File file = new File(MRL);
public void populateNode(DirectoryAdapter.Node n, String path) {
File file = new File(path);
if(!file.exists() || !file.isDirectory())
return;
File[] files = file.listFiles(new AudioDirectoryAdapterFilter());
ArrayList<String> files = new ArrayList<String>();
LibVLC.getExistingInstance().nativeReadDirectory(path, files);
StringBuilder sb = new StringBuilder(100);
/* If no sub-directories or I/O error don't crash */
if(files == null || files.length < 1) {
if(files == null || files.size() < 1) {
//return
} else {
for(int i = 0; i < files.length; i++) {
DirectoryAdapter.Node nss = new DirectoryAdapter.Node(files[i].getName());
if(files[i].isFile())
nss.setIsFile();
if(!nss.isFile() && LibVLC.getExistingInstance().nativeCountDirectoryContents(MRL + "/" + nss.name) < 6) {
String mCurrentDir_old = mCurrentDir;
mCurrentDir = MRL;
this.populateNode(nss, MRL + "/" + nss.name);
mCurrentDir = mCurrentDir_old;
for(int i = 0; i < files.size(); i++) {
String filename = files.get(i);
/* Avoid infinite loop */
if(filename.equals(".") || filename.equals("..")) continue;
DirectoryAdapter.Node nss = new DirectoryAdapter.Node(filename);
nss.isFile = false;
sb.append(path);
sb.append("/");
sb.append(filename);
String newPath = sb.toString();
sb.setLength(0);
if(LibVLC.getExistingInstance().nativeIsPathDirectory(newPath)) {
ArrayList<String> files_int = new ArrayList<String>();
LibVLC.getExistingInstance().nativeReadDirectory(newPath, files_int);
if(files_int.size() < 8) { /* Optimisation: If there are more than 8
sub-folders, don't scan each one, otherwise
when scaled it is very slow to load */
String mCurrentDir_old = mCurrentDir;
mCurrentDir = path;
this.populateNode(nss, newPath);
mCurrentDir = mCurrentDir_old;
}
} else {
if(acceptedPath(newPath))
nss.setIsFile();
else
continue;
}
n.children.add(nss);
......@@ -243,6 +249,7 @@ public class DirectoryAdapter extends BaseAdapter {
String holderText = "";
if(selectedNode.isFile()) {
Log.d(TAG, "Loading media " + selectedNode.name);
Media m = new Media(mContext, getMediaLocation(position), false);
holder.title.setText(m.getTitle());
holderText = m.getArtist() + " - " + m.getAlbum();
......
......@@ -25,6 +25,7 @@ import java.util.ArrayList;
import org.videolan.vlc.AudioServiceController;
import org.videolan.vlc.LibVLC;
import org.videolan.vlc.Media;
import org.videolan.vlc.MediaLibrary;
import org.videolan.vlc.R;
import org.videolan.vlc.Util;
......@@ -51,7 +52,6 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.View;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment