desc:推流相关

main
xiaowusky 1 year ago
parent 3316d8561c
commit f81bd2c76d

@ -32,7 +32,6 @@ object TestUtils {
fun insertData() {
getSupportCodec()
PushHelper.setPushUrl("rtsp://192.168.5.17:554/123")
GlobalScope.launch() {
// 构造气体数据
val timeMillis = System.currentTimeMillis()

@ -3,18 +3,8 @@ package com.yinuo.safetywatcher.watcher
import com.common.commonlib.CommonApplication
import com.common.commonlib.db.DBUtils
import com.common.commonlib.db.entity.Warning
import com.yinuo.safetywatcher.R
import com.yinuo.safetywatcher.TestUtils
import com.yinuo.safetywatcher.watcher.constant.CAMERA_DNS
import com.yinuo.safetywatcher.watcher.constant.CAMERA_GATEWAY
import com.yinuo.safetywatcher.watcher.constant.CAMERA_IP
import com.yinuo.safetywatcher.watcher.constant.CAMERA_NETMASK
import com.yinuo.safetywatcher.watcher.port.cmd.GasPortStatus
import com.yinuo.safetywatcher.watcher.utils.GPIOUtils
import com.yinuo.safetywatcher.watcher.utils.PlatformUtils
import com.yinuo.safetywatcher.watcher.utils.SoundUtils
import com.yinuo.safetywatcher.watcher.wifi.WiFiConfig
import com.yinuo.safetywatcher.watcher.wifi.WiFiModule
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope

@ -29,6 +29,7 @@ import com.yinuo.safetywatcher.watcher.utils.WifiHelper
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.easydarwin.PushHelper
import org.easydarwin.TxtOverlay
import org.easydarwin.video.EasyPlayerClient
import java.io.File
@ -101,6 +102,9 @@ class HomeActivity : NoOptionsActivity() {
private fun onCameraOpen() {
// 启动录制编码
RecordHelper.startRecording()
// 启动推送
PushHelper.opSwitch(true)
PushHelper.startStream(true)
// 开启GPIO
GPIOUtils.openCamera()
setForCamera()
@ -109,6 +113,9 @@ class HomeActivity : NoOptionsActivity() {
private fun onCameraClose() {
// 暂停录制编码
RecordHelper.stopRecording()
// 关闭推流
PushHelper.opSwitch(false)
PushHelper.stop()
// 关闭GPIO
GPIOUtils.closeCamera()
// 关闭视频播放

@ -5,8 +5,10 @@ import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import androidx.annotation.NonNull;
@ -15,7 +17,6 @@ import com.common.commonlib.utils.LogUtils;
import org.easydarwin.PushHelper;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.concurrent.ArrayBlockingQueue;
@TargetApi(Build.VERSION_CODES.M)
@ -42,9 +43,6 @@ public class MediaCodecManager {
private boolean isFlush = false;
private long lastPauseTime = -1;//上次暂停时间
private boolean isHasKeyFrame;
private Handler mHandler;
private int off_y = 50, off_x = 100;
@ -182,14 +180,14 @@ public class MediaCodecManager {
int videoH = rotation == 90 || rotation == 270 ? dstWidth : dstHeight;
mediaFormat = MediaFormat.createVideoFormat(MIME_TYPE,//注意这里旋转后有一个大坑就是要交换mHeight和mWidth的位置。否则录制出来的视频时花屏的。
videoW, videoH);
int frameRate = 25; // 15fps
int frameRate = 24; // 15fps
int compressRatio = 256;
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_COLOR_FORMAT, mColorFormat);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
mediaFormat.setFloat(MediaFormat.KEY_I_FRAME_INTERVAL, 5f);
LogUtils.w("prepare format: " + mediaFormat);
}
@ -197,7 +195,6 @@ public class MediaCodecManager {
public static final int NAL_VPS = 32;
private byte[] vps_sps_pps_buf;
byte[] outData;
private void start() {
if (!isInitCodec)
@ -244,45 +241,39 @@ public class MediaCodecManager {
@Override
public void onOutputBufferAvailable(@NonNull MediaCodec codec, int index, @NonNull MediaCodec.BufferInfo info) {
buildKeyFrame();
ByteBuffer outputBuffer = codec.getOutputBuffer(index);
if (!isHasKeyFrame && info.flags == MediaCodec.BUFFER_FLAG_KEY_FRAME) {
isHasKeyFrame = true;
}
if (outData == null) {
outData = new byte[info.size];
}
if (outputBuffer == null)
if (outputBuffer == null) {
return;
else if (info.presentationTimeUs < lastPauseTime || !isHasKeyFrame) {//上一视频的数据,或者无关键帧,丢弃
//视频第一帧一定要是关键帧
outputBuffer.get(outData);
} else if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
LogUtils.w(TAG, "ignoring BUFFER_FLAG_CODEC_CONFIG");
} else {
outputBuffer.position(info.offset);
outputBuffer.limit(info.offset + info.size);
if (androidMuxer != null) {
if (androidMuxer != null && mTrackIndex != -1) {
androidMuxer.writeSampleData(mTrackIndex, outputBuffer, info);
}
byte[] outData = new byte[info.size];
outputBuffer.get(outData);
int offset = 4;
if (outData[2] == 0x01) {
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);
} else if (type == NAL_I) {
if (vps_sps_pps_buf != null) {
} else {
if (type == NAL_I && vps_sps_pps_buf != null) {
byte[] newBuf = new byte[vps_sps_pps_buf.length + outData.length];
System.arraycopy(vps_sps_pps_buf, 0, newBuf, 0, vps_sps_pps_buf.length);
System.arraycopy(outData, 0, newBuf, vps_sps_pps_buf.length, outData.length);
outData = newBuf;
PushHelper.INSTANCE.pushData(outData, outData.length, info.presentationTimeUs / 1000);
}
}
PushHelper.INSTANCE.pushData(outData, outData.length, info.presentationTimeUs / 1000);
codec.releaseOutputBuffer(index, false);
}
codec.releaseOutputBuffer(index, false);
try {
Thread.sleep(0);
} catch (InterruptedException e) {
@ -313,6 +304,17 @@ public class MediaCodecManager {
isStart = true;
}
long timeStamp = -1L;
void buildKeyFrame() {
if (System.currentTimeMillis() - timeStamp >= 5000) {//1000毫秒后设置参数
timeStamp = System.currentTimeMillis();
Bundle params = new Bundle();
params.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
mMediaCodec.setParameters(params);
}
}
/**
*
*/
@ -320,9 +322,9 @@ public class MediaCodecManager {
LogUtils.w(TAG, "flushMediaCodec");
frameBytes.clear();
isFlush = true;
lastPauseTime = (System.nanoTime()) / 1000;//记录
isHasKeyFrame = false;
// lastPauseTime = (System.nanoTime()) / 1000;//记录
//
// isHasKeyFrame = false;
}
@ -339,7 +341,7 @@ public class MediaCodecManager {
}
isStart = false;
isPause = true;
isHasKeyFrame = false;
// isHasKeyFrame = false;
LogUtils.w(TAG, "stopMediaCodec video");
});
}

@ -22,8 +22,14 @@ object PushHelper {
private var mInitialized = false
private var switchOpen = true
fun opSwitch(open: Boolean) {
switchOpen = open
}
var callback = InitCallback { code ->
var msg = ""
var msg = "$code"
when (code) {
EasyPusher.OnInitPusherCallback.CODE.EASY_ACTIVATE_INVALID_KEY -> msg = "无效Key"
EasyPusher.OnInitPusherCallback.CODE.EASY_ACTIVATE_SUCCESS -> msg = "未开始"
@ -50,14 +56,16 @@ object PushHelper {
mIp = mUri.host
mPort = mUri.port.toString()
mId = mUri.path
if (mId?.startsWith("/")!!){
if (mId?.startsWith("/")!!) {
mId = mId!!.substring(1)
}
}
fun startStream(hevc: Boolean) {
stop()
initHelper(hevc)
if (switchOpen) {
stop()
initHelper(hevc)
}
}
fun stop() {

Loading…
Cancel
Save