Created
April 20, 2018 06:54
-
-
Save WildOrangutan/6afa081bd8c6b76d836590fb2f841210 to your computer and use it in GitHub Desktop.
UVCC dual camera capture quick example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<!-- | |
~ UVCCamera | |
~ library and sample to access to UVC web camera on non-rooted Android device | |
~ | |
~ Copyright (c) 2014-2017 saki t_saki@serenegiant.com | |
~ | |
~ Licensed under the Apache License, Version 2.0 (the "License"); | |
~ you may not use this file except in compliance with the License. | |
~ You may obtain a copy of the License at | |
~ | |
~ http://www.apache.org/licenses/LICENSE-2.0 | |
~ | |
~ Unless required by applicable law or agreed to in writing, software | |
~ distributed under the License is distributed on an "AS IS" BASIS, | |
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
~ See the License for the specific language governing permissions and | |
~ limitations under the License. | |
~ | |
~ All files in the folder are under this Apache License, Version 2.0. | |
~ Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder | |
~ may have a different license, see the respective files. | |
--> | |
<android.support.v4.widget.DrawerLayout | |
xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/drawer_layout" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
> | |
<RelativeLayout | |
android:id="@+id/RelativeLayout1" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:background="#ffffffff" | |
tools:context="com.serenegiant.usbcameratest3.MainActivity" | |
tools:ignore="MergeRootFrame"> | |
<HorizontalScrollView | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
> | |
<ScrollView | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
> | |
<LinearLayout | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:layout_centerInParent="true" | |
android:baselineAligned="false" | |
android:orientation="vertical"> | |
<RelativeLayout | |
android:id="@+id/camera_layout_L" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:layout_weight="1"> | |
<com.serenegiant.widget.UVCCameraTextureView | |
android:id="@+id/camera_view_L" | |
android:layout_width="1280px" | |
android:layout_height="720px" | |
android:layout_centerHorizontal="true" | |
/> | |
<ImageView | |
android:id="@+id/frame_image_L" | |
android:layout_width="1280px" | |
android:layout_height="720px" | |
android:layout_alignBottom="@+id/camera_view_L" | |
android:layout_alignLeft="@+id/camera_view_L" | |
android:layout_alignRight="@+id/camera_view_L" | |
android:layout_alignTop="@+id/camera_view_L" | |
android:src="@drawable/border"/> | |
</RelativeLayout> | |
<RelativeLayout | |
android:id="@+id/camera_layout_R" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:layout_weight="1"> | |
<com.serenegiant.widget.UVCCameraTextureView | |
android:id="@+id/camera_view_R" | |
android:layout_width="1280px" | |
android:layout_height="720px" | |
android:layout_centerHorizontal="true" | |
/> | |
<ImageView | |
android:id="@+id/frame_image_R" | |
android:layout_width="1280px" | |
android:layout_height="720px" | |
android:layout_alignBottom="@+id/camera_view_R" | |
android:layout_alignLeft="@+id/camera_view_R" | |
android:layout_alignRight="@+id/camera_view_R" | |
android:layout_alignTop="@+id/camera_view_R" | |
android:src="@drawable/border"/> | |
</RelativeLayout> | |
</LinearLayout> | |
</ScrollView> | |
</HorizontalScrollView> | |
<ImageButton | |
android:id="@+id/capture_button" | |
android:layout_width="@dimen/button_size" | |
android:layout_height="@dimen/button_size" | |
android:layout_centerVertical="true" | |
android:layout_alignParentRight="true" | |
android:layout_marginBottom="6dp" | |
android:background="@null" | |
android:scaleType="centerCrop" | |
android:src="@android:drawable/ic_menu_camera"/> | |
</RelativeLayout> | |
<LinearLayout | |
android:layout_width="wrap_content" | |
android:layout_height="match_parent" | |
android:layout_gravity="left" | |
android:background="@color/WHITE" | |
android:orientation="vertical" | |
> | |
<EditText | |
android:id="@+id/drawerText" | |
android:minWidth="150dp" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:hint="description" | |
android:text="" | |
android:lines="1" | |
android:textColor="@color/BLACK" | |
/> | |
</LinearLayout> | |
</android.support.v4.widget.DrawerLayout> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* UVCCamera | |
* library and sample to access to UVC web camera on non-rooted Android device | |
* | |
* Copyright (c) 2014-2017 saki t_saki@serenegiant.com | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
* | |
* All files in the folder are under this Apache License, Version 2.0. | |
* Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder | |
* may have a different license, see the respective files. | |
*/ | |
package com.serenegiant.usbcameratest7; | |
import android.graphics.SurfaceTexture; | |
import android.hardware.usb.UsbDevice; | |
import android.os.Bundle; | |
import android.os.Environment; | |
import android.util.Log; | |
import android.view.Surface; | |
import android.view.View; | |
import android.view.View.OnClickListener; | |
import android.view.View.OnLongClickListener; | |
import android.widget.EditText; | |
import android.widget.ImageButton; | |
import android.widget.Toast; | |
import com.serenegiant.common.BaseActivity; | |
import com.serenegiant.encoder.MediaMuxerWrapper; | |
import com.serenegiant.usb.CameraDialog; | |
import com.serenegiant.usb.USBMonitor; | |
import com.serenegiant.usb.USBMonitor.OnDeviceConnectListener; | |
import com.serenegiant.usb.USBMonitor.UsbControlBlock; | |
import com.serenegiant.usbcameracommon.UVCCameraHandler; | |
import com.serenegiant.widget.CameraViewInterface; | |
import com.serenegiant.widget.UVCCameraTextureView; | |
import java.io.File; | |
/** | |
* Show side by side view from two camera. | |
* You cane record video images from both camera, but secondarily started recording can not record | |
* audio because of limitation of Android AudioRecord(only one instance of AudioRecord is available | |
* on the device) now. | |
*/ | |
public final class MainActivity extends BaseActivity implements CameraDialog.CameraDialogParent { | |
private static final boolean DEBUG = true; // FIXME set false when production | |
private static final String TAG = "MainActivity"; | |
private static final float[] BANDWIDTH_FACTORS = {1.0f, 1.0f}; | |
private static final int[] RESOLUTION = {1280, 720}; | |
// for accessing USB and USB camera | |
private USBMonitor mUSBMonitor; | |
private UVCCameraHandler mHandlerR; | |
private CameraViewInterface mUVCCameraViewR; | |
private Surface mRightPreviewSurface; | |
private UVCCameraHandler mHandlerL; | |
private CameraViewInterface mUVCCameraViewL; | |
private Surface mLeftPreviewSurface; | |
private ImageButton mCaptureButton; | |
@Override | |
protected void onCreate(final Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main); | |
findViewById(R.id.RelativeLayout1).setOnClickListener(mOnClickListener); | |
mUVCCameraViewL = (CameraViewInterface) findViewById(R.id.camera_view_L); | |
mUVCCameraViewL.setAspectRatio(RESOLUTION[0], RESOLUTION[1]); | |
((UVCCameraTextureView) mUVCCameraViewL).setOnClickListener(mOnClickListener); | |
mHandlerL = UVCCameraHandler.createHandler(this, mUVCCameraViewL, RESOLUTION[0], | |
RESOLUTION[1], BANDWIDTH_FACTORS[0]); | |
mUVCCameraViewR = (CameraViewInterface) findViewById(R.id.camera_view_R); | |
mUVCCameraViewR.setAspectRatio(RESOLUTION[0], RESOLUTION[1]); | |
((UVCCameraTextureView) mUVCCameraViewR).setOnClickListener(mOnClickListener); | |
mHandlerR = UVCCameraHandler.createHandler(this, mUVCCameraViewR, RESOLUTION[0], | |
RESOLUTION[1], BANDWIDTH_FACTORS[1]); | |
mCaptureButton = (ImageButton) findViewById(R.id.capture_button); | |
mCaptureButton.setOnClickListener(mOnClickListener); | |
mCaptureButton.setVisibility(View.INVISIBLE); | |
mUSBMonitor = new USBMonitor(this, mOnDeviceConnectListener); | |
} | |
@Override | |
protected void onStart() { | |
super.onStart(); | |
mUSBMonitor.register(); | |
if (mUVCCameraViewR != null) | |
mUVCCameraViewR.onResume(); | |
if (mUVCCameraViewL != null) | |
mUVCCameraViewL.onResume(); | |
} | |
@Override | |
protected void onStop() { | |
mHandlerR.close(); | |
if (mUVCCameraViewR != null) | |
mUVCCameraViewR.onPause(); | |
mHandlerL.close(); | |
if (mUVCCameraViewL != null) | |
mUVCCameraViewL.onPause(); | |
mCaptureButton.setVisibility(View.INVISIBLE); | |
mUSBMonitor.unregister(); | |
super.onStop(); | |
} | |
@Override | |
protected void onDestroy() { | |
if (mHandlerR != null) { | |
mHandlerR = null; | |
} | |
if (mHandlerL != null) { | |
mHandlerL = null; | |
} | |
if (mUSBMonitor != null) { | |
mUSBMonitor.destroy(); | |
mUSBMonitor = null; | |
} | |
mUVCCameraViewR = null; | |
mUVCCameraViewL = null; | |
mCaptureButton = null; | |
super.onDestroy(); | |
} | |
private final OnClickListener mOnClickListener = new OnClickListener() { | |
@Override | |
public void onClick(final View view) { | |
switch (view.getId()) { | |
case R.id.camera_view_L: | |
if (mHandlerL != null) { | |
if (!mHandlerL.isOpened()) { | |
CameraDialog.showDialog(MainActivity.this); | |
} else { | |
mHandlerL.close(); | |
setCameraButton(); | |
} | |
} | |
break; | |
case R.id.camera_view_R: | |
if (mHandlerR != null) { | |
if (!mHandlerR.isOpened()) { | |
CameraDialog.showDialog(MainActivity.this); | |
} else { | |
mHandlerR.close(); | |
setCameraButton(); | |
} | |
} | |
break; | |
case R.id.capture_button: | |
if (mHandlerL != null && mHandlerR != null) { | |
if (mHandlerL.isOpened() && mHandlerR.isOpened()) { | |
if (checkPermissionWriteExternalStorage()) { | |
if (!mHandlerL.isRecording()) { | |
String drawerText = ((EditText)findViewById(R.id.drawerText)).getText().toString(); | |
if(null == drawerText || drawerText.isEmpty()) | |
drawerText = ""; | |
else | |
drawerText = "_(" + drawerText + ")"; | |
final File outputFileL = MediaMuxerWrapper.getCaptureFile( | |
Environment.DIRECTORY_DCIM, drawerText + "_L.png"); | |
final File outputFileR = MediaMuxerWrapper.getCaptureFile( | |
Environment.DIRECTORY_DCIM, drawerText + "_R.png"); | |
mHandlerL.captureStill(outputFileL.toString()); | |
mHandlerR.captureStill(outputFileR.toString()); | |
} else { | |
mCaptureButton.setColorFilter(0); // return to default color | |
mHandlerL.stopRecording(); | |
mHandlerR.stopRecording(); | |
} | |
} | |
} | |
} | |
break; | |
} | |
} | |
}; | |
private final OnLongClickListener mOnLongClickListener = new OnLongClickListener() { | |
@Override | |
public boolean onLongClick(View v) { | |
switch (v.getId()) { | |
case R.id.capture_button: | |
if (mHandlerL != null && mHandlerR != null) { | |
if (mHandlerL.isOpened() && mHandlerR.isOpened()) { | |
if (checkPermissionWriteExternalStorage() && checkPermissionAudio()) { | |
if (!mHandlerL.isRecording() && !mHandlerR.isRecording()) { | |
mCaptureButton.setColorFilter(0xffff0000); // turn red | |
mHandlerL.startRecording(); | |
mHandlerR.startRecording(); | |
} else { | |
mCaptureButton.setColorFilter(0); // return to default color | |
mHandlerL.stopRecording(); | |
mHandlerR.stopRecording(); | |
} | |
} | |
} | |
} | |
return true; | |
} | |
return false; | |
} | |
}; | |
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(); | |
USBMonitor usbMonitor = getUSBMonitor(); | |
usbMonitor.requestPermission(device); | |
} | |
@Override | |
public void onConnect(final UsbDevice device, final UsbControlBlock ctrlBlock, final | |
boolean createNew) { | |
if (DEBUG) Log.v(TAG, "onConnect:" + device); | |
if (!mHandlerL.isOpened()) { | |
mHandlerL.open(ctrlBlock); | |
final SurfaceTexture st = mUVCCameraViewL.getSurfaceTexture(); | |
mHandlerL.startPreview(new Surface(st)); | |
runOnUiThread(new Runnable() { | |
@Override | |
public void run() { | |
mCaptureButton.setVisibility(View.VISIBLE); | |
} | |
}); | |
} else if (!mHandlerR.isOpened()) { | |
mHandlerR.open(ctrlBlock); | |
final SurfaceTexture st = mUVCCameraViewR.getSurfaceTexture(); | |
mHandlerR.startPreview(new Surface(st)); | |
runOnUiThread(new Runnable() { | |
@Override | |
public void run() { | |
mCaptureButton.setVisibility(View.VISIBLE); | |
} | |
}); | |
} | |
} | |
@Override | |
public void onDisconnect(final UsbDevice device, final UsbControlBlock ctrlBlock) { | |
if (DEBUG) Log.v(TAG, "onDisconnect:" + device); | |
if ((mHandlerL != null) && !mHandlerL.isEqual(device)) { | |
queueEvent(new Runnable() { | |
@Override | |
public void run() { | |
mHandlerL.close(); | |
if (mLeftPreviewSurface != null) { | |
mLeftPreviewSurface.release(); | |
mLeftPreviewSurface = null; | |
} | |
setCameraButton(); | |
} | |
}, 0); | |
} else if ((mHandlerR != null) && !mHandlerR.isEqual(device)) { | |
queueEvent(new Runnable() { | |
@Override | |
public void run() { | |
mHandlerR.close(); | |
if (mRightPreviewSurface != null) { | |
mRightPreviewSurface.release(); | |
mRightPreviewSurface = null; | |
} | |
setCameraButton(); | |
} | |
}, 0); | |
} | |
} | |
@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(); | |
} | |
@Override | |
public void onCancel(final UsbDevice device) { | |
if (DEBUG) Log.v(TAG, "onCancel:"); | |
} | |
}; | |
/** | |
* to access from CameraDialog | |
* | |
* @return | |
*/ | |
@Override | |
public USBMonitor getUSBMonitor() { | |
return mUSBMonitor; | |
} | |
@Override | |
public void onDialogResult(boolean canceled) { | |
if (canceled) { | |
runOnUiThread(new Runnable() { | |
@Override | |
public void run() { | |
setCameraButton(); | |
} | |
}, 0); | |
} | |
} | |
private void setCameraButton() { | |
runOnUiThread(new Runnable() { | |
@Override | |
public void run() { | |
if ((mHandlerL != null) && !mHandlerL.isOpened() && (mHandlerR != null) && | |
!mHandlerR.isOpened() && (mCaptureButton != null)) { | |
mCaptureButton.setVisibility(View.INVISIBLE); | |
} | |
} | |
}, 0); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment