diff --git a/app/src/main/java/com/yinuo/safetywatcher/TestUtils.kt b/app/src/main/java/com/yinuo/safetywatcher/TestUtils.kt index e417c0c..892ccf7 100644 --- a/app/src/main/java/com/yinuo/safetywatcher/TestUtils.kt +++ b/app/src/main/java/com/yinuo/safetywatcher/TestUtils.kt @@ -32,7 +32,6 @@ object TestUtils { fun insertData() { getSupportCodec() - PushHelper.setPushUrl("rtsp://192.168.5.17:554/123") GlobalScope.launch() { // 构造气体数据 val timeMillis = System.currentTimeMillis() diff --git a/app/src/main/java/com/yinuo/safetywatcher/watcher/App.kt b/app/src/main/java/com/yinuo/safetywatcher/watcher/App.kt index 1f388aa..85e0baa 100644 --- a/app/src/main/java/com/yinuo/safetywatcher/watcher/App.kt +++ b/app/src/main/java/com/yinuo/safetywatcher/watcher/App.kt @@ -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 diff --git a/app/src/main/java/com/yinuo/safetywatcher/watcher/ui/HomeActivity.kt b/app/src/main/java/com/yinuo/safetywatcher/watcher/ui/HomeActivity.kt index 0691d72..0afa8e9 100644 --- a/app/src/main/java/com/yinuo/safetywatcher/watcher/ui/HomeActivity.kt +++ b/app/src/main/java/com/yinuo/safetywatcher/watcher/ui/HomeActivity.kt @@ -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() // 关闭视频播放 diff --git a/library-push/src/main/java/com/yinuo/library/vlc/encoder/MediaCodecManager.java b/library-push/src/main/java/com/yinuo/library/vlc/encoder/MediaCodecManager.java index 192e798..90545c9 100644 --- a/library-push/src/main/java/com/yinuo/library/vlc/encoder/MediaCodecManager.java +++ b/library-push/src/main/java/com/yinuo/library/vlc/encoder/MediaCodecManager.java @@ -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"); }); } diff --git a/library-push/src/main/java/org/easydarwin/PushHelper.kt b/library-push/src/main/java/org/easydarwin/PushHelper.kt index 59af174..b7cb340 100644 --- a/library-push/src/main/java/org/easydarwin/PushHelper.kt +++ b/library-push/src/main/java/org/easydarwin/PushHelper.kt @@ -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() {