把Android手機變成遠程監控攝像頭
要買新手機了舊手機怎么辦?我們可以廢物利用下,把舊的手機變成一個遠程監控攝像頭。這里使用Java創建手機camera客戶端和遠程服務上的監控界面。


實現方法考慮幾點:
-
創建一個Android自定義的攝像頭應用
-
把preview的數據發送到服務端
-
preview的NV21數據解碼
-
把圖像畫出來
Android攝像頭,Socket鏈接,服務端圖像顯示
創建preview回調函數:
private Camera.PreviewCallback mPreviewCallback = new PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
// TODO Auto-generated method stub
synchronized (mQueue) {
if (mQueue.size() == MAX_BUFFER) {
mQueue.poll();
}
mQueue.add(data);
}
}
}; 注冊回調函數:
try {
mCamera.setPreviewCallback(mPreviewCallback);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
} 停止釋放攝像頭:
public void onPause() {
if (mCamera != null) {
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
}
resetBuff();
} 使用AlertDialog來設置服務器IP地址:
private void setting() {
LayoutInflater factory = LayoutInflater.from(this);
final View textEntryView = factory.inflate(R.layout.server_setting, null);
AlertDialog dialog = new AlertDialog.Builder(IPCamera.this)
.setIconAttribute(android.R.attr.alertDialogIcon)
.setTitle(R.string.setting_title)
.setView(textEntryView)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
EditText ipEdit = (EditText)textEntryView.findViewById(R.id.ip_edit);
EditText portEdit = (EditText)textEntryView.findViewById(R.id.port_edit);
mIP = ipEdit.getText().toString();
mPort = Integer.parseInt(portEdit.getText().toString());
Toast.makeText(IPCamera.this, "New address: " + mIP + ":" + mPort, Toast.LENGTH_LONG).show();
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
/* User clicked cancel so do some stuff */
}
})
.create();
dialog.show();
} 啟動線程來創建socket鏈接,發送JSON數據和每一幀的圖像數據:
mSocket = new Socket();
mSocket.connect(new InetSocketAddress(mIP, mPort), 10000);
BufferedOutputStream outputStream = new BufferedOutputStream(mSocket.getOutputStream());
BufferedInputStream inputStream = new BufferedInputStream(mSocket.getInputStream());
JsonObject jsonObj = new JsonObject();
jsonObj.addProperty("type", "data");
jsonObj.addProperty("length", mCameraPreview.getPreviewLength());
jsonObj.addProperty("width", mCameraPreview.getPreviewWidth());
jsonObj.addProperty("height", mCameraPreview.getPreviewHeight());
byte[] buff = new byte[256];
int len = 0;
String msg = null;
outputStream.write(jsonObj.toString().getBytes());
outputStream.flush();
while ((len = inputStream.read(buff)) != -1) {
msg = new String(buff, 0, len);
// JSON analysis
JsonParser parser = new JsonParser();
boolean isJSON = true;
JsonElement element = null;
try {
element = parser.parse(msg);
}
catch (JsonParseException e) {
Log.e(TAG, "exception: " + e);
isJSON = false;
}
if (isJSON && element != null) {
JsonObject obj = element.getAsJsonObject();
element = obj.get("state");
if (element != null && element.getAsString().equals("ok")) {
// send data
while (true) {
outputStream.write(mCameraPreview.getImageBuffer());
outputStream.flush();
if (Thread.currentThread().isInterrupted())
break;
}
break;
}
}
else {
break;
}
}
outputStream.close();
inputStream.close(); 服務端接收數據:
public int fillBuffer(byte[] data, int off, int len, LinkedList<byte[]> YUVQueue) {
mTotalLength += len;
mByteArrayOutputStream.write(data, off, len);
if (mTotalLength == mFrameLength) {
synchronized (YUVQueue) {
YUVQueue.add(mByteArrayOutputStream.toByteArray());
mByteArrayOutputStream.reset();
}
mTotalLength = 0;
System.out.println("received file");
}
return 0;
} NV21解碼:
public static int[] convertYUVtoRGB(byte[] yuv, int width, int height)
throws NullPointerException, IllegalArgumentException {
int[] out = new int[width * height];
int sz = width * height;
int i, j;
int Y, Cr = 0, Cb = 0;
for (j = 0; j < height; j++) {
int pixPtr = j * width;
final int jDiv2 = j >> 1;
for (i = 0; i < width; i++) {
Y = yuv[pixPtr];
if (Y < 0)
Y += 255;
if ((i & 0x1) != 1) {
final int cOff = sz + jDiv2 * width + (i >> 1) * 2;
Cb = yuv[cOff];
if (Cb < 0)
Cb += 127;
else
Cb -= 128;
Cr = yuv[cOff + 1];
if (Cr < 0)
Cr += 127;
else
Cr -= 128;
}
int R = Y + Cr + (Cr >> 2) + (Cr >> 3) + (Cr >> 5);
if (R < 0)
R = 0;
else if (R > 255)
R = 255;
int G = Y - (Cb >> 2) + (Cb >> 4) + (Cb >> 5) - (Cr >> 1)
+ (Cr >> 3) + (Cr >> 4) + (Cr >> 5);
if (G < 0)
G = 0;
else if (G > 255)
G = 255;
int B = Y + Cb + (Cb >> 1) + (Cb >> 2) + (Cb >> 6);
if (B < 0)
B = 0;
else if (B > 255)
B = 255;
out[pixPtr++] = 0xff000000 + (B << 16) + (G << 8) + R;
}
}
return out;
} 使用Swing繪制BufferedImage:
BufferedImage bufferedImage = null; int[] rgbArray = Utils.convertYUVtoRGB(data, mWidth, mHeight); bufferedImage = new BufferedImage(mWidth, mHeight, BufferedImage.TYPE_USHORT_565_RGB); bufferedImage.setRGB(0, 0, mWidth, mHeight, rgbArray, 0, mWidth);
synchronized (mQueue) {
if (mQueue.size() > 0) {
mLastFrame = mQueue.poll();
}
}
if (mLastFrame != null) {
g.drawImage(mLastFrame, 0, 0, null);
}
else if (mImage != null) {
g.drawImage(mImage, 0, 0, null);
}
}源碼
https://github.com/DynamsoftRD/Android-IP-Camera
原文地址:http://www.codepool.biz/tech-frontier/android/making-android-smart-phone-a-remote-ip-camera.html
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!