desc:推流

main
xiaowusky 1 year ago
parent ac3d2b32c5
commit 774c47aca6

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

@ -165,7 +165,7 @@ public class VideoEncoderCoreAvc extends MediaEncoderCore {
outData = iframeData;
}
//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);

@ -173,7 +173,7 @@ public class VideoEncoderCoreHevc extends MediaEncoderCore {
System.arraycopy(outData, 0, newBuf, vps_sps_pps_buf.length, outData.length);
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);

@ -72,7 +72,10 @@ object PushHelper {
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()) {
LogUtils.e("PushHelper error, please setPushUrl before!!")
return
@ -81,7 +84,7 @@ object PushHelper {
LogUtils.e("PushHelper error, please init first!!")
return
}
mPusher?.push(h264, 0, length, timeStamp, 1)
mPusher?.push(h264, 0, length, timeStamp, type)
}
private fun initHelper(hevc: Boolean) {

Loading…
Cancel
Save