Skip to content

Instantly share code, notes, and snippets.

@WildOrangutan
Created April 20, 2018 06:54
Show Gist options
  • Save WildOrangutan/6afa081bd8c6b76d836590fb2f841210 to your computer and use it in GitHub Desktop.
Save WildOrangutan/6afa081bd8c6b76d836590fb2f841210 to your computer and use it in GitHub Desktop.
UVCC dual camera capture quick example
<?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>
/*
* 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