X-Git-Url: http://dolda2000.com/gitweb/?p=kaka%2Fcakelight.git;a=blobdiff_plain;f=src%2Fkaka%2Fcakelight%2FFrameGrabber.java;h=5354ea69a8ab1a13dbb5bbf132fc491beee55b4b;hp=e654c9183075f51198340ea0184cf79210915c28;hb=eba8feca754a0875f30b8284dab67c8c01f85ef6;hpb=579c24625e93b67fd74245fe835cb34906ee7090 diff --git a/src/kaka/cakelight/FrameGrabber.java b/src/kaka/cakelight/FrameGrabber.java index e654c91..5354ea6 100644 --- a/src/kaka/cakelight/FrameGrabber.java +++ b/src/kaka/cakelight/FrameGrabber.java @@ -1,5 +1,7 @@ package kaka.cakelight; +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; import java.io.*; import java.util.Optional; @@ -10,6 +12,7 @@ public class FrameGrabber implements Closeable { private File file; private int bytesPerFrame; private InputStream fileStream; + private final ByteArrayOutputStream bufferedBytes = new ByteArrayOutputStream(); private FrameGrabber() { } @@ -39,11 +42,26 @@ public class FrameGrabber implements Closeable { */ public Optional grabFrame() { try { - byte[] data = new byte[bytesPerFrame]; - int count = fileStream.read(data); - if (count != bytesPerFrame) { - log("Expected to read " + bytesPerFrame + " bytes per frame but read " + count); + byte[] data; + if (config.video.mjpg) { + byte[] jpgData = readStreamingJpgData(); + if (jpgData == null) { + return Optional.empty(); + } + saveTemporaryJpgFile(jpgData); + byte[] bmpData = convertJpgFileToByteArray(); + if (bmpData == null) { + return Optional.empty(); + } + data = bmpData; + } else { + data = new byte[bytesPerFrame]; + int count = fileStream.read(data); + if (count != bytesPerFrame) { + log("Expected to read " + bytesPerFrame + " bytes per frame but read " + count); + } } + return Optional.of(VideoFrame.of(data, config)); } catch (IOException e) { e.printStackTrace(); @@ -52,6 +70,62 @@ public class FrameGrabber implements Closeable { return Optional.empty(); } + private byte[] readStreamingJpgData() throws IOException { + byte[] data; + byte[] batch = new byte[1024]; + boolean lastByteIsXX = false; + loop: + while (true) { + int batchCount = fileStream.read(batch); + if (batchCount == -1) { + return null; + } + if (lastByteIsXX) { + if (batch[0] == (byte) 0xd8) { + data = bufferedBytes.toByteArray(); + bufferedBytes.reset(); + bufferedBytes.write(0xff); + bufferedBytes.write(batch, 0, batchCount); + break; + } + bufferedBytes.write(0xff); + } + for (int i = 0; i < batchCount - 1; i++) { + if (batch[i] == (byte) 0xff && batch[i + 1] == (byte) 0xd8) { // start of jpeg + if (i > 0) { + bufferedBytes.write(batch, 0, i); + } + data = bufferedBytes.toByteArray(); + bufferedBytes.reset(); + bufferedBytes.write(batch, i, batchCount - i); + break loop; + } + } + lastByteIsXX = batch[batchCount - 1] == (byte) 0xff; + bufferedBytes.write(batch, 0, batchCount - (lastByteIsXX ? 1 : 0)); + } + return data; + } + + private void saveTemporaryJpgFile(byte[] data) throws IOException { + try (FileOutputStream fos = new FileOutputStream("/tmp/cakelight-video-stream.jpg")) { + fos.write(data); + } + } + + private byte[] convertJpgFileToByteArray() throws IOException { + BufferedImage image = ImageIO.read(new File("/tmp/cakelight-video-stream.jpg")); + if (image != null) { // will almost always be null the first time + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + ImageIO.write(image, "bmp", baos); + baos.flush(); + return baos.toByteArray(); + } + } else { + return null; + } + } + @Override public void close() throws IOException { fileStream.close();