desc:推流

main
xiaowusky 1 year ago
parent ac3d2b32c5
commit 774c47aca6

@ -31,4 +31,43 @@ object BitmapUtils {
// backBitmap.recycle() // backBitmap.recycle()
return backBitmap return backBitmap
} }
private var rgbaData: ByteArray? = null
fun nv12ToRgba(nv12Data: ByteArray, width: Int, height: Int): ByteArray {
if (rgbaData == null) {
rgbaData = ByteArray(width * height * 4)
}
val frameSize = width * height
val uvIndex = frameSize
for (j in 0 until height) {
val rgbIndex = j * width
val uvIndexLine = (j shr 1) * width
for (i in 0 until width) {
val uvIndexOffset = (i shr 1) * 2
val y = 0xff and nv12Data[rgbIndex + i].toInt()
val u = 0xff and nv12Data[uvIndex + uvIndexOffset].toInt() - 128
val v = 0xff and nv12Data[uvIndex + uvIndexOffset + 1].toInt() - 128
// 转换YUV到RGB
val r = y + 1.402f * v
val g = y - 0.344f * u - 0.714f * v
val b = y + 1.772f * u
// 将RGB值限制在0-255范围内
val pixelR = r.coerceIn(0f, 255f).toInt()
val pixelG = g.coerceIn(0f, 255f).toInt()
val pixelB = b.coerceIn(0f, 255f).toInt()
// 设置RGBA值
val rgbaIndex = (j * width + i) * 4
rgbaData!![rgbaIndex] = pixelR.toByte()
rgbaData!![rgbaIndex + 1] = pixelG.toByte()
rgbaData!![rgbaIndex + 2] = pixelB.toByte()
rgbaData!![rgbaIndex + 3] = 255.toByte()
}
}
return rgbaData!!
}
} }

