Merge branch 'master' of ssh://aha/home/gitroot/album
Conflicts: src/main/java/org/forkalsrud/album/video/MovieCoder.java
This commit is contained in:
commit
984bc2f72c
8 changed files with 266 additions and 33 deletions
170
src/main/java/org/forkalsrud/album/video/FlvFilter.java
Normal file
170
src/main/java/org/forkalsrud/album/video/FlvFilter.java
Normal file
|
|
@ -0,0 +1,170 @@
|
||||||
|
package org.forkalsrud.album.video;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Separates the FLV header boxes from the body boxes.
|
||||||
|
* After streaming a file through the header can be rewritten with metadata appropriate for streaming.
|
||||||
|
*/
|
||||||
|
public class FlvFilter extends OutputStream {
|
||||||
|
|
||||||
|
private static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(FlvFilter.class);
|
||||||
|
|
||||||
|
private final static int FLV_SIZE_TAGHEADER = 11;
|
||||||
|
private final static int FLV_SIZE_TAGFOOTER = 4;
|
||||||
|
private final static int FLV_SIZE_FILEHEADER = 13;
|
||||||
|
|
||||||
|
private final static int FLV_TAG_AUDIO = 8;
|
||||||
|
private final static int FLV_TAG_VIDEO = 9;
|
||||||
|
private final static int FLV_TAG_SCRIPTDATA = 18;
|
||||||
|
|
||||||
|
private OutputStream headerDst;
|
||||||
|
private OutputStream bodyDst;
|
||||||
|
|
||||||
|
private byte[] fileHeader = new byte[FLV_SIZE_FILEHEADER];
|
||||||
|
private int byteCounter = 0;
|
||||||
|
private byte[] currentBoxHeader = new byte[FLV_SIZE_TAGHEADER];
|
||||||
|
private int currentBoxWriteIdx = 0;
|
||||||
|
|
||||||
|
private int currentTagPos;
|
||||||
|
private int currentTagType;
|
||||||
|
private int currentDataSize;
|
||||||
|
private int currentTagTimestamp;
|
||||||
|
|
||||||
|
private int currentTagSize;
|
||||||
|
private byte[] currentBox;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive some bytes of FLV output
|
||||||
|
* @param b
|
||||||
|
* @param off
|
||||||
|
* @param len
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void write(byte[] b, int off, int len) throws IOException {
|
||||||
|
|
||||||
|
// stateful
|
||||||
|
// initially we receive the header 'FLV.....'
|
||||||
|
// then we receive one box after another
|
||||||
|
// if a box can be classified as a header we write it to header dst
|
||||||
|
// else it is for body dst
|
||||||
|
int remainingInputLength = len;
|
||||||
|
int readOffset = off;
|
||||||
|
if (byteCounter < FLV_SIZE_FILEHEADER) {
|
||||||
|
int headerBytesToRead = Math.min(FLV_SIZE_FILEHEADER - byteCounter, remainingInputLength);
|
||||||
|
for (int i = 0; i < headerBytesToRead; i++) {
|
||||||
|
fileHeader[byteCounter++] = b[readOffset++];
|
||||||
|
}
|
||||||
|
remainingInputLength -= headerBytesToRead;
|
||||||
|
currentTagPos = byteCounter;
|
||||||
|
}
|
||||||
|
while (remainingInputLength > 0) {
|
||||||
|
// read the header first
|
||||||
|
if (currentBoxWriteIdx < FLV_SIZE_TAGHEADER) {
|
||||||
|
int headerBytesToRead = Math.min(FLV_SIZE_TAGHEADER - currentBoxWriteIdx, remainingInputLength);
|
||||||
|
for (int i = 0; i < headerBytesToRead; i++) {
|
||||||
|
currentBoxHeader[currentBoxWriteIdx++] = b[readOffset++];
|
||||||
|
byteCounter++;
|
||||||
|
}
|
||||||
|
remainingInputLength -= headerBytesToRead;
|
||||||
|
if (currentBoxWriteIdx < FLV_SIZE_TAGHEADER) {
|
||||||
|
// Don't have a full header yet, wait for next
|
||||||
|
if (remainingInputLength > 0) {
|
||||||
|
throw new RuntimeException("something is off in the lengths we're trying to read");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Got the header, prepare the buffer for the entire box
|
||||||
|
currentTagType = decodeUint8(currentBoxHeader, 0);
|
||||||
|
currentDataSize = decodeUint24(currentBoxHeader, 1);
|
||||||
|
currentTagTimestamp = decodeTimestamp(currentBoxHeader, 4);
|
||||||
|
currentTagSize = currentDataSize + FLV_SIZE_TAGHEADER + FLV_SIZE_TAGFOOTER;
|
||||||
|
currentBox = new byte[currentTagSize];
|
||||||
|
for (int i = 0; i < FLV_SIZE_TAGHEADER; i++) {
|
||||||
|
currentBox[i] = currentBoxHeader[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int bodyBytesToRead = Math.min(currentTagSize - currentBoxWriteIdx, remainingInputLength);
|
||||||
|
for (int i = 0; i < bodyBytesToRead; i++) {
|
||||||
|
currentBox[currentBoxWriteIdx++] = b[readOffset++];
|
||||||
|
byteCounter++;
|
||||||
|
}
|
||||||
|
remainingInputLength -= bodyBytesToRead;
|
||||||
|
if (currentBoxWriteIdx < currentTagSize) {
|
||||||
|
if (remainingInputLength > 0) {
|
||||||
|
throw new RuntimeException("something is off in the lengths we're trying to read");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
processBox();
|
||||||
|
currentTagType = 0;
|
||||||
|
currentDataSize = 0;
|
||||||
|
currentTagTimestamp = 0;
|
||||||
|
currentTagSize = 0;
|
||||||
|
currentBox = null;
|
||||||
|
currentBoxWriteIdx = 0;
|
||||||
|
Arrays.fill(currentBoxHeader, (byte)0);
|
||||||
|
currentTagPos = byteCounter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void processBox() {
|
||||||
|
|
||||||
|
switch (currentTagType) {
|
||||||
|
case FLV_TAG_VIDEO:
|
||||||
|
int flags = decodeUint8(currentBox, FLV_SIZE_TAGHEADER);
|
||||||
|
boolean isKeyFrame = ((flags >> 4) & 0xf) == 1;
|
||||||
|
if (isKeyFrame) {
|
||||||
|
log.info("Keyframe ts " + currentTagTimestamp + " @ " + currentTagPos + " (" + (currentTagPos + currentTagSize) + ")");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FLV_TAG_SCRIPTDATA:
|
||||||
|
log.info("SCRIPTDATA @ " + currentTagPos + " - len: " + currentTagSize);
|
||||||
|
break;
|
||||||
|
case FLV_TAG_AUDIO:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log.error("Unknown box type: " + currentTagType);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int decodeUint32(byte[] buf, int offset) {
|
||||||
|
int ch1 = buf[offset + 0] & 0xff;
|
||||||
|
int ch2 = buf[offset + 1] & 0xff;
|
||||||
|
int ch3 = buf[offset + 2] & 0xff;
|
||||||
|
int ch4 = buf[offset + 3] & 0xff;
|
||||||
|
return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
int decodeUint24(byte[] buf, int offset) {
|
||||||
|
int ch1 = buf[offset + 0] & 0xff;
|
||||||
|
int ch2 = buf[offset + 1] & 0xff;
|
||||||
|
int ch3 = buf[offset + 2] & 0xff;
|
||||||
|
return ((ch1 << 16) + (ch2 << 8) + (ch3 << 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
int decodeUint8(byte[] buf, int offset) {
|
||||||
|
return buf[offset] & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
int decodeTimestamp(byte[] buf, int offset) {
|
||||||
|
int ch1 = buf[offset + 0] & 0xff;
|
||||||
|
int ch2 = buf[offset + 1] & 0xff;
|
||||||
|
int ch3 = buf[offset + 2] & 0xff;
|
||||||
|
int ch4 = buf[offset + 3] & 0xff;
|
||||||
|
return ((ch4 << 24) + (ch1 << 16) + (ch2 << 8) + (ch3 << 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(int b) throws IOException {
|
||||||
|
write(new byte[] { (byte)b });
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -16,8 +16,8 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.forkalsrud.album.db.MovieDatabase;
|
|
||||||
import org.forkalsrud.album.db.Chunk;
|
import org.forkalsrud.album.db.Chunk;
|
||||||
|
import org.forkalsrud.album.db.MovieDatabase;
|
||||||
import org.forkalsrud.album.exif.Dimension;
|
import org.forkalsrud.album.exif.Dimension;
|
||||||
import org.forkalsrud.album.exif.Thumbnail;
|
import org.forkalsrud.album.exif.Thumbnail;
|
||||||
import org.forkalsrud.album.web.CachedImage;
|
import org.forkalsrud.album.web.CachedImage;
|
||||||
|
|
@ -64,7 +64,7 @@ public class MovieCoder {
|
||||||
stdin.close();
|
stdin.close();
|
||||||
InputStream stdout = p.getInputStream();
|
InputStream stdout = p.getInputStream();
|
||||||
String searchPath = IOUtils.toString(stdout);
|
String searchPath = IOUtils.toString(stdout);
|
||||||
int returnStatus = p.waitFor();
|
p.waitFor();
|
||||||
|
|
||||||
String separator = System.getProperty("path.separator");
|
String separator = System.getProperty("path.separator");
|
||||||
if (searchPath != null && separator != null && !"".equals(separator)) {
|
if (searchPath != null && separator != null && !"".equals(separator)) {
|
||||||
|
|
@ -100,7 +100,7 @@ public class MovieCoder {
|
||||||
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();
|
p.waitFor();
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-HHmmss");
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-HHmmss");
|
||||||
String width = "", height = "", length = "";
|
String width = "", height = "", length = "";
|
||||||
for (String line : lines) {
|
for (String line : lines) {
|
||||||
|
|
@ -155,9 +155,7 @@ public class MovieCoder {
|
||||||
Process p = pb.start();
|
Process p = pb.start();
|
||||||
p.getOutputStream().close();
|
p.getOutputStream().close();
|
||||||
log.debug(IOUtils.toString(p.getInputStream()));
|
log.debug(IOUtils.toString(p.getInputStream()));
|
||||||
int returnStatus = p.waitFor();
|
p.waitFor();
|
||||||
|
|
||||||
String key = file.getPath() + ":" + secondNo + ":" + size;
|
|
||||||
CachedImage ci = pictureScaler.scalePicture(frame, thumbnail, size);
|
CachedImage ci = pictureScaler.scalePicture(frame, thumbnail, size);
|
||||||
return ci;
|
return ci;
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -267,6 +265,7 @@ public class MovieCoder {
|
||||||
* <outfile>.mp4
|
* <outfile>.mp4
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -357,7 +356,7 @@ public class MovieCoder {
|
||||||
System.out.println("being asked to stream " + file + " size=" + size);
|
System.out.println("being asked to stream " + file + " size=" + size);
|
||||||
Dimension targetSize = thumbnail.getSize().scale(size);
|
Dimension targetSize = thumbnail.getSize().scale(size);
|
||||||
new EncodingProcess(file, thumbnail, targetSize).streamTo(out);
|
new EncodingProcess(file, thumbnail, targetSize).streamTo(out);
|
||||||
/*
|
/*
|
||||||
String key = file.getPath() + ":" + targetSize.getWidth();
|
String key = file.getPath() + ":" + targetSize.getWidth();
|
||||||
int chunkNo = 0;
|
int chunkNo = 0;
|
||||||
boolean done = false;
|
boolean done = false;
|
||||||
|
|
@ -368,7 +367,7 @@ System.out.println("being asked to stream " + file + " size=" + size);
|
||||||
}
|
}
|
||||||
out.write(chunk.bits);
|
out.write(chunk.bits);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -296,11 +296,41 @@ public class AlbumServlet
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleMovieFrame(HttpServletRequest req, HttpServletResponse res, FileEntry entry) {
|
void handleMovieFrame(HttpServletRequest req, HttpServletResponse res, FileEntry entry) {
|
||||||
try {
|
|
||||||
|
File file = entry.getPath();
|
||||||
|
if (notModified(req, file)) {
|
||||||
|
res.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
|
||||||
|
res.setDateHeader("Expires", System.currentTimeMillis() + (30 * 24 * 3600 * 1000L)); // 30 days
|
||||||
|
log.info(file.getName() + " not modified (based on date)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int secondNo = 3;
|
||||||
String size = req.getParameter("size");
|
String size = req.getParameter("size");
|
||||||
CachedImage cimg = movieCoder.extractFrame(entry.getPath(), 3, entry.getThumbnail(), size != null ? size : "250");
|
if (size == null) {
|
||||||
|
size = "250";
|
||||||
|
}
|
||||||
|
String key = file.getPath() + ":" + secondNo + ":" + size;
|
||||||
|
CachedImage cimg = thumbDb.load(key);
|
||||||
|
if (cimg != null) {
|
||||||
|
if (cimg.lastModified == file.lastModified()) {
|
||||||
|
log.info("cache hit on " + key);
|
||||||
|
} else {
|
||||||
|
log.info(" " + key + " has changed so cache entry wil be refreshed");
|
||||||
|
cimg = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cimg == null) {
|
||||||
|
try {
|
||||||
|
cimg = movieCoder.extractFrame(file, secondNo, entry.getThumbnail(), size);
|
||||||
|
thumbDb.store(key, cimg);
|
||||||
|
log.info(" " + key + " added to the cache with size " + cimg.bits.length + " -- now " + thumbDb.size() + " entries");
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("sadness", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
res.setStatus(HttpServletResponse.SC_OK);
|
res.setStatus(HttpServletResponse.SC_OK);
|
||||||
res.setDateHeader("Last-Modified", entry.getPath().lastModified());
|
res.setDateHeader("Last-Modified", file.lastModified());
|
||||||
res.setDateHeader("Expires", System.currentTimeMillis() + (30 * 24 * 3600 * 1000L)); // 30 days
|
res.setDateHeader("Expires", System.currentTimeMillis() + (30 * 24 * 3600 * 1000L)); // 30 days
|
||||||
res.setContentType(cimg.mimeType);
|
res.setContentType(cimg.mimeType);
|
||||||
res.setContentLength(cimg.bits.length);
|
res.setContentLength(cimg.bits.length);
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,7 @@ public class PictureScaler {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
public CachedImage call() throws Exception {
|
public CachedImage call() throws Exception {
|
||||||
return scalePictureReally(file, thumbnail, size);
|
return scalePictureReally(file, thumbnail, size);
|
||||||
}
|
}
|
||||||
|
|
@ -108,6 +109,7 @@ public class PictureScaler {
|
||||||
|
|
||||||
return new Comparator<PictureRequest>() {
|
return new Comparator<PictureRequest>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
public int compare(PictureRequest o1, PictureRequest o2) {
|
public int compare(PictureRequest o1, PictureRequest o2) {
|
||||||
return Long.signum(o1.priority - o2.priority);
|
return Long.signum(o1.priority - o2.priority);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ $(document).ready(function() {
|
||||||
return captionElement.innerHTML;
|
return captionElement.innerHTML;
|
||||||
}
|
}
|
||||||
var selectedImg = window.location.search;
|
var selectedImg = window.location.search;
|
||||||
var selectedPos;
|
var selectedPos = undefined;
|
||||||
if (/^\?focus=/.test(selectedImg)) {
|
if (/^\?focus=/.test(selectedImg)) {
|
||||||
selectedImg = selectedImg.substring('?focus='.length);
|
selectedImg = selectedImg.substring('?focus='.length);
|
||||||
$("a.ss").each(function(index) {
|
$("a.ss").each(function(index) {
|
||||||
|
|
@ -98,7 +98,7 @@ $(document).ready(function() {
|
||||||
'easingOut' : 'easeOutQuad',
|
'easingOut' : 'easeOutQuad',
|
||||||
'titleFormat' : formatTitle
|
'titleFormat' : formatTitle
|
||||||
});
|
});
|
||||||
if (selectedPos) {
|
if (selectedPos !== undefined) {
|
||||||
$(gallery[selectedPos]).trigger('click');
|
$(gallery[selectedPos]).trigger('click');
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -98,14 +98,18 @@ $(function() {
|
||||||
|
|
||||||
$("#name").html(data.name);
|
$("#name").html(data.name);
|
||||||
|
|
||||||
|
var thmb = 250;
|
||||||
|
var picSize = 800;
|
||||||
|
var movieSize = 640;
|
||||||
|
|
||||||
$.each(data.contents, function(idx, entry) {
|
$.each(data.contents, function(idx, entry) {
|
||||||
|
|
||||||
var dim = scale(entry.width, entry.height, 250);
|
var dim = scale(entry.width, entry.height, thmb);
|
||||||
|
|
||||||
var gridDiv = $("<div class=\"grid\">\n"
|
var gridDiv = $("<div class=\"grid\">\n"
|
||||||
+ " <span class=\"name\">" + entry.name + "</span><br/>\n"
|
+ " <span class=\"name\">" + entry.name + "</span><br/>\n"
|
||||||
+ " <div class=\"imgborder\"><a class=\"ss\" id=\"ent" + idx + "\" href=\"album" + entry.path + "?size=800\" title=\"" + entry.name + "\">"
|
+ " <div class=\"imgborder\"><a class=\"ss\" id=\"ent" + idx + "\" href=\"album" + entry.path + "?size=" + picSize + "\" title=\"" + entry.name + "\">"
|
||||||
+ "<img class=\"picture\" src=\"album" + (entry.type == "movie" ? entry.path + ".frame" : entry.path) + "?size=250\" border=\"0\" width=\"" + dim.w + "\" height=\"" + dim.h + "\"/></a></div>\n"
|
+ "<img class=\"picture\" src=\"album" + (entry.type == "movie" ? entry.path + ".frame" : entry.path) + "?size=" + thmb + "\" border=\"0\" width=\"" + dim.w + "\" height=\"" + dim.h + "\"/></a></div>\n"
|
||||||
+ "<p id=\"" + entry.name + "\" class=\"caption\"></p>\n"
|
+ "<p id=\"" + entry.name + "\" class=\"caption\"></p>\n"
|
||||||
+ "</div>\n");
|
+ "</div>\n");
|
||||||
gridDiv.appendTo('body');
|
gridDiv.appendTo('body');
|
||||||
|
|
@ -116,7 +120,9 @@ $(function() {
|
||||||
|
|
||||||
switch (entry.type) {
|
switch (entry.type) {
|
||||||
case "movie":
|
case "movie":
|
||||||
$("#ent" + idx).attr("rel", "album").attr("href", "/album" + entry.path + ".movie?size=640").fancybox({
|
var size = scale(entry.width, entry.height, movieSize);
|
||||||
|
var href = "album" + escape(entry.path) + ".movie?size=" + movieSize;
|
||||||
|
$("#ent" + idx).attr("rel", "album").attr("href", href).fancybox({
|
||||||
'titlePosition' : 'inside',
|
'titlePosition' : 'inside',
|
||||||
'transitionIn' : 'elastic',
|
'transitionIn' : 'elastic',
|
||||||
'transitionOut' : 'elastic',
|
'transitionOut' : 'elastic',
|
||||||
|
|
@ -125,17 +131,23 @@ $(function() {
|
||||||
'titleFormat' : formatTitle,
|
'titleFormat' : formatTitle,
|
||||||
'padding' : 0,
|
'padding' : 0,
|
||||||
'href' : "assets/flowplayer/flowplayer-3.0.3.swf",
|
'href' : "assets/flowplayer/flowplayer-3.0.3.swf",
|
||||||
'width' : entry.width,
|
'width' : size.w,
|
||||||
'height' : entry.height,
|
'height' : size.h,
|
||||||
'type' : 'swf',
|
'type' : 'swf',
|
||||||
'swf' : {
|
'swf' : {
|
||||||
'allowfullscreen' : 'true',
|
'allowfullscreen' : 'true',
|
||||||
'wmode' : 'transparent',
|
'wmode' : 'transparent',
|
||||||
'flashvars':
|
'flashvars':
|
||||||
"config={ 'clip': { 'url': '/album" + escape(entry.path) + ".movie?size=640' },\
|
"config={\
|
||||||
|
'clip': {\
|
||||||
|
'url': '" + href + "'\
|
||||||
|
},\
|
||||||
|
'plugins': {\
|
||||||
'controls': {\
|
'controls': {\
|
||||||
'url': 'assets/flowplayer/flowplayer.controls-3.0.3.swf',\
|
'url': 'assets/flowplayer/flowplayer.controls-3.0.3.swf',\
|
||||||
'backgroundColor': 'transparent', 'progressColor': 'transparent', 'bufferColor': 'transparent',\
|
'backgroundColor': 'transparent',\
|
||||||
|
'progressColor': 'transparent',\
|
||||||
|
'bufferColor': 'transparent',\
|
||||||
'play':true,\
|
'play':true,\
|
||||||
'fullscreen':true,\
|
'fullscreen':true,\
|
||||||
'autoHide': 'always'\
|
'autoHide': 'always'\
|
||||||
|
|
@ -146,7 +158,7 @@ $(function() {
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "image":
|
case "image":
|
||||||
var largeDim = scale(entry.width, entry.height, 800);
|
var largeDim = scale(entry.width, entry.height, picSize);
|
||||||
$("#ent" + idx).attr("rel", "album").fancybox({
|
$("#ent" + idx).attr("rel", "album").fancybox({
|
||||||
'titlePosition' : 'inside',
|
'titlePosition' : 'inside',
|
||||||
'transitionIn' : 'elastic',
|
'transitionIn' : 'elastic',
|
||||||
|
|
@ -168,7 +180,7 @@ $(function() {
|
||||||
|
|
||||||
|
|
||||||
var selectedImg = window.location.search;
|
var selectedImg = window.location.search;
|
||||||
var selectedPos;
|
var selectedPos = undefined;
|
||||||
if (/^\?focus=/.test(selectedImg)) {
|
if (/^\?focus=/.test(selectedImg)) {
|
||||||
selectedImg = selectedImg.substring('?focus='.length);
|
selectedImg = selectedImg.substring('?focus='.length);
|
||||||
$("a.ss").each(function(index) {
|
$("a.ss").each(function(index) {
|
||||||
|
|
@ -179,7 +191,7 @@ $(function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (selectedPos) {
|
if (selectedPos !== undefined) {
|
||||||
$(gallery[selectedPos]).trigger('click');
|
$(gallery[selectedPos]).trigger('click');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
20
src/test/java/org/forkalsrud/album/video/FlvFilterTest.java
Normal file
20
src/test/java/org/forkalsrud/album/video/FlvFilterTest.java
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
package org.forkalsrud.album.video;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
|
||||||
|
public class FlvFilterTest extends TestCase {
|
||||||
|
|
||||||
|
public void testWrite() throws IOException {
|
||||||
|
|
||||||
|
InputStream is = getClass().getResourceAsStream("VideoAd.flv");
|
||||||
|
OutputStream os = new FlvFilter();
|
||||||
|
IOUtils.copy(is, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
BIN
src/test/java/org/forkalsrud/album/video/VideoAd.flv
Normal file
BIN
src/test/java/org/forkalsrud/album/video/VideoAd.flv
Normal file
Binary file not shown.
Loading…
Add table
Reference in a new issue