Clean up thread synchronization.
Make sure encoder and streamer use same dimension.
This commit is contained in:
parent
e65c87ac86
commit
461adb098f
3 changed files with 68 additions and 60 deletions
|
|
@ -99,4 +99,11 @@ public class Dimension {
|
|||
return outd;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Dimension even() {
|
||||
return new Dimension(this.w % 2 > 0 ? this.w + 1 : this.w,
|
||||
this.h % 2 > 0 ? this.h + 1 : this.h);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -283,18 +283,18 @@ public class MovieCoder {
|
|||
private Chunk currentChunk = null;
|
||||
private int chunkPos;
|
||||
private int remainingCapacity;
|
||||
private int chunkNo = 0;
|
||||
private volatile int chunkInProgress = 0;
|
||||
private volatile int chunkAvailable = 0;
|
||||
private FlvFilter filter;
|
||||
private String dbKey;
|
||||
private long fileTimestamp;
|
||||
private int orientation;
|
||||
private volatile boolean done = false;
|
||||
|
||||
public EncodingProcess(File file, Thumbnail thumbnail, Dimension size) {
|
||||
this.file = file;
|
||||
this.fileTimestamp = file.lastModified();
|
||||
this.targetSize = size;
|
||||
if (targetSize.getWidth() % 2 > 0) targetSize = new Dimension(targetSize.getWidth() + 1, targetSize.getHeight());
|
||||
if (targetSize.getHeight() % 2 > 0) targetSize = new Dimension(targetSize.getWidth(), targetSize.getHeight() + 1);
|
||||
this.targetSize = size.even();
|
||||
this.dbKey = key(file, targetSize);
|
||||
FlvMetadata extraMeta = new FlvMetadata();
|
||||
extraMeta.setDuration(thumbnail.getDuration());
|
||||
|
|
@ -381,36 +381,54 @@ public class MovieCoder {
|
|||
// Generate header again to get updated metadata
|
||||
// TODO (knut 30 JUL 2011) Add some metadata about the file in the first chunk of the file
|
||||
// size of first chunk, size of last chunk, number number of chunks between first-last, size of chunks between first-last
|
||||
// This will be used to determine the right chunk number from a given byte offset in a range oritented HTTP request
|
||||
// This will be used to determine the right chunk number from a given byte offset in a range oriented HTTP request
|
||||
filter.generateHeaderChunk();
|
||||
} catch (Exception e) {
|
||||
log.error("uh?", e);
|
||||
movieDb.delete(dbKey);
|
||||
synchronized (this) {
|
||||
this.chunkAvailable = Integer.MAX_VALUE;
|
||||
}
|
||||
} finally {
|
||||
synchronized (MovieCoder.this) {
|
||||
currentEncodings.remove(key(file, targetSize));
|
||||
}
|
||||
notifyListeners(chunkNo, true);
|
||||
done = true;
|
||||
notifyListeners(chunkAvailable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return number of chunks available.
|
||||
* -Integer.MAX_VALUE if something went very wrong
|
||||
* -1 * number of chunks available when we're done.
|
||||
*/
|
||||
public synchronized int waitForData() {
|
||||
if (!this.done) {
|
||||
try {
|
||||
this.wait(2000L);
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
int numChunks = this.chunkAvailable + 1;
|
||||
return this.done ? -numChunks : numChunks;
|
||||
}
|
||||
|
||||
private synchronized void notifyListeners(int chunkNo) {
|
||||
|
||||
this.chunkAvailable = chunkNo;
|
||||
this.notifyAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeHeader(byte[] data) {
|
||||
int len = data.length;
|
||||
Chunk chunk0 = new Chunk(fileTimestamp, len, 0);
|
||||
chunk0.bits = data;
|
||||
log.info("Writing " + dbKey + " seq 0 (" + chunkInProgress + ") " + data.length);
|
||||
movieDb.store(dbKey, 0, chunk0);
|
||||
notifyListeners(0, false);
|
||||
}
|
||||
|
||||
private void notifyListeners(int chunkNo, boolean end) {
|
||||
for (EncodingProcessListener listener : listeners) {
|
||||
if (end) {
|
||||
listener.codingFinished(chunkNo);
|
||||
} else {
|
||||
listener.chunkAvailable(chunkNo);
|
||||
}
|
||||
}
|
||||
notifyListeners(chunkInProgress);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -440,7 +458,7 @@ public class MovieCoder {
|
|||
|
||||
private void startNewChunk() {
|
||||
|
||||
this.chunkNo++;
|
||||
this.chunkInProgress++;
|
||||
this.currentChunk = new Chunk(fileTimestamp, chunkSize, 0);
|
||||
this.chunkPos = 0;
|
||||
this.remainingCapacity = chunkSize;
|
||||
|
|
@ -448,10 +466,11 @@ public class MovieCoder {
|
|||
|
||||
private void endChunk() {
|
||||
|
||||
log.info("Receiving chunk " + chunkNo);
|
||||
movieDb.store(dbKey, chunkNo, currentChunk);
|
||||
log.info("store chunk " + chunkInProgress);
|
||||
movieDb.store(dbKey, chunkInProgress, currentChunk);
|
||||
log.info("Writing " + dbKey + " seq " + chunkInProgress + " (" + chunkInProgress + ") " + currentChunk.bits.length);
|
||||
currentChunk = null;
|
||||
notifyListeners(chunkNo, false);
|
||||
notifyListeners(chunkInProgress);
|
||||
}
|
||||
|
||||
private void endLastChunk() {
|
||||
|
|
@ -462,16 +481,16 @@ public class MovieCoder {
|
|||
// reallocate
|
||||
Chunk last = new Chunk(fileTimestamp, chunkPos, 0);
|
||||
System.arraycopy(currentChunk.bits, 0, last.bits, 0, chunkPos);
|
||||
movieDb.store(key(file, targetSize), chunkNo, last);
|
||||
movieDb.store(dbKey, chunkInProgress, last);
|
||||
log.info("Writing " + dbKey + " seq " + chunkInProgress + " (" + chunkInProgress + ") " + last.bits.length);
|
||||
currentChunk = null;
|
||||
notifyListeners(chunkNo, true);
|
||||
}
|
||||
|
||||
public synchronized void addListener(EncodingProcessListener videoStreamer) {
|
||||
listeners.add(videoStreamer);
|
||||
}
|
||||
|
||||
public void removeListener(VideoStreamer videoStreamer) {
|
||||
public synchronized void removeListener(VideoStreamer videoStreamer) {
|
||||
listeners.remove(videoStreamer);
|
||||
}
|
||||
}
|
||||
|
|
@ -522,7 +541,7 @@ public class MovieCoder {
|
|||
|
||||
synchronized VideoStreamer grabStream(File file, Thumbnail thumbnail, String size) {
|
||||
|
||||
Dimension targetSize = thumbnail.getSize().scale(size);
|
||||
Dimension targetSize = thumbnail.getSize().scale(size).even();
|
||||
String key = key(file, targetSize);
|
||||
|
||||
// See if we have (at least the beginning of) the file in the DB
|
||||
|
|
@ -547,21 +566,18 @@ public class MovieCoder {
|
|||
}
|
||||
|
||||
|
||||
class VideoStreamer implements EncodingProcessListener {
|
||||
class VideoStreamer {
|
||||
|
||||
private int chunkNo = 0;
|
||||
private int lastChunkNo = -1;
|
||||
private EncodingProcess ep;
|
||||
private Chunk chunk;
|
||||
private String key;
|
||||
private boolean done = false;
|
||||
|
||||
private VideoStreamer(String key, EncodingProcess ep, Chunk chunk0) {
|
||||
this.key = key;
|
||||
this.ep = ep;
|
||||
this.chunk = chunk0;
|
||||
if (ep != null) {
|
||||
ep.addListener(this);
|
||||
}
|
||||
// Range requests can hook in here
|
||||
// if we have chunk metadata in chunk0 we can use that to compute the first
|
||||
// chunk we want and set this.chunkNo accordingly. Otherwise (not likely
|
||||
|
|
@ -571,16 +587,12 @@ public class MovieCoder {
|
|||
// The end of the range is also a matter of counting the bytes.
|
||||
}
|
||||
|
||||
private boolean done() {
|
||||
return lastChunkNo >= 0 && chunkNo > lastChunkNo;
|
||||
}
|
||||
|
||||
public void stream(OutputStream out) throws IOException, InterruptedException {
|
||||
|
||||
while (!done()) {
|
||||
while (!done) {
|
||||
|
||||
if (chunk == null) {
|
||||
log.info("Looking for " + chunkNo);
|
||||
log.info("Looking for " + key + " - " + chunkNo);
|
||||
chunk = movieDb.load(key, chunkNo);
|
||||
}
|
||||
if (chunk != null) {
|
||||
|
|
@ -590,35 +602,23 @@ public class MovieCoder {
|
|||
chunkNo++;
|
||||
continue;
|
||||
}
|
||||
if (!done()) {
|
||||
if (!done) {
|
||||
if (ep != null) {
|
||||
synchronized (this) {
|
||||
wait(2000L);
|
||||
int numChunks = ep.waitForData();
|
||||
System.out.println("Got " + numChunks);
|
||||
if (numChunks < 0) {
|
||||
this.done = true;
|
||||
}
|
||||
} else {
|
||||
// We ran out of chunks, so we must be done.
|
||||
this.done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ep != null) {
|
||||
ep.removeListener(this);
|
||||
}
|
||||
log.info("done sending");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public synchronized void chunkAvailable(int chunkNo) {
|
||||
notify();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void codingFinished(int lastCunkNo) {
|
||||
this.lastChunkNo = lastCunkNo;
|
||||
ep = null;
|
||||
notify();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -466,6 +466,7 @@ public class AlbumServlet
|
|||
boolean notModified(HttpServletRequest req, File f) {
|
||||
long reqDate = req.getDateHeader("If-Modified-Since");
|
||||
long fDate = f.lastModified();
|
||||
System.out.println("reqDate is " + new Date(reqDate) + " fDate is " + new Date(fDate) + " " + req.getHeader("If-Modified-Since"));
|
||||
return reqDate > 0 && fDate > 0 && fDate <= reqDate;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue