#include "VideoCaptureWrap.h" #include "Matrix.h" #include "OpenCV.h" #include Nan::Persistent VideoCaptureWrap::constructor; struct videocapture_baton { Nan::Persistent cb; VideoCaptureWrap *vc; Matrix *im; uv_work_t request; }; void VideoCaptureWrap::Init(Local target) { Nan::HandleScope scope; //Class Local ctor = Nan::New(VideoCaptureWrap::New); constructor.Reset(ctor); ctor->InstanceTemplate()->SetInternalFieldCount(1); ctor->SetClassName(Nan::New("VideoCapture").ToLocalChecked()); // Prototype //Local proto = constructor->PrototypeTemplate(); Nan::SetPrototypeMethod(ctor, "read", Read); Nan::SetPrototypeMethod(ctor, "setWidth", SetWidth); Nan::SetPrototypeMethod(ctor, "setHeight", SetHeight); Nan::SetPrototypeMethod(ctor, "setPosition", SetPosition); Nan::SetPrototypeMethod(ctor, "getFrameAt", GetFrameAt); Nan::SetPrototypeMethod(ctor, "getFrameCount", GetFrameCount); Nan::SetPrototypeMethod(ctor, "release", Release); Nan::SetPrototypeMethod(ctor, "ReadSync", ReadSync); Nan::SetPrototypeMethod(ctor, "grab", Grab); Nan::SetPrototypeMethod(ctor, "retrieve", Retrieve); target->Set(Nan::New("VideoCapture").ToLocalChecked(), ctor->GetFunction()); } NAN_METHOD(VideoCaptureWrap::New) { Nan::HandleScope scope; if (info.This()->InternalFieldCount() == 0) return Nan::ThrowTypeError("Cannot Instantiate without new"); VideoCaptureWrap *v; if (info[0]->IsNumber()) { v = new VideoCaptureWrap(info[0]->NumberValue()); } else { //TODO - assumes that we have string, verify v = new VideoCaptureWrap(std::string(*Nan::Utf8String(info[0]->ToString()))); } v->Wrap(info.This()); info.GetReturnValue().Set(info.This()); } VideoCaptureWrap::VideoCaptureWrap(int device) { Nan::HandleScope scope; cap.open(device); if(!cap.isOpened()) { Nan::ThrowError("Camera could not be opened"); } } VideoCaptureWrap::VideoCaptureWrap(const std::string& filename) { Nan::HandleScope scope; cap.open(filename); // TODO! At the moment this only takes a full path - do relative too. if(!cap.isOpened()) { Nan::ThrowError("Video file could not be opened (opencv reqs. non relative paths)"); } } NAN_METHOD(VideoCaptureWrap::SetWidth) { Nan::HandleScope scope; VideoCaptureWrap *v = Nan::ObjectWrap::Unwrap(info.This()); if(info.Length() != 1) return; int w = info[0]->IntegerValue(); if(v->cap.isOpened()) v->cap.set(CV_CAP_PROP_FRAME_WIDTH, w); return; } NAN_METHOD(VideoCaptureWrap::GetFrameCount) { Nan::HandleScope scope; VideoCaptureWrap *v = Nan::ObjectWrap::Unwrap(info.This()); int cnt = int(v->cap.get(CV_CAP_PROP_FRAME_COUNT)); info.GetReturnValue().Set(Nan::New(cnt)); } NAN_METHOD(VideoCaptureWrap::SetHeight) { Nan::HandleScope scope; VideoCaptureWrap *v = Nan::ObjectWrap::Unwrap(info.This()); if(info.Length() != 1) return; int h = info[0]->IntegerValue(); v->cap.set(CV_CAP_PROP_FRAME_HEIGHT, h); return; } NAN_METHOD(VideoCaptureWrap::SetPosition) { Nan::HandleScope scope; VideoCaptureWrap *v = Nan::ObjectWrap::Unwrap(info.This()); if(info.Length() != 1) return; int pos = info[0]->IntegerValue(); v->cap.set(CV_CAP_PROP_POS_FRAMES, pos); return; } NAN_METHOD(VideoCaptureWrap::GetFrameAt) { Nan::HandleScope scope; VideoCaptureWrap *v = Nan::ObjectWrap::Unwrap(info.This()); if(info.Length() != 1) return; int pos = info[0]->IntegerValue(); v->cap.set(CV_CAP_PROP_POS_MSEC, pos); return; } NAN_METHOD(VideoCaptureWrap::Release) { Nan::HandleScope scope; VideoCaptureWrap *v = Nan::ObjectWrap::Unwrap(info.This()); v->cap.release(); return; } class AsyncVCWorker: public Nan::AsyncWorker { public: AsyncVCWorker(Nan::Callback *callback, VideoCaptureWrap* vc, bool retrieve = false, int channel = 0) : Nan::AsyncWorker(callback), vc(vc), retrieve(retrieve), channel(channel) { } ~AsyncVCWorker() { } // 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() { if (retrieve) { if (!this->vc->cap.retrieve(mat, channel)) { SetErrorMessage("retrieve failed"); } return; } this->vc->cap.read(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 im_to_return= Nan::New(Matrix::constructor)->GetFunction()->NewInstance(); Matrix *img = Nan::ObjectWrap::Unwrap(im_to_return); img->mat = mat; Local argv[] = { Nan::Null() , im_to_return }; Nan::TryCatch try_catch; callback->Call(2, argv); if (try_catch.HasCaught()) { Nan::FatalException(try_catch); } } private: VideoCaptureWrap *vc; cv::Mat mat; bool retrieve; int channel; }; NAN_METHOD(VideoCaptureWrap::Read) { Nan::HandleScope scope; VideoCaptureWrap *v = Nan::ObjectWrap::Unwrap(info.This()); REQ_FUN_ARG(0, cb); Nan::Callback *callback = new Nan::Callback(cb.As()); Nan::AsyncQueueWorker(new AsyncVCWorker(callback, v)); return; } NAN_METHOD(VideoCaptureWrap::ReadSync) { Nan::HandleScope scope; VideoCaptureWrap *v = Nan::ObjectWrap::Unwrap(info.This()); Local im_to_return= Nan::New(Matrix::constructor)->GetFunction()->NewInstance(); Matrix *img = Nan::ObjectWrap::Unwrap(im_to_return); v->cap.read(img->mat); info.GetReturnValue().Set(im_to_return); } class AsyncGrabWorker: public Nan::AsyncWorker { public: AsyncGrabWorker(Nan::Callback *callback, VideoCaptureWrap* vc) : Nan::AsyncWorker(callback), vc(vc) { } ~AsyncGrabWorker() { } void Execute() { if (!this->vc->cap.grab()) { SetErrorMessage("grab failed"); } } private: VideoCaptureWrap *vc; }; NAN_METHOD(VideoCaptureWrap::Grab) { Nan::HandleScope scope; VideoCaptureWrap *v = Nan::ObjectWrap::Unwrap(info.This()); REQ_FUN_ARG(0, cb); Nan::Callback *callback = new Nan::Callback(cb.As()); Nan::AsyncQueueWorker(new AsyncGrabWorker(callback, v)); return; } NAN_METHOD(VideoCaptureWrap::Retrieve) { Nan::HandleScope scope; VideoCaptureWrap *v = Nan::ObjectWrap::Unwrap(info.This()); int channel = 0; REQ_FUN_ARG(0, cb); INT_FROM_ARGS(channel, 1); Nan::Callback *callback = new Nan::Callback(cb.As()); Nan::AsyncQueueWorker(new AsyncVCWorker(callback, v, true, channel)); return; }