From 8bc72ebc21e04e3d52f7250716c44d3104bfecfa Mon Sep 17 00:00:00 2001
From: Dana <Dana_Lee1016@126.com>
Date: 星期二, 02 十二月 2025 15:28:10 +0800
Subject: [PATCH] 1.修改文件推流
---
app/src/main/java/com/anyun/h264/H264FileTransmitter.java | 187 +++++++++++++++++++++++++++++++++++++++-------
1 files changed, 157 insertions(+), 30 deletions(-)
diff --git a/app/src/main/java/com/anyun/h264/H264FileTransmitter.java b/app/src/main/java/com/anyun/h264/H264FileTransmitter.java
index 6f76ca1..7e77d79 100644
--- a/app/src/main/java/com/anyun/h264/H264FileTransmitter.java
+++ b/app/src/main/java/com/anyun/h264/H264FileTransmitter.java
@@ -55,6 +55,10 @@
private int frameRate = 25; // 甯х巼锛岀敤浜庤绠楁椂闂存埑闂撮殧
private long frameInterval = 1000 / 25; // 甯ч棿闅旓紙姣锛�
+ // SPS/PPS缂撳瓨
+ private byte[] spsBuffer;
+ private byte[] ppsBuffer;
+
// 鏃堕棿鎴崇鐞�
private long lastIFrameTime = 0; // 涓婁竴涓狪甯ф椂闂�
private long lastFrameTime = 0; // 涓婁竴甯ф椂闂�
@@ -151,6 +155,8 @@
baseTimestamp = System.currentTimeMillis();
lastIFrameTime = 0;
lastFrameTime = 0;
+ spsBuffer = null;
+ ppsBuffer = null;
Timber.d("Socket initialized successfully");
return true;
@@ -427,36 +433,7 @@
int dataType = isKeyFrame ? JT1076ProtocolHelper.DATA_TYPE_I_FRAME :
JT1076ProtocolHelper.DATA_TYPE_P_FRAME;
- // 鍒嗗寘鍙戦�侊紙濡傛灉鏁版嵁瓒呰繃鏈�澶у寘澶у皬锛�
- int offset = 0;
- int totalPackets = (int) Math.ceil((double) frameData.length / JT1076ProtocolHelper.MAX_PACKET_SIZE);
-
- for (int i = 0; i < totalPackets; i++) {
- int packetDataSize = Math.min(JT1076ProtocolHelper.MAX_PACKET_SIZE, frameData.length - offset);
- byte[] packetData = Arrays.copyOfRange(frameData, offset, offset + packetDataSize);
-
- // 纭畾鍒嗗寘鏍囪
- int packetMark;
- if (totalPackets == 1) {
- packetMark = JT1076ProtocolHelper.PACKET_MARK_ATOMIC;
- } else if (i == 0) {
- packetMark = JT1076ProtocolHelper.PACKET_MARK_FIRST;
- } else if (i == totalPackets - 1) {
- packetMark = JT1076ProtocolHelper.PACKET_MARK_LAST;
- } else {
- packetMark = JT1076ProtocolHelper.PACKET_MARK_MIDDLE;
- }
-
- // 鍒涘缓RTP鍖�
- byte[] rtpPacket = protocolHelper.createVideoRtpPacket(
- packetData, timestamp, dataType, packetMark,
- lastIFrameInterval, lastFrameInterval);
-
- // 鍙戦�丷TP鍖咃紙UDP鎴朤CP锛屾牴鎹崗璁被鍨嬭嚜鍔ㄩ�夋嫨锛�
- protocolHelper.sendPacket(rtpPacket);
-
- offset += packetDataSize;
- }
+ processNalUnits(frameData, timestamp, lastIFrameInterval, lastFrameInterval);
// 鎺у埗鍙戦�侀�熺巼锛堟ā鎷熷抚鐜囷級
if (frameInterval > 0) {
@@ -498,10 +475,160 @@
protocolHelper.closeSocket();
}
+ spsBuffer = null;
+ ppsBuffer = null;
+
Timber.d("H264 file transmitter stopped");
}
/**
+ * 瑙f瀽甯т腑鐨凬AL鍗曞厓骞舵牴鎹被鍨嬪鐞�
+ */
+ private void processNalUnits(byte[] frameData, long timestamp,
+ long lastIFrameInterval, long lastFrameInterval) {
+ if (frameData == null || frameData.length == 0) {
+ return;
+ }
+
+ boolean nalProcessed = false;
+ int offset = 0;
+ while (offset < frameData.length) {
+ int startCodePos = findStartCode(frameData, offset);
+ if (startCodePos < 0) {
+ break;
+ }
+
+ int startCodeLen = getStartCodeLength(frameData, startCodePos);
+ int nalDataStart = startCodePos + startCodeLen;
+ if (nalDataStart >= frameData.length) {
+ break;
+ }
+
+ int nextStart = findStartCode(frameData, nalDataStart);
+ int nalEnd = (nextStart == -1) ? frameData.length : nextStart;
+ int nalLength = nalEnd - startCodePos;
+ if (nalLength <= startCodeLen) {
+ break;
+ }
+
+ byte[] nalUnit = Arrays.copyOfRange(frameData, startCodePos, nalEnd);
+ int nalType = nalUnit[startCodeLen] & 0x1F;
+
+ handleNalUnit(nalUnit, nalType, timestamp, lastIFrameInterval, lastFrameInterval);
+ nalProcessed = true;
+ offset = nalEnd;
+ }
+
+ if (!nalProcessed) {
+ // 娌℃湁瑙f瀽鍑篘AL鍗曞厓鏃讹紝鐩存帴鎸塒甯у彂閫�
+ sendFramePayload(frameData, timestamp, false, lastIFrameInterval, lastFrameInterval);
+ }
+ }
+
+ private void handleNalUnit(byte[] nalUnit, int nalType, long timestamp,
+ long lastIFrameInterval, long lastFrameInterval) {
+ switch (nalType) {
+ case 7: // SPS
+ spsBuffer = nalUnit.clone();
+ Timber.d("Cached SPS, size: %d", spsBuffer.length);
+ break;
+ case 8: // PPS
+ ppsBuffer = nalUnit.clone();
+ Timber.d("Cached PPS, size: %d", ppsBuffer.length);
+ break;
+ case 5: // IDR
+ if (spsBuffer != null && ppsBuffer != null) {
+ byte[] combined = combineFrameData(spsBuffer, ppsBuffer, nalUnit);
+ sendFramePayload(combined, timestamp, true, lastIFrameInterval, lastFrameInterval);
+ } else {
+ Timber.w("IDR frame without SPS/PPS cache, sending raw IDR");
+ sendFramePayload(nalUnit, timestamp, true, lastIFrameInterval, lastFrameInterval);
+ }
+ break;
+ case 1: // P frame
+ sendFramePayload(nalUnit, timestamp, false, lastIFrameInterval, lastFrameInterval);
+ break;
+ default:
+ Timber.d("Forwarding NAL type %d, size: %d", nalType, nalUnit.length);
+ sendFramePayload(nalUnit, timestamp, false, lastIFrameInterval, lastFrameInterval);
+ break;
+ }
+ }
+
+ private void sendFramePayload(byte[] payload, long timestamp, boolean isKeyFrame,
+ long lastIFrameInterval, long lastFrameInterval) {
+ if (payload == null || payload.length == 0) {
+ return;
+ }
+
+ int dataType = isKeyFrame ? JT1076ProtocolHelper.DATA_TYPE_I_FRAME :
+ JT1076ProtocolHelper.DATA_TYPE_P_FRAME;
+
+ int offset = 0;
+ int totalPackets = (int) Math.ceil((double) payload.length / JT1076ProtocolHelper.MAX_PACKET_SIZE);
+ for (int i = 0; i < totalPackets; i++) {
+ int packetDataSize = Math.min(JT1076ProtocolHelper.MAX_PACKET_SIZE, payload.length - offset);
+ byte[] packetData = Arrays.copyOfRange(payload, offset, offset + packetDataSize);
+
+ int packetMark;
+ if (totalPackets == 1) {
+ packetMark = JT1076ProtocolHelper.PACKET_MARK_ATOMIC;
+ } else if (i == 0) {
+ packetMark = JT1076ProtocolHelper.PACKET_MARK_FIRST;
+ } else if (i == totalPackets - 1) {
+ packetMark = JT1076ProtocolHelper.PACKET_MARK_LAST;
+ } else {
+ packetMark = JT1076ProtocolHelper.PACKET_MARK_MIDDLE;
+ }
+
+ byte[] rtpPacket = protocolHelper.createVideoRtpPacket(
+ packetData, timestamp, dataType, packetMark,
+ lastIFrameInterval, lastFrameInterval);
+ protocolHelper.sendPacket(rtpPacket);
+ offset += packetDataSize;
+ }
+ }
+
+ private int findStartCode(byte[] data, int startPos) {
+ if (data == null || startPos >= data.length - 3) {
+ return -1;
+ }
+ for (int i = startPos; i < data.length - 3; i++) {
+ if (isStartCodeAt(data, i)) {
+ return i;
+ }
+ }
+ // 澶勭悊鍓╀綑涓嶈冻4瀛楄妭浣嗗彲鑳芥槸3瀛楄妭璧峰鐮佺殑鎯呭喌
+ for (int i = Math.max(startPos, data.length - 3); i < data.length - 2; i++) {
+ if (isStartCodeAt(data, i)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private byte[] combineFrameData(byte[] sps, byte[] pps, byte[] idr) {
+ int totalLength = (sps != null ? sps.length : 0) +
+ (pps != null ? pps.length : 0) +
+ (idr != null ? idr.length : 0);
+ byte[] combined = new byte[totalLength];
+ int offset = 0;
+ if (sps != null) {
+ System.arraycopy(sps, 0, combined, offset, sps.length);
+ offset += sps.length;
+ }
+ if (pps != null) {
+ System.arraycopy(pps, 0, combined, offset, pps.length);
+ offset += pps.length;
+ }
+ if (idr != null) {
+ System.arraycopy(idr, 0, combined, offset, idr.length);
+ }
+ Timber.d("Combined SPS/PPS/IDR payload, total: %d", totalLength);
+ return combined;
+ }
+
+ /**
* 閲婃斁璧勬簮
*/
public void release() {
--
Gitblit v1.8.0