jean343 / Node-OpenMAX

Node wrapper for the OpenMAX library
https://www.npmjs.com/package/openmax
MIT License
16 stars 5 forks source link

Freeing used resources #2

Closed bmmlms closed 7 years ago

bmmlms commented 8 years ago

Hi Jean,

first of all thanks for this great project!

I am trying to play many videos in sequence. The problem is that resources used by VideoDecode/VideoRender do not get released so Node crashes after some videos. In Node's output I can see the COMPONENTTYPE() outputs when the constructor is called, but destructors are never called.

What's the best way to achieve releasing resources after a file was played in the 'finish' event?

jean343 commented 8 years ago

I do have destructors such as ~COMPONENTTYPE() I do remember that the javascript variables need to be out of the global scope for v8 to gc them. try (function() { var VideoDecode; var VideoRender; ... })(); You can try adding a gc() call, see https://simonmcmanus.wordpress.com/2013/01/03/forcing-garbage-collection-with-node-js-and-v8/

bmmlms commented 8 years ago

I tried as you suggested, but destructors are not called. Maybe I am doing something wrong... This is the code I am using:

let runPlayer = function() {
  (function() {
    let VideoDecode = new omx.VideoDecode();
    let VideoRender = new omx.VideoRender();

    VideoDecode.init().then(() => {
      return VideoRender.init();
    }).then(() => {
      VideoDecode.setVideoPortFormat(omx.OMX_VIDEO_CODINGTYPE.OMX_VIDEO_CodingAVC);
      fs.createReadStream("/storage/videos/57bb52a5d1f2e5657dbc88c9.video").pipe(VideoDecode).pipe(VideoRender).on('finish', () => {
        VideoDecode = null;
        VideoRender = null;

        global.gc();

        process.nextTick(() => runPlayer());
      });
    });
  })();
}

runPlayer();
jean343 commented 8 years ago

Thanks for trying. Unfortunately, I don't have a PI with me now. It might be a real bug, it's difficult to close asynchronous streams. Feel free to send me a pull request if you have a solution. You could try something such as.

(function() { let VideoDecode = new omx.VideoDecode(); let VideoRender = new omx.VideoRender();

VideoDecode.init().then(() => {
  return VideoRender.init();
}).then(() => {
  VideoDecode.setVideoPortFormat(omx.OMX_VIDEO_CODINGTYPE.OMX_VIDEO_CodingAVC);
  fs.createReadStream("/storage/videos/57bb52a5d1f2e5657dbc88c9.video").pipe(VideoDecode).pipe(VideoRender).on('finish', () => {
  });
});

})();

setInterval(function(){ global.gc(); }, 500);

jean343 commented 8 years ago

I remember the problem, it's due to obj->Ref(); in COMPONENTTYPE::New. The ref is necessary because we have an event loop, but I did not call Unref(). Removing Ref will make the app crash when the variable is GCed but events are still sent.

The solution is to call Unref(), the right place is not in the destructor. This is a problem, I will fix it when I have time.

bmmlms commented 8 years ago

Thank you :+1:

jean343 commented 8 years ago

I did fix this problem by adding a close method in the component. You can try in this sample https://github.com/jean343/Node-OpenMAX/blob/master/perf/Memory.ts with --expose-gc and my logs enabled, the components are destructed.

However, it does crash when playing videos in a loop. Still investigating this issue.

jean343 commented 7 years ago

Fixed in 1.3.1! It took a while to understand why node was throwing a seg fault, it was due to the lack of uv_close and receiving events after destruction. I updated https://github.com/jean343/Node-OpenMAX/blob/master/perf/Memory.ts and it can play the simple video in a loop without crashing or leaking memory.