把Android手机变成远程监控摄像头

要买新手机了旧手机怎么办?我们可以废物利用下,把旧的手机变成一个远程监控摄像头。这里使用Java创建手机camera客户端和远程服务上的监控界面。

实现方法考虑几点:

  1. 创建一个Android自定义的摄像头应用
  2. 把preview的数据发送到服务端
  3. preview的NV21数据解码
  4. 把图像画出来

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);
        }
    }

源码

1">https://github.com/DynamsoftRD/Android-IP-Camera

时间: 2024-11-05 13:49:33

把Android手机变成远程监控摄像头的相关文章

在 Android 手机上使用 Terminal IDE 远程登录你的 Mac/Ubuntu

我的主力博客:半亩方塘 以下内容系原创,转载请务必注明地址 在 Android 手机上使用 Terminal IDE 远程登录你的 Mac 可以让你随时随地远程对你的 Mac 进行操作,这个很爽,特别是当你躺在床上还能操作你在某个地方开着的 Mac 计算机的时候,其实依照这种方法也可以类似地远程登录Ubuntu,有兴趣的可以试试,简单几步就可以实现了: 首先,需要下载 Terminal IDE,废话不说,请 google 下载之,下载完成后将 Terminal IDE 装到你的安卓手机上, In

Android 手机上安装并运行 Ubuntu 12.04(转,没实测)

设备需要root权限,并且安装了BusyBox最小 1GHz 处理器(推荐)Android 系统版本 2.1 或以上Android 设备需要自定义的ROM固件SD卡至2.5GB (安装大映像的需要3.5GB)设备需要支持WIFI (这个用于其他设备通过WIFI登录)支持 Ext2 文件系统(大部分 Android 设备应该都支持)我的设备手机型号:Mi-One Plus处理器主频:1.5GHz * 2SD卡:16G class 4系统ROM:MIUI_v4_2.8.10BusyBox版本:1.2

Android上的远程调试

来源: http://www.seejs.com/archives/296 目录 远程调试概述 使用 Chrome 的 ADB 扩展进行远程调试 1. 安装 ADB 扩展 2. 启用你的移动设备上的 USB 调试功能 3. 通过 USB 连接你的 PC 和移动设备 4. 开始使用 ADB 扩展进行调试 5. 调试你的应用程序 注意 端口反向转发(实验) 1. 连接你的移动设备 2. 启用端口反向转发 3. 添加一个端口转发规则 4. 利益 注意: 我们在远程调试中使用的交互协议信息,请参阅调试协

Android手机严重漏洞,可造成手机全面瘫痪!

趋势科技发现最新Android系统漏洞,可利用藏有恶意软件的App或网页,针对Android 移动设备进行攻击,一旦用户安装此App或是浏览这些网页,将会开启一个有害的MKV文档,此文档将会在设备开机时自动执行启动,造成手机无法接电话.收发短信或是屏幕全黑导致死机 !此漏洞影响遍及Android 4.3至5.1.1版本,在漏洞修补之前建议Android用户应防范此最新漏洞攻击, 攻击者只需要知道用户手机号码,经由多媒体信息即可入侵用户手机,并远程执行程序代码,所以你首先要在手机上停用多媒体信息,

手机控车OBD-移动管家手机控车方案基于Android手机智能控制汽车系统的研究与实现;

基于Android手机智能控制汽车系统的研究与实现:汽车手机启动,汽车远程启动是装置在智能汽车的一部分,是实现简远程遥控启动汽车的一个智能装置,同时也可以熄火.汽车手机启动可以在原车钥匙保留模式改装,也可以独立在汽车上改装. 目前很多汽车已经配有一键启动智能无钥匙进入系统设备,相对配置手机远程动的车辆比较少,关于智能汽车,PKE智能系统.一键启动.手机撑控配合使用才会显示智能操控的简捷性.国内生产汽车手机启动汽智能一键启动厂家已经在50家左右.汽车手机智能控制系统,体积小巧,简便安装.根据原车线

android手机安全卫士、Kotlin漫画、支付宝动画、沉浸状态栏等源码

Android精选源码 轻量级底部导航栏 android手机卫士源码 android实现高仿今日头条源码 一个用Kotlin写的简单漫画App源码 android吐槽项目完整源码 实现可以滑动文字逐渐变色的TabLayout android实现将app隐藏加密功能的源码 android实现横向滚动的卡片堆叠布局 android仿支付宝的咻咻动画源码 android状态栏和沉浸式导航栏管理源码 Android优质博客 从BaseActivity与BaseFragment的封装谈起 这篇博客主要是从

Android手机 Fildder真机抓包

Android 手机 Fildder 真Fiddler是一个http调试代理,它能 够记录所有的你电脑和互联网之间的http通讯,Fiddler 可以也可以让你检查所有的http通讯,设置断点,以及Fiddle 所有的"进出"的数据(指cookie,html,js,css等文件,这些都可以让你胡乱修改的意思). Fiddler 要比其他的网络调试器要更加简单,因为它仅仅暴露http通讯还有提供一个用户友好的格式. 对于Android开发的同事最头疼的事情莫过于真机抓包,然后Fiddle

mac 无法连接android手机进行调试 解决方案

第一步: 查看usb设备信息 在 终端输入:system_profiler SPUSBDataType     可以查看连接的usb设备的信息 比如我的usb信息如下(部分内容): Android: Product ID: 0x2769              Vendor ID: 0x22d9              Version: 2.31              Serial Number: 6e5d48a4              Speed: Up to 480 Mb/sec

Android手机使用Fiddler方法介绍(原)

Fiddler是一款免费的抓包.调试工具,比Wireshark要小巧,更简洁,本节就来介绍如何通过WIFI来抓取Android手机的HTTP和HTTPS包. 一.连接Android手机 1.1.手机端配置 电脑配置WIFI后,手机需要设置当前WIFI的代理,而这个代理地址可以通过电脑的"ipconfig"命令得到,如下图所示: 以上的192.168.191.1就是本机的IP地址,然后在手机端的WIFI的高级设置中将代理地址设置为查询到的IP,端口号码自己定义,一会儿要用到,IP代理模式