Browse Source

新增mp4文件自动保存,屏蔽声音功能

main
jiangdongguo 7 years ago
parent
commit
1a05fa7402
  1. 8
      app/app.iml
  2. 11
      app/src/main/java/com/jiangdg/usbcamera/view/USBCameraActivity.java
  3. 1
      app/src/main/res/layout/activity_usbcamera.xml
  4. 6
      libusbcamera/src/main/java/com/jiangdg/usbcamera/USBCameraManager.java
  5. 147
      libusbcamera/src/main/java/com/serenegiant/usb/common/AbstractUVCCameraHandler.java
  6. 36
      libusbcamera/src/main/java/com/serenegiant/usb/encoder/RecordParams.java
  7. 4
      libusbcamera/src/main/java/com/serenegiant/usb/encoder/biz/Mp4MediaMuxer.java

8
app/app.iml

@ -82,13 +82,21 @@
<sourceFolder url="file://$MODULE_DIR$/src/test/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-safeguard" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content>
<orderEntry type="jdk" jdkName="Android API 25 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />

11
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格式音频流

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

@ -35,5 +35,4 @@
android:textSize="16sp"
android:text="开始录制"/>
</RelativeLayout>

6
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();

147
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<CameraThread> 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();
@ -313,7 +332,8 @@ public abstract class AbstractUVCCameraHandler extends Handler {
thread.handleCaptureStill((String)msg.obj);
break;
case MSG_CAPTURE_START:
thread.handleStartRecording((String)msg.obj);
// thread.handleStartRecording((String)msg.obj);
thread.handleStartRecording((RecordParams)msg.obj);
break;
case MSG_CAPTURE_STOP:
thread.handleStopRecording();
@ -324,6 +344,13 @@ public abstract class AbstractUVCCameraHandler extends Handler {
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,45 +617,27 @@ 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
mH264Consumer = new H264EncodeConsumer();
mH264Consumer.setOnH264EncodeResultListener(new H264EncodeConsumer.OnH264EncodeResultListener() {
@Override
public void onEncodeResult(byte[] data, int offset, int length, long timestamp) {
if(mListener != null){
mListener.onEncodeResult(data,offset,length,timestamp,1);
}
}
});
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);
// 初始化混合器
mMuxer = new Mp4MediaMuxer(params.getRecordPath(),
params.getRecordDuration() * 60 * 1000);
// 启动视频编码线程
startVideoRecord();
// 启动音频编码线程
if(! params.isVoiceClose()) {
startAudioRecord();
}
callOnStartRecording();
}
public void handleStopRecording(){
// 停止混合器
if (mMuxer != null){
@ -630,14 +646,39 @@ public abstract class AbstractUVCCameraHandler extends Handler {
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
public void onEncodeResult(byte[] data, int offset, int length, long timestamp) {
if(mListener != null){
mListener.onEncodeResult(data,offset,length,timestamp,1);
}
}
});
mH264Consumer.start();
// 添加混合器
if(mH264Consumer != null){
mH264Consumer.setTmpuMuxer(null);
mH264Consumer.setTmpuMuxer(mMuxer);
}
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;
}
// 停止录制视频

36
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;
}
}

4
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));

Loading…
Cancel
Save