H
holger27
Gast
Hallo!
Ich möchte auf Android eine Mjpeg App programmieren welche es mir ermöglicht die Bilder eines MJPEG Streams auf meiner SD Karte abzuspeichern.
Ich habe mit hierfür im Netz einen Code gesucht und diesen so ummodelliert das er eigentlich Android Lauffähig ist, bzw. sich kompilieren lässt und normalerweise gehen sollte.
Das Problem ist nur das die App direkt nach dem Start abstürzt. Das komische ist dabei wenn ich das als normales Java Projekt lauffen lassen funktioniert das ganze perfekt! Von daher kann die "Code Logik" eigentlich nicht falsch sein...
Permissions für Internet und SD Karte habe ich beide eingetragen, daran kann es also auch nicht liegen. Ich habe mir den Code wirklich tausend mal angeschaut aber finde einfach keinen Fehler und im Android Debugger wird auch nichts angezeigt.
Es wäre wirklich toll wenn jemand mal über den Code drüberkucken könnte, vlt übersehe ich ja was ausschlaggebendes, aber wie gesagt unter java läuft der Code perfekt und sichert mir die Einzelbilder.
(Die Benutzer und Passwort Abfrage habe ich vorerst ausgeklammert, funktioniert bei diesem Stream auch ohne)
Klasse1:
Klasse2:
Ich möchte auf Android eine Mjpeg App programmieren welche es mir ermöglicht die Bilder eines MJPEG Streams auf meiner SD Karte abzuspeichern.
Ich habe mit hierfür im Netz einen Code gesucht und diesen so ummodelliert das er eigentlich Android Lauffähig ist, bzw. sich kompilieren lässt und normalerweise gehen sollte.
Das Problem ist nur das die App direkt nach dem Start abstürzt. Das komische ist dabei wenn ich das als normales Java Projekt lauffen lassen funktioniert das ganze perfekt! Von daher kann die "Code Logik" eigentlich nicht falsch sein...
Permissions für Internet und SD Karte habe ich beide eingetragen, daran kann es also auch nicht liegen. Ich habe mir den Code wirklich tausend mal angeschaut aber finde einfach keinen Fehler und im Android Debugger wird auch nichts angezeigt.
Es wäre wirklich toll wenn jemand mal über den Code drüberkucken könnte, vlt übersehe ich ja was ausschlaggebendes, aber wie gesagt unter java läuft der Code perfekt und sichert mir die Einzelbilder.
(Die Benutzer und Passwort Abfrage habe ich vorerst ausgeklammert, funktioniert bei diesem Stream auch ohne)
Klasse1:
Code:
package and.pro;
import java.awt.*;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.app.Activity;
import android.app.AlertDialog;
import android.os.Bundle;
import android.widget.Toast;
public class MjpegReaderActivity extends Activity {
public static String mjpgURL = "http://217.169.130.244/axis-cgi/mjpg/video.cgi?resolution=320x240";
String username = "";
String password = "";
static String base64authorization = null;
//private Image image = null;
private static boolean connected = false;
private boolean initCompleted = false;
static HttpURLConnection huc = null;
Runnable updater;
Integer frameNumber = 0;
/**
* Used to calculate an average FPS
*/
long[] frameTimes = new long[10];
static MJPEGParser parser;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
doIt();
}
public MjpegReaderActivity() {
// only use authorization if all informations are available
if (username != null && password != null) {
//base64authorization = encodeUsernameAndPasswordInBase64(username, password);
//MJPEGBean axPanel = new MJPEGBean();
// new Thread(axPanel).start();
}
}
public static void connect() {
try {
URL u = new URL(mjpgURL);
huc = (HttpURLConnection) u.openConnection();
// if authorization is required set up the connection with the encoded authorization-information
//if (base64authorization != null) {
//huc.setDoInput(true);
//huc.setRequestProperty("Authorization", base64authorization);
huc.connect();
//}
/*
* This is the boundary string that my camera uses. I don't know if it is a standard or not, I kind of doubt
* it...
*/
String boundary = "--myboundary";
String contentType = huc.getContentType();
Pattern pattern = Pattern.compile("boundary=(.*)$");
Matcher matcher = pattern.matcher(contentType);
try {
matcher.find();
boundary = matcher.group(1);
} catch (Exception e) {
}
InputStream is = huc.getInputStream();
connected = true;
parser = new MJPEGParser(is, boundary);
//parser.addChangeListener(this);
} catch (IOException e) { // incase no connection exists wait and try again, instead of printing the error
try {
huc.disconnect();
Thread.sleep(60);
} catch (InterruptedException ie) {
huc.disconnect();
}
connect();
} catch (Exception e) {
;
}
}
public void disconnect() {
try {
if (connected) {
parser.setCanceled(true);
connected = false;
}
} catch (Exception e) {
;
}
}
NumberFormat decFormat = DecimalFormat.getNumberInstance();
public static void doIt()
{
connect();
try {
parser.parse();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Klasse2:
Code:
package and.pro;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class MJPEGParser {
private static final byte[] JPEG_START = new byte[]{(byte) 0xFF, (byte) 0xD8};
private static final int INITIAL_BUFFER_SIZE = 4096;
InputStream in;
byte[] boundary;
byte[] segment;
byte[] buf;
int cur, len;
boolean canceled = false;
static int frameCounter = 0;
/**
* Stores ChangeListeners listening for when there is a new segment to be processed
*/
// protected EventListenerList listenerList = new EventListenerList();
public boolean isCanceled() {
return canceled;
}
public void setCanceled(boolean canceled) {
this.canceled = canceled;
if (canceled) {
try {
// TODO make this thread-safe
in.close();
} catch (IOException e) {
}
}
}
/**
* Creates a new MJPEG parser. Call parse() to begin parsing.
*
* @param in
* An input stream to parse
* @param boundary
* The boundary marker for this MJPEG stream.
*/
public MJPEGParser(InputStream in, String boundary) {
this.in = in;
this.boundary = boundary.getBytes();
buf = new byte[INITIAL_BUFFER_SIZE];
cur = 0;
len = INITIAL_BUFFER_SIZE;
}
/**
* Reads from the MJPEG input stream, parsing it for JPEG segments. Every time a JPEG segment is found, all
* registered change listeners will be notifed. They can retrieve the latest segment via getSegment(). Note that this
* isn't thread-safe: change listeners should retrieve the segment in the same thread in which they are notified.
*
*/
public void parse() throws IOException {
int b;
while ((b = in.read()) != -1 && !canceled) {
append(b);
if (checkBoundary()) {
// We found a boundary marker. Process the segment to find the JPEG image in it
processSegment();
// And clear out our internal buffer.
cur = 0;
}
}
}
/**
* Processes the current byte buffer. Ignores the last len(BOUNDARY) bytes in the buffer. Searches through the buffer
* for the start of a JPEG. If a JPEG is found, the bytes comprising the JPEG are copied into the
* <code>segment</code> field. If no JPEG is found, nothing is done.
*
*/
protected void processSegment() {
// First, look through the new segment for the start of a JPEG
boolean found = false;
int i;
for (i = 0; i < cur - JPEG_START.length; i++) {
if (segmentsEqual(buf, i, JPEG_START, 0, JPEG_START.length)) {
found = true;
break;
}
}
if (found) {
int segLength = cur - boundary.length - i;
segment = new byte[segLength];
System.arraycopy(buf, i, segment, 0, segLength);
getLastImage();
//fireChange();
}
}
/**
* @return The last JPEG segment found in the MJPEG stream.
*/
public void getLastImage()
{
frameCounter++;
byte[] buffer;
buffer = getSegment();
createImage(buffer);
}
public byte[] getSegment() {
return segment;
}
public static boolean createImage(byte[] datei)
{
FileOutputStream outStream;
if(datei.length <= 0)
return false;
try {
outStream = new FileOutputStream("/sdcard/bild" + frameCounter + ".jpeg");
outStream.write(datei,0,datei.length);
outStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* Compares sections of two buffers to see if they are equal.
*
* @param b1
* The first buffer.
* @param b1Start
* The starting offset into the first buffer.
* @param b2
* The second buffer.
* @param b2Start
* The starting offset into the second buffer.
* @param len
* The number of bytes to compare.
* @return <code>true</code> if the <code>len</code> consecutive bytes in <code>b1</code> starting at
* <code>b1Start</code> are equal to the <code>len</code>consecutive bytes in <code>b2</code> starting
* at <code>b2Start</code>, <code>false</code> otherwise.
*/
protected boolean segmentsEqual(byte[] b1, int b1Start, byte[] b2, int b2Start, int len) {
if (b1Start < 0 || b2Start < 0 || b1Start + len > b1.length || b2Start + len > b2.length) {
return false;
} else {
for (int i = 0; i < len; i++) {
if (b1[b1Start + i] != b2[b2Start + i]) {
return false;
}
}
return true;
}
}
/**
* @return true if if the end of the buffer matches the boundary
*/
protected boolean checkBoundary() {
return segmentsEqual(buf, cur - boundary.length, boundary, 0, boundary.length);
}
/**
* @return the length of the internal image buffer in bytes
*/
public int getBufferSize() {
return len;
}
/**
* Appends the given byte into the internal buffer. If it won't fit, the buffer's size is doubled.
*
* @param i
* the byte to append onto the internal byte buffer
*/
protected void append(int i) {
if (cur >= len) {
// make buf bigger
byte[] newBuf = new byte[len * 2];
System.arraycopy(buf, 0, newBuf, 0, len);
buf = newBuf;
len = len * 2;
}
buf[cur++] = (byte) i;
}
}