如何通过蓝牙在其他设备上显示相机预览?

时间:2016-02-02 06:36:36

标签: java android bitmap bluetooth camera

我正在尝试创建蓝牙相机应用,其中2台设备通过蓝牙连接,点击设备1上的开始按钮启动设备2上的相机相机预览应显示在设备上。 当用户在设备1上单击捕获时,设备2应捕获照片。

Full project is here

我正在使用蓝牙聊天示例代码,我能够给出启动命令,但我没有得到如何显示来自相机的预览数据流,这是在byte []并在其他设备上显示预览

我尝试将byte []转换为位图,但位图为空。

在设备1上预览数据

Call to undefined method stdClass::update()

在另一台设备上,它连续读取设备1写入的数据,处理程序传递byte []中的读取数据和此字节[]我试图在surfaceview或imageview中显示,但两者都无法正常工作

BluetoothCameraFragment

camera.setPreviewCallback(new Camera.PreviewCallback() {
            @Override
            public void onPreviewFrame(byte[] data, Camera camera) {

                  //Here I am writing data through connected channel
                  //tried to convert byte[] to bitmap here also but its showing null
             BitmapFactory.Options options = new BitmapFactory.Options();
            bitmap = BitmapFactory.decodeByteArray(image, 0, image.length, options); 
               //setting bitmap to imageview but bitmap itself is null


            }

}

BluetoothManager

public class BluetoothCameraFragment extends Fragment implements SurfaceHolder.Callback{


TextView testView;
Camera camera;
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
Camera.PictureCallback rawCallback;
Camera.ShutterCallback shutterCallback;
Camera.PictureCallback jpegCallback;
private final String tag = "tagg";

Button start, stop, capture;

private static final String TAG = "BluetoothCamera";


private static final int REQUEST_CONNECT_DEVICE_SECURE = 1;
private static final int REQUEST_CONNECT_DEVICE_INSECURE = 2;
private static final int REQUEST_ENABLE_BT = 3;


private ListView mConversationView;
private EditText mOutEditText;
private Button mSendButton;
private ImageView imageview;


private String mConnectedDeviceName = null;


private ArrayAdapter<String> mConversationArrayAdapter;


private StringBuffer mOutStringBuffer;


private BluetoothAdapter mBluetoothAdapter = null;


private BluetoothCameraManager mCameraService = null;
private boolean isCameraRunning = false;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);

    mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();


    if (mBluetoothAdapter == null) {
        FragmentActivity activity = getActivity();
        Toast.makeText(activity, "Bluetooth is not available", Toast.LENGTH_LONG).show();
        activity.finish();
    }
}


@Override
public void onStart() {
    super.onStart();


    if (!mBluetoothAdapter.isEnabled()) {
        Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(enableIntent, REQUEST_ENABLE_BT);

    } else if (mCameraService == null) {
        setup();
    }
}

@Override
public void onDestroy() {
    super.onDestroy();
    if (mCameraService != null) {
        mCameraService.stop();
    }
}

@Override
public void onResume() {
    super.onResume();




    if (mCameraService != null) {

        if (mCameraService.getState() == BluetoothCameraManager.STATE_NONE) {

            mCameraService.start();
        }
    }
}

@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
                         @Nullable Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_bluetooth_camera, container, false);
}

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {

    mSendButton = (Button) view.findViewById(R.id.button_send);
    stop = (Button) view.findViewById(R.id.stop);
    capture = (Button) view.findViewById(R.id.capture);
    imageview = (ImageView) view.findViewById(R.id.previewImage);
}


