diff --git a/app/src/main/java/com/pedro/streamer/rotation/CameraFragment.kt b/app/src/main/java/com/pedro/streamer/rotation/CameraFragment.kt index 7d2446b16..979b06469 100644 --- a/app/src/main/java/com/pedro/streamer/rotation/CameraFragment.kt +++ b/app/src/main/java/com/pedro/streamer/rotation/CameraFragment.kt @@ -30,6 +30,7 @@ import android.widget.TextView import androidx.annotation.RequiresApi import androidx.fragment.app.Fragment import com.pedro.common.ConnectChecker +import com.pedro.common.VideoCodec import com.pedro.common.onMainThreadHandler import com.pedro.encoder.input.sources.video.Camera1Source import com.pedro.encoder.input.sources.video.Camera2Source @@ -78,6 +79,7 @@ class CameraFragment: Fragment(), ConnectChecker { val genericStream: GenericStream by lazy { GenericStream(requireContext(), this).apply { getGlInterface().autoHandleOrientation = true + setVideoCodec(VideoCodec.H265) } } private lateinit var surfaceView: SurfaceView diff --git a/rtsp/src/main/java/com/pedro/rtsp/rtp/packets/H264Packet.kt b/rtsp/src/main/java/com/pedro/rtsp/rtp/packets/H264Packet.kt index 6a3747571..987e8cf86 100644 --- a/rtsp/src/main/java/com/pedro/rtsp/rtp/packets/H264Packet.kt +++ b/rtsp/src/main/java/com/pedro/rtsp/rtp/packets/H264Packet.kt @@ -68,10 +68,9 @@ class H264Packet: BasePacket(RtpConstants.clockVideoFrequency, if (nals.isEmpty()) return val ts = mediaFrame.info.timestamp * 1000L - val nalType = nals[0].get() - val naluLength = nals.sumOf { it.remaining() } - val type: Int = (nalType and 0x1F).toInt() val frames = mutableListOf() + val nalType = nals[0].get(0) + val type: Int = (nalType and 0x1F).toInt() if (type == RtpConstants.IDR || mediaFrame.info.isKeyFrame) { stapA?.let { val buffer = getBuffer(it.size + RtpConstants.RTP_HEADER_LENGTH) @@ -87,50 +86,52 @@ class H264Packet: BasePacket(RtpConstants.clockVideoFrequency, } } if (sendKeyFrame) { - // Small NAL unit => Single NAL unit - if (nals.size == 1 && naluLength <= maxPacketSize - RtpConstants.RTP_HEADER_LENGTH - 1) { - val buffer = getBuffer(naluLength + RtpConstants.RTP_HEADER_LENGTH + 1) - buffer[RtpConstants.RTP_HEADER_LENGTH] = nalType - nals[0].get(buffer, RtpConstants.RTP_HEADER_LENGTH + 1, naluLength) - val rtpTs = updateTimeStamp(buffer, ts) - markPacket(buffer) //mark end frame - updateSeq(buffer) - val rtpFrame = RtpFrame(buffer, rtpTs, buffer.size, channelIdentifier) - frames.add(rtpFrame) - } else { - // Set FU-A header - header[1] = nalType and 0x1F // FU header type - header[1] = header[1].plus(0x80).toByte() // set start bit to 1 - // Set FU-A indicator - header[0] = nalType and 0x60 and 0xFF.toByte() // FU indicator NRI - header[0] = header[0].plus(28).toByte() nals.forEachIndexed { index, data -> - var sum = 0 + val nalType = data.get() val nalSize = data.remaining() - while (sum < nalSize) { - val length = if (nalSize - sum > maxPacketSize - RtpConstants.RTP_HEADER_LENGTH - 2) { - maxPacketSize - RtpConstants.RTP_HEADER_LENGTH - 2 - } else { - data.remaining() - } - val buffer = getBuffer(length + RtpConstants.RTP_HEADER_LENGTH + 2) - buffer[RtpConstants.RTP_HEADER_LENGTH] = header[0] - // Switch start bit - buffer[RtpConstants.RTP_HEADER_LENGTH + 1] = if (sum > 0) header[1] and 0x7F else header[1] + // Small NAL unit => Single NAL unit + if (nalSize <= maxPacketSize - RtpConstants.RTP_HEADER_LENGTH - 1) { + val buffer = getBuffer(nalSize + RtpConstants.RTP_HEADER_LENGTH + 1) + buffer[RtpConstants.RTP_HEADER_LENGTH] = nalType + data.get(buffer, RtpConstants.RTP_HEADER_LENGTH + 1, nalSize) val rtpTs = updateTimeStamp(buffer, ts) - data.get(buffer, RtpConstants.RTP_HEADER_LENGTH + 2, length) - sum += length - // Last packet before next NAL - if (sum >= nalSize) { - // End bit on - buffer[RtpConstants.RTP_HEADER_LENGTH + 1] = buffer[RtpConstants.RTP_HEADER_LENGTH + 1].plus(0x40).toByte() - if (index == nals.size - 1) markPacket(buffer) //mark end frame - } + if (index == nals.size - 1) markPacket(buffer) //mark end frame updateSeq(buffer) val rtpFrame = RtpFrame(buffer, rtpTs, buffer.size, channelIdentifier) frames.add(rtpFrame) + } else { + // Set FU-A header + header[1] = nalType and 0x1F // FU header type + header[1] = header[1].plus(0x80).toByte() // set start bit to 1 + // Set FU-A indicator + header[0] = nalType and 0x60 and 0xFF.toByte() // FU indicator NRI + header[0] = header[0].plus(28).toByte() + + var sum = 0 + while (sum < nalSize) { + val length = if (nalSize - sum > maxPacketSize - RtpConstants.RTP_HEADER_LENGTH - 2) { + maxPacketSize - RtpConstants.RTP_HEADER_LENGTH - 2 + } else { + data.remaining() + } + val buffer = getBuffer(length + RtpConstants.RTP_HEADER_LENGTH + 2) + buffer[RtpConstants.RTP_HEADER_LENGTH] = header[0] + // Switch start bit + buffer[RtpConstants.RTP_HEADER_LENGTH + 1] = if (sum > 0) header[1] and 0x7F else header[1] + val rtpTs = updateTimeStamp(buffer, ts) + data.get(buffer, RtpConstants.RTP_HEADER_LENGTH + 2, length) + sum += length + // Last packet before next NAL + if (sum >= nalSize) { + // End bit on + buffer[RtpConstants.RTP_HEADER_LENGTH + 1] = buffer[RtpConstants.RTP_HEADER_LENGTH + 1].plus(0x40).toByte() + if (index == nals.size - 1) markPacket(buffer) //mark end frame + } + updateSeq(buffer) + val rtpFrame = RtpFrame(buffer, rtpTs, buffer.size, channelIdentifier) + frames.add(rtpFrame) + } } - } } } else { Log.i(TAG, "waiting for keyframe") diff --git a/rtsp/src/main/java/com/pedro/rtsp/rtp/packets/H265Packet.kt b/rtsp/src/main/java/com/pedro/rtsp/rtp/packets/H265Packet.kt index 170c4f5a0..6932cad2d 100644 --- a/rtsp/src/main/java/com/pedro/rtsp/rtp/packets/H265Packet.kt +++ b/rtsp/src/main/java/com/pedro/rtsp/rtp/packets/H265Packet.kt @@ -23,7 +23,6 @@ import com.pedro.common.nal.NalReader import com.pedro.common.removeInfo import com.pedro.rtsp.rtsp.RtpFrame import com.pedro.rtsp.utils.RtpConstants -import com.pedro.rtsp.utils.getVideoStartCodeSize import java.nio.ByteBuffer import kotlin.experimental.and @@ -32,7 +31,7 @@ import kotlin.experimental.and * * RFC 7798. */ -class H265Packet: BasePacket( +class H265Packet : BasePacket( RtpConstants.clockVideoFrequency, RtpConstants.payloadType + RtpConstants.trackVideo ) { @@ -64,38 +63,39 @@ class H265Packet: BasePacket( if (nals.isEmpty()) return val ts = mediaFrame.info.timestamp * 1000L - val nalType = nals[0].get() - val nalType2 = nals[0].get() - val naluLength = nals.sumOf { it.remaining() } - val type: Int = nalType.toInt().shr(1 and 0x3f) val frames = mutableListOf() - // Small NAL unit => Single NAL unit - if (nals.size == 1 && naluLength <= maxPacketSize - RtpConstants.RTP_HEADER_LENGTH - 2) { - val buffer = getBuffer(naluLength + RtpConstants.RTP_HEADER_LENGTH + 2) - //Set PayloadHdr (exact copy of nal unit header) - buffer[RtpConstants.RTP_HEADER_LENGTH] = nalType - buffer[RtpConstants.RTP_HEADER_LENGTH + 1] = nalType2 - nals[0].get(buffer, RtpConstants.RTP_HEADER_LENGTH + 2, naluLength) - val rtpTs = updateTimeStamp(buffer, ts) - markPacket(buffer) //mark end frame - updateSeq(buffer) - val rtpFrame = RtpFrame(buffer, rtpTs, buffer.size, channelIdentifier) - frames.add(rtpFrame) - } else { - //Set PayloadHdr (16bit type=49) - header[0] = (49 shl 1).toByte() - header[1] = 1 - // Set FU header - // +---------------+ - // |0|1|2|3|4|5|6|7| - // +-+-+-+-+-+-+-+-+ - // |S|E| FuType | - // +---------------+ - header[2] = type.toByte() // FU header type - header[2] = header[2].plus(0x80).toByte() // Start bit - nals.forEachIndexed { index, data -> + + nals.forEachIndexed { index, data -> + val nalType = data.get() + val nalType2 = data.get() + val nalSize = data.remaining() + // Small NAL unit => Single NAL unit + if (nalSize <= maxPacketSize - RtpConstants.RTP_HEADER_LENGTH - 2) { + val buffer = getBuffer(nalSize + RtpConstants.RTP_HEADER_LENGTH + 2) + //Set PayloadHdr (exact copy of nal unit header) + buffer[RtpConstants.RTP_HEADER_LENGTH] = nalType + buffer[RtpConstants.RTP_HEADER_LENGTH + 1] = nalType2 + data.get(buffer, RtpConstants.RTP_HEADER_LENGTH + 2, nalSize) + val rtpTs = updateTimeStamp(buffer, ts) + if (index == nals.size - 1) markPacket(buffer) //mark end frame + updateSeq(buffer) + val rtpFrame = RtpFrame(buffer, rtpTs, buffer.size, channelIdentifier) + frames.add(rtpFrame) + } else { + val type: Int = nalType.toInt().shr(1 and 0x3f) + //Set PayloadHdr (16bit type=49) + header[0] = (49 shl 1).toByte() + header[1] = 1 + // Set FU header + // +---------------+ + // |0|1|2|3|4|5|6|7| + // +-+-+-+-+-+-+-+-+ + // |S|E| FuType | + // +---------------+ + header[2] = type.toByte() // FU header type + header[2] = header[2].plus(0x80).toByte() // Start bit + var sum = 0 - val nalSize = data.remaining() while (sum < nalSize) { val length = if (nalSize - sum > maxPacketSize - RtpConstants.RTP_HEADER_LENGTH - 3) { maxPacketSize - RtpConstants.RTP_HEADER_LENGTH - 3