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 0ecf3b9..b39d6f3 100644 --- a/app/src/main/java/com/jiangdg/usbcamera/view/USBCameraActivity.java +++ b/app/src/main/java/com/jiangdg/usbcamera/view/USBCameraActivity.java @@ -160,13 +160,6 @@ public class USBCameraActivity extends AppCompatActivity implements CameraDialog showShortMsg("录制异常,摄像头未开启"); return; } - File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() - +File.separator+System.currentTimeMillis()+".txt"); - try { - fos = new FileOutputStream(file); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } if(! mUSBManager.isRecording()){ String videoPath = USBCameraManager.ROOT_PATH+System.currentTimeMillis() @@ -174,32 +167,13 @@ public class USBCameraActivity extends AppCompatActivity implements CameraDialog mUSBManager.startRecording(videoPath, new AbstractUVCCameraHandler.OnEncodeResultListener() { @Override public void onEncodeResult(byte[] data, int offset, int length, long timestamp, int type) { - String tip = null; - if(data == null){ - tip = "data = null"; - }else{ - tip = "大小"+data.length+ "类型"+type + ";"; - } - try { - if(fos != null){ - fos.write(tip.getBytes()); - } - } catch (IOException e) { - e.printStackTrace(); - } + } }); mBtnRecord.setText("正在录制"); } else { mUSBManager.stopRecording(); - try { - if(fos != null){ - fos.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } mBtnRecord.setText("开始录制"); } break; diff --git a/libusbcamera/src/main/java/com/serenegiant/usb/encoder/MediaEncoder.java b/libusbcamera/src/main/java/com/serenegiant/usb/encoder/MediaEncoder.java index fe1404e..b651f76 100644 --- a/libusbcamera/src/main/java/com/serenegiant/usb/encoder/MediaEncoder.java +++ b/libusbcamera/src/main/java/com/serenegiant/usb/encoder/MediaEncoder.java @@ -25,8 +25,14 @@ package com.serenegiant.usb.encoder; import android.media.MediaCodec; import android.media.MediaFormat; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; import android.util.Log; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; import java.lang.ref.WeakReference; import java.nio.ByteBuffer; @@ -361,6 +367,11 @@ public abstract class MediaEncoder implements Runnable { } } + byte[] mPpsSps = new byte[0]; + byte[] h264 = new byte[640 * 480 * 3 / 2]; + ByteBuffer mBuffer = ByteBuffer.allocate(10240); + long timeStamp = System.currentTimeMillis(); + /** * drain encoded data and write them to muxer */ @@ -375,9 +386,7 @@ public abstract class MediaEncoder implements Runnable { Log.w(TAG, "muxer is unexpectedly null"); return; } - byte[] mPpsSps = new byte[0]; - byte[] h264 = new byte[640 * 480]; - ByteBuffer mBuffer = ByteBuffer.allocate(10240); + LOOP: while (mIsCapturing) { // get encoded data with maximum timeout duration of TIMEOUT_USEC(=10[msec]) @@ -447,57 +456,58 @@ LOOP: while (mIsCapturing) { muxer.writeSampleData(mTrackIndex, encodedData, mBufferInfo); prevOutputPTSUs = mBufferInfo.presentationTimeUs; - // 推流,获取h.264数据流 -// if(mListener != null){ -// byte[] temp = new byte[mBufferInfo.size]; -// encodedData.get(temp); -// mListener.onEncodeResult(temp, 0,mBufferInfo.size, mBufferInfo.presentationTimeUs / 1000,TYPE_VIDEO); -// } + // 推流,获取h.264数据流 // 根据mBufferInfo.size来判断音视频 // > 1000,视频;< 1000,音频 - if(mBufferInfo.size > 1000){ - boolean sync = false; - if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {// sps - sync = (mBufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0; - if (!sync) { - byte[] temp = new byte[mBufferInfo.size]; - encodedData.get(temp); - mPpsSps = temp; - mMediaCodec.releaseOutputBuffer(encoderStatus, false); - continue; + synchronized (this){ + if(mBufferInfo.size > 1000) { + int type = encodedData.get(4) & 0x07; + if(type == 7 || type == 8) { + byte[] outData = new byte[mBufferInfo.size]; + encodedData.get(outData); + mPpsSps = outData; + }else if(type == 5) { + System.arraycopy(mPpsSps,0,h264,0,mPpsSps.length); + if(mBufferInfo.size > h264.length) { + continue; + } + encodedData.get(h264,mPpsSps.length,mBufferInfo.size); + if(mListener != null) { + mListener.onEncodeResult(h264, 0,mPpsSps.length + mBufferInfo.size, + mBufferInfo.presentationTimeUs / 1000,TYPE_VIDEO); + } } else { - mPpsSps = new byte[0]; + if(mBufferInfo.size > h264.length){ + continue ; + } + encodedData.get(h264,0,mBufferInfo.size); + if(System.currentTimeMillis() - timeStamp >= 3000) { + timeStamp = System.currentTimeMillis(); + if(Build.VERSION.SDK_INT >= 23) { + Bundle params = new Bundle(); + params.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0); + mMediaCodec.setParameters(params); + } + } + if(mListener != null) { + mListener.onEncodeResult(h264, 0,mBufferInfo.size, + mBufferInfo.presentationTimeUs / 1000,TYPE_VIDEO); + } } - } - sync |= (mBufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0; - int len = mPpsSps.length + mBufferInfo.size; - if (len > h264.length) { - h264 = new byte[len]; - } - if (sync) { - System.arraycopy(mPpsSps, 0, h264, 0, mPpsSps.length); - encodedData.get(h264, mPpsSps.length, mBufferInfo.size); - if(mListener != null){ - mListener.onEncodeResult(h264, 0,mPpsSps.length + mBufferInfo.size, mBufferInfo.presentationTimeUs / 1000,TYPE_VIDEO); - } } else { - encodedData.get(h264, 0, mBufferInfo.size); + mBuffer.clear(); + encodedData.get(mBuffer.array(), 7, mBufferInfo.size); + encodedData.clear(); + mBuffer.position(7 + mBufferInfo.size); + addADTStoPacket(mBuffer.array(), mBufferInfo.size + 7); + mBuffer.flip(); if(mListener != null){ - mListener.onEncodeResult(h264, 0,mBufferInfo.size, mBufferInfo.presentationTimeUs / 1000,TYPE_VIDEO); + mListener.onEncodeResult(mBuffer.array(),0, mBufferInfo.size + 7, mBufferInfo.presentationTimeUs / 1000,TYPE_AUDIO); } } - } else { - mBuffer.clear(); - encodedData.get(mBuffer.array(), 7, mBufferInfo.size); - encodedData.clear(); - mBuffer.position(7 + mBufferInfo.size); - addADTStoPacket(mBuffer.array(), mBufferInfo.size + 7); - mBuffer.flip(); - if(mListener != null){ - mListener.onEncodeResult(mBuffer.array(),0, mBufferInfo.size + 7, mBufferInfo.presentationTimeUs / 1000,TYPE_AUDIO); - } } + } // return buffer to encoder mMediaCodec.releaseOutputBuffer(encoderStatus, false); diff --git a/libusbcamera/src/main/java/com/serenegiant/usb/encoder/MediaMuxerWrapper.java b/libusbcamera/src/main/java/com/serenegiant/usb/encoder/MediaMuxerWrapper.java index f71b6b8..f139826 100644 --- a/libusbcamera/src/main/java/com/serenegiant/usb/encoder/MediaMuxerWrapper.java +++ b/libusbcamera/src/main/java/com/serenegiant/usb/encoder/MediaMuxerWrapper.java @@ -1,8 +1,10 @@ package com.serenegiant.usb.encoder; +import android.annotation.TargetApi; import android.media.MediaCodec; import android.media.MediaFormat; import android.media.MediaMuxer; +import android.os.Build; import android.os.Environment; import android.text.TextUtils; import android.util.Log; @@ -27,6 +29,7 @@ public class MediaMuxerWrapper { private boolean mIsStarted; private MediaEncoder mVideoEncoder, mAudioEncoder; + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) public MediaMuxerWrapper(String path) throws IOException { try { // 保存到自定义路径还是手机默认Movies路径 diff --git a/libusbcamera/src/main/java/com/serenegiant/usb/encoder/MediaVideoEncoder.java b/libusbcamera/src/main/java/com/serenegiant/usb/encoder/MediaVideoEncoder.java index 1f0fa0b..5976235 100644 --- a/libusbcamera/src/main/java/com/serenegiant/usb/encoder/MediaVideoEncoder.java +++ b/libusbcamera/src/main/java/com/serenegiant/usb/encoder/MediaVideoEncoder.java @@ -23,10 +23,12 @@ package com.serenegiant.usb.encoder; +import android.annotation.TargetApi; import android.media.MediaCodec; import android.media.MediaCodecInfo; import android.media.MediaCodecList; import android.media.MediaFormat; +import android.os.Build; import android.util.Log; import android.view.Surface; @@ -82,6 +84,7 @@ public class MediaVideoEncoder extends MediaEncoder implements IVideoEncoder { return result; } + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) @Override protected void prepare() throws IOException { if (DEBUG) Log.i(TAG, "prepare: "); @@ -99,7 +102,7 @@ public class MediaVideoEncoder extends MediaEncoder implements IVideoEncoder { format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface); // API >= 18 format.setInteger(MediaFormat.KEY_BIT_RATE, calcBitRate()); format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE); - format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10); + format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1); if (DEBUG) Log.i(TAG, "format: " + format); mMediaCodec = MediaCodec.createEncoderByType(MIME_TYPE);