private void setup() {
    Log.d(TAG, "setup()");












    mSendButton.setOnClickListener(new Button.OnClickListener()
    {
        public void onClick(View arg0) {

            sendMessage("start-camera".getBytes());

        }
    });

    View view = getView();
    if (null != view) {
        stop = (Button)view.findViewById(R.id.stop);
        capture = (Button) view.findViewById(R.id.capture);
    }

    stop.setOnClickListener(new Button.OnClickListener()
    {
        public void onClick(View arg0) {
            sendMessage("stop-camera".getBytes());
        }
    });
    capture.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {

            sendMessage("take-picture".getBytes());
        }
    });

    surfaceView = (SurfaceView)view.findViewById(R.id.surfaceview);
    surfaceHolder = surfaceView.getHolder();
    surfaceHolder.addCallback(this);
    surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    rawCallback = new Camera.PictureCallback() {
        public void onPictureTaken(byte[] data, Camera camera) {
            Log.d("Log", "onPictureTaken - raw");
        }
    };


    shutterCallback = new Camera.ShutterCallback() {
        public void onShutter() {
            Log.i("Log", "onShutter'd");
        }
    };
    jpegCallback = new Camera.PictureCallback() {
        public void onPictureTaken(byte[] data, Camera camera) {
            FileOutputStream outStream = null;
            try {
                outStream = new FileOutputStream(String.format(
                        "/sdcard/%d.jpg", System.currentTimeMillis()));
                outStream.write(data);
                outStream.close();
                Log.d("Log", "onPictureTaken - wrote bytes: " + data.length);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
            }
            Log.d("Log", "onPictureTaken - jpeg");
        }
    };



    mCameraService = new BluetoothCameraManager(getActivity(), mHandler);


    mOutStringBuffer = new StringBuffer("");
}


private void ensureDiscoverable() {
    if (mBluetoothAdapter.getScanMode() !=
            BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
        Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
        discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
        startActivity(discoverableIntent);
    }
}


private void sendMessage(byte[] preview) {

    if (mCameraService.getState() != BluetoothCameraManager.STATE_CONNECTED) {
        Toast.makeText(getActivity(), R.string.not_connected, Toast.LENGTH_SHORT).show();
        return;
    }


    Log.d("sttatt","sending data");
        mCameraService.write(preview);



}


private TextView.OnEditorActionListener mWriteListener
        = new TextView.OnEditorActionListener() {
    public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {

        if (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_UP) {
            String message = view.getText().toString();

        }
        return true;
    }
};


private void setStatus(int resId) {
    FragmentActivity activity = getActivity();
    if (null == activity) {
        return;
    }
    final ActionBar actionBar = activity.getActionBar();
    if (null == actionBar) {
        return;
    }
    actionBar.setSubtitle(resId);
}


private void setStatus(CharSequence subTitle) {
    FragmentActivity activity = getActivity();
    if (null == activity) {
        return;
    }
    final ActionBar actionBar = activity.getActionBar();
    if (null == actionBar) {
        return;
    }
    actionBar.setSubtitle(subTitle);
}


