From a58b0748738ceb04b3316a344193df4f211f1b3f Mon Sep 17 00:00:00 2001 From: Knut Forkalsrud Date: Sat, 9 Jul 2011 18:19:48 -0700 Subject: [PATCH] Debugging more video streaming. Works without regenerating onMetadata. --- .../org/forkalsrud/album/video/FlvFilter.java | 18 ++++-- .../forkalsrud/album/video/MovieCoder.java | 58 +++++++++++++------ .../forkalsrud/album/web/AlbumServlet.java | 3 + .../forkalsrud/album/video/FlvFilterTest.java | 3 + 4 files changed, 60 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/forkalsrud/album/video/FlvFilter.java b/src/main/java/org/forkalsrud/album/video/FlvFilter.java index 0fc2c35..6439cda 100644 --- a/src/main/java/org/forkalsrud/album/video/FlvFilter.java +++ b/src/main/java/org/forkalsrud/album/video/FlvFilter.java @@ -46,6 +46,7 @@ public class FlvFilter extends OutputStream { private FlvMetadata metadata; private FlvMetadata extraMetadata; + private int bodyLen = 0; public FlvFilter(FlvReceiver receiver, FlvMetadata metadata) { this.receiver = receiver; @@ -151,7 +152,7 @@ public class FlvFilter extends OutputStream { headerWritten = true; } else { log.warn("SCRIPTDATA out of order"); - receiver.writeBody(currentBox); + writeBody(); } } else if (currentTagType == FLV_TAG_VIDEO || currentTagType == FLV_TAG_AUDIO) { if (!headerWritten) { @@ -166,14 +167,21 @@ public class FlvFilter extends OutputStream { } else { // currentTagType == FLV_TAG_AUDIO metadata.addAudioFrame(currentTagPos, currentTagTimestamp); } - receiver.writeBody(currentBox); - metadata.setFileSize(currentTagPos + currentTagSize); + writeBody(); } else { log.error("Unknown box type: " + currentTagType); - receiver.writeBody(currentBox); + writeBody(); } } + /** + * + */ + private void writeBody() { + receiver.writeBody(currentBox); + bodyLen += currentBox.length; + } + @Override public void flush() throws IOException { @@ -184,9 +192,11 @@ public class FlvFilter extends OutputStream { public void generateHeader() throws IOException { + metadata.setFileSize(fileHeader.length + incomingMetadataLength + bodyLen); int metadataLength = metadata.calculateLength(); ByteArrayOutputStream out = new ByteArrayOutputStream(fileHeader.length + metadataLength); out.write(fileHeader); + metadata.setFileSize(fileHeader.length + metadataLength + bodyLen); metadata.setFileOffsetDelta(metadataLength - incomingMetadataLength); metadata.writeOnMetadata(out); diff --git a/src/main/java/org/forkalsrud/album/video/MovieCoder.java b/src/main/java/org/forkalsrud/album/video/MovieCoder.java index 28ac312..f57e90d 100644 --- a/src/main/java/org/forkalsrud/album/video/MovieCoder.java +++ b/src/main/java/org/forkalsrud/album/video/MovieCoder.java @@ -149,17 +149,17 @@ public class MovieCoder { class EncodingProcess implements Runnable, FlvFilter.FlvReceiver { - final int chunkSize = 4 * 65536; - File file; - Thumbnail thumbnail; - Dimension targetSize; - ArrayList listeners = new ArrayList(); - Chunk currentChunk = null; - int chunkPos; - int remainingCapacity; - int chunkNo = 0; - FlvFilter filter; - String dbKey; + private final int chunkSize = 4 * 65536; + private File file; + private Thumbnail thumbnail; + private Dimension targetSize; + private ArrayList listeners = new ArrayList(); + private Chunk currentChunk = null; + private int chunkPos; + private int remainingCapacity; + private int chunkNo = 0; + private FlvFilter filter; + private String dbKey; public EncodingProcess(File file, Thumbnail thumbnail, Dimension size) { this.file = file; @@ -219,7 +219,7 @@ public class MovieCoder { p.getOutputStream().close(); InputStream movieStream = p.getInputStream(); InputStream diagnostic = p.getErrorStream(); - new Thread(new ErrorStreamPumper(diagnostic)).start(); + new Thread(new ErrorStreamPumper("ffmpeg", diagnostic)).start(); byte[] buffer = new byte[65536]; int len; @@ -228,6 +228,9 @@ public class MovieCoder { } filter.flush(); 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) { log.error("uh?", e); movieDb.delete(dbKey); @@ -282,6 +285,7 @@ public class MovieCoder { System.arraycopy(data, inputPos, currentChunk.bits, chunkPos, copyLen); chunkPos += copyLen; remainingCapacity -= copyLen; + inputPos += copyLen; remainingInput -= copyLen; if (remainingCapacity == 0) { endChunk(); @@ -299,6 +303,7 @@ public class MovieCoder { private void endChunk() { + log.info("Receiving chunk " + chunkNo); movieDb.store(dbKey, chunkNo, currentChunk); currentChunk = null; notifyListeners(chunkNo, false); @@ -328,18 +333,22 @@ public class MovieCoder { class ErrorStreamPumper implements Runnable { - InputStream is; - public ErrorStreamPumper(InputStream is) { + private InputStream is; + private String name; + + public ErrorStreamPumper(String processName, InputStream is) { + this.name = processName; this.is = is; } @Override public void run() { + org.slf4j.Logger diag = org.slf4j.LoggerFactory.getLogger(this.name); try { LineNumberReader lnr = new LineNumberReader(new InputStreamReader(is)); String line; while ((line = lnr.readLine()) != null) { - log.info(line); + diag.info(line); } } catch (Exception e) { log.error("stderr?", e); @@ -352,7 +361,11 @@ public class MovieCoder { // range requests etcetera public void stream(File file, Thumbnail thumbnail, String size, OutputStream out) throws IOException, InterruptedException { - grabStream(file, thumbnail, size).stream(out); + try { + grabStream(file, thumbnail, size).stream(out); + } catch (Exception e) { + log.error("stream fail", e); + } } private static String key(File file, Dimension size) { @@ -412,9 +425,17 @@ public class MovieCoder { public void stream(OutputStream out) throws IOException, InterruptedException { 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); - chunk = movieDb.load(key, ++chunkNo); + chunk = null; + chunkNo++; + continue; } if (!done()) { if (ep != null) { @@ -430,6 +451,7 @@ public class MovieCoder { if (ep != null) { ep.removeListener(this); } + log.info("done sending"); } diff --git a/src/main/java/org/forkalsrud/album/web/AlbumServlet.java b/src/main/java/org/forkalsrud/album/web/AlbumServlet.java index 5a67e1c..8bf9cda 100644 --- a/src/main/java/org/forkalsrud/album/web/AlbumServlet.java +++ b/src/main/java/org/forkalsrud/album/web/AlbumServlet.java @@ -344,8 +344,11 @@ public class AlbumServlet try { String size = req.getParameter("size"); res.setStatus(HttpServletResponse.SC_OK); + /* res.setDateHeader("Last-Modified", entry.getPath().lastModified()); res.setDateHeader("Expires", System.currentTimeMillis() + (30 * 24 * 3600 * 1000L)); // 30 days + */ + res.setHeader("Cache-control", "no-cache"); res.setContentType("video/x-flv"); movieCoder.stream(entry.getPath(), entry.getThumbnail(), size, res.getOutputStream()); } catch (Exception ex) { diff --git a/src/test/java/org/forkalsrud/album/video/FlvFilterTest.java b/src/test/java/org/forkalsrud/album/video/FlvFilterTest.java index b922b1b..4317a9b 100644 --- a/src/test/java/org/forkalsrud/album/video/FlvFilterTest.java +++ b/src/test/java/org/forkalsrud/album/video/FlvFilterTest.java @@ -37,4 +37,7 @@ public class FlvFilterTest extends TestCase { assertEquals("HEADER[252]BODY[0]HEADER[579]BODY[911684]", buf.toString()); } + public void testFoo() { + System.out.println(0x40128); + } }