diff --git a/app/app.iml b/app/app.iml
index dc9ae4e..e03e0af 100644
--- a/app/app.iml
+++ b/app/app.iml
@@ -82,13 +82,21 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/com/jiangdg/usbcamera/view/USBCameraActivity.java b/app/src/main/java/com/jiangdg/usbcamera/view/USBCameraActivity.java
index 5aa2b97..eed9bdd 100644
--- a/app/src/main/java/com/jiangdg/usbcamera/view/USBCameraActivity.java
+++ b/app/src/main/java/com/jiangdg/usbcamera/view/USBCameraActivity.java
@@ -18,6 +18,7 @@ import com.jiangdg.usbcamera.USBCameraManager;
import com.serenegiant.usb.CameraDialog;
import com.serenegiant.usb.USBMonitor;
import com.serenegiant.usb.common.AbstractUVCCameraHandler;
+import com.serenegiant.usb.encoder.RecordParams;
import com.serenegiant.usb.widget.CameraViewInterface;
import java.io.BufferedOutputStream;
@@ -166,11 +167,13 @@ public class USBCameraActivity extends AppCompatActivity implements CameraDialog
}
if(! mUSBManager.isRecording()){
- String videoPath = USBCameraManager.ROOT_PATH+System.currentTimeMillis()
- +USBCameraManager.SUFFIX_MP4;
+ String videoPath = USBCameraManager.ROOT_PATH+System.currentTimeMillis();
FileUtils.createfile(FileUtils.ROOT_PATH+"test666.h264");
-
- mUSBManager.startRecording(videoPath, new AbstractUVCCameraHandler.OnEncodeResultListener() {
+ RecordParams params = new RecordParams();
+ params.setRecordPath(videoPath);
+ params.setRecordDuration(0); // 设置为0,不分割保存
+ params.setVoiceClose(false); // 不屏蔽声音
+ mUSBManager.startRecording(params, new AbstractUVCCameraHandler.OnEncodeResultListener() {
@Override
public void onEncodeResult(byte[] data, int offset, int length, long timestamp, int type) {
// type = 0,aac格式音频流
diff --git a/app/src/main/res/layout/activity_usbcamera.xml b/app/src/main/res/layout/activity_usbcamera.xml
index 32f05b8..1873184 100644
--- a/app/src/main/res/layout/activity_usbcamera.xml
+++ b/app/src/main/res/layout/activity_usbcamera.xml
@@ -35,5 +35,4 @@
android:textSize="16sp"
android:text="开始录制"/>
-
\ No newline at end of file
diff --git a/libusbcamera/src/main/java/com/jiangdg/usbcamera/USBCameraManager.java b/libusbcamera/src/main/java/com/jiangdg/usbcamera/USBCameraManager.java
index 3a28709..d0e131d 100644
--- a/libusbcamera/src/main/java/com/jiangdg/usbcamera/USBCameraManager.java
+++ b/libusbcamera/src/main/java/com/jiangdg/usbcamera/USBCameraManager.java
@@ -11,6 +11,7 @@ import com.serenegiant.usb.DeviceFilter;
import com.serenegiant.usb.USBMonitor;
import com.serenegiant.usb.common.AbstractUVCCameraHandler;
import com.serenegiant.usb.common.UVCCameraHandler;
+import com.serenegiant.usb.encoder.RecordParams;
import com.serenegiant.usb.widget.CameraViewInterface;
import java.io.File;
@@ -182,12 +183,13 @@ public class USBCameraManager{
}
}
- public void startRecording(String videoPath, AbstractUVCCameraHandler.OnEncodeResultListener listener){
+ public void startRecording(RecordParams params, AbstractUVCCameraHandler.OnEncodeResultListener listener){
if(mCameraHandler != null && ! isRecording()){
- mCameraHandler.startRecording(videoPath,listener);
+ mCameraHandler.startRecording(params,listener);
}
}
+
public void stopRecording(){
if(mCameraHandler != null && isRecording()){
mCameraHandler.stopRecording();
diff --git a/libusbcamera/src/main/java/com/serenegiant/usb/common/AbstractUVCCameraHandler.java b/libusbcamera/src/main/java/com/serenegiant/usb/common/AbstractUVCCameraHandler.java
index cdb6f2d..3edfe46 100644
--- a/libusbcamera/src/main/java/com/serenegiant/usb/common/AbstractUVCCameraHandler.java
+++ b/libusbcamera/src/main/java/com/serenegiant/usb/common/AbstractUVCCameraHandler.java
@@ -26,6 +26,7 @@ import com.serenegiant.usb.encoder.MediaMuxerWrapper;
import com.serenegiant.usb.encoder.MediaSurfaceEncoder;
import com.serenegiant.usb.encoder.MediaVideoBufferEncoder;
import com.serenegiant.usb.encoder.MediaVideoEncoder;
+import com.serenegiant.usb.encoder.RecordParams;
import com.serenegiant.usb.encoder.biz.AACEncodeConsumer;
import com.serenegiant.usb.encoder.biz.H264EncodeConsumer;
import com.serenegiant.usb.encoder.biz.Mp4MediaMuxer;
@@ -79,6 +80,9 @@ public abstract class AbstractUVCCameraHandler extends Handler {
private static final int MSG_CAPTURE_STOP = 6;
private static final int MSG_MEDIA_UPDATE = 7;
private static final int MSG_RELEASE = 9;
+ // 音频线程
+// private static final int MSG_AUDIO_START = 10;
+// private static final int MSG_AUDIO_STOP = 11;
private final WeakReference mWeakThread;
private volatile boolean mReleased;
@@ -112,6 +116,11 @@ public abstract class AbstractUVCCameraHandler extends Handler {
return thread != null && thread.isRecording();
}
+// public boolean isAudioThreadStart() {
+// final CameraThread thread = mWeakThread.get();
+// return thread != null && thread.isAudioRecording();
+// }
+
public boolean isEqual(final UsbDevice device) {
final CameraThread thread = mWeakThread.get();
return (thread != null) && thread.isEqual(device);
@@ -198,11 +207,11 @@ public abstract class AbstractUVCCameraHandler extends Handler {
}
// 开始录制
- public void startRecording(final String path, OnEncodeResultListener listener) {
+ public void startRecording(final RecordParams params, OnEncodeResultListener listener) {
AbstractUVCCameraHandler.mListener = listener;
checkReleased();
// sendEmptyMessage(MSG_CAPTURE_START);
- sendMessage(obtainMessage(MSG_CAPTURE_START, path));
+ sendMessage(obtainMessage(MSG_CAPTURE_START, params));
}
// 停止录制
@@ -210,6 +219,16 @@ public abstract class AbstractUVCCameraHandler extends Handler {
sendEmptyMessage(MSG_CAPTURE_STOP);
}
+// // 启动音频线程
+// public void startAudioThread(){
+// sendEmptyMessage(MSG_AUDIO_START);
+// }
+//
+// // 关闭音频线程
+// public void stopAudioThread(){
+// sendEmptyMessage(MSG_AUDIO_STOP);
+// }
+
public void release() {
mReleased = true;
close();
@@ -297,35 +316,43 @@ public abstract class AbstractUVCCameraHandler extends Handler {
final CameraThread thread = mWeakThread.get();
if (thread == null) return;
switch (msg.what) {
- case MSG_OPEN:
- thread.handleOpen((USBMonitor.UsbControlBlock)msg.obj);
- break;
- case MSG_CLOSE:
- thread.handleClose();
- break;
- case MSG_PREVIEW_START:
- thread.handleStartPreview(msg.obj);
- break;
- case MSG_PREVIEW_STOP:
- thread.handleStopPreview();
- break;
- case MSG_CAPTURE_STILL:
- thread.handleCaptureStill((String)msg.obj);
- break;
- case MSG_CAPTURE_START:
- thread.handleStartRecording((String)msg.obj);
- break;
- case MSG_CAPTURE_STOP:
- thread.handleStopRecording();
- break;
- case MSG_MEDIA_UPDATE:
- thread.handleUpdateMedia((String)msg.obj);
- break;
- case MSG_RELEASE:
- thread.handleRelease();
- break;
- default:
- throw new RuntimeException("unsupported message:what=" + msg.what);
+ case MSG_OPEN:
+ thread.handleOpen((USBMonitor.UsbControlBlock)msg.obj);
+ break;
+ case MSG_CLOSE:
+ thread.handleClose();
+ break;
+ case MSG_PREVIEW_START:
+ thread.handleStartPreview(msg.obj);
+ break;
+ case MSG_PREVIEW_STOP:
+ thread.handleStopPreview();
+ break;
+ case MSG_CAPTURE_STILL:
+ thread.handleCaptureStill((String)msg.obj);
+ break;
+ case MSG_CAPTURE_START:
+// thread.handleStartRecording((String)msg.obj);
+ thread.handleStartRecording((RecordParams)msg.obj);
+ break;
+ case MSG_CAPTURE_STOP:
+ thread.handleStopRecording();
+ break;
+ case MSG_MEDIA_UPDATE:
+ thread.handleUpdateMedia((String)msg.obj);
+ break;
+ case MSG_RELEASE:
+ thread.handleRelease();
+ break;
+ // 音频线程
+// case MSG_AUDIO_START:
+// thread.startAudioRecord();
+// break;
+// case MSG_AUDIO_STOP:
+// thread.stopAudioRecord();
+// break;
+ default:
+ throw new RuntimeException("unsupported message:what=" + msg.what);
}
}
@@ -352,6 +379,7 @@ public abstract class AbstractUVCCameraHandler extends Handler {
// private MediaMuxerWrapper mMuxer;
private MediaVideoBufferEncoder mVideoEncoder;
private Mp4MediaMuxer mMuxer;
+// private boolean isAudioThreadStart;
/** 构造方法
*
@@ -429,6 +457,12 @@ public abstract class AbstractUVCCameraHandler extends Handler {
}
}
+// public boolean isAudioRecording(){
+// synchronized (mSync){
+// return isAudioThreadStart;
+// }
+// }
+
public boolean isEqual(final UsbDevice device) {
return (mUVCCamera != null) && (mUVCCamera.getDevice() != null) && mUVCCamera.getDevice().equals(device);
}
@@ -583,12 +617,48 @@ public abstract class AbstractUVCCameraHandler extends Handler {
private AACEncodeConsumer mAacConsumer;
private H264EncodeConsumer mH264Consumer;
- public void handleStartRecording(String path){
+ public void handleStartRecording(RecordParams params){
if ((mUVCCamera == null) || (mMuxer != null))
return;
+ if (params == null)
+ throw new NullPointerException("RecordParams can not be null!");
// 获取USB Camera预览数据
mUVCCamera.setFrameCallback(mIFrameCallback, UVCCamera.PIXEL_FORMAT_NV21);
- // 启动视频编码线程,type=1
+ // 初始化混合器
+ mMuxer = new Mp4MediaMuxer(params.getRecordPath(),
+ params.getRecordDuration() * 60 * 1000);
+
+ // 启动视频编码线程
+ startVideoRecord();
+ // 启动音频编码线程
+ if(! params.isVoiceClose()) {
+ startAudioRecord();
+ }
+ callOnStartRecording();
+ }
+
+
+ public void handleStopRecording(){
+ // 停止混合器
+ if (mMuxer != null){
+ mMuxer.release();
+ mMuxer = null;
+ Log.i(TAG,TAG+"---->停止本地录制");
+ }
+ // 停止音视频编码线程
+ stopAudioRecord();
+ stopVideoRecord();
+ // 停止捕获视频数据
+ if (mUVCCamera != null) {
+ mUVCCamera.stopCapture();
+ mUVCCamera.setFrameCallback(null, 0);
+ }
+ mWeakCameraView.get().setVideoEncoder(null);
+ // you should not wait here
+ callOnStopRecording();
+ }
+
+ private void startVideoRecord() {
mH264Consumer = new H264EncodeConsumer();
mH264Consumer.setOnH264EncodeResultListener(new H264EncodeConsumer.OnH264EncodeResultListener() {
@Override
@@ -599,45 +669,16 @@ public abstract class AbstractUVCCameraHandler extends Handler {
}
});
mH264Consumer.start();
- // 启动音频编码线程,type=0
- mAacConsumer = new AACEncodeConsumer();
- mAacConsumer.setOnAACEncodeResultListener(new AACEncodeConsumer.OnAACEncodeResultListener() {
- @Override
- public void onEncodeResult(byte[] data, int offset, int length, long timestamp) {
- if(mListener != null){
- mListener.onEncodeResult(data,offset,length,timestamp,0);
- }
- }
- });
- mAacConsumer.start();
- // 启动混合器
- long millis = 30 * 60 * 1000;
- mMuxer = new Mp4MediaMuxer(new File(FileUtils.ROOT_PATH, new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss").format(new Date())).toString(), millis);
+ // 添加混合器
if(mH264Consumer != null){
mH264Consumer.setTmpuMuxer(mMuxer);
}
- if(mAacConsumer != null){
- mAacConsumer.setTmpuMuxer(mMuxer);
- }
- callOnStartRecording();
}
- public void handleStopRecording(){
- // 停止混合器
- if (mMuxer != null){
- mMuxer.release();
- mMuxer = null;
- Log.i(TAG,TAG+"---->停止本地录制");
- }
- // 停止音视频编码线程
- if(mH264Consumer != null){
- mH264Consumer.setTmpuMuxer(null);
- }
- if(mAacConsumer != null){
- mAacConsumer.setTmpuMuxer(null);
- }
+ private void stopVideoRecord(){
if(mH264Consumer != null){
mH264Consumer.exit();
+ mH264Consumer.setTmpuMuxer(null);
try {
Thread t2 = mH264Consumer;
mH264Consumer = null;
@@ -649,8 +690,30 @@ public abstract class AbstractUVCCameraHandler extends Handler {
e.printStackTrace();
}
}
+ }
+
+ private void startAudioRecord(){
+ mAacConsumer = new AACEncodeConsumer();
+ mAacConsumer.setOnAACEncodeResultListener(new AACEncodeConsumer.OnAACEncodeResultListener() {
+ @Override
+ public void onEncodeResult(byte[] data, int offset, int length, long timestamp) {
+ if(mListener != null){
+ mListener.onEncodeResult(data,offset,length,timestamp,0);
+ }
+ }
+ });
+ mAacConsumer.start();
+ // 添加混合器
+ if(mAacConsumer != null){
+ mAacConsumer.setTmpuMuxer(mMuxer);
+ }
+// isAudioThreadStart = true;
+ }
+
+ private void stopAudioRecord(){
if(mAacConsumer != null){
mAacConsumer.exit();
+ mAacConsumer.setTmpuMuxer(null);
try {
Thread t1 = mAacConsumer;
mAacConsumer = null;
@@ -662,14 +725,8 @@ public abstract class AbstractUVCCameraHandler extends Handler {
e.printStackTrace();
}
}
- // 停止捕获视频数据
- if (mUVCCamera != null) {
- mUVCCamera.stopCapture();
- mUVCCamera.setFrameCallback(null, 0);
- }
- mWeakCameraView.get().setVideoEncoder(null);
- // you should not wait here
- callOnStopRecording();
+
+// isAudioThreadStart = false;
}
// 停止录制视频
diff --git a/libusbcamera/src/main/java/com/serenegiant/usb/encoder/RecordParams.java b/libusbcamera/src/main/java/com/serenegiant/usb/encoder/RecordParams.java
new file mode 100644
index 0000000..361f1fd
--- /dev/null
+++ b/libusbcamera/src/main/java/com/serenegiant/usb/encoder/RecordParams.java
@@ -0,0 +1,36 @@
+package com.serenegiant.usb.encoder;
+
+/** 录制参数
+ *
+ * Created by jiangdongguo on 2017/10/19.
+ */
+
+public class RecordParams {
+ private String recordPath;
+ private int recordDuration;
+ private boolean voiceClose;
+
+ public boolean isVoiceClose() {
+ return voiceClose;
+ }
+
+ public void setVoiceClose(boolean voiceClose) {
+ this.voiceClose = voiceClose;
+ }
+
+ public String getRecordPath() {
+ return recordPath;
+ }
+
+ public void setRecordPath(String recordPath) {
+ this.recordPath = recordPath;
+ }
+
+ public int getRecordDuration() {
+ return recordDuration;
+ }
+
+ public void setRecordDuration(int recordDuration) {
+ this.recordDuration = recordDuration;
+ }
+}
diff --git a/libusbcamera/src/main/java/com/serenegiant/usb/encoder/biz/Mp4MediaMuxer.java b/libusbcamera/src/main/java/com/serenegiant/usb/encoder/biz/Mp4MediaMuxer.java
index e964530..e08b7f0 100644
--- a/libusbcamera/src/main/java/com/serenegiant/usb/encoder/biz/Mp4MediaMuxer.java
+++ b/libusbcamera/src/main/java/com/serenegiant/usb/encoder/biz/Mp4MediaMuxer.java
@@ -44,6 +44,8 @@ public class Mp4MediaMuxer {
}
}
+
+
public synchronized void addTrack(MediaFormat format, boolean isVideo) {
// now that we have the Magic Goodies, start the muxer
if (mAudioTrackIndex != -1 && mVideoTrackIndex != -1)
@@ -102,7 +104,7 @@ public class Mp4MediaMuxer {
// Log.i(TAG, "BUFFER_FLAG_END_OF_STREAM received");
}
- if (System.currentTimeMillis() - mBeginMillis >= durationMillis) {
+ if (durationMillis!=0 && System.currentTimeMillis() - mBeginMillis >= durationMillis) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
// if (VERBOSE)
// Log.i(TAG, String.format("record file reach expiration.create new file:" + index));