diff --git a/examples/async-resize.js b/examples/async-resize.js index 70a1c7d..d2beaa2 100644 --- a/examples/async-resize.js +++ b/examples/async-resize.js @@ -16,6 +16,8 @@ cv.readImage("./files/mona.png", function(err, im) { } img.save("./tmp/resize-async-image.png"); console.log('Image saved to ./tmp/resize-async-image.png at '+img.width()+'x'+img.height()); + img.release(); + delete img; }; var newwidth = width*0.95; @@ -25,6 +27,8 @@ cv.readImage("./files/mona.png", function(err, im) { if (Async){ // note - generates a new image im.resize(newwidth, newheight, AfterResize); + im.release(); // test release image before resize if done + delete im; } else { // sync - note - modifies the input image im.resize(newwidth, newheight); diff --git a/examples/bgsubtractor.js b/examples/bgsubtractor.js index b780644..23eca4b 100644 --- a/examples/bgsubtractor.js +++ b/examples/bgsubtractor.js @@ -3,9 +3,10 @@ var path = require('path'), var bg = null; -require("v8").setFlagsFromString('--expose_gc'); -var gc = require("vm").runInNewContext('gc'); +// gc stuff which we shojld not need with release() begin used +//require("v8").setFlagsFromString('--expose_gc'); +//var gc = require("vm").runInNewContext('gc'); var do_sync = function(done){ // When opening a file, the full path must be passed to opencv @@ -17,15 +18,20 @@ var do_sync = function(done){ vid.read(function(err, m2){ if (err) throw err; var mat = bg.apply(m2); + m2.release(); delete m2; // mat is a monochrome img where moving objects are white + // do something with the return data + // we are done with the return data + mat.release(); + delete mat; if (x++<100){ //console.log("iter "+x); setTimeout(iter, 1); } else { delete vid; console.log("bg sync done"); - gc(); + // gc(); - no need to gc if we release both m2 and mat if (undefined !== done) done(); } @@ -45,7 +51,10 @@ var do_async = function(done){ vid.read(function(err, m2){ if (err) throw err; bg.apply(m2, function(err, mat){ - delete mat; + // do something with the return data + // we are done with the return data + mat.release(); + delete mat; if (err) throw err; // mat is a monochrome img where moving objects are white if (x++<100){ @@ -54,11 +63,12 @@ var do_async = function(done){ } else { console.log("bg async done"); delete vid; - gc(); + // gc(); - no need to gc if we release both m2 and mat if (undefined !== done) done(); } }); + m2.release(); }) }; diff --git a/examples/write-video.js b/examples/write-video.js index f2a95f3..6382bd5 100644 --- a/examples/write-video.js +++ b/examples/write-video.js @@ -27,3 +27,33 @@ vid.read(function(err, mat) { }); + +// restart video read +var vid2 = new cv.VideoCapture(path.join(__dirname, 'files', 'motion.mov')); + +var filename2 = './tmp/output-async-'+new Date().getTime()+'.avi'; +var writer2 = null; +var x = 0; + +// do the same write async +var iter = function () { + vid2.read(function (err, m2) { + if (writer2 === null) + writer2 = new cv.VideoWriter(filename2, 'DIVX', vid2.getFPS(), m2.size(), true); + + x++; + writer2.write(m2, function(err){ + if (x < 100) { + iter(); + } else { + vid2.release(); + writer2.release(); + } + }); + m2.release(); + delete m2; + }); +}; + +// kick it off +iter(); diff --git a/src/BackgroundSubtractor.cc b/src/BackgroundSubtractor.cc index 114c613..cf95236 100644 --- a/src/BackgroundSubtractor.cc +++ b/src/BackgroundSubtractor.cc @@ -313,13 +313,15 @@ public: AsyncBackgroundSubtractorWorker( Nan::Callback *callback, BackgroundSubtractorWrap *bg, - Matrix *img) : + cv::Mat &img_mat): Nan::AsyncWorker(callback), bg(bg), - img(img) { + img_mat(img_mat) { // note: this makes a new cv::Mat, and so increments the ref count for the data without copying it + } ~AsyncBackgroundSubtractorWorker() { + // upon destroy, img_mat will reduce refcount on data by one } // Executed inside the worker-thread. @@ -330,9 +332,9 @@ public: // wait here if already in apply - auto-release on scope exit BGAutoMutex(bg->applymutex); #if CV_MAJOR_VERSION >= 3 - bg->subtractor->apply(this->img->mat, _fgMask); + bg->subtractor->apply(this->img_mat, _fgMask); #else - bg->subtractor->operator()(this->img->mat, _fgMask); + bg->subtractor->operator()(this->img_mat, _fgMask); #endif } @@ -360,7 +362,7 @@ public: private: BackgroundSubtractorWrap *bg; - Matrix *img; + cv::Mat img_mat; cv::Mat _fgMask; }; @@ -399,8 +401,8 @@ NAN_METHOD(BackgroundSubtractorWrap::Apply) { } Nan::Callback *callback = new Nan::Callback(cb.As()); - Matrix *_img = Nan::ObjectWrap::Unwrap(info[0]->ToObject()); - Nan::AsyncQueueWorker(new AsyncBackgroundSubtractorWorker( callback, self, _img)); + Matrix *_img = Nan::ObjectWrap::Unwrap(info[0]->ToObject()); + Nan::AsyncQueueWorker(new AsyncBackgroundSubtractorWorker( callback, self, _img->mat)); return; } else { //synchronous - return the image diff --git a/src/Matrix.cc b/src/Matrix.cc index 319853d..c2f2dc0 100755 --- a/src/Matrix.cc +++ b/src/Matrix.cc @@ -769,21 +769,22 @@ NAN_METHOD(Matrix::ToBuffer) { class AsyncToBufferWorker: public Nan::AsyncWorker { public: - AsyncToBufferWorker(Nan::Callback *callback, Matrix* matrix, std::string ext, + AsyncToBufferWorker(Nan::Callback *callback, cv::Mat mat, std::string ext, std::vector params) : Nan::AsyncWorker(callback), - matrix(matrix), + mat(mat), // dulipcate mat, adding ref, but not copying data ext(ext), params(params) { } ~AsyncToBufferWorker() { + // mat is released, decrementing refcount } void Execute() { std::vector vec(0); // std::vector params(0);//CV_IMWRITE_JPEG_QUALITY 90 - cv::imencode(ext, this->matrix->mat, vec, this->params); + cv::imencode(ext, this->mat, vec, this->params); res = vec; } @@ -813,7 +814,7 @@ public: } private: - Matrix* matrix; + cv::Mat mat; std::string ext; std::vector params; std::vector res; @@ -853,7 +854,7 @@ NAN_METHOD(Matrix::ToBufferAsync) { } Nan::Callback *callback = new Nan::Callback(cb.As()); - Nan::AsyncQueueWorker(new AsyncToBufferWorker(callback, self, ext, params)); + Nan::AsyncQueueWorker(new AsyncToBufferWorker(callback, self->mat, ext, params)); return; } @@ -1046,9 +1047,9 @@ NAN_METHOD(Matrix::Save) { // https://github.com/rvagg/nan/blob/c579ae858ae3208d7e702e8400042ba9d48fa64b/examples/async_pi_estimate/async.cc class AsyncSaveWorker: public Nan::AsyncWorker { public: - AsyncSaveWorker(Nan::Callback *callback, Matrix* matrix, char* filename) : + AsyncSaveWorker(Nan::Callback *callback, cv::Mat mat, char* filename) : Nan::AsyncWorker(callback), - matrix(matrix), + mat(mat), filename(filename) { } @@ -1060,7 +1061,7 @@ public: // here, so everything we need for input and output // should go on `this`. void Execute() { - res = cv::imwrite(this->filename, this->matrix->mat); + res = cv::imwrite(this->filename, this->mat); } // Executed when the async work is complete @@ -1082,7 +1083,7 @@ public: } private: - Matrix* matrix; + cv::Mat mat; std::string filename; int res; }; @@ -1099,7 +1100,7 @@ NAN_METHOD(Matrix::SaveAsync) { REQ_FUN_ARG(1, cb); Nan::Callback *callback = new Nan::Callback(cb.As()); - Nan::AsyncQueueWorker(new AsyncSaveWorker(callback, self, *filename)); + Nan::AsyncQueueWorker(new AsyncSaveWorker(callback, self->mat, *filename)); return; } @@ -1892,9 +1893,9 @@ cv::Rect* setRect(Local objRect, cv::Rect &result) { class ResizeASyncWorker: public Nan::AsyncWorker { public: - ResizeASyncWorker(Nan::Callback *callback, Matrix *image, cv::Size size, double fx, double fy, int interpolation) : + ResizeASyncWorker(Nan::Callback *callback, cv::Mat image, cv::Size size, double fx, double fy, int interpolation) : Nan::AsyncWorker(callback), - image(image), + image(image), // here, the cv::Mat is duplicated, adding to refcount without data copy dest(NULL), size(size), fx(fx), @@ -1908,12 +1909,13 @@ public: // could happen if NaN does not call HandleSuccess? delete dest; dest = NULL; + // cv::Mat image will be deleted, which will reduce refcount } void Execute() { try { dest = new Matrix(); - cv::resize(image->mat, dest->mat, size, fx, fy, interpolation); + cv::resize(image, dest->mat, size, fx, fy, interpolation); success = 1; } catch(...){ success = 0; @@ -1973,7 +1975,7 @@ public: } private: - Matrix *image; + cv::Mat image; Matrix *dest; cv::Size size; double fx; @@ -2039,7 +2041,7 @@ NAN_METHOD(Matrix::Resize) { if (isAsync){ REQ_FUN_ARG(numargs-1, cb); Nan::Callback *callback = new Nan::Callback(cb.As()); - Nan::AsyncQueueWorker(new ResizeASyncWorker(callback, self, size, fx, fy, interpolation)); + Nan::AsyncQueueWorker(new ResizeASyncWorker(callback, self->mat, size, fx, fy, interpolation)); info.GetReturnValue().Set(Nan::Null()); } else { try{ diff --git a/src/VideoWriterWrap.cc b/src/VideoWriterWrap.cc index 37fbcbc..2a095fb 100755 --- a/src/VideoWriterWrap.cc +++ b/src/VideoWriterWrap.cc @@ -90,10 +90,10 @@ NAN_METHOD(VideoWriterWrap::Release) { class AsyncVWWorker: public Nan::AsyncWorker { public: - AsyncVWWorker(Nan::Callback *callback, VideoWriterWrap *vw, Matrix *im) : + AsyncVWWorker(Nan::Callback *callback, VideoWriterWrap *vw, cv::Mat mat) : Nan::AsyncWorker(callback), vw(vw), - im(im) { + mat(mat) { } ~AsyncVWWorker() { @@ -104,7 +104,7 @@ public: // here, so everything we need for input and output // should go on `this`. void Execute() { - this->vw->writer.write(im->mat); + this->vw->writer.write(mat); } // Executed when the async work is complete @@ -126,7 +126,7 @@ public: private: VideoWriterWrap *vw; - Matrix* im; + cv::Mat mat; }; NAN_METHOD(VideoWriterWrap::Write) { @@ -137,7 +137,7 @@ NAN_METHOD(VideoWriterWrap::Write) { REQ_FUN_ARG(1, cb); Nan::Callback *callback = new Nan::Callback(cb.As()); - Nan::AsyncQueueWorker(new AsyncVWWorker(callback, v, im)); + Nan::AsyncQueueWorker(new AsyncVWWorker(callback, v, im->mat)); return; }