Debugging more video streaming. Works without regenerating onMetadata.
This commit is contained in:
parent
494c0e5930
commit
a58b074873
4 changed files with 60 additions and 22 deletions
|
|
@ -46,6 +46,7 @@ public class FlvFilter extends OutputStream {
|
||||||
|
|
||||||
private FlvMetadata metadata;
|
private FlvMetadata metadata;
|
||||||
private FlvMetadata extraMetadata;
|
private FlvMetadata extraMetadata;
|
||||||
|
private int bodyLen = 0;
|
||||||
|
|
||||||
public FlvFilter(FlvReceiver receiver, FlvMetadata metadata) {
|
public FlvFilter(FlvReceiver receiver, FlvMetadata metadata) {
|
||||||
this.receiver = receiver;
|
this.receiver = receiver;
|
||||||
|
|
@ -151,7 +152,7 @@ public class FlvFilter extends OutputStream {
|
||||||
headerWritten = true;
|
headerWritten = true;
|
||||||
} else {
|
} else {
|
||||||
log.warn("SCRIPTDATA out of order");
|
log.warn("SCRIPTDATA out of order");
|
||||||
receiver.writeBody(currentBox);
|
writeBody();
|
||||||
}
|
}
|
||||||
} else if (currentTagType == FLV_TAG_VIDEO || currentTagType == FLV_TAG_AUDIO) {
|
} else if (currentTagType == FLV_TAG_VIDEO || currentTagType == FLV_TAG_AUDIO) {
|
||||||
if (!headerWritten) {
|
if (!headerWritten) {
|
||||||
|
|
@ -166,14 +167,21 @@ public class FlvFilter extends OutputStream {
|
||||||
} else { // currentTagType == FLV_TAG_AUDIO
|
} else { // currentTagType == FLV_TAG_AUDIO
|
||||||
metadata.addAudioFrame(currentTagPos, currentTagTimestamp);
|
metadata.addAudioFrame(currentTagPos, currentTagTimestamp);
|
||||||
}
|
}
|
||||||
receiver.writeBody(currentBox);
|
writeBody();
|
||||||
metadata.setFileSize(currentTagPos + currentTagSize);
|
|
||||||
} else {
|
} else {
|
||||||
log.error("Unknown box type: " + currentTagType);
|
log.error("Unknown box type: " + currentTagType);
|
||||||
receiver.writeBody(currentBox);
|
writeBody();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private void writeBody() {
|
||||||
|
receiver.writeBody(currentBox);
|
||||||
|
bodyLen += currentBox.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void flush() throws IOException {
|
public void flush() throws IOException {
|
||||||
|
|
@ -184,9 +192,11 @@ public class FlvFilter extends OutputStream {
|
||||||
|
|
||||||
public void generateHeader() throws IOException {
|
public void generateHeader() throws IOException {
|
||||||
|
|
||||||
|
metadata.setFileSize(fileHeader.length + incomingMetadataLength + bodyLen);
|
||||||
int metadataLength = metadata.calculateLength();
|
int metadataLength = metadata.calculateLength();
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream(fileHeader.length + metadataLength);
|
ByteArrayOutputStream out = new ByteArrayOutputStream(fileHeader.length + metadataLength);
|
||||||
out.write(fileHeader);
|
out.write(fileHeader);
|
||||||
|
metadata.setFileSize(fileHeader.length + metadataLength + bodyLen);
|
||||||
metadata.setFileOffsetDelta(metadataLength - incomingMetadataLength);
|
metadata.setFileOffsetDelta(metadataLength - incomingMetadataLength);
|
||||||
metadata.writeOnMetadata(out);
|
metadata.writeOnMetadata(out);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -149,17 +149,17 @@ public class MovieCoder {
|
||||||
|
|
||||||
class EncodingProcess implements Runnable, FlvFilter.FlvReceiver {
|
class EncodingProcess implements Runnable, FlvFilter.FlvReceiver {
|
||||||
|
|
||||||
final int chunkSize = 4 * 65536;
|
private final int chunkSize = 4 * 65536;
|
||||||
File file;
|
private File file;
|
||||||
Thumbnail thumbnail;
|
private Thumbnail thumbnail;
|
||||||
Dimension targetSize;
|
private Dimension targetSize;
|
||||||
ArrayList<EncodingProcessListener> listeners = new ArrayList<EncodingProcessListener>();
|
private ArrayList<EncodingProcessListener> listeners = new ArrayList<EncodingProcessListener>();
|
||||||
Chunk currentChunk = null;
|
private Chunk currentChunk = null;
|
||||||
int chunkPos;
|
private int chunkPos;
|
||||||
int remainingCapacity;
|
private int remainingCapacity;
|
||||||
int chunkNo = 0;
|
private int chunkNo = 0;
|
||||||
FlvFilter filter;
|
private FlvFilter filter;
|
||||||
String dbKey;
|
private String dbKey;
|
||||||
|
|
||||||
public EncodingProcess(File file, Thumbnail thumbnail, Dimension size) {
|
public EncodingProcess(File file, Thumbnail thumbnail, Dimension size) {
|
||||||
this.file = file;
|
this.file = file;
|
||||||
|
|
@ -219,7 +219,7 @@ public class MovieCoder {
|
||||||
p.getOutputStream().close();
|
p.getOutputStream().close();
|
||||||
InputStream movieStream = p.getInputStream();
|
InputStream movieStream = p.getInputStream();
|
||||||
InputStream diagnostic = p.getErrorStream();
|
InputStream diagnostic = p.getErrorStream();
|
||||||
new Thread(new ErrorStreamPumper(diagnostic)).start();
|
new Thread(new ErrorStreamPumper("ffmpeg", diagnostic)).start();
|
||||||
|
|
||||||
byte[] buffer = new byte[65536];
|
byte[] buffer = new byte[65536];
|
||||||
int len;
|
int len;
|
||||||
|
|
@ -228,6 +228,9 @@ public class MovieCoder {
|
||||||
}
|
}
|
||||||
filter.flush();
|
filter.flush();
|
||||||
endLastChunk();
|
endLastChunk();
|
||||||
|
// Generate header again to get updated metadata
|
||||||
|
// TODO (knut 09 JUL 2011) Figure out why the generated header doesn't work
|
||||||
|
// filter.generateHeader();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("uh?", e);
|
log.error("uh?", e);
|
||||||
movieDb.delete(dbKey);
|
movieDb.delete(dbKey);
|
||||||
|
|
@ -282,6 +285,7 @@ public class MovieCoder {
|
||||||
System.arraycopy(data, inputPos, currentChunk.bits, chunkPos, copyLen);
|
System.arraycopy(data, inputPos, currentChunk.bits, chunkPos, copyLen);
|
||||||
chunkPos += copyLen;
|
chunkPos += copyLen;
|
||||||
remainingCapacity -= copyLen;
|
remainingCapacity -= copyLen;
|
||||||
|
inputPos += copyLen;
|
||||||
remainingInput -= copyLen;
|
remainingInput -= copyLen;
|
||||||
if (remainingCapacity == 0) {
|
if (remainingCapacity == 0) {
|
||||||
endChunk();
|
endChunk();
|
||||||
|
|
@ -299,6 +303,7 @@ public class MovieCoder {
|
||||||
|
|
||||||
private void endChunk() {
|
private void endChunk() {
|
||||||
|
|
||||||
|
log.info("Receiving chunk " + chunkNo);
|
||||||
movieDb.store(dbKey, chunkNo, currentChunk);
|
movieDb.store(dbKey, chunkNo, currentChunk);
|
||||||
currentChunk = null;
|
currentChunk = null;
|
||||||
notifyListeners(chunkNo, false);
|
notifyListeners(chunkNo, false);
|
||||||
|
|
@ -328,18 +333,22 @@ public class MovieCoder {
|
||||||
|
|
||||||
class ErrorStreamPumper implements Runnable {
|
class ErrorStreamPumper implements Runnable {
|
||||||
|
|
||||||
InputStream is;
|
private InputStream is;
|
||||||
public ErrorStreamPumper(InputStream is) {
|
private String name;
|
||||||
|
|
||||||
|
public ErrorStreamPumper(String processName, InputStream is) {
|
||||||
|
this.name = processName;
|
||||||
this.is = is;
|
this.is = is;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
org.slf4j.Logger diag = org.slf4j.LoggerFactory.getLogger(this.name);
|
||||||
try {
|
try {
|
||||||
LineNumberReader lnr = new LineNumberReader(new InputStreamReader(is));
|
LineNumberReader lnr = new LineNumberReader(new InputStreamReader(is));
|
||||||
String line;
|
String line;
|
||||||
while ((line = lnr.readLine()) != null) {
|
while ((line = lnr.readLine()) != null) {
|
||||||
log.info(line);
|
diag.info(line);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("stderr?", e);
|
log.error("stderr?", e);
|
||||||
|
|
@ -352,7 +361,11 @@ public class MovieCoder {
|
||||||
// range requests etcetera
|
// range requests etcetera
|
||||||
public void stream(File file, Thumbnail thumbnail, String size, OutputStream out) throws IOException, InterruptedException {
|
public void stream(File file, Thumbnail thumbnail, String size, OutputStream out) throws IOException, InterruptedException {
|
||||||
|
|
||||||
|
try {
|
||||||
grabStream(file, thumbnail, size).stream(out);
|
grabStream(file, thumbnail, size).stream(out);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("stream fail", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String key(File file, Dimension size) {
|
private static String key(File file, Dimension size) {
|
||||||
|
|
@ -412,9 +425,17 @@ public class MovieCoder {
|
||||||
public void stream(OutputStream out) throws IOException, InterruptedException {
|
public void stream(OutputStream out) throws IOException, InterruptedException {
|
||||||
|
|
||||||
while (!done()) {
|
while (!done()) {
|
||||||
while (chunk != null) {
|
|
||||||
|
if (chunk == null) {
|
||||||
|
log.info("Looking for " + chunkNo);
|
||||||
|
chunk = movieDb.load(key, chunkNo);
|
||||||
|
}
|
||||||
|
if (chunk != null) {
|
||||||
|
log.info("Sending " + chunkNo + ", " + chunk.bits.length + " bytes");
|
||||||
out.write(chunk.bits);
|
out.write(chunk.bits);
|
||||||
chunk = movieDb.load(key, ++chunkNo);
|
chunk = null;
|
||||||
|
chunkNo++;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (!done()) {
|
if (!done()) {
|
||||||
if (ep != null) {
|
if (ep != null) {
|
||||||
|
|
@ -430,6 +451,7 @@ public class MovieCoder {
|
||||||
if (ep != null) {
|
if (ep != null) {
|
||||||
ep.removeListener(this);
|
ep.removeListener(this);
|
||||||
}
|
}
|
||||||
|
log.info("done sending");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -344,8 +344,11 @@ public class AlbumServlet
|
||||||
try {
|
try {
|
||||||
String size = req.getParameter("size");
|
String size = req.getParameter("size");
|
||||||
res.setStatus(HttpServletResponse.SC_OK);
|
res.setStatus(HttpServletResponse.SC_OK);
|
||||||
|
/*
|
||||||
res.setDateHeader("Last-Modified", entry.getPath().lastModified());
|
res.setDateHeader("Last-Modified", entry.getPath().lastModified());
|
||||||
res.setDateHeader("Expires", System.currentTimeMillis() + (30 * 24 * 3600 * 1000L)); // 30 days
|
res.setDateHeader("Expires", System.currentTimeMillis() + (30 * 24 * 3600 * 1000L)); // 30 days
|
||||||
|
*/
|
||||||
|
res.setHeader("Cache-control", "no-cache");
|
||||||
res.setContentType("video/x-flv");
|
res.setContentType("video/x-flv");
|
||||||
movieCoder.stream(entry.getPath(), entry.getThumbnail(), size, res.getOutputStream());
|
movieCoder.stream(entry.getPath(), entry.getThumbnail(), size, res.getOutputStream());
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
|
|
|
||||||
|
|
@ -37,4 +37,7 @@ public class FlvFilterTest extends TestCase {
|
||||||
assertEquals("HEADER[252]BODY[0]HEADER[579]BODY[911684]", buf.toString());
|
assertEquals("HEADER[252]BODY[0]HEADER[579]BODY[911684]", buf.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testFoo() {
|
||||||
|
System.out.println(0x40128);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue