广告位
首页 其它 把安卓手机改造成网络高清摄像头

把安卓手机改造成网络高清摄像头

如今的手机,得益于庞大的市场需求和激烈的市场竞争产生了先进的算法,价格相对低廉的手机摄像头拍摄出来的照片质量远远超过于昂贵的工业相机。所以,在某些特定的场合下,你对拍摄速度不讲究 …

如今的手机,得益于庞大的市场需求和激烈的市场竞争产生了先进的算法,价格相对低廉的手机摄像头拍摄出来的照片质量远远超过于昂贵的工业相机。所以,在某些特定的场合下,你对拍摄速度不讲究 但是对图像质量以及成本十分敏感的话,用手机去替代相机,未尝不是一个很好的思路。

1 编写手机端APP,该app 主要实现以下功能:和外部主机建立tcp连接,接收外部主机命令,打开摄像头,并将图片经过压缩后传输回主机。核心代码一个是网络传输处理的类TcpConnect,一个是控制摄像头的页面 cameraFramement。

class TcpConnect : Runnable {
    private var mServerSocket: ServerSocket? = null   //tcp主端  本地端
    private var mClient: Socket? = null   //tcp客户端  远程端
    private var callback: Handler.Callback? = null    //消息回调   实现了接口的页面对象
    private var out: BufferedOutputStream? = null  //输出流
    private val SendBufferSize = 16777216  //发送缓冲区 取16M 默认8K
    private val SERVER_PORT = 10086 //端口号

    //建立tcp主端
    init {
        try {
            mServerSocket = ServerSocket(SERVER_PORT)
            mServerSocket!!.reuseAddress = true
            println("建立Socket")
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

    //给客户端发送数据
    fun sendData(data: ByteArray?) {
        if (mClient == null || !mClient!!.isConnected) {
            return
        }
        try {
            out = BufferedOutputStream(mClient!!.getOutputStream())
            if (data != null && data.isNotEmpty()) {
                out!!.write(data)
                //  mClient.shutdownOutput();
            }
        } catch (e: IOException) {
            Log.e("output", "输入输出异常")
            e.printStackTrace()
        }
    }

    //把实现了callback接口的framement传进来
    @JvmName("setCallback1")
    fun setCallback(_callback: Handler.Callback?) {
        callback = _callback
    }

    //监听tcp端口 收到消息后 调用framement的handleMessage方法进行处理
    fun listen() {
        while (true) try {
            if (mServerSocket == null) {
                mServerSocket = ServerSocket(SERVER_PORT)
                mServerSocket!!.reuseAddress = true
            }
            mClient = mServerSocket!!.accept()
            mClient?.run {
                reuseAddress = true
                sendBufferSize = SendBufferSize
            }
            println("TcpConnect 在监听")
            val `in` = BufferedInputStream(mClient?.getInputStream())
            val buffer = ByteArray(2)
            //从文件中按字节读取内容,到文件尾部时read方法将返回-1
            while (`in`.read(buffer).also { bytesRead = it } != -1) {
                val msg = Message()
                msg.what = buffer[1].toInt()
                callback!!.handleMessage(msg)
            }
        } catch (e: IOException) {
            println("TcpConnect" + e.message)
        }
    }
class CameraFragment : Handler.Callback {
   //页面打开时初始化摄像头
  @SuppressLint("MissingPermission")
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
     //启动tcp
      Thread {
                tcp=TcpConnect()
                tcp.setCallback(this@CameraFragment)
                tcp.listen()
            }.start()
      //初始化摄像头
        initializeCamera()
    }
  
    private fun initializeCamera() = lifecycleScope.launch(Dispatchers.Main) {
        // 打开摄像头
        camera = openCamera(cameraManager, args.cameraId, cameraHandler)
        // 设置拍摄画面的最大分辨率以及图像格式
        val size = characteristics.get(
                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)!!
                .getOutputSizes(args.pixelFormat).maxByOrNull { it.height * it.width }!!
        imageReader = ImageReader.newInstance(
                size.width, size.height, args.pixelFormat, IMAGE_BUFFER_SIZE)
      //这里比较关键,监听摄像头拍到的每帧图片 然后转成二进制流发送到客户端
        imageReader.setOnImageAvailableListener({
            val image = it.acquireNextImage()       
                val buffer = image.planes[0].buffer;
                val len = buffer.remaining()
                var outData = ByteArray(len)                        
                buffer.get(outData, 0, len)
                imageSendThread.run {
                    Runnable {
                        tcp.sendData(outData)
                        tcp.flush()
                        buffer.clear()
                    }.run()
                }          
            image.close();
        }, imageReaderHandler)
  
}

2 主机端应用程序。主要实现 发送控制命令(打开/关闭手机摄像头),接收图像并显示出来。我这里PC端是基于.net core的wpf。

public partial class MainWindow : Window
{
    Socket client;
    Thread listen;
    readonly BitmapImage bmp = new();
    byte[] imgData;

    public MainWindow()
    {
        InitializeComponent();
    }
  //与主端建立连接
    private void ConnectApp()
    {
        client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        client.SendTimeout = 5000;
        client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        client.ReceiveBufferSize = 4096 * 4096;
        IPAddress myIP = IPAddress.Parse("127.0.0.1");
        IPEndPoint EPhost = new IPEndPoint(myIP, 12580);
        client.Connect(EPhost);
        listen = new Thread(Received) { IsBackground = true };
        listen.Start();
    }
  
 //监听回调 收到数据后还原为图像 并显示
    void Received()
        {
            while (true)
            {
               // Thread.Sleep(1);
                if (client == null)
                {
                    continue;
                }
                if (!client.Connected || !listening)
                {
                    ShowData(3, "连接已断开,停止监听");
                    break;
                }

                try
                {
                    client.Receive(buffer);
                  .....
                }
            }
        }
本文来自网络,不代表千度号立场。转载请注明出处: https://www.taibaowl.com/26032.html
广告位
上一篇
下一篇

作者: 395045033

为您推荐

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

联系我们

联系我们

在线咨询: QQ交谈

邮箱: 395045033@qq.com

工作时间:周一至周五,9:00-18:30,节假日休息
返回顶部