I am having application to play 30 videos at a time. I am using Xuggler to decode video files and Swing windows for display.
But I am facing problems like:
How can I tune garbage collector and what other performance parameters, I should take care?
Is Xuggler-Java combination not good?
EDIT
My video decoding loop was:
private boolean decodeStreams() throws Exception {
IPacket packet = IPacket.make();
long firstTimestampInStream = Global.NO_PTS;
long systemClockStartTime = 0;
viewer.urlStatusUpdate(index, Globals.STATUS_PLAYING);
while (container.readNextPacket(packet) >= 0) {
if (stopPlaying) {
if (isStopPlaying(2)) {
return false;
}
}
if (packet.getStreamIndex() == videoStreamID) {
IVideoPicture picture = IVideoPicture.make(videoCoder.getPixelType(), videoCoder.getWidth(), videoCoder.getHeight());
int offset = 0;
while (offset < packet.getSize()) {
int bytesDecoded = videoCoder.decodeVideo(picture, packet, offset);
if (bytesDecoded < 0) {
throw new Exception("Got error on decoding video");
}
offset += bytesDecoded;
if (picture.isComplete()) {
if (firstTimestampInStream == Global.NO_PTS) {
firstTimestampInStream = picture.getTimeStamp();
systemClockStartTime = System.currentTimeMillis();
} else {
long millisecondsToSleep = (
((picture.getTimeStamp() - firstTimestampInStream) / 1000)
- (System.currentTimeMillis() - systemClockStartTime)
);
if (millisecondsToSleep > 50) {
try {
Thread.sleep(millisecondsToSleep - 50);
} catch (Exception e) {
}
}
}
viewer.videoImageUpdate(index, converter.toImage(picture));
}
}
}
}
return true;
}
And I changed place of IVideoPicture declaration:
private boolean decodeStreams() throws Exception {
IPacket packet = IPacket.make();
long firstTimestampInStream = Global.NO_PTS;
long systemClockStartTime = 0;
viewer.urlStatusUpdate(index, Globals.STATUS_PLAYING);
IVideoPicture picture = IVideoPicture.make(videoCoder.getPixelType(), videoCoder.getWidth(), videoCoder.getHeight());
while (container.readNextPacket(packet) >= 0) {
if (stopPlaying) {
if (isStopPlaying(2)) {
return false;
}
}
if (packet.getStreamIndex() == videoStreamID) {
int offset = 0;
while (offset < packet.getSize()) {
int bytesDecoded = videoCoder.decodeVideo(picture, packet, offset);
if (bytesDecoded < 0) {
throw new Exception("Got error on decoding video");
}
offset += bytesDecoded;
if (picture.isComplete()) {
if (firstTimestampInStream == Global.NO_PTS) {
firstTimestampInStream = picture.getTimeStamp();
systemClockStartTime = System.currentTimeMillis();
} else {
long millisecondsToSleep = (
((picture.getTimeStamp() - firstTimestampInStream) / 1000)
- (System.currentTimeMillis() - systemClockStartTime)
);
if (millisecondsToSleep > 50) {
try {
Thread.sleep(millisecondsToSleep - 50);
} catch (Exception e) {
}
}
}
viewer.videoImageUpdate(index, converter.toImage(picture));
}
}
}
}
return true;
}
Now GC is spending less than 10% time, around 5% to 8& normally. And I got all 30 videos playing smoothly at a time.
Is changing place (Putting IVideoPicture declaration outside, and allocating memory only once) can be problem? Will timestamps of picture set everytime new video picture is decoded on allocated memory?
Thanks
Chances are that your current GC ill suits your task. To get a predictable GC timings you may try to use G1 garbage collector (I'm assuming you're on Java 7u4 or later).G1 is planned as the long term replacement for the Concurrent Mark-Sweep Collector (CMS). Comparing G1 with CMS, there are differences that make G1 a better solution. G1 offers more predictable garbage collection pauses than the CMS collector, and allows users to specify desired pause targets.
Play with the following options to archive the best performance for your particular case:
-XX:+UseG1GC - Tells the JVM to use the G1 Garbage collector.
-XX:MaxGCPauseMillis=500 - Sets a target for the maximum GC pause time. This is a soft goal, and the JVM will make its best effort to achieve it. Therefore, the pause time goal will sometimes not be met. The default value is 200 milliseconds.
-XX:InitiatingHeapOccupancyPercent=80 - Percentage of the heap occupancy to start a concurrent GC cycle. It is used by G1 to trigger a concurrent GC cycle based on the occupancy of the entire heap, not just one of the generations. A value of 0 denotes 'do constant GC cycles'. The default value is 45%.
More details available here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With