Wednesday, October 20, 2010

JMF JVM Crashes



Recently I encountered following strange error which I got when running my VideoChat.

#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0cd32890, pid=2128, tid=1668
#
# JRE version: 6.0_17-b04
# Java VM: Java HotSpot(TM) Client VM (14.3-b01 mixed mode, sharing windows-x86 )
# Problematic frame:
# C [jmjpeg.dll+0x12890]

At first I thought this was caused by the camera driver, or a bug in the native c code.
I could track the error down to the reception part of an incoming RTP Stream.

Following code was used to display the video stream from a datasource:

Component comp;
JPanel video = new JPanel();
try {
receptionPlayer = Manager.createRealizedPlayer(clientReceptionDS);
receptionPlayer.start();

if ((comp = receptionPlayer.getVisualComponent()) != null) {

video.add(comp);
}

Everything fine, except the random crashes from the JVM.
So I started to debug the code and uncommented the video.add(cmp) and voila no crashes.

That led me to the conclusion there might be a timing problem with the player and its different states.

The solution then was to create just a Player with the incoming DataSource and add a ControllerListener who listens for state changes and tells me when the player is really realized.

Following new code was then used:

If a new stream is received we get informed via the ReceiveStreamListener which offers an Update method

public synchronized void update(ReceiveStreamEvent evt)

Inside this method we can retrive our DataSource with:

ReceiveStream stream = evt.getReceiveStream();
dataSource = stream.getDataSource();

And initialise the Player in the following way:

Player p = null;

try {
p = Manager.createPlayer(dataSource);
} catch (NoPlayerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

if (p == null)

return;

p.addControllerListener(this);

p.realize();

The ControllerListener:

public void controllerUpdate(ControllerEvent ce) {
Player p = (Player)ce.getSourceController();
if (p == null)
return;

if (ce instanceof RealizeCompleteEvent) {
vsc.startReceptionVideo(dataSource, p);
}

if (ce instanceof ControllerErrorEvent) {
p.removeControllerListener(this);
}
}

You see when there is a RealizeCompleteEvent I hand the realized Player and the DataSource over to the GUI where it will be displayed with this code:

if ((comp = receptionPlayer.getVisualComponent()) != null) {
video.add(comp);
}

receptionPlayer.start();

Result: It does not crash anymore and you have full control over the Player and its states.

1 comment: