some more work ont the video related code, largely related to running on Mac OSX

This commit is contained in:
Knut Forkalsrud 2011-03-13 23:41:05 -07:00
parent e6bad87622
commit ddb7a87e2c
3 changed files with 90 additions and 10 deletions

BIN
photos/salmon.avi Normal file

Binary file not shown.

View file

@ -112,7 +112,7 @@ public class DirectoryEntry extends EntryWithChildren<Entry> {
return props; return props;
} }
DirectoryProps generateCache() throws IOException { DirectoryProps generateCache() throws IOException, InterruptedException {
DirectoryProps props = new DirectoryMetadataGenerator(file).generate(); DirectoryProps props = new DirectoryMetadataGenerator(file).generate();
db.store(file.getAbsolutePath(), props); db.store(file.getAbsolutePath(), props);

View file

@ -3,9 +3,12 @@ package org.forkalsrud.album.exif;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
@ -44,7 +47,7 @@ public class DirectoryMetadataGenerator {
} }
public DirectoryProps generate() throws IOException { public DirectoryProps generate() throws IOException, InterruptedException {
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
DirectoryProps props = new DirectoryProps(); DirectoryProps props = new DirectoryProps();
@ -56,7 +59,7 @@ public class DirectoryMetadataGenerator {
} }
private void generateFileEntries(Properties props) throws IOException { private void generateFileEntries(Properties props) throws IOException, InterruptedException {
File[] files = dir.listFiles(); File[] files = dir.listFiles();
for (File f : files) { for (File f : files) {
@ -80,14 +83,28 @@ public class DirectoryMetadataGenerator {
continue; continue;
} }
if (name.endsWith(".jpg") || name.endsWith(".jpeg") || name.endsWith(".JPG")) { if (name.endsWith(".jpg") || name.endsWith(".jpeg") || name.endsWith(".JPG")) {
String base = "file." + f.getName() + ".";
Map<String, String> p = generateThumbnailProperties(f); Map<String, String> p = generateThumbnailProperties(f);
addPropsForFile(props, f, p);
} else if (name.endsWith(".MOV") || name.endsWith(".mp4") || name.endsWith(".avi")) {
Map<String, String> p = generateVideoProperties(f);
addPropsForFile(props, f, p);
}
}
}
/**
* Adds properties by prefixing each with "file." plus the file name
* @param props all props
* @param f file (to get the name)
* @param p the props to add
*/
private void addPropsForFile(Properties props, File f, Map<String, String> p) {
String base = "file." + f.getName() + ".";
for (Map.Entry<String, String> e : p.entrySet()) { for (Map.Entry<String, String> e : p.entrySet()) {
props.setProperty(base + e.getKey(), e.getValue()); props.setProperty(base + e.getKey(), e.getValue());
} }
} }
}
}
private void generateDirectoryProperties(Properties props, File f) { private void generateDirectoryProperties(Properties props, File f) {
@ -167,20 +184,82 @@ public class DirectoryMetadataGenerator {
return props; return props;
} }
/**
* The crazy Mac OSX does not even set the PATH to a reasonable value, so
* we have to jump through hoops to guess where we may find the executables
* for mplayer and friends.
*
* @param name
* @return
* @throws IOException
* @throws InterruptedException
*/
private String findExecutableInShellPath(String name) throws IOException, InterruptedException {
String executableForName = name;
ProcessBuilder pb = new ProcessBuilder(Arrays.asList(System.getenv("SHELL")));
pb.redirectErrorStream(true); // send errors to stdout
Process p = pb.start();
PrintStream stdin = new PrintStream(p.getOutputStream());
stdin.print("echo $PATH"); // This is still not entirely portable. Windows would like %PATH%
stdin.close();
InputStream stdout = p.getInputStream();
String searchPath = IOUtils.toString(stdout);
int returnStatus = p.waitFor();
String separator = System.getProperty("path.separator");
if (searchPath != null && separator != null && !"".equals(separator)) {
String[] elements = searchPath.split(separator);
for (String path : elements) {
File executable = new File(path, name);
if (executable.isFile()) {
executableForName = executable.getAbsolutePath();
break;
}
}
}
return executableForName;
}
/*
* Transcoding probably needs to go in at some point.
* A suitable command line may be like the one below, as suggested by
* http://rob.opendot.cl/index.php/useful-stuff/ffmpeg-x264-encoding-guide/
* http://rob.opendot.cl/index.php/useful-stuff/encoding-a-flv-video-for-embedded-web-playback/
*
* Assuming video in is 1280x720 pixels resolution and we want to show 640x360
* and we want an output bitrate about 1 Mbit/sec
* we can do a one pass encoding like this:
*
* ffmpeg -i <infile> -aspect 1280:720 -s 640x360 -b 1000000 -crf 25 \
* -vcodec libx264 -vpre knut_low \
* -acodec libfaac -aq 100 \
* <outfile>.mp4
*/
/** /**
* *
* @param f the jpeg file * @param f the movie file
* @return a map with the following keys: orientation dimensions captureDate comment etag * @return a map with the following keys: orientation dimensions captureDate comment etag
* @throws IOException * @throws IOException
* @throws InterruptedException
*/ */
private Map<String, String> generateVideoProperties(File f) throws IOException { private Map<String, String> generateVideoProperties(File f) throws IOException, InterruptedException {
String mplayerExecutable = findExecutableInShellPath("mplayer");
Map<String, String> props = new HashMap<String, String>(); Map<String, String> props = new HashMap<String, String>();
ProcessBuilder pb = new ProcessBuilder().command( ProcessBuilder pb = new ProcessBuilder().command(
"mplayer", "-vo", "null", "-ao", "null", "-frames", "0", "-identify", f.getAbsolutePath()); mplayerExecutable, "-vo", "null", "-ao", "null", "-frames", "0", "-identify", f.getAbsolutePath());
pb.redirectErrorStream(false); pb.redirectErrorStream(false);
Process p = pb.start(); Process p = pb.start();
p.getOutputStream().close(); p.getOutputStream().close();
List<String> lines = IOUtils.readLines(p.getInputStream()); List<String> lines = IOUtils.readLines(p.getInputStream());
int returnStatus = p.waitFor();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-HHmmss"); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-HHmmss");
String width = "", height = ""; String width = "", height = "";
for (String line : lines) { for (String line : lines) {
@ -192,6 +271,7 @@ public class DirectoryMetadataGenerator {
if (name.equals("ID_VIDEO_HEIGHT")) height = value; if (name.equals("ID_VIDEO_HEIGHT")) height = value;
} }
} }
props.put("type", "movie");
props.put("orientation", "1"); props.put("orientation", "1");
props.put("dimensions", new Dimension(width, height).toString()); props.put("dimensions", new Dimension(width, height).toString());
props.put("captureDate", sdf.format(new Date(f.lastModified()))); props.put("captureDate", sdf.format(new Date(f.lastModified())));