|
@ -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) { |
|
|