/*- * Copyright (C) 2009 Peter Baldwin * * 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 3 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, see <http://www.gnu.org/licenses/>. */ package org.peterbaldwin.vlcremote.model; import android.content.Intent; import android.net.Uri; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.peterbaldwin.vlcremote.util.MimeTypeMap; public final class File { public enum Type { DIRECTORY(0), FILE(1), LIBRARY(2), LIBRARY_NAME(3), LIBRARY_DIRECTORY(4); private final int type; private Type(int type) { this.type = type; } public int getId() { return type; } } public static File getLibrary(String libraryName) { return new File(File.Type.LIBRARY_NAME, 0L, null, "library://" + libraryName, libraryName, null); } public static final File LIBRARIES = new File(Type.LIBRARY, 0L, null, "library://", "Libraries", null); public static final int PATH_UNIX = 0; public static final int PATH_WINDOWS = 1; public static int PATH_TYPE = PATH_UNIX; private static final MimeTypeMap sMimeTypeMap = MimeTypeMap.getSingleton(); private static final Pattern schemedPathPattern = Pattern.compile("^([A-Za-z]+://)?(.*)$"); private static String parseExtension(String path) { int index = path.lastIndexOf('.'); if (index != -1) { return path.substring(index + 1); } else { return null; } } public static String baseName(String path) { if(path == null) { return null; } String fileProtocol = "file:///"; int offset = 0; if(path.startsWith(fileProtocol)) { offset = fileProtocol.length(); } int bslash = path.lastIndexOf('\\'); int fslash = path.substring(offset).lastIndexOf('/') + offset; if(fslash == -1 && bslash == -1) { return path; } return path.substring(Math.max(bslash, fslash) + 1); } private Type mType; private Long mSize; private String mDate; private String mPath; private String mName; private String mExtension; public File(Type type, Long size, String date, String path, String name, String extension) { mType = type; mSize = size; mDate = date; mPath = path; mName = name; mExtension = extension != null ? extension : path != null ? parseExtension(path) : null; } public Type getType() { return mType; } public void setType(Type type) { mType = type; } public boolean isType(Type type) { return mType == type; } public boolean isDirectory() { // Type is "directory" in VLC 1.0 and "dir" in VLC 1.1 return mType == Type.DIRECTORY; } public boolean isLibrary() { return mType == Type.LIBRARY; } public boolean isLibraryName() { return mType == Type.LIBRARY_NAME; } public boolean isLibraryDir() { return mType == Type.LIBRARY_DIRECTORY; } public boolean isBrowsable() { return isLibrary() || isDirectory() || isLibraryName() || isLibraryDir(); } /** * Checks if this File is a parent entry (name is ..) * @return true if this File is a parent entry, false otherwise. */ public boolean isParent() { return "..".equals(mName); } public static boolean isImage(String ext) { String mimeType = getMimeType(ext); return mimeType != null && mimeType.startsWith("image/"); } public Long getSize() { return mSize; } public void setSize(Long size) { mSize = size; } public String getDate() { return mDate; } public void setDate(String date) { mDate = date; } public String getPath() { return mPath; } public String getNormalizedPath() { return getNormalizedPath(mPath); } /** * Get the normalized path for the given file path. * Any parent directories (..) will be resolved. * @param file file path * @return */ public static String getNormalizedPath(String file) { Matcher m = schemedPathPattern.matcher(file); if(!m.find()) { return Directory.ROOT_DIRECTORY; } String scheme = m.group(1); String path = m.group(2); if(scheme == null) { scheme = ""; } String[] st = path.split("(\\\\|/)+"); ArrayDeque<String> segmentList = new ArrayDeque<String>(); for(String segment : st) { if("..".equals(segment)) { segmentList.pollFirst(); continue; } segmentList.offerFirst(segment); } if(segmentList.isEmpty() && scheme.isEmpty()) { return Directory.ROOT_DIRECTORY; } StringBuilder sb = new StringBuilder(); sb.append(scheme); while(!segmentList.isEmpty()) { sb.append(segmentList.pollLast()); if(segmentList.peekLast() != null) { sb.append('/'); } } return sb.length() == 0 ? Directory.ROOT_DIRECTORY : sb.toString(); } public String getMrl() { return getMrl(mPath, mExtension); } public static String getMrl(String path, String extension) { if (isImage(extension)) { return "fake://"; } else { return Uri.fromFile(new java.io.File(path)).toString(); } } public List<String> getOptions() { if (isImage(mExtension)) { return Collections.singletonList(":fake-file=" + getPath()); } else { return Collections.emptyList(); } } public List<String> getStreamingOptions() { List<String> options = new ArrayList<String>(getOptions()); String mimeType = getMimeType(); if (mimeType != null && mimeType.startsWith("audio/")) { options.add(":sout=#transcode{acodec=vorb,ab=128}:standard{access=http,mux=ogg,dst=0.0.0.0:8000}"); } else { options.add(":sout=#transcode{vcodec=mp4v,vb=384,acodec=mp4a,ab=64,channels=2,fps=25,venc=x264{profile=baseline,keyint=50,bframes=0,no-cabac,ref=1,vbv-maxrate=4096,vbv-bufsize=1024,aq-mode=0,no-mbtree,partitions=none,no-weightb,weightp=0,me=dia,subme=0,no-mixed-refs,no-8x8dct,trellis=0,level1.3},vfilter=canvas{width=320,height=180,aspect=320:180,padd},senc,soverlay}:rtp{sdp=rtsp://0.0.0.0:5554/stream.sdp,caching=4000}}"); } return options; } public Intent getIntentForStreaming(String authority) { Intent intent = new Intent(Intent.ACTION_VIEW); String mimeType = getMimeType(); if (mimeType != null && mimeType.startsWith("audio/")) { Uri.Builder builder = new Uri.Builder(); builder.scheme("rtsp"); builder.encodedAuthority(swapPortNumber(authority, 5554)); builder.path("stream.sdp"); Uri data = builder.build(); intent.setData(data); } else { Uri.Builder builder = new Uri.Builder(); builder.scheme("http"); builder.encodedAuthority(swapPortNumber(authority, 8000)); Uri data = builder.build(); intent.setDataAndType(data, "application/ogg"); } return intent; } public void setPath(String path) { mPath = path; if (mExtension == null && path != null) { mExtension = parseExtension(path); } } public String getName() { return mName; } public void setName(String name) { mName = name; } public String getExtension() { return mExtension; } public void setExtension(String extension) { mExtension = extension; } public String getMimeType() { return getMimeType(mExtension); } public static String getMimeType(String ext) { if (ext != null) { // See http://code.google.com/p/android/issues/detail?id=8806 String extension = ext.toLowerCase(); return sMimeTypeMap.getMimeTypeFromExtension(extension); } else { return null; } } @Override public String toString() { return mName; } private static String removePortNumber(String authority) { int index = authority.lastIndexOf(':'); if (index != -1) { // Remove port number authority = authority.substring(0, index); } return authority; } private static String swapPortNumber(String authority, int port) { return removePortNumber(authority) + ":" + port; } }