Медленное получение данных UDP на Android - PullRequest
0 голосов
/ 02 октября 2019

Я пытаюсь транслировать видео, отправленное камерой, по Wi-Fi. Официальное приложение имеет хорошую производительность, и мне интересно, почему моя реализация отстает.

Камера отправляет данные по UDP, и каждый пакет содержит одно изображение JPEG + несколько метаданных.

Мой вопрос здесь об общемструктура моего бесконечного цикла. Как вы думаете, этот код может быть более эффективным и / или более надежным?

Я также получаю много poll timed out error (частота зависит, конечно, от времени ожидания, которое я положил в сокет).

Кроме того, метод run выполняется в фоновом потоке.

override fun run() {

        android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND)

        socket = null
        try {
            socket = DatagramSocket(udpPort)
            socket?.soTimeout = 1000
        } catch (error: Exception) {
            error.message?.let {
                Log.e("$TAG/run", "Can't create the socket for streaming: ${error.message}")
            }
        }

        socket?.let { socket ->

            // The camera sends each image in one UDP packet, normally between 25000 and 30000 bytes.
            // We set 35000 here to be safe.
            var udpPacketBuffer: ByteArray
            var currentFrame: Bitmap?

            var receivedPacket: DatagramPacket? = null

            currentFrame = null
            while (!Thread.interrupted()) {
                try {

                    udpPacketBuffer = ByteArray(35000)
                    receivedPacket = DatagramPacket(
                        udpPacketBuffer, udpPacketBuffer.size,
                        address, udpPort
                    )

                    socket?.receive(receivedPacket)

                    imageExecutor.submit {

                        currentFrame = getImage(receivedPacket)
                        currentFrame?.let { currentFrame ->
                            // Display the image in the app.
                            // Commenting this does not remove the lag.
                            imageConsumer(currentFrame)
                        }
                    }

                } catch (error: Exception) {
                    error.message?.let { Log.e("$TAG/run", it) }
                }
            }
        }

        imageExecutor.shutdown()
        socket?.close()
        Thread.interrupted()
    }

    private fun getImage(receivedPacket: DatagramPacket): Bitmap? {

        var currentFrame: Bitmap? = null
        try {
            var imageData = getImageData(receivedPacket)
            currentFrame = BitmapFactory.decodeByteArray(imageData, 0, imageData.size)

        } catch (error: Exception) {
            error.message?.let { Log.e("$TAG/getImage", it) }
            onLoading?.let { it() }
        }

        return currentFrame
    }

    private fun getImageData(receivedPacket: DatagramPacket): ByteArray {
        val udpData = receivedPacket.data
        // The camera adds some kind of header to each packet, which we need to ignore
        val videoDataStart = getImageDataStart(receivedPacket, udpData)
        return Arrays.copyOfRange(udpData, videoDataStart, receivedPacket.length)
    }

    private fun getImageDataStart(receivedPacket: DatagramPacket, udpData: ByteArray): Int {
        var videoDataStart = 130

        // The image data starts somewhere after the first 130 bytes, but at last in 320 bytes
        var k = 130
        while (k < 320 && k < receivedPacket.length - 1) {
            // The bytes FF and D8 signify the start of the jpeg data, see https://en.wikipedia.org/wiki/JPEG_File_Interchange_Format
            if (udpData[k] == 0xFF.toByte() && udpData[k + 1] == 0xD8.toByte()) {
                videoDataStart = k
            }
            k++
        }
        return videoDataStart
    }

...