Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RtmpClient uses H265 encoding to push the stream, and the program crashes with the error message java.lang.IndexOutOfBoundsException: index=20 out of bounds (limit=20) #1544

Closed
sheng930920 opened this issue Aug 14, 2024 · 7 comments

Comments

@sheng930920
Copy link

sheng930920 commented Aug 14, 2024

Describe the bug
Using the latest version 2.4.7, RtmpClient uses H265 encoding to push the stream, and the program crashes with the error message java.lang.IndexOutOfBoundsException: index=20 out of bounds (limit=20)

implementation 'com.github.pedroSG94.RootEncoder:library:2.4.7'

Below is the code I wrote

class FPVWidget @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0,
) : SurfaceView(context, attrs, defStyleAttr), SurfaceHolder.Callback, FFmpegDecoder.H264CallBack,
    ConnectChecker {

    private val h265File: String = "${App.context.getExternalFilesDir(null)}${File.separator}test.h265"
    private var rtmpUrl = "rtmp://192.168.100.231:9900/live/2345"

    private val mVideoInfo = MediaCodec.BufferInfo()
    private val mRtmpClient by lazy {
        RtmpClient(this).apply {
            setOnlyVideo(true)
            setReTries(Integer.MAX_VALUE)
            setFps(30)
            resizeCache(10 * 1024)
            setLogs(true)
            setVideoCodec(VideoCodec.H264)
        }
    }

    init {
        FFmpegDecoder.createDecoder("rtsp://192.168.100.231:9902/hls/3455", this)
        holder.addCallback(this)
        holder.setFormat(PixelFormat.RGBA_8888);
    }

    override fun surfaceCreated(holder: SurfaceHolder) {
        FFmpegDecoder.setPlaySurface(holder.surface)
        FFmpegDecoder.startDecode()
    }

    override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
        LogUtils.d(TAG, "surfaceChanged")
    }

    override fun surfaceDestroyed(holder: SurfaceHolder) {
        LogUtils.d(TAG, "surfaceDestroyed")
    }

    override fun onReceiveStream(data: ByteArray, size: Int, isH264: Boolean, isKeyFrame: Boolean) {
        writeToLocal(h265File, data)
        mVideoInfo.apply {
            this.size = size
            offset = 0
            presentationTimeUs = System.nanoTime() / 1000
            flags = if (isKeyFrame) MediaCodec.BUFFER_FLAG_KEY_FRAME else 0
        }

        if (!mRtmpClient.isStreaming) {
            val startCodeSize = getStartCodeSize(data)
            val naluType = if (isH264) {
                (data[startCodeSize] and 0x1f).toInt()
            } else {
                (data[startCodeSize].toInt() and 0x7E) ushr 1
            }
            if (isH264) {
                if (naluType == 7 || naluType == 8) {
                    decodeSpsPpsFromH264(data, size)?.let { buffer ->
                        mRtmpClient.setVideoCodec(VideoCodec.H264)
                        mRtmpClient.setVideoInfo(buffer.first, buffer.second, null)
                        mRtmpClient.connect(rtmpUrl, true)
                    }
                }
            } else {
                if (naluType == 32 || naluType == 33 || naluType == 34) {
                    LogUtils.d(TAG, "H265 sps pps, startCodeSize:$startCodeSize  naluType:$naluType")
                    decodeSpsPpsFromH265(data)?.let { result ->
//                        extractVpsSpsPpsFromH265(data)?.let { result ->
                        mRtmpClient.setVideoCodec(VideoCodec.H265)
                        mRtmpClient.setVideoInfo(
                            ByteBuffer.wrap(result.first),
                            ByteBuffer.wrap(result.second),
                            ByteBuffer.wrap(result.third)
                        )
                        mRtmpClient.connect(rtmpUrl, true)
                    }
                }
            }
        }
        if (mRtmpClient.isStreaming) {
            val videoBuffer = ByteBuffer.wrap(data)
            mRtmpClient.sendVideo(videoBuffer, mVideoInfo)
        }
    }

    private fun getStartCodeSize(byteBuffer: ByteArray): Int {
        var startCodeSize = 0
        if (byteBuffer[0].toInt() == 0x00 && byteBuffer[1].toInt() == 0x00
            && byteBuffer[2].toInt() == 0x00 && byteBuffer[3].toInt() == 0x01
        ) {
            //match 00 00 00 01
            startCodeSize = 4
        } else if (byteBuffer[0].toInt() == 0x00 && byteBuffer[1].toInt() == 0x00
            && byteBuffer[2].toInt() == 0x01
        ) {
            //match 00 00 01
            startCodeSize = 3
        }
        return startCodeSize
    }

    private fun decodeSpsPpsFromH264(
        videoArray: ByteArray,
        length: Int,
    ): Pair<ByteBuffer, ByteBuffer>? {
        var spsIndex = -1
        var ppsIndex = -1
        val ppsEndIndex = length - 1
        for (i in 0 until length) {
            if (videoArray[i].toInt() == 0x00 && videoArray[i + 1].toInt() == 0x00
                && videoArray[i + 2].toInt() == 0x00 && videoArray[i + 3].toInt() == 0x01
            ) {
                if (videoArray[i + 4].toInt() == 0x67) {
                    spsIndex = i
                } else if (videoArray[i + 4].toInt() == 0x68) {
                    ppsIndex = i
                }
            }
        }
        val spsLength = ppsIndex - spsIndex
        val ppsLength = ppsEndIndex - ppsIndex
        if (spsIndex != -1 && ppsIndex != -1) {
            val sps = ByteArray(spsLength)
            System.arraycopy(videoArray, spsIndex, sps, 0, spsLength)
            val pps = ByteArray(ppsLength)
            System.arraycopy(videoArray, ppsIndex, pps, 0, ppsLength)
            return Pair.create(ByteBuffer.wrap(sps), ByteBuffer.wrap(pps))
        }
        return null
    }


    private fun decodeSpsPpsFromH265(csdArray: ByteArray): Triple<ByteArray, ByteArray, ByteArray>? {
        var spsIndex = -1
        var ppsIndex = -1
        var vpsIndex = -1
        var ppsEndIndex = -1

        var index = 0
        while (index + 3 < csdArray.size) {
            if (csdArray[index].toInt() == 0x00 &&
                csdArray[index + 1].toInt() == 0x00 &&
                csdArray[index + 2].toInt() == 0x00 &&
                csdArray[index + 3].toInt() == 0x01
            ) {
                val nalType = (csdArray[index + 4].toInt() and 0x7E) ushr 1
                println("nalType: $nalType")
                when (nalType) {
                    // VPS
                    32 -> vpsIndex = index
                    // SPS
                    33 -> spsIndex = index
                    // PPS
                    34 -> ppsIndex = index
                    // IDR
                    19, 20 -> {
                        ppsEndIndex = index
                        break
                    }
                }
            }
            index++
        }
        println("vpsIndex: $vpsIndex  spsIndex:$spsIndex   ppsIndex:$ppsIndex")

        val vpsLength = spsIndex - vpsIndex
        val spsLength = ppsIndex - spsIndex
        val ppsLength = ppsEndIndex - ppsIndex

        val vps = ByteArray(vpsLength).apply {
            System.arraycopy(csdArray, vpsIndex, this, 0, vpsLength)
        }
        val sps = ByteArray(spsLength).apply {
            System.arraycopy(csdArray, spsIndex, this, 0, spsLength)
        }
        val pps = ByteArray(ppsLength).apply {
            System.arraycopy(csdArray, ppsIndex, this, 0, ppsLength)
        }
        LogUtils.d(TAG, "VPS: ${vps.joinToString(", ")}")
        LogUtils.d(TAG, "SPS: ${sps.joinToString(", ")}")
        LogUtils.d(TAG, "PPS: ${pps.joinToString(", ")}")
        return Triple(vps, sps, pps)
    }

    private fun extractVpsSpsPpsFromH265(csdArray: ByteArray): Triple<ByteArray, ByteArray, ByteArray>? {
        var vpsPosition = -1
        var spsPosition = -1
        var ppsPosition = -1
        var contBufferInitiation = 0

        for (i in csdArray.indices) {
            if (contBufferInitiation == 3 && csdArray[i].toInt() == 1) {
                if (vpsPosition == -1) {
                    vpsPosition = i - 3
                } else if (spsPosition == -1) {
                    spsPosition = i - 3
                } else {
                    ppsPosition = i - 3
                }
            }
            if (csdArray[i].toInt() == 0) {
                contBufferInitiation++
            } else {
                contBufferInitiation = 0
            }
        }

        if (spsPosition == -1 || ppsPosition == -1) {
            return null
        }

        val vps = ByteArray(spsPosition)
        val sps = ByteArray(ppsPosition - spsPosition)
        val pps = ByteArray(csdArray.size - ppsPosition)
        for (i in csdArray.indices) {
            if (i < spsPosition) {
                vps[i] = csdArray[i]
            } else if (i < ppsPosition) {
                sps[i - spsPosition] = csdArray[i]
            } else {
                pps[i - ppsPosition] = csdArray[i]
            }
        }

        LogUtils.d(TAG, "VPS: ${vps.joinToString(", ")}")
        LogUtils.d(TAG, "SPS: ${sps.joinToString(", ")}")
        LogUtils.d(TAG, "PPS: ${pps.joinToString(", ")}")

        return Triple(vps, sps, pps)
    }

    private fun isKeyFrame(videoBuffer: ByteBuffer, isH264: Boolean): Boolean {
        val header = ByteArray(5)
        if (videoBuffer.remaining() < header.size) {
            return false
        }
        videoBuffer.duplicate()[header, 0, header.size]
        return if (isH264 && header[4].toInt() and 0x1F == IDR) {  //h264
            true
        } else { //h265
            (!isH264 && (header[4].toInt() shr 1 and 0x3f == IDR_W_DLP || header[4].toInt() shr 1 and 0x3f == IDR_N_LP))
        }
    }

    override fun onAuthError() {}

    override fun onAuthSuccess() {}

    override fun onConnectionFailed(reason: String) {
        mRtmpClient.reConnect(200L)
    }

    override fun onConnectionStarted(url: String) {}

    override fun onConnectionSuccess() {}

    override fun onDisconnect() {}

    override fun onNewBitrate(bitrate: Long) {}

    private fun writeToLocal(file: String, content: ByteArray) {
        val videoFile = File(file)
        if (!videoFile.exists()) {
            videoFile.createNewFile()
        }
        ByteArrayInputStream(content).use { `is` ->
            FileOutputStream(videoFile, true).use { out ->
                val buff = ByteArray(1024)
                var len: Int
                while (`is`.read(buff).also { len = it } != -1) {
                    out.write(buff, 0, len)
                }
            }
        }
    }
}

