Skip to content

Commit

Permalink
Add leak detection and leak fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Jotschi committed Jan 4, 2022
1 parent 00b331a commit 9bbe783
Show file tree
Hide file tree
Showing 19 changed files with 648 additions and 62 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## v1.1.0



## v1.0.0

* Initial release of Video4j
28 changes: 24 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ Video4j is a highlevel library ontop of `org.openpnp:opencv` which provides APIs

```xml
<dependency>
<groupId>io.metaloom.video</groupId>
<artifactId>video4j</artifactId>
<version>1.0.0</version>
<groupId>io.metaloom.video</groupId>
<artifactId>video4j</artifactId>
<version>1.0.0</version>
</dependency>
```

Expand Down Expand Up @@ -53,7 +53,6 @@ try (Video video = Videos.open(BIG_BUCK_BUNNY2_PATH)) {
// Display the frame in a window
ImageUtils.show(image);
}

```

## Streaming of frames
Expand Down Expand Up @@ -125,6 +124,27 @@ The `VideoUtils` contains methods to startup a very basic video player which can

The `CVUtils` contain utility methods that can be used to modify the frame image data (e.g blur, greyscale, canny filter, contrast..)

## Tips / Pitfalls


### Memory

Video frame data will be provided via opencv `Mat` objects. These objects are linked to JNI data which means they need to be manually released after usage. The `MatProvider` methods can be used to instantiate new `Mat` objects. The provider will in-turn keep track of the instances. The `CVUtils#free` methods can be used to `release` the mat objects after use.
For development the `MatProvider#printLeaks` method can be used to verify that all instances have been released.

### Performance

When using `Mat` instances it is advised to reuse them if possible and to provide existing Mats to read frame data. This can for example be done by usage of the `Video#frame(Mat)` method.

```java
Mat frame = MatProvider.mat();
while (true) {
if (!video.frame(frame)) {
break;
}
```

## Requirements / Limitations

The library uses OpenCV via JNI. Thus the JNI library `libopencv4.5-jni` must be installed on the host system.
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>io.metaloom.video</groupId>
<artifactId>video4j</artifactId>
<version>1.0.0</version>
<version>1.0.1-SNAPSHOT</version>

<parent>
<groupId>io.metaloom</groupId>
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/io/metaloom/video4j/Video.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ static Video open(String path) {
*/
Mat frameToMat();

/**
* Read the next frame data into the provided {@link Mat}
*
* @param mat
* @return True if the frame could be read
*/
boolean frame(Mat mat);

/**
* Read the current frame and return it as a resized buffered image. This operation will advance the position to the next frame.
*
Expand Down Expand Up @@ -68,6 +76,15 @@ static Video open(String path) {
*/
Mat boxedFrameToMat(int width);

/**
* Read the next frame.
*
* @param frame
* @param width
* @return True if the frame could be reads
*/
boolean boxedFrame(Mat frame, int width);

/**
* Return the current set frame.
*
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/io/metaloom/video4j/VideoFrame.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import org.opencv.core.Mat;

public interface VideoFrame {
public interface VideoFrame extends AutoCloseable {

/**
* Return the frame number.
Expand Down
44 changes: 44 additions & 0 deletions src/main/java/io/metaloom/video4j/impl/MatProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package io.metaloom.video4j.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.opencv.core.Mat;
import org.opencv.core.Scalar;

public class MatProvider {

public static Map<Mat, UnreleasedMatException> trackedInstances = new HashMap<>();

public static Mat mat() {
Mat mat = new Mat();
track(mat);
return mat;
}

public static void released(Mat mat) {
mat.release();
trackedInstances.remove(mat);
}

public static boolean hasLeaks() {
return !trackedInstances.isEmpty();
}

public static void printLeaks() {
for (Entry<Mat, UnreleasedMatException> entry : trackedInstances.entrySet()) {
entry.getValue().printStackTrace();
}
}

public static Mat empty(Mat source) {
Mat mat = new Mat(source.size(), source.type(), Scalar.all(0f));
track(mat);
return mat;
}

private static void track(Mat mat) {
trackedInstances.put(mat, new UnreleasedMatException());
}
}
Loading

0 comments on commit 9bbe783

Please sign in to comment.