From 4b7822b4df64fee3b91c57be1d4566dcc231d761 Mon Sep 17 00:00:00 2001 From: Dennis Van Roeyen Date: Fri, 18 Aug 2017 14:51:35 +0200 Subject: [PATCH 1/6] added getFPS to VideoCapture --- src/VideoCaptureWrap.cc | 11 +++++++++++ src/VideoCaptureWrap.h | 2 ++ 2 files changed, 13 insertions(+) diff --git a/src/VideoCaptureWrap.cc b/src/VideoCaptureWrap.cc index 47eb8d5..aa4cd8d 100755 --- a/src/VideoCaptureWrap.cc +++ b/src/VideoCaptureWrap.cc @@ -33,6 +33,7 @@ void VideoCaptureWrap::Init(Local target) { Nan::SetPrototypeMethod(ctor, "setPosition", SetPosition); Nan::SetPrototypeMethod(ctor, "getFrameAt", GetFrameAt); Nan::SetPrototypeMethod(ctor, "getFrameCount", GetFrameCount); + Nan::SetPrototypeMethod(ctor, "getFPS", GetFPS); Nan::SetPrototypeMethod(ctor, "release", Release); Nan::SetPrototypeMethod(ctor, "ReadSync", ReadSync); Nan::SetPrototypeMethod(ctor, "grab", Grab); @@ -103,6 +104,16 @@ NAN_METHOD(VideoCaptureWrap::GetFrameCount) { info.GetReturnValue().Set(Nan::New(cnt)); } + +NAN_METHOD(VideoCaptureWrap::GetFPS) { + Nan::HandleScope scope; + VideoCaptureWrap *v = Nan::ObjectWrap::Unwrap(info.This()); + + int fps = int(v->cap.get(CV_CAP_PROP_FPS)); + + info.GetReturnValue().Set(Nan::New(fps)); +} + NAN_METHOD(VideoCaptureWrap::SetHeight) { Nan::HandleScope scope; VideoCaptureWrap *v = Nan::ObjectWrap::Unwrap(info.This()); diff --git a/src/VideoCaptureWrap.h b/src/VideoCaptureWrap.h index cb01a72..ce77a83 100755 --- a/src/VideoCaptureWrap.h +++ b/src/VideoCaptureWrap.h @@ -25,6 +25,8 @@ public: static NAN_METHOD(SetPosition); static NAN_METHOD(GetFrameCount); + static NAN_METHOD(GetFPS); + static NAN_METHOD(GetFrameAt); // release the stream From 245a245605e81848ba38d673a99961d98169a5e3 Mon Sep 17 00:00:00 2001 From: Dennis Van Roeyen Date: Fri, 18 Aug 2017 19:57:57 +0200 Subject: [PATCH 2/6] VideoWriterWrap --- binding.gyp | 1 + lib/opencv.js | 1 + src/VideoWriterWrap.cc | 152 +++++++++++++++++++++++++++++++++++++++++ src/VideoWriterWrap.h | 18 +++++ src/init.cc | 2 + 5 files changed, 174 insertions(+) create mode 100755 src/VideoWriterWrap.cc create mode 100755 src/VideoWriterWrap.h diff --git a/binding.gyp b/binding.gyp index 69b4d12..3301093 100755 --- a/binding.gyp +++ b/binding.gyp @@ -11,6 +11,7 @@ "src/Contours.cc", "src/Point.cc", "src/VideoCaptureWrap.cc", + "src/VideoWriterWrap.cc", "src/CamShift.cc", "src/HighGUI.cc", "src/FaceRecognizer.cc", diff --git a/lib/opencv.js b/lib/opencv.js index dc043a0..56702ea 100755 --- a/lib/opencv.js +++ b/lib/opencv.js @@ -7,6 +7,7 @@ var cv = module.exports = require('./bindings'); var Matrix = cv.Matrix , VideoCapture = cv.VideoCapture + , VideoWriter = cv.VideoWriter , ImageStream , ImageDataStream , ObjectDetectionStream diff --git a/src/VideoWriterWrap.cc b/src/VideoWriterWrap.cc new file mode 100755 index 0000000..dcc0e1d --- /dev/null +++ b/src/VideoWriterWrap.cc @@ -0,0 +1,152 @@ +#include "VideoWriterWrap.h" +#include "Matrix.h" +#include "OpenCV.h" + +#include + +Nan::Persistent VideoWriterWrap::constructor; + +struct videowriter_baton { + + Nan::Persistent cb; + VideoWriterWrap *vc; + Matrix *im; + + uv_work_t request; +}; + +void VideoWriterWrap::Init(Local target) { + Nan::HandleScope scope; + + //Class + Local ctor = Nan::New(VideoWriterWrap::New); + constructor.Reset(ctor); + ctor->InstanceTemplate()->SetInternalFieldCount(1); + ctor->SetClassName(Nan::New("VideoWriter").ToLocalChecked()); + + Nan::SetPrototypeMethod(ctor, "write", Write); + Nan::SetPrototypeMethod(ctor, "writeSync", WriteSync); + Nan::SetPrototypeMethod(ctor, "release", Release); + + target->Set(Nan::New("VideoWriter").ToLocalChecked(), ctor->GetFunction()); +} + +NAN_METHOD(VideoWriterWrap::New) { + Nan::HandleScope scope; + + if (info.This()->InternalFieldCount() == 0) + return Nan::ThrowTypeError("Cannot Instantiate without new"); + + VideoWriterWrap *v; + + + // Arg 0 is the output filename + std::string filename = std::string(*Nan::Utf8String(info[0]->ToString())); + + // Arg 1 is the fourcc code + const char *fourccStr = std::string(*Nan::Utf8String(info[1]->ToString())).c_str(); + int fourcc = CV_FOURCC(fourccStr[0],fourccStr[1],fourccStr[2],fourccStr[3]); + + // Arg 2 is the output fps + double fps = Nan::To(info[2]).FromJust(); + + // Arg 3 is the image size + cv::Size imageSize; + if (info[3]->IsArray()) { + Local v8sz = info[3]->ToObject(); + imageSize = cv::Size(v8sz->Get(1)->IntegerValue(), v8sz->Get(0)->IntegerValue()); + } else { + JSTHROW_TYPE("Must pass image size"); + } + + // Arg 4 is the color flag + bool isColor = info[4]->BooleanValue(); + v = new VideoWriterWrap(filename, fourcc, fps, imageSize, isColor); + + v->Wrap(info.This()); + + info.GetReturnValue().Set(info.This()); +} + +VideoWriterWrap::VideoWriterWrap(const std::string& filename, int fourcc, double fps, cv::Size frameSize, bool isColor) { + Nan::HandleScope scope; + writer.open(filename, fourcc, fps, frameSize, isColor); + + if(!writer.isOpened()) { + Nan::ThrowError("Writer could not be opened"); + } +} + +NAN_METHOD(VideoWriterWrap::Release) { + Nan::HandleScope scope; + VideoWriterWrap *v = Nan::ObjectWrap::Unwrap(info.This()); + + v->writer.release(); + + return; +} + +class AsyncVWWorker: public Nan::AsyncWorker { +public: + AsyncVWWorker(Nan::Callback *callback, VideoWriterWrap *vw, Matrix *im) : + Nan::AsyncWorker(callback), + vw(vw), + im(im) { + } + + ~AsyncVWWorker() { + } + + // Executed inside the worker-thread. + // It is not safe to access V8, or V8 data structures + // here, so everything we need for input and output + // should go on `this`. + void Execute() { + this->vw->writer.write(im->mat); + } + + // Executed when the async work is complete + // this function will be run inside the main event loop + // so it is safe to use V8 again + void HandleOKCallback() { + Nan::HandleScope scope; + + Local argv[] = { + Nan::Null() + }; + + Nan::TryCatch try_catch; + callback->Call(1, argv); + if (try_catch.HasCaught()) { + Nan::FatalException(try_catch); + } + } + +private: + VideoWriterWrap *vw; + Matrix* im; +}; + +NAN_METHOD(VideoWriterWrap::Write) { + Nan::HandleScope scope; + VideoWriterWrap *v = Nan::ObjectWrap::Unwrap(info.This()); + + Matrix *im = Nan::ObjectWrap::Unwrap < Matrix > (info[0]->ToObject()); + REQ_FUN_ARG(1, cb); + + Nan::Callback *callback = new Nan::Callback(cb.As()); + Nan::AsyncQueueWorker(new AsyncVWWorker(callback, v, im)); + + return; +} + +NAN_METHOD(VideoWriterWrap::WriteSync) { + Nan::HandleScope scope; + VideoWriterWrap *v = Nan::ObjectWrap::Unwrap(info.This()); + Matrix *im = Nan::ObjectWrap::Unwrap < Matrix > (info[0]->ToObject()); + + v->writer.write(im->mat); + + info.GetReturnValue().Set(Nan::Null()); +} + diff --git a/src/VideoWriterWrap.h b/src/VideoWriterWrap.h new file mode 100755 index 0000000..1023854 --- /dev/null +++ b/src/VideoWriterWrap.h @@ -0,0 +1,18 @@ +#include "OpenCV.h" + +class VideoWriterWrap: public Nan::ObjectWrap { +public: + cv::VideoWriter writer; + + static Nan::Persistent constructor; + static void Init(Local target); + static NAN_METHOD(New); + + VideoWriterWrap(const std::string& filename, int fourcc, double fps, cv::Size frameSize, bool isColor=true); + + static NAN_METHOD(Write); + static NAN_METHOD(WriteSync); + + // release the stream + static NAN_METHOD(Release); +}; diff --git a/src/init.cc b/src/init.cc index 7d91bbe..077ba14 100755 --- a/src/init.cc +++ b/src/init.cc @@ -4,6 +4,7 @@ #include "Matrix.h" #include "CascadeClassifierWrap.h" #include "VideoCaptureWrap.h" +#include "VideoWriterWrap.h" #include "Contours.h" #include "CamShift.h" #include "HighGUI.h" @@ -24,6 +25,7 @@ extern "C" void init(Local target) { Matrix::Init(target); CascadeClassifierWrap::Init(target); VideoCaptureWrap::Init(target); + VideoWriterWrap::Init(target); Contour::Init(target); TrackedObject::Init(target); NamedWindow::Init(target); From 3482027b300fc074855d0138f9b17016cffb05e3 Mon Sep 17 00:00:00 2001 From: Dennis Van Roeyen Date: Fri, 18 Aug 2017 20:51:07 +0200 Subject: [PATCH 3/6] VideoWriter example --- examples/write-video.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 examples/write-video.js diff --git a/examples/write-video.js b/examples/write-video.js new file mode 100644 index 0000000..510ee9c --- /dev/null +++ b/examples/write-video.js @@ -0,0 +1,27 @@ +var cv = require('../lib/opencv'); + +var vid = new cv.VideoCapture(0); + +vid.read(function(err, mat) { + if (err) throw err; + + var writer = new cv.VideoWriter('./tmp/output.mp4', 'MP4V', vid.getFPS(), mat.size(), true); + writer.writeSync(mat); + + var x = 0; + var iter = function () { + vid.read(function (err, m2) { + x++; + writer.writeSync(m2); + if (x < 100) { + iter(); + } else { + vid.release(); + writer.release(); + } + }) + }; + iter(); +}); + + From 82567ac11c72295105ca404a881ec229797c2913 Mon Sep 17 00:00:00 2001 From: Dennis Van Roeyen Date: Fri, 18 Aug 2017 21:39:16 +0200 Subject: [PATCH 4/6] use file instead of camera in write-video.js --- examples/write-video.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/write-video.js b/examples/write-video.js index 510ee9c..9f84c18 100644 --- a/examples/write-video.js +++ b/examples/write-video.js @@ -1,11 +1,13 @@ var cv = require('../lib/opencv'); +var path = require('path'); -var vid = new cv.VideoCapture(0); +var vid = new cv.VideoCapture(path.join(__dirname, 'files', 'motion.mov')); vid.read(function(err, mat) { if (err) throw err; - var writer = new cv.VideoWriter('./tmp/output.mp4', 'MP4V', vid.getFPS(), mat.size(), true); + var filename = './tmp/output-'+new Date().getTime()+'.mp4'; + var writer = new cv.VideoWriter(filename, 'MP4V', vid.getFPS(), mat.size(), true); writer.writeSync(mat); var x = 0; From 82c3274d5976ce3feb4638981f0d85117198a3b8 Mon Sep 17 00:00:00 2001 From: Dennis Van Roeyen Date: Fri, 18 Aug 2017 22:14:36 +0200 Subject: [PATCH 5/6] changed fourcc to X264 --- examples/write-video.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/write-video.js b/examples/write-video.js index 9f84c18..bdee693 100644 --- a/examples/write-video.js +++ b/examples/write-video.js @@ -6,8 +6,8 @@ var vid = new cv.VideoCapture(path.join(__dirname, 'files', 'motion.mov')); vid.read(function(err, mat) { if (err) throw err; - var filename = './tmp/output-'+new Date().getTime()+'.mp4'; - var writer = new cv.VideoWriter(filename, 'MP4V', vid.getFPS(), mat.size(), true); + var filename = './tmp/output-'+new Date().getTime()+'.mov'; + var writer = new cv.VideoWriter(filename, 'X264', vid.getFPS(), mat.size(), true); writer.writeSync(mat); var x = 0; From 47411fa73b9cd778d48774cfd190971e000ecf87 Mon Sep 17 00:00:00 2001 From: Dennis Van Roeyen Date: Sat, 19 Aug 2017 23:28:32 +0200 Subject: [PATCH 6/6] use DIVX in write-video.js --- examples/write-video.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/write-video.js b/examples/write-video.js index bdee693..f2a95f3 100644 --- a/examples/write-video.js +++ b/examples/write-video.js @@ -6,8 +6,8 @@ var vid = new cv.VideoCapture(path.join(__dirname, 'files', 'motion.mov')); vid.read(function(err, mat) { if (err) throw err; - var filename = './tmp/output-'+new Date().getTime()+'.mov'; - var writer = new cv.VideoWriter(filename, 'X264', vid.getFPS(), mat.size(), true); + var filename = './tmp/output-'+new Date().getTime()+'.avi'; + var writer = new cv.VideoWriter(filename, 'DIVX', vid.getFPS(), mat.size(), true); writer.writeSync(mat); var x = 0;