logcat info

2024-08-14 13:12:57.833 31832-31898 UAVStation-FPVWidget    com.shd.station                      D  ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2024-08-14 13:12:57.833 31832-31898 UAVStation-FPVWidget    com.shd.station                      DThread: Thread-19
2024-08-14 13:12:57.833 31832-31898 UAVStation-FPVWidget    com.shd.station                      D  ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
2024-08-14 13:12:57.833 31832-31898 UAVStation-FPVWidget    com.shd.station                      DFPVWidget.onReceiveStream  (FPVWidget.kt:101)
2024-08-14 13:12:57.834 31832-31898 UAVStation-FPVWidget    com.shd.station                      D  ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
2024-08-14 13:12:57.834 31832-31898 UAVStation-FPVWidget    com.shd.station                      DH265 sps ppsstartCodeSize4  naluType:32
2024-08-14 13:12:57.834 31832-31898 UAVStation-FPVWidget    com.shd.station                      D  └────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2024-08-14 13:12:57.834 31832-31898 System.out              com.shd.station                      I  nalType: 32
2024-08-14 13:12:57.834 31832-31898 System.out              com.shd.station                      I  nalType: 33
2024-08-14 13:12:57.834 31832-31898 System.out              com.shd.station                      I  nalType: 34
2024-08-14 13:12:57.834 31832-31898 System.out              com.shd.station                      I  nalType: 19
2024-08-14 13:12:57.835 31832-31898 System.out              com.shd.station                      I  vpsIndex: 0  spsIndex:28   ppsIndex:77
2024-08-14 13:12:57.941 31832-31846 com.shd.statio          com.shd.station                      I  NativeAlloc concurrent copying GC freed 28525(3196KB) AllocSpace objects, 22(560KB) LOS objects, 49% free, 6641KB/12MB, paused 327us total 518.948ms
2024-08-14 13:12:57.985 31832-31898 UAVStation-FPVWidget    com.shd.station                      D  ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2024-08-14 13:12:57.986 31832-31898 UAVStation-FPVWidget    com.shd.station                      DThread: Thread-19
2024-08-14 13:12:57.986 31832-31898 UAVStation-FPVWidget    com.shd.station                      D  ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
2024-08-14 13:12:57.986 31832-31898 UAVStation-FPVWidget    com.shd.station                      DFPVWidget.onReceiveStream  (FPVWidget.kt:102)
2024-08-14 13:12:57.986 31832-31898 UAVStation-FPVWidget    com.shd.station                      DFPVWidget.decodeSpsPpsFromH265  (FPVWidget.kt:255)
2024-08-14 13:12:57.986 31832-31898 UAVStation-FPVWidget    com.shd.station                      D  ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
2024-08-14 13:12:57.987 31832-31898 UAVStation-FPVWidget    com.shd.station                      DVPS: 0, 0, 0, 1, 64, 1, 12, 1, -1, -1, 1, 64, 0, 0, 3, 0, 0, 3, 0, 0, 3, 0, 0, 3, 0, 120, -84, 9
2024-08-14 13:12:57.987 31832-31898 UAVStation-FPVWidget    com.shd.station                      D  └────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2024-08-14 13:12:57.988 31832-31898 UAVStation-FPVWidget    com.shd.station                      D  ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2024-08-14 13:12:57.988 31832-31898 UAVStation-FPVWidget    com.shd.station                      DThread: Thread-19
2024-08-14 13:12:57.988 31832-31898 UAVStation-FPVWidget    com.shd.station                      D  ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
2024-08-14 13:12:57.988 31832-31898 UAVStation-FPVWidget    com.shd.station                      DFPVWidget.onReceiveStream  (FPVWidget.kt:102)
2024-08-14 13:12:57.988 31832-31898 UAVStation-FPVWidget    com.shd.station                      DFPVWidget.decodeSpsPpsFromH265  (FPVWidget.kt:256)
2024-08-14 13:12:57.988 31832-31898 UAVStation-FPVWidget    com.shd.station                      D  ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
2024-08-14 13:12:57.988 31832-31898 UAVStation-FPVWidget    com.shd.station                      DSPS: 0, 0, 0, 1, 66, 1, 1, 1, 64, 0, 0, 3, 0, 0, 3, 0, 0, 3, 0, 0, 3, 0, 120, -96, 3, -64, -128, 17, 7, -53, -106, -76, -92, 37, -110, -29, 1, 1, 0, 0, 3, 0, 1, 0, 0, 3, 0, 15, 8
2024-08-14 13:12:57.988 31832-31898 UAVStation-FPVWidget    com.shd.station                      D  └────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2024-08-14 13:12:57.989 31832-31898 UAVStation-FPVWidget    com.shd.station                      D  ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2024-08-14 13:12:57.989 31832-31898 UAVStation-FPVWidget    com.shd.station                      DThread: Thread-19
2024-08-14 13:12:57.989 31832-31898 UAVStation-FPVWidget    com.shd.station                      D  ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
2024-08-14 13:12:57.989 31832-31898 UAVStation-FPVWidget    com.shd.station                      DFPVWidget.onReceiveStream  (FPVWidget.kt:102)
2024-08-14 13:12:57.989 31832-31898 UAVStation-FPVWidget    com.shd.station                      DFPVWidget.decodeSpsPpsFromH265  (FPVWidget.kt:257)
2024-08-14 13:12:57.989 31832-31898 UAVStation-FPVWidget    com.shd.station                      D  ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
2024-08-14 13:12:57.989 31832-31898 UAVStation-FPVWidget    com.shd.station                      DPPS: 0, 0, 0, 1, 68, 1, -64, -9, -64, -52, -112
2024-08-14 13:12:57.993 31832-31898 UAVStation-FPVWidget    com.shd.station                      D  └────────────────────────────────────────────────────────────────────────────────────────────────────────────────
2024-08-14 13:12:57.994 31832-31898 RtmpClient              com.shd.station                      I  send sps and pps
2024-08-14 13:12:58.034 31832-31893 Handshake               com.shd.station                      I  writing C0
2024-08-14 13:12:58.034 31832-31893 Handshake               com.shd.station                      I  C0 write successful
2024-08-14 13:12:58.034 31832-31893 Handshake               com.shd.station                      I  writing C1
2024-08-14 13:12:58.034 31832-31893 Handshake               com.shd.station                      I  writing time 1723612378 to c1
2024-08-14 13:12:58.034 31832-31893 Handshake               com.shd.station                      I  writing zero to c1
2024-08-14 13:12:58.034 31832-31893 Handshake               com.shd.station                      I  writing random to c1
2024-08-14 13:12:58.097 31832-31893 Handshake               com.shd.station                      I  C1 write successful
2024-08-14 13:12:58.101 31832-31893 Handshake               com.shd.station                      I  reading S0
2024-08-14 13:12:58.103 31832-31893 Handshake               com.shd.station                      I  read S0 successful
2024-08-14 13:12:58.103 31832-31893 Handshake               com.shd.station                      I  reading S1
2024-08-14 13:12:58.106 31832-31893 Handshake               com.shd.station                      I  read S1 successful
2024-08-14 13:12:58.106 31832-31893 Handshake               com.shd.station                      I  writing C2
2024-08-14 13:12:58.106 31832-31893 Handshake               com.shd.station                      I  C2 write successful
2024-08-14 13:12:58.107 31832-31893 Handshake               com.shd.station                      I  reading S2
2024-08-14 13:12:58.107 31832-31893 Handshake               com.shd.station                      I  read S2 successful
2024-08-14 13:12:58.110 31832-31893 CommandsManager         com.shd.station                      I  using default write chunk size 128
2024-08-14 13:12:58.138 31832-31857 com.shd.statio          com.shd.station                      I  Waiting for a blocking GC ProfileSaver
2024-08-14 13:12:58.146 31832-31857 com.shd.statio          com.shd.station                      I  WaitForGcToComplete blocked ProfileSaver on RunEmptyCheckpoint for 7.432ms
2024-08-14 13:12:58.185 31832-31893 CommandsManager         com.shd.station                      I  send Command(name='connect', transactionId=1, timeStamp=0, streamId=0, data=[AmfString value: connect, AmfNumber value: 1.0, AmfObject properties: {AmfString value: app=AmfString value: live, AmfString value: flashVer=AmfString value: FMLE/3.0 (compatible; Lavf57.56.101), AmfString value: tcUrl=AmfString value: rtmp://192.168.100.231:9900/live, AmfString value: fourCcList=AmfStrictArray items: [AmfString value: hvc1], AmfString value: objectEncoding=AmfNumber value: 0.0}], bodySize=175)
2024-08-14 13:12:58.241 31832-31893 CommandsManager         com.shd.station                      I  read SetChunkSize(chunkSize=60000)
2024-08-14 13:12:58.247 31832-31893 RtmpClient              com.shd.station                      I  chunk size configured to 60000
2024-08-14 13:12:58.248 31832-31893 CommandsManager         com.shd.station                      I  read WindowAcknowledgementSize(acknowledgementWindowSize=5000000)
2024-08-14 13:12:58.256 31832-31893 CommandsManager         com.shd.station                      I  read SetPeerBandwidth(acknowledgementWindowSize=5000000, type=DYNAMIC)
2024-08-14 13:12:58.277 31832-31893 CommandsManager         com.shd.station                      I  read Command(name='_result', transactionId=1, timeStamp=0, streamId=0, data=[AmfString value: _result, AmfNumber value: 1.0, AmfObject properties: {AmfString value: capabilities=AmfNumber value: 31.0, AmfString value: fmsVer=AmfString value: FMS/3,0,1,123}, AmfObject properties: {AmfString value: code=AmfString value: NetConnection.Connect.Success, AmfString value: description=AmfString value: Connection succeeded., AmfString value: level=AmfString value: status, AmfString value: objectEncoding=AmfNumber value: 0.0}], bodySize=190)
2024-08-14 13:12:58.285 31832-31893 CommandsManager         com.shd.station                      I  send Command(name='releaseStream', transactionId=2, timeStamp=0, streamId=0, data=[AmfString value: releaseStream, AmfNumber value: 2.0, AmfNull, AmfString value: 2345], bodySize=33)
2024-08-14 13:12:58.295 31832-31893 CommandsManager         com.shd.station                      I  send Command(name='FCPublish', transactionId=3, timeStamp=0, streamId=0, data=[AmfString value: FCPublish, AmfNumber value: 3.0, AmfNull, AmfString value: 2345], bodySize=29)
2024-08-14 13:12:58.296 31832-31893 CommandsManager         com.shd.station                      I  send Command(name='createStream', transactionId=4, timeStamp=0, streamId=0, data=[AmfString value: createStream, AmfNumber value: 4.0, AmfNull], bodySize=25)
2024-08-14 13:12:58.311 31832-31893 RtmpClient              com.shd.station                      I  success response received from connect
2024-08-14 13:12:58.313 31832-31893 CommandsManager         com.shd.station                      I  read Command(name='onBWDone', transactionId=0, timeStamp=0, streamId=0, data=[AmfString value: onBWDone, AmfNumber value: 0.0, AmfNull], bodySize=21)
2024-08-14 13:12:58.315 31832-31893 RtmpClient              com.shd.station                      I  unknown onBWDone response received from unknown command
2024-08-14 13:12:58.321 31832-31893 CommandsManager         com.shd.station                      I  read Command(name='_result', transactionId=4, timeStamp=0, streamId=0, data=[AmfString value: _result, AmfNumber value: 4.0, AmfNull, AmfNumber value: 1.0], bodySize=29)
2024-08-14 13:12:58.334 31832-31893 CommandsManager         com.shd.station                      I  send Command(name='publish', transactionId=5, timeStamp=0, streamId=1, data=[AmfString value: publish, AmfNumber value: 5.0, AmfNull, AmfString value: 2345, AmfString value: live], bodySize=34)
2024-08-14 13:12:58.338 31832-31893 RtmpClient              com.shd.station                      I  success response received from createStream
2024-08-14 13:12:58.348 31832-31893 CommandsManager         com.shd.station                      I  read Command(name='onStatus', transactionId=5, timeStamp=0, streamId=0, data=[AmfString value: onStatus, AmfNumber value: 5.0, AmfNull, AmfObject properties: {AmfString value: clientid=AmfString value: 0, AmfString value: code=AmfString value: NetStream.Publish.Start, AmfString value: description=AmfString value: Started publishing stream., AmfString value: level=AmfString value: status}], bodySize=129)
2024-08-14 13:12:58.385 31832-31893 CommandsManager         com.shd.station                      I  send Data(name='@setDataFrame', data=[AmfString value: onMetaData, AmfEcmaArray length: 7, properties: {AmfString value: duration=AmfNumber value: 0.0, AmfString value: width=AmfNumber value: 640.0, AmfString value: height=AmfNumber value: 480.0, AmfString value: videocodecid=AmfNumber value: 1.752589105E9, AmfString value: framerate=AmfNumber value: 30.0, AmfString value: videodatarate=AmfNumber value: 0.0, AmfString value: filesize=AmfNumber value: 0.0}], bodySize=175)
2024-08-14 13:12:58.419 31832-31913 com.shd.statio          com.shd.station                      W  Long monitor contention with owner amap-global-threadPool-2 (31955) at void com.amap.api.col.3l.ip$a.runTask()(StatisticsManager.java:1135) waiters=0 in void com.amap.api.col.3l.ip.a(com.amap.api.col.3l.io, android.content.Context) for 712ms
2024-08-14 13:12:58.423 31832-31898 AndroidRuntime          com.shd.station                      E  FATAL EXCEPTION: Thread-29
                                                                                                    Process: com.shd.station, PID: 31832
                                                                                                    java.lang.IndexOutOfBoundsException: index=20 out of bounds (limit=20)
                                                                                                    	at java.nio.Buffer.checkIndex(Buffer.java:556)
                                                                                                    	at java.nio.DirectByteBuffer.get(DirectByteBuffer.java:224)
                                                                                                    	at com.pedro.rtmp.utils.BitBuffer.getLong(BitBuffer.kt:54)
                                                                                                    	at com.pedro.rtmp.utils.BitBuffer.getLong(BitBuffer.kt:66)
                                                                                                    	at com.pedro.rtmp.utils.BitBuffer.getInt(BitBuffer.kt:47)
                                                                                                    	at com.pedro.rtmp.utils.BitBuffer.readUE(BitBuffer.kt:79)
                                                                                                    	at com.pedro.rtmp.flv.video.config.SPSH265Parser.parse(SPSH265Parser.kt:107)
                                                                                                    	at com.pedro.rtmp.flv.video.config.SPSH265Parser.parse(SPSH265Parser.kt:40)
                                                                                                    	at com.pedro.rtmp.flv.video.config.VideoSpecificConfigHEVC.write(VideoSpecificConfigHEVC.kt:80)
                                                                                                    	at com.pedro.rtmp.flv.video.packet.H265Packet.createFlvPacket(H265Packet.kt:100)
                                                                                                    	at com.pedro.rtmp.rtmp.RtmpSender.sendVideoFrame(RtmpSender.kt:119)
                                                                                                    	at com.pedro.rtmp.rtmp.RtmpClient.sendVideo(RtmpClient.kt:559)
                                                                                                    	at com.shd.station.widget.FPVWidget.onReceiveStream(FPVWidget.kt:117)
2024-08-14 13:12:58.474 31832-31898 Process                 com.shd.station                      I  Sending signal. PID: 31832 SIG: 9
image
@pedroSG94
Copy link
Owner

Hello,

This seems that the SPS is not correct and fail to parse.
Is the code working with version 2.4.5? I haven't any changes in the parser.

Can you share me the byte array of SPS, PPS and VPS?

@sheng930920
Copy link
Author

The following is the sps, pps, and vps data obtained using the decodeSpsPpsFromH265 function,Switch to version 2.4.5, the problem still exists

VPS: 0, 0, 0, 1, 64, 1, 12, 1, -1, -1, 1, 64, 0, 0, 3, 0, 0, 3, 0, 0, 3, 0, 0, 3, 0, 120, -84, 9

SPS: 0, 0, 0, 1, 66, 1, 1, 1, 64, 0, 0, 3, 0, 0, 3, 0, 0, 3, 0, 0, 3, 0, 120, -96, 3, -64, -128, 17, 7, -53, -106, -76, -92, 37, -110, -29, 1, 1, 0, 0, 3, 0, 1, 0, 0, 3, 0, 15, 8

PPS: 0, 0, 0, 1, 68, 1, -64, -9, -64, -52, -112

@pedroSG94
Copy link
Owner

Ok, I will test it and let you know the result

@sheng930920
Copy link
Author

Thank you so much!

@pedroSG94
Copy link
Owner

pedroSG94 commented Aug 14, 2024

I found the error. SPS, PPS and VPS are correct the problem is that you send each buffer in the incorrect parameter.

In your case you have:

return Triple(vps, sps, pps)

But setVideoInfo expect:

setVideoInfo(sps: ByteBuffer, pps: ByteBuffer?, vps: ByteBuffer?)

And you are using the method like this:

mRtmpClient.setVideoInfo(
                            ByteBuffer.wrap(result.first),
                            ByteBuffer.wrap(result.second),
                            ByteBuffer.wrap(result.third)
                        )

According with the previous code should be:

mRtmpClient.setVideoInfo(
                            vps = ByteBuffer.wrap(result.first),
                            sps = ByteBuffer.wrap(result.second),
                            pps = ByteBuffer.wrap(result.third)
                        )

@sheng930920
Copy link
Author

I'm very sorry that my carelessness caused such a low-level mistake. The problem has been solved

@pedroSG94
Copy link
Owner

Closing as solved

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants