diff --git a/libuvccamera/src/main/jni/UVCCamera/UVCPreview.h b/libuvccamera/src/main/jni/UVCCamera/UVCPreview.h
index 200b68fd9..33ebb16d3 100644
--- a/libuvccamera/src/main/jni/UVCCamera/UVCPreview.h
+++ b/libuvccamera/src/main/jni/UVCCamera/UVCPreview.h
@@ -34,7 +34,7 @@
#define DEFAULT_PREVIEW_WIDTH 640
#define DEFAULT_PREVIEW_HEIGHT 480
-#define DEFAULT_PREVIEW_FPS 30
+#define DEFAULT_PREVIEW_FPS 15
#define DEFAULT_PREVIEW_MODE 0
#define DEFAULT_BANDWIDTH 1.0f
diff --git a/libuvccamera/src/main/jni/libuvc/src/stream.c b/libuvccamera/src/main/jni/libuvc/src/stream.c
index 33453ff9e..7e072c259 100644
--- a/libuvccamera/src/main/jni/libuvc/src/stream.c
+++ b/libuvccamera/src/main/jni/libuvc/src/stream.c
@@ -1461,6 +1461,7 @@ uvc_error_t uvc_stream_start_bandwidth(uvc_stream_handle_t *strmh,
* packet sizes are increasing. */
const int num_alt = interface->num_altsetting - 1;
for (alt_idx = 0; alt_idx <= num_alt ; alt_idx++) {
+ alt_idx = 4; // FIXME just for test
altsetting = interface->altsetting + alt_idx;
endpoint_bytes_per_packet = 0;
@@ -1484,8 +1485,8 @@ uvc_error_t uvc_stream_start_bandwidth(uvc_stream_handle_t *strmh,
}
// XXX config_bytes_per_packet should not be zero otherwise zero divided exception occur
if (LIKELY(endpoint_bytes_per_packet)) {
- if ( (endpoint_bytes_per_packet >= config_bytes_per_packet)
- || (alt_idx == num_alt) ) { // XXX always match to last altsetting for buggy device
+// if ( (endpoint_bytes_per_packet >= config_bytes_per_packet) // FIXME just for test
+// || (alt_idx == num_alt) ) { // XXX always match to last altsetting for buggy device // FIXME just for test
/* Transfers will be at most one frame long: Divide the maximum frame size
* by the size of the endpoint and round up */
packets_per_transfer = (dwMaxVideoFrameSize
@@ -1498,7 +1499,7 @@ uvc_error_t uvc_stream_start_bandwidth(uvc_stream_handle_t *strmh,
total_transfer_size = packets_per_transfer * endpoint_bytes_per_packet;
break;
- }
+// }
}
}
if (UNLIKELY(!endpoint_bytes_per_packet)) {
@@ -1520,7 +1521,7 @@ uvc_error_t uvc_stream_start_bandwidth(uvc_stream_handle_t *strmh,
} */
/* Select the altsetting */
- MARK("Select the altsetting");
+ MARK("Select altsetting:%d", altsetting->bAlternateSetting);
ret = libusb_set_interface_alt_setting(strmh->devh->usb_devh,
altsetting->bInterfaceNumber, altsetting->bAlternateSetting);
if (UNLIKELY(ret != UVC_SUCCESS)) {
diff --git a/libuvccamera/src/main/libs/armeabi-v7a/libUVCCamera.so b/libuvccamera/src/main/libs/armeabi-v7a/libUVCCamera.so
index 8deecded3..3f5fa3596 100755
Binary files a/libuvccamera/src/main/libs/armeabi-v7a/libUVCCamera.so and b/libuvccamera/src/main/libs/armeabi-v7a/libUVCCamera.so differ
diff --git a/libuvccamera/src/main/libs/armeabi-v7a/libuvc.so b/libuvccamera/src/main/libs/armeabi-v7a/libuvc.so
index e30c36292..4fda2fe64 100755
Binary files a/libuvccamera/src/main/libs/armeabi-v7a/libuvc.so and b/libuvccamera/src/main/libs/armeabi-v7a/libuvc.so differ
diff --git a/libuvccamera/src/main/libs/armeabi/libUVCCamera.so b/libuvccamera/src/main/libs/armeabi/libUVCCamera.so
index 91a709657..553cc413c 100755
Binary files a/libuvccamera/src/main/libs/armeabi/libUVCCamera.so and b/libuvccamera/src/main/libs/armeabi/libUVCCamera.so differ
diff --git a/libuvccamera/src/main/libs/armeabi/libuvc.so b/libuvccamera/src/main/libs/armeabi/libuvc.so
index 380c8103e..ff2f1538c 100755
Binary files a/libuvccamera/src/main/libs/armeabi/libuvc.so and b/libuvccamera/src/main/libs/armeabi/libuvc.so differ
diff --git a/libuvccamera/src/main/libs/mips/libUVCCamera.so b/libuvccamera/src/main/libs/mips/libUVCCamera.so
index ef26c7fd5..814fd3d18 100755
Binary files a/libuvccamera/src/main/libs/mips/libUVCCamera.so and b/libuvccamera/src/main/libs/mips/libUVCCamera.so differ
diff --git a/libuvccamera/src/main/libs/mips/libuvc.so b/libuvccamera/src/main/libs/mips/libuvc.so
index 51d8e10f9..0cdaaee13 100755
Binary files a/libuvccamera/src/main/libs/mips/libuvc.so and b/libuvccamera/src/main/libs/mips/libuvc.so differ
diff --git a/libuvccamera/src/main/libs/x86/libUVCCamera.so b/libuvccamera/src/main/libs/x86/libUVCCamera.so
index 69cebbed1..bc3300606 100755
Binary files a/libuvccamera/src/main/libs/x86/libUVCCamera.so and b/libuvccamera/src/main/libs/x86/libUVCCamera.so differ
diff --git a/libuvccamera/src/main/libs/x86/libuvc.so b/libuvccamera/src/main/libs/x86/libuvc.so
index 0bd9977ea..07cd58eb8 100755
Binary files a/libuvccamera/src/main/libs/x86/libuvc.so and b/libuvccamera/src/main/libs/x86/libuvc.so differ
diff --git a/usbCameraTest7/src/main/AndroidManifest.xml b/usbCameraTest7/src/main/AndroidManifest.xml
index 49c179826..e401efcbd 100644
--- a/usbCameraTest7/src/main/AndroidManifest.xml
+++ b/usbCameraTest7/src/main/AndroidManifest.xml
@@ -35,11 +35,21 @@
+ android:screenOrientation="landscape"
+ android:launchMode="singleTask" >
+
+
+
+
+
+
+
diff --git a/usbCameraTest7/src/main/java/com/serenegiant/usbcameratest7/MainActivity.java b/usbCameraTest7/src/main/java/com/serenegiant/usbcameratest7/MainActivity.java
index 5e248b054..1a3c9f51c 100644
--- a/usbCameraTest7/src/main/java/com/serenegiant/usbcameratest7/MainActivity.java
+++ b/usbCameraTest7/src/main/java/com/serenegiant/usbcameratest7/MainActivity.java
@@ -23,6 +23,10 @@
* Files in the jni/libjpeg, jni/libusb, jin/libuvc, jni/rapidjson folder may have a different license, see the respective files.
*/
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@@ -31,6 +35,8 @@
import android.graphics.SurfaceTexture;
import android.hardware.usb.UsbDevice;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.util.Log;
import android.view.Surface;
import android.view.View;
@@ -38,6 +44,7 @@
import android.widget.Toast;
import com.serenegiant.usb.CameraDialog;
+import com.serenegiant.usb.DeviceFilter;
import com.serenegiant.usb.USBMonitor;
import com.serenegiant.usb.USBMonitor.OnDeviceConnectListener;
import com.serenegiant.usb.USBMonitor.UsbControlBlock;
@@ -45,25 +52,21 @@
import com.serenegiant.widget.UVCCameraTextureView;
public final class MainActivity extends Activity implements CameraDialog.CameraDialogParent {
- private static final boolean DEBUG = false; // FIXME set false when production
+ private static final boolean DEBUG = true; // FIXME set false when production
private static final String TAG = "MainActivity";
// for thread pool
private static final int CORE_POOL_SIZE = 1; // initial/minimum threads
private static final int MAX_POOL_SIZE = 4; // maximum threads
private static final int KEEP_ALIVE_TIME = 10; // time periods while keep the idle thread
- protected static final ThreadPoolExecutor EXECUTER
- = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME,
- TimeUnit.SECONDS, new LinkedBlockingQueue());
+ private final Object mSync = new Object();
+ private final Map mCameras = new HashMap();
// for accessing USB and USB camera
private USBMonitor mUSBMonitor;
- private UVCCamera mLeftCamera;
- private UVCCamera mRightCamera;
private UVCCameraTextureView mUVCCameraViewR;
private UVCCameraTextureView mUVCCameraViewL;
- private Surface mLeftPreviewSurface;
- private Surface mRightPreviewSurface;
+ private Handler mAsyncHandler;
@Override
protected void onCreate(final Bundle savedInstanceState) {
@@ -79,38 +82,67 @@ protected void onCreate(final Bundle savedInstanceState) {
mUVCCameraViewR.setAspectRatio(UVCCamera.DEFAULT_PREVIEW_WIDTH / (float)UVCCamera.DEFAULT_PREVIEW_HEIGHT);
mUVCCameraViewR.setOnClickListener(mOnClickListener);
+ final HandlerThread thread = new HandlerThread(TAG);
+ thread.start();
+ mAsyncHandler = new Handler(thread.getLooper());
mUSBMonitor = new USBMonitor(this, mOnDeviceConnectListener);
+ final List filters = DeviceFilter.getDeviceFilters(this, R.xml.device_filter);
+ mUSBMonitor.setDeviceFilter(filters);
}
@Override
public void onResume() {
super.onResume();
+ if (DEBUG) Log.v(TAG, "onResume:");
mUSBMonitor.register();
- if (mLeftCamera != null)
- mLeftCamera.startPreview();
- if (mRightCamera != null)
- mRightCamera.startPreview();
+ synchronized (mSync) {
+ for (final CameraRec rec: mCameras.values()) {
+ rec.startPreview();
+ }
+ }
+ mAsyncHandler.removeCallbacks(tryOpenTask);
+ mAsyncHandler.postDelayed(tryOpenTask, 1000);
}
@Override
public void onPause() {
- if (mLeftCamera != null)
- mLeftCamera.stopPreview();
- if (mRightCamera != null)
- mRightCamera.stopPreview();
+ if (DEBUG) Log.v(TAG, "onPause:" + mCameras.size());
+ mAsyncHandler.removeCallbacks(tryOpenTask);
+ if (isFinishing()) {
+ final List list = new ArrayList();
+ synchronized (mSync) {
+ list.addAll(mCameras.values());
+ mCameras.clear();
+ }
+ synchronized (mSync) {
+ mAsyncHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (DEBUG) Log.v(TAG, "onPause:" + list.size());
+ for (final CameraRec rec: list) {
+ rec.release();
+ }
+ synchronized (mSync) {
+ mSync.notifyAll();
+ }
+ }
+ });
+ try {
+ mSync.wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ }
mUSBMonitor.unregister();
super.onPause();
+ if (DEBUG) Log.v(TAG, "onPause:finished");
}
@Override
public void onDestroy() {
- if (mLeftCamera != null) {
- mLeftCamera.destroy();
- mLeftCamera = null;
- }
- if (mRightCamera != null) {
- mRightCamera.destroy();
- mRightCamera = null;
+ if (DEBUG) Log.v(TAG, "onDestroy:");
+ if (mAsyncHandler != null) {
+ mAsyncHandler.removeCallbacks(tryOpenTask);
}
if (mUSBMonitor != null) {
mUSBMonitor.destroy();
@@ -118,6 +150,13 @@ public void onDestroy() {
}
mUVCCameraViewR = null;
mUVCCameraViewL = null;
+ try {
+ if (mAsyncHandler != null) {
+ mAsyncHandler.getLooper().quitSafely();
+ }
+ } catch (final Exception e) {
+ }
+ mAsyncHandler = null;
super.onDestroy();
}
@@ -126,115 +165,81 @@ public void onDestroy() {
public void onClick(final View view) {
switch (view.getId()) {
case R.id.camera_view_L:
- if (mLeftCamera == null)
+ {
+ final CameraRec rec = (CameraRec)mUVCCameraViewL.getTag();
+ if (rec == null) {
CameraDialog.showDialog(MainActivity.this);
- else {
- mLeftCamera.destroy();
- mLeftCamera = null;
+ } else {
+ rec.release();
}
break;
+ }
case R.id.camera_view_R:
- if (mRightCamera == null)
+ {
+ final CameraRec rec = (CameraRec)mUVCCameraViewR.getTag();
+ if (rec == null) {
CameraDialog.showDialog(MainActivity.this);
- else {
- mRightCamera.destroy();
- mRightCamera = null;
+ } else {
+ rec.release();
}
break;
}
+ }
}
};
- private static final float[] BANDWIDTH_FACTORS = { 0.67f, 0.67f };
private final OnDeviceConnectListener mOnDeviceConnectListener = new OnDeviceConnectListener() {
@Override
public void onAttach(final UsbDevice device) {
- if (DEBUG) Log.v(TAG, "onAttach:" + device);
- Toast.makeText(MainActivity.this, "USB_DEVICE_ATTACHED", Toast.LENGTH_SHORT).show();
+ if (DEBUG) Log.v(TAG, "onAttach:" + (device != null ? device.getDeviceName() : "null"));
+ mAsyncHandler.removeCallbacks(tryOpenTask);
+ mAsyncHandler.postDelayed(tryOpenTask, 1000);
}
@Override
public void onConnect(final UsbDevice device, final UsbControlBlock ctrlBlock, final boolean createNew) {
- if (mLeftCamera != null && mRightCamera != null) return;
- if (DEBUG) Log.v(TAG, "onConnect:" + device);
- final UVCCamera camera = new UVCCamera();
- EXECUTER.execute(new Runnable() {
+ if (DEBUG) Log.v(TAG, "onConnect:" + (device != null ? device.getDeviceName() : "null"));
+ openCamera(device, ctrlBlock);
+ }
+
+ @Override
+ public void onDisconnect(final UsbDevice device, final UsbControlBlock ctrlBlock) {
+ if (DEBUG) Log.v(TAG, "onDisconnect:" + (device != null ? device.getDeviceName() : "null"));
+ mAsyncHandler.post(new Runnable() {
@Override
public void run() {
- final int open_camera_nums = (mLeftCamera != null ? 1 : 0) + (mRightCamera != null ? 1 : 0);
- camera.open(ctrlBlock);
-// camera.setPreviewTexture(mRightCameraView.getSurfaceTexture());
- try {
- camera.setPreviewSize(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, UVCCamera.FRAME_FORMAT_MJPEG, BANDWIDTH_FACTORS[open_camera_nums]);
- } catch (final IllegalArgumentException e) {
- // fallback to YUV mode
- try {
- camera.setPreviewSize(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, UVCCamera.DEFAULT_PREVIEW_MODE, BANDWIDTH_FACTORS[open_camera_nums]);
- } catch (final IllegalArgumentException e1) {
- camera.destroy();
- return;
+ synchronized (mSync) {
+ final CameraRec rec = mCameras.remove(device);
+ if (rec != null) {
+ rec.release();
}
}
- if (mLeftCamera == null) {
- mLeftCamera = camera;
- if (mLeftPreviewSurface != null) {
- mLeftPreviewSurface.release();
- mLeftPreviewSurface = null;
- }
- final SurfaceTexture st = mUVCCameraViewL.getSurfaceTexture();
- if (st != null)
- mLeftPreviewSurface = new Surface(st);
- camera.setPreviewDisplay(mLeftPreviewSurface);
-// camera.setFrameCallback(mIFrameCallback, UVCCamera.PIXEL_FORMAT_NV21);
- camera.startPreview();
- } else if (mRightCamera == null) {
- mRightCamera = camera;
- if (mRightPreviewSurface != null) {
- mRightPreviewSurface.release();
- mRightPreviewSurface = null;
- }
- final SurfaceTexture st = mUVCCameraViewR.getSurfaceTexture();
- if (st != null)
- mRightPreviewSurface = new Surface(st);
- camera.setPreviewDisplay(mRightPreviewSurface);
-// camera.setFrameCallback(mIFrameCallback, UVCCamera.PIXEL_FORMAT_NV21);
- camera.startPreview();
- }
}
});
}
- @Override
- public void onDisconnect(final UsbDevice device, final UsbControlBlock ctrlBlock) {
- if (DEBUG) Log.v(TAG, "onDisconnect:" + device);
- if (mLeftCamera != null && device.equals(mLeftCamera.getDevice())) {
- mLeftCamera.close();
- if (mLeftPreviewSurface != null) {
- mLeftPreviewSurface.release();
- mLeftPreviewSurface = null;
- }
- mLeftCamera.destroy();
- mLeftCamera = null;
- } else if (mRightCamera != null && device.equals(mRightCamera.getDevice())) {
- mRightCamera.close();
- if (mLeftPreviewSurface != null) {
- mLeftPreviewSurface.release();
- mLeftPreviewSurface = null;
- }
- mRightCamera.destroy();
- mRightCamera = null;
- }
- }
-
@Override
public void onDettach(final UsbDevice device) {
- if (DEBUG) Log.v(TAG, "onDettach:" + device);
- Toast.makeText(MainActivity.this, "USB_DEVICE_DETACHED", Toast.LENGTH_SHORT).show();
+ if (DEBUG) Log.v(TAG, "onDettach:" + (device != null ? device.getDeviceName() : "null"));
+ mAsyncHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mSync) {
+ final CameraRec rec = mCameras.remove(device);
+ if (rec != null) {
+ rec.release();
+ }
+ }
+ }
+ });
}
@Override
public void onCancel() {
if (DEBUG) Log.v(TAG, "onCancel:");
+ synchronized (mSync) {
+ mSync.notifyAll();
+ }
}
};
@@ -254,4 +259,146 @@ public USBMonitor getUSBMonitor() {
public void onFrame(final ByteBuffer frame) {
}
}; */
+
+ private boolean tryOpen(final UsbDevice device) {
+ if (DEBUG) Log.v(TAG, "tryOpen:" + (device != null ? device.getDeviceName() : ""));
+ if (device == null) return false;
+ boolean retry = true;
+ CameraRec rec = null;
+ synchronized (mSync) {
+ rec = mCameras.containsKey(device) ? mCameras.get(device) : null;
+ }
+ if (rec == null) {
+ UVCCameraTextureView view = null;
+ if ((mUVCCameraViewR != null) && (mUVCCameraViewR.getTag() == null)) {
+ view = mUVCCameraViewR;
+ } else if ((mUVCCameraViewL != null) && (mUVCCameraViewL.getTag() == null)) {
+ view = mUVCCameraViewL;
+ }
+ if (view != null) {
+ rec = new CameraRec(view);
+ synchronized (mSync) {
+ mCameras.put(device, rec);
+ mUSBMonitor.requestPermission(device);
+ try {
+ mSync.wait();
+ if (rec.mCamera == null) {
+ if (DEBUG) Log.w(TAG, "failed to start camera");
+ mCameras.remove(device);
+ }
+ } catch (final InterruptedException e) {
+ retry = false;
+ }
+ }
+ } else {
+ if (DEBUG) Log.w(TAG, "there may be more than three connected camera.");
+ retry = false;
+ }
+ } else {
+ if (DEBUG) Log.v(TAG, "will be already connected.");
+ retry = false;
+ }
+ return retry;
+ }
+
+ private static final float[] BANDWIDTH_FACTORS = { 0.67f, 0.67f };
+ private void openCamera(final UsbDevice device, final UsbControlBlock ctrlBlock) {
+ if (DEBUG) Log.v(TAG, "openCamera:" + (device != null ? device.getDeviceName() : "null"));
+ final UVCCamera camera = new UVCCamera();
+ synchronized (mSync) {
+ final CameraRec rec = mCameras.containsKey(device) ? mCameras.get(device) : null;
+ if (rec != null) {
+ final int open_camera_nums = mCameras.size() - 1; // (mLeftCamera != null ? 1 : 0) + (mRightCamera != null ? 1 : 0);
+ camera.open(ctrlBlock);
+ try {
+ camera.setPreviewSize(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, UVCCamera.FRAME_FORMAT_MJPEG, BANDWIDTH_FACTORS[open_camera_nums]);
+ } catch (final IllegalArgumentException e) {
+ // fallback to YUV mode
+ try {
+ camera.setPreviewSize(UVCCamera.DEFAULT_PREVIEW_WIDTH, UVCCamera.DEFAULT_PREVIEW_HEIGHT, UVCCamera.DEFAULT_PREVIEW_MODE, BANDWIDTH_FACTORS[open_camera_nums]);
+ } catch (final IllegalArgumentException e1) {
+ camera.destroy();
+ return;
+ }
+ }
+ rec.setCamera(camera);
+ } else {
+ if (DEBUG) Log.v(TAG, "CameraRec is null");
+ }
+ mSync.notifyAll();
+ }
+ if (DEBUG) Log.v(TAG, "openCamera:finished");
+ }
+
+ private static class CameraRec {
+ private UVCCamera mCamera;
+ private final UVCCameraTextureView mCameraView;
+ private Surface mSurface;
+ public CameraRec(final UVCCameraTextureView view) {
+ mCameraView = view;
+ view.setTag(this);
+ }
+
+ public void release() {
+ if (DEBUG) Log.v(TAG, "release:");
+ mCameraView.setTag(null);
+ if (mCamera != null) {
+ mCamera.destroy();
+ mCamera = null;
+ }
+ if (mSurface != null) {
+ mSurface.release();
+ mSurface = null;
+ }
+ if (DEBUG) Log.v(TAG, "release:finished");
+ }
+
+ public void setCamera(final UVCCamera camera) {
+ if (DEBUG) Log.v(TAG, "setCamera:");
+ mCamera = camera;
+ if (mSurface != null) {
+ mSurface.release();
+ mSurface = null;
+ }
+ final SurfaceTexture st = mCameraView.getSurfaceTexture();
+ if (st != null)
+ mSurface = new Surface(st);
+ camera.setPreviewDisplay(mSurface);
+ camera.startPreview();
+ }
+
+ public void startPreview() {
+ if (mCamera != null) {
+ mCamera.startPreview();
+ }
+ }
+
+ public void stopPreview() {
+ if (mCamera != null) {
+ mCamera.stopPreview();
+ }
+ }
+ }
+
+ private final Runnable tryOpenTask = new Runnable() {
+ @Override
+ public void run() {
+ if (DEBUG) Log.v(TAG, "tryOpenTask#run:");
+ final List list = mUSBMonitor.getDeviceList();
+ int retry = list.size();
+ for (final UsbDevice device: list) {
+ if (mUSBMonitor.hasPermission(device)) {
+ if (!tryOpen(device)) {
+ retry--;
+ }
+ } else {
+ retry--;
+ }
+ }
+ if ((retry > 0) && !isFinishing()) {
+ mAsyncHandler.postDelayed(this, 1000);
+ }
+ if (DEBUG) Log.v(TAG, "tryOpenTask#run:finished");
+ }
+ };
}