Browse Source

修复获取h264数据流

main v1.05
jiangdongguo 7 years ago
parent
commit
a411918d28
  1. 28
      app/src/main/java/com/jiangdg/usbcamera/view/USBCameraActivity.java
  2. 76
      libusbcamera/src/main/java/com/serenegiant/usb/encoder/MediaEncoder.java
  3. 3
      libusbcamera/src/main/java/com/serenegiant/usb/encoder/MediaMuxerWrapper.java
  4. 5
      libusbcamera/src/main/java/com/serenegiant/usb/encoder/MediaVideoEncoder.java

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

@ -160,13 +160,6 @@ public class USBCameraActivity extends AppCompatActivity implements CameraDialog
showShortMsg("录制异常,摄像头未开启"); showShortMsg("录制异常,摄像头未开启");
return; 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()){ if(! mUSBManager.isRecording()){
String videoPath = USBCameraManager.ROOT_PATH+System.currentTimeMillis() String videoPath = USBCameraManager.ROOT_PATH+System.currentTimeMillis()
@ -174,32 +167,13 @@ public class USBCameraActivity extends AppCompatActivity implements CameraDialog
mUSBManager.startRecording(videoPath, new AbstractUVCCameraHandler.OnEncodeResultListener() { mUSBManager.startRecording(videoPath, new AbstractUVCCameraHandler.OnEncodeResultListener() {
@Override @Override
public void onEncodeResult(byte[] data, int offset, int length, long timestamp, int type) { 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("正在录制"); mBtnRecord.setText("正在录制");
} else { } else {
mUSBManager.stopRecording(); mUSBManager.stopRecording();
try {
if(fos != null){
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
mBtnRecord.setText("开始录制"); mBtnRecord.setText("开始录制");
} }
break; break;

76
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.MediaCodec;
import android.media.MediaFormat; import android.media.MediaFormat;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log; import android.util.Log;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.nio.ByteBuffer; 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 * 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"); Log.w(TAG, "muxer is unexpectedly null");
return; return;
} }
byte[] mPpsSps = new byte[0];
byte[] h264 = new byte[640 * 480];
ByteBuffer mBuffer = ByteBuffer.allocate(10240);
LOOP: while (mIsCapturing) { LOOP: while (mIsCapturing) {
// get encoded data with maximum timeout duration of TIMEOUT_USEC(=10[msec]) // get encoded data with maximum timeout duration of TIMEOUT_USEC(=10[msec])
@ -448,45 +457,44 @@ LOOP: while (mIsCapturing) {
prevOutputPTSUs = mBufferInfo.presentationTimeUs; prevOutputPTSUs = mBufferInfo.presentationTimeUs;
// 推流,获取h.264数据流 // 推流,获取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);
// }
// 根据mBufferInfo.size来判断音视频 // 根据mBufferInfo.size来判断音视频
// > 1000,视频;< 1000,音频 // > 1000,视频;< 1000,音频
if(mBufferInfo.size > 1000){ synchronized (this){
boolean sync = false; if(mBufferInfo.size > 1000) {
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {// sps int type = encodedData.get(4) & 0x07;
sync = (mBufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0; if(type == 7 || type == 8) {
if (!sync) { byte[] outData = new byte[mBufferInfo.size];
byte[] temp = new byte[mBufferInfo.size]; encodedData.get(outData);
encodedData.get(temp); mPpsSps = outData;
mPpsSps = temp; }else if(type == 5) {
mMediaCodec.releaseOutputBuffer(encoderStatus, false); System.arraycopy(mPpsSps,0,h264,0,mPpsSps.length);
if(mBufferInfo.size > h264.length) {
continue; continue;
} else {
mPpsSps = new byte[0];
} }
encodedData.get(h264,mPpsSps.length,mBufferInfo.size);
if(mListener != null) {
mListener.onEncodeResult(h264, 0,mPpsSps.length + mBufferInfo.size,
mBufferInfo.presentationTimeUs / 1000,TYPE_VIDEO);
} }
sync |= (mBufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0; } else {
int len = mPpsSps.length + mBufferInfo.size; if(mBufferInfo.size > h264.length){
if (len > h264.length) { continue ;
h264 = new byte[len];
} }
if (sync) { encodedData.get(h264,0,mBufferInfo.size);
System.arraycopy(mPpsSps, 0, h264, 0, mPpsSps.length); if(System.currentTimeMillis() - timeStamp >= 3000) {
encodedData.get(h264, mPpsSps.length, mBufferInfo.size); timeStamp = System.currentTimeMillis();
if(Build.VERSION.SDK_INT >= 23) {
if(mListener != null){ Bundle params = new Bundle();
mListener.onEncodeResult(h264, 0,mPpsSps.length + mBufferInfo.size, mBufferInfo.presentationTimeUs / 1000,TYPE_VIDEO); params.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
mMediaCodec.setParameters(params);
} }
} else {
encodedData.get(h264, 0, mBufferInfo.size);
if(mListener != null){
mListener.onEncodeResult(h264, 0,mBufferInfo.size, mBufferInfo.presentationTimeUs / 1000,TYPE_VIDEO);
} }
if(mListener != null) {
mListener.onEncodeResult(h264, 0,mBufferInfo.size,
mBufferInfo.presentationTimeUs / 1000,TYPE_VIDEO);
} }
}
} else { } else {
mBuffer.clear(); mBuffer.clear();
encodedData.get(mBuffer.array(), 7, mBufferInfo.size); encodedData.get(mBuffer.array(), 7, mBufferInfo.size);
@ -499,6 +507,8 @@ LOOP: while (mIsCapturing) {
} }
} }
} }
}
// return buffer to encoder // return buffer to encoder
mMediaCodec.releaseOutputBuffer(encoderStatus, false); mMediaCodec.releaseOutputBuffer(encoderStatus, false);
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {

3
libusbcamera/src/main/java/com/serenegiant/usb/encoder/MediaMuxerWrapper.java

@ -1,8 +1,10 @@
package com.serenegiant.usb.encoder; package com.serenegiant.usb.encoder;
import android.annotation.TargetApi;
import android.media.MediaCodec; import android.media.MediaCodec;
import android.media.MediaFormat; import android.media.MediaFormat;
import android.media.MediaMuxer; import android.media.MediaMuxer;
import android.os.Build;
import android.os.Environment; import android.os.Environment;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
@ -27,6 +29,7 @@ public class MediaMuxerWrapper {
private boolean mIsStarted; private boolean mIsStarted;
private MediaEncoder mVideoEncoder, mAudioEncoder; private MediaEncoder mVideoEncoder, mAudioEncoder;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public MediaMuxerWrapper(String path) throws IOException { public MediaMuxerWrapper(String path) throws IOException {
try { try {
// 保存到自定义路径还是手机默认Movies路径 // 保存到自定义路径还是手机默认Movies路径

5
libusbcamera/src/main/java/com/serenegiant/usb/encoder/MediaVideoEncoder.java

@ -23,10 +23,12 @@
package com.serenegiant.usb.encoder; package com.serenegiant.usb.encoder;
import android.annotation.TargetApi;
import android.media.MediaCodec; import android.media.MediaCodec;
import android.media.MediaCodecInfo; import android.media.MediaCodecInfo;
import android.media.MediaCodecList; import android.media.MediaCodecList;
import android.media.MediaFormat; import android.media.MediaFormat;
import android.os.Build;
import android.util.Log; import android.util.Log;
import android.view.Surface; import android.view.Surface;
@ -82,6 +84,7 @@ public class MediaVideoEncoder extends MediaEncoder implements IVideoEncoder {
return result; return result;
} }
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
@Override @Override
protected void prepare() throws IOException { protected void prepare() throws IOException {
if (DEBUG) Log.i(TAG, "prepare: "); 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_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface); // API >= 18
format.setInteger(MediaFormat.KEY_BIT_RATE, calcBitRate()); format.setInteger(MediaFormat.KEY_BIT_RATE, calcBitRate());
format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE); 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); if (DEBUG) Log.i(TAG, "format: " + format);
mMediaCodec = MediaCodec.createEncoderByType(MIME_TYPE); mMediaCodec = MediaCodec.createEncoderByType(MIME_TYPE);

Loading…
Cancel
Save