使用套接字发送onPreviewFrame()byte []的正确方法

时间:2014-05-28 07:35:55

标签: java android sockets android-camera

不幸的是,我需要一个朝着正确方向的可靠点。我正在尝试将预览帧从手机的相机发送到平板电脑。在服务器应用程序中,我从onPreviewFrame()启动一个线程来建立一个ServerSocket,然后从客户端应用程序启动另一个响应按钮点击的线程,以进行验证。像这样......

    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        Log.i("Server", "onPreviewFrame() called");
        mParent.new SocketServerThread(data).start();   
    } 

SocketServerThread在哪里......

     ...
     private mData = data;
     ...
     @Override
     public void run() {
         try {
             serverSocket = new ServerSocket(SocketServerPORT);

             while (true) {
                 Socket socket = serverSocket.accept();
                 SocketServerReplyThread socketServerReplyThread = 
                         new SocketServerReplyThread(socket, count, mData);
                 Log.i("Server", "data array sent to reply thread");
                 socketServerReplyThread.run();
             }
         } catch (IOException e) {
             e.printStackTrace();
         }
     }
 }

我可以通过serverSocket.accept()上的块验证连接。乐趣开始尝试处理数据。一次尝试就是这样......

     @Override
     public void run() {
         try {
             outputStream = hostThreadSocket.getOutputStream();
             DataOutputStream dataStream = new DataOutputStream(outputStream);
             dataStream.writeInt(mBuffer.length);
             if (mBuffer.length > 0)
                 outStream.write(mBuffer);
             outStream.close();

         } catch (IOException e) {
             e.printStackTrace();
         }
     }
 }

我设置了断点,一切似乎都正确,除了outStream.close()的断点永远不会被击中。而是返回Socket socket = serverSocket.accept()上的断点。

在客户端,我有一个AsyncTask处理连接,由onClick调用,就像这样......

 @Override
 protected Void doInBackground(Void... arg0) {

     Socket socket = null;
     int bytesRead;

     try {
         socket = new Socket(dstAddress, dstPort);

         InputStream inputStream = socket.getInputStream();
         DataInputStream dis = new DataInputStream(inputStream);                     

         bytesRead = dis.read(buffer);
         if (bytesRead != -1) {
             final Bitmap bitmap = BitmapFactory.decodeByteArray(buffer, 0, bytesRead);
             final DisplayMetrics metrics = new DisplayMetrics();

             AndroidClientActivity.this.runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    getWindowManager().getDefaultDisplay().getMetrics(metrics);
                    //view is an ImageView
                    view.setMinimumHeight(metrics.heightPixels);
                    view.setMinimumWidth(metrics.widthPixels);
                    view.setImageBitmap(bitmap);
                    view.refreshDrawableState();
                }
            });     
         }

     } catch (UnknownHostException e) {
         e.printStackTrace();
     } catch (IOException e) {
         e.printStackTrace();
     }finally{
         if(socket != null){
             try {
                 socket.close();
             } catch (IOException e) {
                 e.printStackTrace();
             }
         }
     }
     return null;
 }

问题是ImageView没有显示任何帧。

问题(S):

  • 在使用byte []设置ImageView之前,是否还需要对byte []执行其他操作?
  • 是否应该在服务器应用程序中完成byte []的处理;有关系吗?
  • 有没有一个更好的方法来解决这个问题?

我应该提一下,前面的代码是一些教程改变的组合,并与我自己的工作相结合。我已尝试使用ByteArray和原始流等备用流来实现相同的目标,但没有运气。我发现在同时调试这两个应用程序时我得到了不可靠的反馈,而在调试另一个应用程序时运行一个应用程序只能让我对这些问题进行部分查看。当我调试两者时,我会在随机的地方获得NPE,否则就不会发生;可能是由于断点暂停。不过不确定。

修改 也会对任何Java API解决方案感兴趣。

1 个答案:

答案 0 :(得分:1)

不,您无法将原始预览帧发送到ImageView。无论如何,ImageView对你来说不是一个好选择,因为它不适用于动态(视频)内容。

如果您想要流式传输视频,则需要在一侧进行压缩并在另一侧进行解码:即使是WiFi也没有足够的带宽来获得合理质量的无压缩视频。幸运的是,Android提供了使用非常高效的硬件编解码器对视频进行编码和解码的API。

此外,您需要一种先进的通信协议来处理延迟,数据包丢失等。从头开始设计和实施是一项艰巨的任务,即使您将其最小化也是如此。幸运的是,没有必要重新发明这个轮子。我强烈推荐libstreaming库,可用于收集,通信和显示实时视频流。