@ -8,6 +8,7 @@ import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -29,7 +30,6 @@ public class MediaCodecManager {
private ArrayBlockingQueue<byte[]> frameBytes; private ArrayBlockingQueue<byte[]> frameBytes;
private MediaCodec mMediaCodec; private MediaCodec mMediaCodec;
private int mColorFormat; private int mColorFormat;
private long mStartTime = 0;
private MediaFormat mediaFormat; private MediaFormat mediaFormat;
private volatile boolean isStart = false; private volatile boolean isStart = false;
private volatile boolean isPause = false; private volatile boolean isPause = false;
@ -40,11 +40,8 @@ public class MediaCodecManager {
private boolean isInitCodec; private boolean isInitCodec;
private boolean isFlush = false;
private Handler mHandler; private Handler mHandler;
private int off_y = 50, off_x = 100;
private int rotation; private int rotation;
private AndroidMuxer androidMuxer; private AndroidMuxer androidMuxer;
@ -73,7 +70,6 @@ public class MediaCodecManager {
* @param dstHeight * @param dstHeight
*/ */
public void initCodecManager(int dstWidth, int dstHeight, int rotation) { public void initCodecManager(int dstWidth, int dstHeight, int rotation) {
isFlush = false;
if (!isInitCodec) { if (!isInitCodec) {
mHandler.post(() -> { mHandler.post(() -> {
frameBytes = new ArrayBlockingQueue<>(100); frameBytes = new ArrayBlockingQueue<>(100);
@ -140,7 +136,6 @@ public class MediaCodecManager {
if (mMediaCodec != null) { if (mMediaCodec != null) {
frameBytes.clear(); frameBytes.clear();
mHandlerThread.quit(); mHandlerThread.quit();
// YuvOsdUtils.releaseOsd();
stopMediaCodec(); stopMediaCodec();
sInstance = null; sInstance = null;
if (androidMuxer != null) { if (androidMuxer != null) {
@ -155,7 +150,6 @@ public class MediaCodecManager {
public void addFrameData(byte[] data) { public void addFrameData(byte[] data) {
if (isStart && !isPause) { if (isStart && !isPause) {
boolean isOffer = frameBytes.offer(data); boolean isOffer = frameBytes.offer(data);
// Logger1.i(TAG, "addFrameData: isOffer=%s", isOffer);
if (!isOffer) { if (!isOffer) {
frameBytes.poll(); frameBytes.poll();
frameBytes.offer(data); frameBytes.offer(data);
@ -184,9 +178,9 @@ public class MediaCodecManager {
int bitRate = dstWidth * dstHeight * 3 * 8 * frameRate / compressRatio; int bitRate = dstWidth * dstHeight * 3 * 8 * frameRate / compressRatio;
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate); mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate); mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, (int) (frameRate * 0.3));
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, mColorFormat); mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, mColorFormat);
mediaFormat.setFloat(MediaFormat.KEY_I_FRAME_INTERVAL, 5f); mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 3);
LogUtils.w("prepare format: " + mediaFormat); LogUtils.w("prepare format: " + mediaFormat);
} }
@ -208,11 +202,12 @@ public class MediaCodecManager {
mMediaCodec = MediaCodec.createEncoderByType(MIME_TYPE); mMediaCodec = MediaCodec.createEncoderByType(MIME_TYPE);
mMediaCodec.configure(mediaFormat, null, null, mMediaCodec.configure(mediaFormat, null, null,
MediaCodec.CONFIGURE_FLAG_ENCODE); MediaCodec.CONFIGURE_FLAG_ENCODE);
Bundle params = new Bundle();
params.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
mMediaCodec.setParameters(params);
mMediaCodec.setCallback(new MediaCodec.Callback() { mMediaCodec.setCallback(new MediaCodec.Callback() {
@Override @Override
public void onInputBufferAvailable(@NonNull MediaCodec codec, int index) { public void onInputBufferAvailable(@NonNull MediaCodec codec, int index) {
byte[] data = null; byte[] data = null;
try { try {
data = frameBytes.take(); data = frameBytes.take();
@ -221,7 +216,6 @@ public class MediaCodecManager {
return; return;
} }
ByteBuffer inputBuffer = codec.getInputBuffer(index); ByteBuffer inputBuffer = codec.getInputBuffer(index);
if (inputBuffer == null) if (inputBuffer == null)
return; return;
@ -259,8 +253,10 @@ public class MediaCodecManager {
offset = 3; offset = 3;
} }
int type = (outData[offset] & 0x7E) >> 1; int type = (outData[offset] & 0x7E) >> 1;
Log.i("cyy", "type = " + type);
if (type == NAL_VPS) { if (type == NAL_VPS) {
vps_sps_pps_buf = outData; vps_sps_pps_buf = outData;
PushHelper.INSTANCE.pushData(outData, outData.length, info.presentationTimeUs / 1000, 2);
} else { } else {
if (type == NAL_I && vps_sps_pps_buf != null) { if (type == NAL_I && vps_sps_pps_buf != null) {
byte[] newBuf = new byte[vps_sps_pps_buf.length + outData.length]; byte[] newBuf = new byte[vps_sps_pps_buf.length + outData.length];
@ -268,8 +264,8 @@ public class MediaCodecManager {
System.arraycopy(outData, 0, newBuf, vps_sps_pps_buf.length, outData.length); System.arraycopy(outData, 0, newBuf, vps_sps_pps_buf.length, outData.length);
outData = newBuf; outData = newBuf;
} }
PushHelper.INSTANCE.pushData(outData, outData.length, info.presentationTimeUs / 1000, type == 19 ? 2 : 1);
} }
PushHelper.INSTANCE.pushData(outData, outData.length, info.presentationTimeUs / 1000);
codec.releaseOutputBuffer(index, false); codec.releaseOutputBuffer(index, false);
} }
try { try {
@ -305,10 +301,10 @@ public class MediaCodecManager {
long timeStamp = -1L; long timeStamp = -1L;
void buildKeyFrame() { void buildKeyFrame() {
if (System.currentTimeMillis() - timeStamp >= 5000) {//1000毫秒后设置参数 if (System.currentTimeMillis() - timeStamp >= 3000) {
timeStamp = System.currentTimeMillis(); timeStamp = System.currentTimeMillis();
Bundle params = new Bundle(); Bundle params = new Bundle();
params.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0); params.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 50);
mMediaCodec.setParameters(params); mMediaCodec.setParameters(params);
} }
} }
@ -319,11 +315,6 @@ public class MediaCodecManager {
public synchronized void flushMediaCodec() { public synchronized void flushMediaCodec() {
LogUtils.w(TAG, "flushMediaCodec"); LogUtils.w(TAG, "flushMediaCodec");
frameBytes.clear(); frameBytes.clear();
isFlush = true;
// lastPauseTime = (System.nanoTime()) / 1000;//记录
//
// isHasKeyFrame = false;
} }
public void stopMediaCodec() { public void stopMediaCodec() {
@ -339,7 +330,6 @@ public class MediaCodecManager {
} }
isStart = false; isStart = false;
isPause = true; isPause = true;
// isHasKeyFrame = false;
LogUtils.w(TAG, "stopMediaCodec video"); LogUtils.w(TAG, "stopMediaCodec video");
}); });
} }

@ -165,7 +165,7 @@ public class VideoEncoderCoreAvc extends MediaEncoderCore {
outData = iframeData; outData = iframeData;
} }
//save(outData, 0, outData.length, Environment.getExternalStorageDirectory() + "/easy.h264", true); //save(outData, 0, outData.length, Environment.getExternalStorageDirectory() + "/easy.h264", true);
PushHelper.INSTANCE.pushData(outData, outData.length, mBufferInfo.presentationTimeUs / 1000); PushHelper.INSTANCE.pushData(outData, outData.length, mBufferInfo.presentationTimeUs / 1000, 1);
} }
mEncoder.releaseOutputBuffer(encoderStatus, false); mEncoder.releaseOutputBuffer(encoderStatus, false);

@ -173,7 +173,7 @@ public class VideoEncoderCoreHevc extends MediaEncoderCore {
System.arraycopy(outData, 0, newBuf, vps_sps_pps_buf.length, outData.length); System.arraycopy(outData, 0, newBuf, vps_sps_pps_buf.length, outData.length);
outData = newBuf; outData = newBuf;
} }
PushHelper.INSTANCE.pushData(outData, outData.length, mBufferInfo.presentationTimeUs / 1000); PushHelper.INSTANCE.pushData(outData, outData.length, mBufferInfo.presentationTimeUs / 1000, 1);
} }
mEncoder.releaseOutputBuffer(encoderStatus, false); mEncoder.releaseOutputBuffer(encoderStatus, false);

@ -72,7 +72,10 @@ object PushHelper {
mPusher = null mPusher = null
} }
fun pushData(h264: ByteArray, length: Int, timeStamp: Long) { fun pushData(h264: ByteArray, length: Int, timeStamp: Long, type: Int = 1) {
if (!switchOpen) {
return
}
if (mIp.isNullOrEmpty() || mPort.isNullOrEmpty() || mId.isNullOrEmpty()) { if (mIp.isNullOrEmpty() || mPort.isNullOrEmpty() || mId.isNullOrEmpty()) {
LogUtils.e("PushHelper error, please setPushUrl before!!") LogUtils.e("PushHelper error, please setPushUrl before!!")
return return
@ -81,7 +84,7 @@ object PushHelper {
LogUtils.e("PushHelper error, please init first!!") LogUtils.e("PushHelper error, please init first!!")
return return
} }
mPusher?.push(h264, 0, length, timeStamp, 1) mPusher?.push(h264, 0, length, timeStamp, type)
} }
private fun initHelper(hevc: Boolean) { private fun initHelper(hevc: Boolean) {

Loading…
Cancel
Save