Native crash when calling DevolayReceiver.close()
Hi there :) I am using the following code to capture frames using NDI and this library:
class NDIIssueSampleCode {
var isConnected: Boolean = false
private set
var sourceName: String = "myNdiSource"
var ndiGroup = "myNdiGroup"
var ip = InetAddress.getLocalHost()
private val finder = DevolayFinder(true, ndiGroup, ip.hostAddress)
private var devolayReceiver: DevolayReceiver? = null
private var captureThread: ThreadWithCancelFlag? = null
fun connect(onNextFrameReceived: (frame: Mat) -> Unit) {
if (isConnected) return
logger.debug("Connecting to NDI source '${sourceName}'...")
logger.debug("Searching source in available sources...")
finder.waitForSources(0)
var source: DevolaySource? = null
val endTime = LocalDateTime.now().plusSeconds(30)
while (source == null && LocalDateTime.now().isBefore(endTime)) {
source = finder.currentSources.firstOrNull { it.sourceName == sourceName }
}
if (source == null) {
disconnect()
throw NoSuchElementException("Source '${sourceName}' not found on the network.")
}
logger.debug("Source found, connecting...")
val receiver = DevolayReceiver(DevolayReceiver.ColorFormat.BGRX_BGRA, DevolayReceiver.RECEIVE_BANDWIDTH_HIGHEST, false, null)
receiver.connect(source)
this.devolayReceiver = receiver
logger.debug("Starting NDI capture thread...")
captureThread = createAndStartConnectThread(receiver, onNextFrameReceived)
}
private fun createAndStartConnectThread(receiver: DevolayReceiver, onNextFrameReceived: (frame: Mat) -> Unit) =
ThreadWithCancelFlag {
Thread {
manageResources {
val videoFrame = DevolayVideoFrame().closeLater()
val audioFrame = DevolayAudioFrame().closeLater()
val metadataFrame = DevolayMetadataFrame().closeLater()
while (!cancelled) {
val captureResult = receiver.receiveCapture(
videoFrame,
audioFrame,
metadataFrame,
1000
)
if (captureResult != DevolayFrameType.VIDEO) continue
val openCvFrame = videoFrame.convertToOpenCvFrame(DevolayFrameFourCCType.BGRA)
onNextFrameReceived(openCvFrame)
}
logger.debug("NDI capture thread exiting now...")
}
}
}.also {
it.thread.name = "ndi-capture-thread"
it.thread.start()
}
fun disconnect() {
logger.debug("Disconnecting from NDI capture...")
isConnected = false
captureThread?.let {
it.cancelled = true
it.thread.join()
}
captureThread = null
devolayReceiver?.close()
devolayReceiver = null
}
}
However, when calling devolayReceiver?.close(), the JVM crashes in native code.
In summary, the NDI Sdk crashes with the following stacktrace:
Stack: [0x0000006471600000,0x0000006471700000], sp=0x00000064716fce70, free space=1011k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [ntdll.dll+0xabf81]
C [ntdll.dll+0x3ab11]
C [msvcrt.dll+0x1cadc]
C 0x000001b720ea3378
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j me.walkerknapp.devolay.DevolayReceiver.receiveDestroy(J)V+0
j me.walkerknapp.devolay.DevolayReceiver.close()V+4
j com.github.vatbub.myProject.capture.NDIInput.disconnect()V+71
// Stack trace shortened for NDA and brevity reasons...
j java.lang.Thread.run()V+13 [email protected]
v ~StubRoutines::call_stub 0x000001b720e8100e
So, the crash happens somewhere in native code when trying to disconnect from the DevolayReceiver.
I am still debugging this, but here is the information that I found so far:
- There is no pending (or in progress) call to
receiver.receiveCapture()as thecancelledflag ofcaptureThreadis set first and thedisconnectmethod waits forcaptureThreadto exit (usingit.thread.join()) before callingreceiver.close(). - The crash is reproducible.
One further hypothesis, which I cannot confirm right now, is that removing the call to receiver.close() avoids the crash, but it also seems to leave the connection to the NDI source open even though no further calls to receiver.receiveCapture() are made. The reason for this hypothesis is that when running the software in the field with a real NDI camera, I was observing a higher network bandwidth than I expected even though I was no longer calling receiver.receiveCapture(). However, since I don't have this camera available to me right now, I can only use NDI Tools to create simulated NDI sources which don't appear as network bandwidth in Task Manager.
If you are still actively developing this library, I would be very grateful if you could help me with this issue, as it is very difficult to find out what's going on there in native code.
Other than that, I really love this library and it made integrating NDI into my project so easy, so thank you very much and Cheers :)
The full crash log and crash dump are as follows:
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffaacc7bf81, pid=16868, tid=6048
#
# JRE version: OpenJDK Runtime Environment Temurin-19.0.2+7 (19.0.2+7) (build 19.0.2+7)
# Java VM: OpenJDK 64-Bit Server VM Temurin-19.0.2+7 (19.0.2+7, mixed mode, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, windows-amd64)
# Problematic frame:
# C [ntdll.dll+0xabf81]
#
# No core dump will be written. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# D:\git\myProject\hs_err_pid16868.log
#
# If you would like to submit a bug report, please visit:
# https://github.com/adoptium/adoptium-support/issues
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#