From 7e305e1fbecf492619f9fd72f2d78887936c8989 Mon Sep 17 00:00:00 2001 From: Alessio Caiazza Date: Thu, 6 Mar 2008 11:18:23 +0100 Subject: [PATCH] FIX:run() method now works on Sony Camera ADD:CaptureToFile demo application Fixed typo on CircularBuffer javadoc --- .hgignore | 3 +- src/it/lilik/capturemjpeg/AsyncProducer.java | 193 +++++++++++---------- src/it/lilik/capturemjpeg/CaptureToFile.java | 122 +++++++++++++ .../lilik/capturemjpeg/utils/CircularBuffer.java | 2 +- 4 files changed, 229 insertions(+), 91 deletions(-) create mode 100644 src/it/lilik/capturemjpeg/CaptureToFile.java diff --git a/.hgignore b/.hgignore index caf2206..3629d00 100644 --- a/.hgignore +++ b/.hgignore @@ -9,4 +9,5 @@ user_pref.xml libs/* .externalToolBuilders/* .settings/* -docs/api/* \ No newline at end of file +docs/api/* +bin/* diff --git a/src/it/lilik/capturemjpeg/AsyncProducer.java b/src/it/lilik/capturemjpeg/AsyncProducer.java index 1946e06..b5adc17 100644 --- a/src/it/lilik/capturemjpeg/AsyncProducer.java +++ b/src/it/lilik/capturemjpeg/AsyncProducer.java @@ -26,7 +26,7 @@ import org.apache.commons.httpclient.auth.AuthScope; * @author Cosimo Cecchi * */ -class AsyncProducer implements Runnable { +class AsyncProducer extends Thread { /** timeout for HTTP request */ protected static final int HTTP_TIMEOUT = 5000; @@ -114,11 +114,11 @@ class AsyncProducer implements Runnable { * @see java.lang.Runnable#run() */ public void run() { - // TODO Auto-generated method stub + BufferedInputStream is = null; + InputStream responseBody = null; + String boundary = ""; + while (!this.shouldStop) { - BufferedInputStream is = null; - InputStream responseBody = null; - String boundary; if (this.isChangePending) { synchronized (this.method) { @@ -136,110 +136,125 @@ class AsyncProducer implements Runnable { } // automagically guess the boundary - Header contentType = this.method.getRequestHeader("content-type"); + Header contentType = this.method.getResponseHeader("Content-Type"); String contentTypeS = contentType.toString(); int startIndex = contentTypeS.indexOf("boundary="); int endIndex = contentTypeS.indexOf(';', startIndex); + if (endIndex == -1) //boundaty is the last option + endIndex = contentTypeS.length(); boundary = contentTypeS.substring(startIndex + 9, endIndex); - } - /* Now flip flop to parse the images. We look for the JPEG magic MIME identifier, - * which is composed by the first two bites set to 0xff and 0xd8. We stop when we find - * another "--$boundary" string. - */ + + this.isChangePending = false; + } //end syncronyzed + } //end if(isChangePending) + + /* Now flip flop to parse the images. We look for the JPEG magic MIME identifier, + * which is composed by the first two bites set to 0xff and 0xd8. We stop when we find + * another "--$boundary" string. + */ + + try { + byte tmp[] = new byte[BYTES_TO_READ]; + ByteArrayOutputStream os = new ByteArrayOutputStream(); + char delimiter[] = (boundary).toCharArray(); + byte magicMIME[] = {(byte) 0xff, + (byte) 0xd8}; + byte partialMatch[] = new byte[delimiter.length]; + int bytesRead = 0; + int last = 0; + boolean foundStart = false; - try { - byte tmp[] = new byte[BYTES_TO_READ]; - ByteArrayOutputStream os = new ByteArrayOutputStream(); - char delimiter[] = ("--" + boundary).toCharArray(); - byte magicMIME[] = {(byte) 0xff, - (byte) 0xd8}; - byte partialMatch[] = new byte[delimiter.length]; - int bytesRead = 0; - int last = 0; - boolean foundStart = false; + /* This first cycle ensures we start parsing the stream on the first + * magic MIME identifier. + */ + /*while (true) { + int data; + data = is.read(); - /* This first cycle ensures we start parsing the stream on the first - * magic MIME identifier. - */ - /*while (true) { - int data; - data = is.read(); - - if ((byte) data == magicMIME[0]) { - foundStart = true; - is.mark(2); - continue; - } - - if (foundStart && ((byte) data) == magicMIME[1]) { - is.reset(); - break; - } - - if (foundStart) - foundStart = false; - } */ - /* This cycle splits the stream into several ByteArrayInputStreams containing - * the real image, and pushs them to our internal buffer. - */ - int startIdx = 0; - last = 0; - boolean lookinForMagicMIME = true; - while ((bytesRead = is.read(tmp)) != -1) { - for (int i = 0; i < bytesRead; i++) { - if (lookinForMagicMIME) { - if (tmp[i] == magicMIME[last]) { - partialMatch[last] = tmp[i]; - last++; - - if (last == 2) { - os.write(partialMatch, 0, 2); - last = 0; - lookinForMagicMIME = false; - } - } else { + if ((byte) data == magicMIME[0]) { + foundStart = true; + is.mark(2); + continue; + } + + if (foundStart && ((byte) data) == magicMIME[1]) { + is.reset(); + break; + } + + if (foundStart) + foundStart = false; + } */ + /* This cycle splits the stream into several ByteArrayInputStreams containing + * the real image, and pushs them to our internal buffer. + */ + int startIdx = 0; + last = 0; + boolean lookinForMagicMIME = true; + boolean imageComplete; + imageComplete = false; + while (!imageComplete && (bytesRead = is.read(tmp)) != -1) { + for (int i = 0; i < bytesRead; i++) { + if (lookinForMagicMIME) { + if (tmp[i] == magicMIME[last]) { + partialMatch[last] = tmp[i]; + last++; + + if (last == 2) { + os.write(partialMatch, 0, 2); last = 0; + lookinForMagicMIME = false; } - }else { //lookinForBoundary - if (tmp[i] == delimiter[last]) { - partialMatch[last] = tmp[i]; - last++; - - if (last == delimiter.length) { - this.buffer.push(new ByteArrayInputStream(os.toByteArray())); - lookinForMagicMIME = true; - last = 0; - } - } else if (last > 0) { - partialMatch[last++] = tmp[i]; - os.write(partialMatch, 0 , last); + } else { + last = 0; + } + }else { //lookinForBoundary + if (tmp[i] == delimiter[last]) { + partialMatch[last] = tmp[i]; + last++; + + if (last == delimiter.length) { + this.buffer.push(new ByteArrayInputStream(os.toByteArray())); + lookinForMagicMIME = true; last = 0; - } else { - os.write(tmp[i]); + imageComplete = true; + break; } + } else if (last > 0) { + partialMatch[last++] = tmp[i]; + os.write(partialMatch, 0 , last); + last = 0; + } else { + os.write(tmp[i]); } - } + + } - } - }catch (IOException e) { - // TODO: handle exception - } - - - + } + }catch (IOException e) { + // TODO: handle exception } } } /** - * Dummy main for testing purpose - * @param args + * Return the first image available as {@link java.io.ByteArrayInputStream}. + * @return the first image available */ - public static void main(String[] args) { - // TODO Auto-generated method stub - + public ByteArrayInputStream pop() { + return this.buffer.pop(); + } + + /** + * Return true if there is at least one image available into + * the internal buffer. + * + * @return the availability status + */ + public boolean isImageAvailable() { + return !this.buffer.isEmpty(); } } diff --git a/src/it/lilik/capturemjpeg/CaptureToFile.java b/src/it/lilik/capturemjpeg/CaptureToFile.java new file mode 100644 index 0000000..29dfe90 --- /dev/null +++ b/src/it/lilik/capturemjpeg/CaptureToFile.java @@ -0,0 +1,122 @@ +/** + * + */ +package it.lilik.capturemjpeg; + +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; + +import org.apache.commons.httpclient.methods.GetMethod; + +/** + * @author Alessio Caiazza + * @author Cosimo Cecchi + * + */ +public class CaptureToFile { + + private String path; + private String url; + private AsyncProducer client; + + /** + * @param args + */ + public static void main(String[] args) { + if (args.length < 2 || args.length == 3 || args.length > 4) { + System.err.println("Wrong parameters"); + System.out.println("Usage:"); + System.exit(-1); + } + String user = null , pass = null; + if (args.length == 4) { + user = args[2]; + pass = args[3]; + } + CaptureToFile ctf = new CaptureToFile(args[0], + args[1], user, pass); + + ctf.start(); + //start capturing images from buffer + try { + ctf.capture(20); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + try { + ctf.stop(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + } + + public CaptureToFile(String path, String url, + String user, String password) { + if (path.lastIndexOf('/') == path.length()) + this.path = path; + else + this.path = path + "/"; + + this.url = url; + client = new AsyncProducer(new GetMethod(url), + user, password); + } + + public void capture(int images) throws FileNotFoundException { + File fout; + FileOutputStream fos; + BufferedOutputStream os; + ByteArrayInputStream img; + byte buff[] = new byte[1024]; + int readBytes; + for( int i = 0; i < images; i++ ) { + fout = new File(getPath() + String.valueOf(i) + ".jpg"); + fos = new FileOutputStream(fout); + os = new BufferedOutputStream(fos); + + //TODO: is this the better way? + while( !client.isImageAvailable() ) { + Thread.yield(); + } + + img = client.pop(); + try { + while((readBytes = img.read(buff)) != -1) { + os.write(buff, 0, readBytes); + } + os.close(); + img.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * @return the path + */ + public synchronized String getPath() { + return path; + } + + public CaptureToFile(String path, String url) { + this(path, url, null, null ); + } + + public void start() { + client.start(); + } + + public void stop() throws InterruptedException { + client.setShouldStop(true); + client.join(); + } + +} diff --git a/src/it/lilik/capturemjpeg/utils/CircularBuffer.java b/src/it/lilik/capturemjpeg/utils/CircularBuffer.java index 602f282..b263ce4 100644 --- a/src/it/lilik/capturemjpeg/utils/CircularBuffer.java +++ b/src/it/lilik/capturemjpeg/utils/CircularBuffer.java @@ -96,7 +96,7 @@ public class CircularBuffer { * Get the first available element. * * @return the first element - * @throws IndexOutOfVoundsExceptions + * @throws IndexOutOfBoundsExceptions */ public synchronized ByteArrayInputStream pop() { if (isEmpty()) { -- 2.11.4.GIT