private final Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        FragmentActivity activity = getActivity();
        switch (msg.what) {
            case Constants.MESSAGE_STATE_CHANGE:
                switch (msg.arg1) {
                    case BluetoothCameraManager.STATE_CONNECTED:
                        setStatus(getString(R.string.title_connected_to, mConnectedDeviceName));

                        break;
                    case BluetoothCameraManager.STATE_CONNECTING:
                        setStatus(R.string.title_connecting);
                        break;
                    case BluetoothCameraManager.STATE_LISTEN:
                    case BluetoothCameraManager.STATE_NONE:
                        setStatus(R.string.title_not_connected);
                        break;
                }
                break;
            case Constants.START_CAMERA_SERVICE:

                byte[] readBuf = (byte[]) msg.obj;
                String command  = new String(readBuf).toString();
                Log.d("cammy", "" + command);
                if(command.equals("start-camera")){
                    Log.d("cammy","Startcam");
                    start_camera();
                    Toast.makeText(getActivity(),"starting camera",Toast.LENGTH_LONG).show();

                }else if(command.equals("stop-camera")){
                    Log.d("cammy","Stopcam");
                    stop_camera();
                    Toast.makeText(getActivity(),"stopping camera",Toast.LENGTH_LONG).show();
                }else if(command.equals("take-picture")){
                    Log.d("cammy","takepic");
                    captureImage();
                    Toast.makeText(getActivity(),"Take picture",Toast.LENGTH_LONG).show();
                }else {
                    Log.d("cammy","No trigger");
                }



                break;
            case Constants.STOP_CAMERA:

                break;
            case Constants.TAKE_PICTURE:

                break;
            case Constants.MESSAGE_WRITE:

                mSendButton.setClickable(false);


                Log.d("sttatt","writing data");





                break;
            case Constants.MESSAGE_READ:








                break;
            case Constants.MESSAGE_DEVICE_NAME:

                mConnectedDeviceName = msg.getData().getString(Constants.DEVICE_NAME);
                if (null != activity) {
                    Toast.makeText(activity, "Connected to "
                            + mConnectedDeviceName, Toast.LENGTH_SHORT).show();
                }
                break;
            case Constants.MESSAGE_TOAST:
                if (null != activity) {
                    Toast.makeText(activity, msg.getData().getString(Constants.TOAST),
                            Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }
};

public void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
        case REQUEST_CONNECT_DEVICE_SECURE:

            if (resultCode == Activity.RESULT_OK) {
                connectDevice(data, true);
            }
            break;
        case REQUEST_CONNECT_DEVICE_INSECURE:

            if (resultCode == Activity.RESULT_OK) {
                connectDevice(data, false);
            }
            break;
        case REQUEST_ENABLE_BT:

            if (resultCode == Activity.RESULT_OK) {

                setup();
            } else {

                Log.d(TAG, "BT not enabled");
                Toast.makeText(getActivity(), R.string.bt_not_enabled_leaving,
                        Toast.LENGTH_SHORT).show();
                getActivity().finish();
            }
    }
}


private void connectDevice(Intent data, boolean secure) {

    String address = data.getExtras()
            .getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);

    BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);

    mCameraService.connect(device, secure);
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.bluetooth_camera, menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.secure_connect_scan: {

            Intent serverIntent = new Intent(getActivity(), DeviceListActivity.class);
            startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_SECURE);
            return true;
        }
        case R.id.insecure_connect_scan: {

            Intent serverIntent = new Intent(getActivity(), DeviceListActivity.class);
            startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_INSECURE);
            return true;
        }
        case R.id.discoverable: {

            ensureDiscoverable();
            return true;
        }
    }
    return false;
}


private void captureImage() {
    camera.takePicture(shutterCallback, rawCallback, jpegCallback);
}

private void start_camera(){
    try{
        camera = Camera.open();
        isCameraRunning=true;
    }catch(RuntimeException e){
        Log.e(tag, "init_camera: " + e);
        return;
    }
    Camera.Parameters param;
    param = camera.getParameters();

    param.setPreviewFrameRate(20);
    param.setPreviewSize(176, 144);
    camera.setParameters(param);
    try {
        camera.setPreviewDisplay(surfaceHolder);
        camera.setPreviewCallback(new Camera.PreviewCallback() {
            @Override
            public void onPreviewFrame(byte[] data, Camera camera) {




            }
        });
        camera.startPreview();

    } catch (Exception e) {
        Log.e(tag, "init_camera: " + e);
        return;
    }
}

private void stop_camera()
{
        camera.stopPreview();
        camera.release();
}

public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {

}

public void surfaceCreated(SurfaceHolder holder) {

}

public void surfaceDestroyed(SurfaceHolder holder) {

}

1 个答案:

答案 0 :(得分:3)

通常蓝牙发送图像帧的速度很慢,但您不需要发送每一帧。您将面临的一个问题是框架碰撞。蓝牙套接字将您的数据(帧)作为字节数组发送。因此,在大多数时间从其他端接收数据时,前一帧和当前帧的字节将发生冲突。因此,您需要确保远程移动设备接收到第一帧并成功处理。在远程移动设备处理时创建的帧不应该存储在缓冲区中以便稍后发送,而应该忽略它们(不应该发送)。某些帧可能会遗漏,但您将作为实时Feed使用。现在Android手机将根据相机分辨率创建大帧预览。所以你只需要发送小尺寸的画面,在显示器的剩余空间你可以显示相机控制。

我在Github回购中发布了一个示例项目。 Bluetooth Camera