Browse Source

支持切换分辨率

main v1.2.0
jiangdongguo 7 years ago
parent
commit
0f6f4f5da9
  1. 35
      app/src/main/java/com/jiangdg/usbcamera/view/USBCameraActivity.java
  2. 10
      app/src/main/res/layout/activity_usbcamera.xml
  3. 65
      libusbcamera/src/main/java/com/jiangdg/usbcamera/USBCameraManager.java
  4. 31
      libusbcamera/src/main/java/com/serenegiant/usb/common/AbstractUVCCameraHandler.java
  5. 4
      libusbcamera/src/main/java/com/serenegiant/usb/common/UVCCameraHandler.java
  6. 4
      libusbcamera/src/main/java/com/serenegiant/usb/common/UVCCameraHandlerMultiSurface.java
  7. 16
      libusbcamera/src/main/java/com/serenegiant/usb/encoder/biz/H264EncodeConsumer.java

35
app/src/main/java/com/jiangdg/usbcamera/view/USBCameraActivity.java

@ -44,13 +44,13 @@ public class USBCameraActivity extends AppCompatActivity implements CameraDialog
public Button mBtnCapture; public Button mBtnCapture;
@BindView(R.id.btn_rec_video) @BindView(R.id.btn_rec_video)
public Button mBtnRecord; public Button mBtnRecord;
@BindView(R.id.btn_update_resolution)
public Button mBtnUpdateResultion;
private USBCameraManager mUSBManager; private USBCameraManager mUSBManager;
private CameraViewInterface mUVCCameraView; private CameraViewInterface mUVCCameraView;
private boolean isRequest; private boolean isRequest;
private static String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/test1.h264";
private BufferedOutputStream outputStream;
/** /**
* USB设备事件监听器 * USB设备事件监听器
@ -85,8 +85,10 @@ public class USBCameraActivity extends AppCompatActivity implements CameraDialog
// 连接USB设备成功 // 连接USB设备成功
@Override @Override
public void onConnectDev(UsbDevice device) { public void onConnectDev(UsbDevice device,boolean isConnected) {
if(! isConnected) {
showShortMsg("连接失败,请检查分辨率参数是否正确");
}
} }
// 与USB设备断开连接 // 与USB设备断开连接
@ -115,10 +117,6 @@ public class USBCameraActivity extends AppCompatActivity implements CameraDialog
if(mUSBManager != null){ if(mUSBManager != null){
mUSBManager.registerUSB(); mUSBManager.registerUSB();
} }
// 恢复Camera预览
if(mUVCCameraView != null){
mUVCCameraView.onResume();
}
} }
@Override @Override
@ -128,16 +126,27 @@ public class USBCameraActivity extends AppCompatActivity implements CameraDialog
if(mUSBManager != null){ if(mUSBManager != null){
mUSBManager.unregisterUSB(); mUSBManager.unregisterUSB();
} }
// 暂停Camera预览
if(mUVCCameraView != null){
mUVCCameraView.onPause();
}
} }
@OnClick({R.id.camera_view, R.id.btn_capture_pic, R.id.btn_rec_video}) @OnClick({R.id.camera_view, R.id.btn_capture_pic, R.id.btn_rec_video,R.id.btn_update_resolution})
public void onViewClick(View view) { public void onViewClick(View view) {
int vId = view.getId(); int vId = view.getId();
switch (vId) { switch (vId) {
// 切换分辨率
case R.id.btn_update_resolution:
if(mUSBManager == null)
return;
mUSBManager.updateResolution(this, mUVCCameraView, 320, 240, new USBCameraManager.OnPreviewListener() {
@Override
public void onPreviewResult(boolean isSuccess) {
if(! isSuccess) {
showShortMsg("预览失败,不支持该分辨率");
}else {
showShortMsg("以切换到分辨率为320x240");
}
}
});
break;
// 开启或关闭Camera // 开启或关闭Camera
case R.id.camera_view: case R.id.camera_view:
// if(mUSBManager != null){ // if(mUSBManager != null){

10
app/src/main/res/layout/activity_usbcamera.xml

@ -35,4 +35,14 @@
android:textSize="16sp" android:textSize="16sp"
android:text="开始录制"/> android:text="开始录制"/>
<Button
android:layout_above="@id/btn_rec_video"
android:id="@+id/btn_update_resolution"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:layout_marginLeft="10dp"
android:textSize="16sp"
android:text="切换分辨率为320x240"/>
</RelativeLayout> </RelativeLayout>

65
libusbcamera/src/main/java/com/jiangdg/usbcamera/USBCameraManager.java

@ -17,8 +17,6 @@ import com.serenegiant.usb.widget.CameraViewInterface;
import java.io.File; import java.io.File;
import java.util.List; import java.util.List;
import static android.R.attr.filter;
/**USB摄像头工具类 /**USB摄像头工具类
* *
* Created by jiangdongguo on 2017/9/30. * Created by jiangdongguo on 2017/9/30.
@ -30,8 +28,8 @@ public class USBCameraManager{
public static final String SUFFIX_PNG = ".png"; public static final String SUFFIX_PNG = ".png";
public static final String SUFFIX_MP4 = ".mp4"; public static final String SUFFIX_MP4 = ".mp4";
private static final String TAG = "USBCameraManager"; private static final String TAG = "USBCameraManager";
private static final int PREVIEW_WIDTH = 640; private int previewWidth = 640;
private static final int PREVIEW_HEIGHT = 480; private int previewHeight = 480;
// 使用MediaVideoBufferEncoder // 使用MediaVideoBufferEncoder
private static final int ENCODER_TYPE = 2; private static final int ENCODER_TYPE = 2;
//0为YUYV,1为MJPEG //0为YUYV,1为MJPEG
@ -44,6 +42,7 @@ public class USBCameraManager{
private UVCCameraHandler mCameraHandler; private UVCCameraHandler mCameraHandler;
private Context mContext; private Context mContext;
private USBMonitor.UsbControlBlock mCtrlBlock;
private USBCameraManager(){} private USBCameraManager(){}
@ -57,10 +56,14 @@ public class USBCameraManager{
public interface OnMyDevConnectListener{ public interface OnMyDevConnectListener{
void onAttachDev(UsbDevice device); void onAttachDev(UsbDevice device);
void onDettachDev(UsbDevice device); void onDettachDev(UsbDevice device);
void onConnectDev(UsbDevice device); void onConnectDev(UsbDevice device,boolean isConnected);
void onDisConnectDev(UsbDevice device); void onDisConnectDev(UsbDevice device);
} }
public interface OnPreviewListener{
void onPreviewResult(boolean isSuccess);
}
/** 初始化 /** 初始化
* *
* context 上下文 * context 上下文
@ -73,6 +76,7 @@ public class USBCameraManager{
mContext = activity.getApplicationContext(); mContext = activity.getApplicationContext();
mUSBMonitor = new USBMonitor(activity.getApplicationContext(), new USBMonitor.OnDeviceConnectListener() { mUSBMonitor = new USBMonitor(activity.getApplicationContext(), new USBMonitor.OnDeviceConnectListener() {
// 当检测到USB设备,被回调 // 当检测到USB设备,被回调
@Override @Override
public void onAttach(UsbDevice device) { public void onAttach(UsbDevice device) {
@ -91,14 +95,19 @@ public class USBCameraManager{
// 当连接到USB Camera时,被回调 // 当连接到USB Camera时,被回调
@Override @Override
public void onConnect(UsbDevice device, USBMonitor.UsbControlBlock ctrlBlock, boolean createNew) { public void onConnect(final UsbDevice device, USBMonitor.UsbControlBlock ctrlBlock, boolean createNew) {
if(listener != null){ mCtrlBlock = ctrlBlock;
listener.onConnectDev(device);
}
// 打开摄像头 // 打开摄像头
openCamera(ctrlBlock); openCamera(ctrlBlock);
// 开启预览 // 开启预览
startPreview(cameraView); startPreview(cameraView, new AbstractUVCCameraHandler.OnPreViewResultListener() {
@Override
public void onPreviewResult(boolean isConnected) {
if(listener != null){
listener.onConnectDev(device,isConnected);
}
}
});
} }
// 当与USB Camera断开连接时,被回调 // 当与USB Camera断开连接时,被回调
@ -115,11 +124,37 @@ public class USBCameraManager{
public void onCancel(UsbDevice device) { public void onCancel(UsbDevice device) {
} }
}); });
cameraView.setAspectRatio(previewWidth / (float)previewHeight);
mCameraHandler = UVCCameraHandler.createHandler(activity,cameraView,ENCODER_TYPE,
previewWidth,previewHeight,PREVIEW_FORMAT);
}
// 切换分辨率
public void updateResolution(Activity activity, CameraViewInterface cameraView, int width, int height, final OnPreviewListener mPreviewListener){
this.previewWidth = width;
this.previewHeight = height;
// 设置长宽比 // 关闭摄像头
cameraView.setAspectRatio(PREVIEW_WIDTH / (float)PREVIEW_HEIGHT); closeCamera();
// 释放CameraHandler占用的相关资源
if(mCameraHandler != null){
mCameraHandler.release();
mCameraHandler = null;
}
// 重新初始化mCameraHandler
cameraView.setAspectRatio(previewWidth / (float)previewHeight);
mCameraHandler = UVCCameraHandler.createHandler(activity,cameraView,ENCODER_TYPE, mCameraHandler = UVCCameraHandler.createHandler(activity,cameraView,ENCODER_TYPE,
PREVIEW_WIDTH,PREVIEW_HEIGHT,PREVIEW_FORMAT); previewWidth,previewHeight,PREVIEW_FORMAT);
openCamera(mCtrlBlock);
// 开始预览
startPreview(cameraView, new AbstractUVCCameraHandler.OnPreViewResultListener() {
@Override
public void onPreviewResult(boolean result) {
if(mPreviewListener != null){
mPreviewListener.onPreviewResult(result);
}
}
});
} }
/** /**
@ -247,10 +282,10 @@ public class USBCameraManager{
} }
} }
public void startPreview(CameraViewInterface cameraView) { public void startPreview(CameraViewInterface cameraView,AbstractUVCCameraHandler.OnPreViewResultListener mPreviewListener) {
SurfaceTexture st = cameraView.getSurfaceTexture(); SurfaceTexture st = cameraView.getSurfaceTexture();
if(mCameraHandler != null){ if(mCameraHandler != null){
mCameraHandler.startPreview(st); mCameraHandler.startPreview(st,mPreviewListener);
} }
} }
} }

31
libusbcamera/src/main/java/com/serenegiant/usb/common/AbstractUVCCameraHandler.java

@ -66,11 +66,16 @@ public abstract class AbstractUVCCameraHandler extends Handler {
} }
public static OnEncodeResultListener mListener; public static OnEncodeResultListener mListener;
public static OnPreViewResultListener mPreviewListener;
public interface OnEncodeResultListener{ public interface OnEncodeResultListener{
void onEncodeResult(byte[] data, int offset, int length, long timestamp, int type); void onEncodeResult(byte[] data, int offset, int length, long timestamp, int type);
} }
public interface OnPreViewResultListener{
void onPreviewResult(boolean result);
}
private static final int MSG_OPEN = 0; private static final int MSG_OPEN = 0;
private static final int MSG_CLOSE = 1; private static final int MSG_CLOSE = 1;
private static final int MSG_PREVIEW_START = 2; private static final int MSG_PREVIEW_START = 2;
@ -163,11 +168,13 @@ public abstract class AbstractUVCCameraHandler extends Handler {
} }
// 开启Camera预览 // 开启Camera预览
protected void startPreview(final Object surface) { protected void startPreview(final Object surface,OnPreViewResultListener listener) {
checkReleased(); checkReleased();
if (!((surface instanceof SurfaceHolder) || (surface instanceof Surface) || (surface instanceof SurfaceTexture))) { if (!((surface instanceof SurfaceHolder) || (surface instanceof Surface) || (surface instanceof SurfaceTexture))) {
throw new IllegalArgumentException("surface should be one of SurfaceHolder, Surface or SurfaceTexture"); throw new IllegalArgumentException("surface should be one of SurfaceHolder, Surface or SurfaceTexture");
} }
this.mPreviewListener = listener;
sendMessage(obtainMessage(MSG_PREVIEW_START, surface)); sendMessage(obtainMessage(MSG_PREVIEW_START, surface));
} }
@ -210,7 +217,6 @@ public abstract class AbstractUVCCameraHandler extends Handler {
public void startRecording(final RecordParams params, OnEncodeResultListener listener) { public void startRecording(final RecordParams params, OnEncodeResultListener listener) {
AbstractUVCCameraHandler.mListener = listener; AbstractUVCCameraHandler.mListener = listener;
checkReleased(); checkReleased();
// sendEmptyMessage(MSG_CAPTURE_START);
sendMessage(obtainMessage(MSG_CAPTURE_START, params)); sendMessage(obtainMessage(MSG_CAPTURE_START, params));
} }
@ -503,14 +509,21 @@ public abstract class AbstractUVCCameraHandler extends Handler {
if ((mUVCCamera == null) || mIsPreviewing) return; if ((mUVCCamera == null) || mIsPreviewing) return;
try { try {
mUVCCamera.setPreviewSize(mWidth, mHeight, 1, 31, mPreviewMode, mBandwidthFactor); mUVCCamera.setPreviewSize(mWidth, mHeight, 1, 31, mPreviewMode, mBandwidthFactor);
if(mPreviewListener != null){
mPreviewListener.onPreviewResult(true);
}
} catch (final IllegalArgumentException e) { } catch (final IllegalArgumentException e) {
try { // 添加分辨率参数合法性检测
// fallback to YUV mode if(mPreviewListener != null){
mUVCCamera.setPreviewSize(mWidth, mHeight, 1, 31, UVCCamera.DEFAULT_PREVIEW_MODE, mBandwidthFactor); mPreviewListener.onPreviewResult(false);
} catch (final IllegalArgumentException e1) {
callOnError(e1);
return;
} }
// try {
// // fallback to YUV mode
// mUVCCamera.setPreviewSize(mWidth, mHeight, 1, 31, UVCCamera.DEFAULT_PREVIEW_MODE, mBandwidthFactor);
// } catch (final IllegalArgumentException e1) {
// callOnError(e1);
// return;
// }
} }
if (surface instanceof SurfaceHolder) { if (surface instanceof SurfaceHolder) {
mUVCCamera.setPreviewDisplay((SurfaceHolder)surface); mUVCCamera.setPreviewDisplay((SurfaceHolder)surface);
@ -659,7 +672,7 @@ public abstract class AbstractUVCCameraHandler extends Handler {
} }
private void startVideoRecord() { private void startVideoRecord() {
mH264Consumer = new H264EncodeConsumer(); mH264Consumer = new H264EncodeConsumer(getWidth(),getHeight());
mH264Consumer.setOnH264EncodeResultListener(new H264EncodeConsumer.OnH264EncodeResultListener() { mH264Consumer.setOnH264EncodeResultListener(new H264EncodeConsumer.OnH264EncodeResultListener() {
@Override @Override
public void onEncodeResult(byte[] data, int offset, int length, long timestamp) { public void onEncodeResult(byte[] data, int offset, int length, long timestamp) {

4
libusbcamera/src/main/java/com/serenegiant/usb/common/UVCCameraHandler.java

@ -119,8 +119,8 @@ public class UVCCameraHandler extends AbstractUVCCameraHandler {
} }
@Override @Override
public void startPreview(final Object surface) { public void startPreview(final Object surface,final AbstractUVCCameraHandler.OnPreViewResultListener listener) {
super.startPreview(surface); super.startPreview(surface, listener);
} }
@Override @Override

4
libusbcamera/src/main/java/com/serenegiant/usb/common/UVCCameraHandlerMultiSurface.java

@ -136,10 +136,10 @@ public class UVCCameraHandlerMultiSurface extends AbstractUVCCameraHandler {
} }
} }
public synchronized void startPreview() { public synchronized void startPreview(OnPreViewResultListener listener) {
checkReleased(); checkReleased();
if (mRendererHolder != null) { if (mRendererHolder != null) {
super.startPreview(mRendererHolder.getSurface()); super.startPreview(mRendererHolder.getSurface(),listener);
} else { } else {
throw new IllegalStateException(); throw new IllegalStateException();
} }

16
libusbcamera/src/main/java/com/serenegiant/usb/encoder/biz/H264EncodeConsumer.java

@ -60,6 +60,15 @@ public class H264EncodeConsumer extends Thread {
this.listener = listener; this.listener = listener;
} }
public H264EncodeConsumer(){
}
public H264EncodeConsumer(int width,int height){
this.mWidth = width;
this.mHeight = height;
}
public synchronized void setTmpuMuxer(Mp4MediaMuxer mMuxer){ public synchronized void setTmpuMuxer(Mp4MediaMuxer mMuxer){
this.mMuxerRef = new WeakReference<>(mMuxer); this.mMuxerRef = new WeakReference<>(mMuxer);
Mp4MediaMuxer muxer = mMuxerRef.get(); Mp4MediaMuxer muxer = mMuxerRef.get();
@ -77,8 +86,11 @@ public class H264EncodeConsumer extends Thread {
// 根据编码器支持转换颜色空间格式 // 根据编码器支持转换颜色空间格式
// 即 nv21 ---> YUV420sp(21) // 即 nv21 ---> YUV420sp(21)
// nv21 ---> YUV420p (19) // nv21 ---> YUV420p (19)
if(mWidth != width || mHeight != height){
mWidth = width; mWidth = width;
mHeight = height; mHeight = height;
return;
}
try { try {
if (lastPush == 0) { if (lastPush == 0) {
lastPush = System.currentTimeMillis(); lastPush = System.currentTimeMillis();
@ -240,7 +252,7 @@ public class H264EncodeConsumer extends Thread {
return; return;
} }
final MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, 640, 480); final MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, mWidth, mHeight);
format.setInteger(MediaFormat.KEY_COLOR_FORMAT, mColorFormat); format.setInteger(MediaFormat.KEY_COLOR_FORMAT, mColorFormat);
format.setInteger(MediaFormat.KEY_BIT_RATE, calcBitRate()); format.setInteger(MediaFormat.KEY_BIT_RATE, calcBitRate());
format.setInteger(MediaFormat.KEY_FRAME_RATE, 15); format.setInteger(MediaFormat.KEY_FRAME_RATE, 15);
@ -283,7 +295,7 @@ public class H264EncodeConsumer extends Thread {
private static final int FRAME_RATE = 15; private static final int FRAME_RATE = 15;
private static final float BPP = 0.50f; private static final float BPP = 0.50f;
private int calcBitRate() { private int calcBitRate() {
final int bitrate = (int)(BPP * FRAME_RATE * 640 * 480); final int bitrate = (int)(BPP * FRAME_RATE * mWidth * mHeight);
Log.i(TAG, String.format("bitrate=%5.2f[Mbps]", bitrate / 1024f / 1024f)); Log.i(TAG, String.format("bitrate=%5.2f[Mbps]", bitrate / 1024f / 1024f));
return bitrate; return bitrate;
} }

Loading…
Cancel
Save