#include "VideoCaptureWrap.h" #include "Matrix.h" #include "OpenCV.h" #include using namespace std; v8::Persistent VideoCaptureWrap::constructor; struct videocapture_baton { Persistent cb; VideoCaptureWrap *vc; Matrix *im; uv_work_t request; }; void VideoCaptureWrap::Init(Handle target) { NanScope(); //Class Local ctor = NanNew(VideoCaptureWrap::New); NanAssignPersistent(constructor, ctor); ctor->InstanceTemplate()->SetInternalFieldCount(1); ctor->SetClassName(NanNew("VideoCapture")); // Prototype //Local proto = constructor->PrototypeTemplate(); NODE_SET_PROTOTYPE_METHOD(ctor, "read", Read); NODE_SET_PROTOTYPE_METHOD(ctor, "setWidth", SetWidth); NODE_SET_PROTOTYPE_METHOD(ctor, "setHeight", SetHeight); NODE_SET_PROTOTYPE_METHOD(ctor, "setPosition", SetPosition); NODE_SET_PROTOTYPE_METHOD(ctor, "close", Close); NODE_SET_PROTOTYPE_METHOD(ctor, "ReadSync", ReadSync); NODE_SET_PROTOTYPE_METHOD(ctor, "grab", Grab); NODE_SET_PROTOTYPE_METHOD(ctor, "retrieve", Retrieve); target->Set(NanNew("VideoCapture"), ctor->GetFunction()); } NAN_METHOD(VideoCaptureWrap::New) { NanScope(); if (args.This()->InternalFieldCount() == 0) return NanThrowTypeError("Cannot Instantiate without new"); VideoCaptureWrap *v; if (args[0]->IsNumber()) { v = new VideoCaptureWrap(args[0]->NumberValue()); } else { //TODO - assumes that we have string, verify v = new VideoCaptureWrap(std::string(*NanAsciiString(args[0]->ToString()))); } v->Wrap(args.This()); NanReturnValue(args.This()); } VideoCaptureWrap::VideoCaptureWrap(int device) { NanScope(); cap.open(device); if(!cap.isOpened()) { NanThrowError("Camera could not be opened"); } } VideoCaptureWrap::VideoCaptureWrap(const std::string& filename) { NanScope(); cap.open(filename); // TODO! At the moment this only takes a full path - do relative too. if(!cap.isOpened()) { NanThrowError("Video file could not be opened (opencv reqs. non relative paths)"); } } NAN_METHOD(VideoCaptureWrap::SetWidth) { NanScope(); VideoCaptureWrap *v = ObjectWrap::Unwrap(args.This()); if(args.Length() != 1) NanReturnUndefined(); int w = args[0]->IntegerValue(); if(v->cap.isOpened()) v->cap.set(CV_CAP_PROP_FRAME_WIDTH, w); NanReturnUndefined(); } NAN_METHOD(VideoCaptureWrap::SetHeight) { NanScope(); VideoCaptureWrap *v = ObjectWrap::Unwrap(args.This()); if(args.Length() != 1) NanReturnUndefined(); int h = args[0]->IntegerValue(); v->cap.set(CV_CAP_PROP_FRAME_HEIGHT, h); NanReturnUndefined(); } NAN_METHOD(VideoCaptureWrap::SetPosition) { NanScope(); VideoCaptureWrap *v = ObjectWrap::Unwrap(args.This()); if(args.Length() != 1) NanReturnUndefined(); int pos = args[0]->IntegerValue(); v->cap.set(CV_CAP_PROP_POS_FRAMES, pos); NanReturnUndefined(); } NAN_METHOD(VideoCaptureWrap::Close) { NanScope(); VideoCaptureWrap *v = ObjectWrap::Unwrap(args.This()); v->cap.release(); NanReturnUndefined(); } class AsyncVCWorker: public NanAsyncWorker { public: AsyncVCWorker(NanCallback *callback, VideoCaptureWrap* vc, bool retrieve = false, int channel = 0) : NanAsyncWorker(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() { NanScope(); Local im_to_return= NanNew(Matrix::constructor)->GetFunction()->NewInstance(); Matrix *img = ObjectWrap::Unwrap(im_to_return); img->mat = mat; Local argv[] = { NanNull() , im_to_return }; TryCatch try_catch; callback->Call(2, argv); if (try_catch.HasCaught()) { FatalException(try_catch); } } private: VideoCaptureWrap *vc; cv::Mat mat; bool retrieve; int channel; }; NAN_METHOD(VideoCaptureWrap::Read) { NanScope(); VideoCaptureWrap *v = ObjectWrap::Unwrap(args.This()); REQ_FUN_ARG(0, cb); NanCallback *callback = new NanCallback(cb.As()); NanAsyncQueueWorker(new AsyncVCWorker(callback, v)); NanReturnUndefined(); } NAN_METHOD(VideoCaptureWrap::ReadSync) { NanScope(); VideoCaptureWrap *v = ObjectWrap::Unwrap(args.This()); Local im_to_return= NanNew(Matrix::constructor)->GetFunction()->NewInstance(); Matrix *img = ObjectWrap::Unwrap(im_to_return); v->cap.read(img->mat); NanReturnValue(im_to_return); } class AsyncGrabWorker: public NanAsyncWorker { public: AsyncGrabWorker(NanCallback *callback, VideoCaptureWrap* vc) : NanAsyncWorker(callback), vc(vc) { } ~AsyncGrabWorker() { } void Execute() { if (!this->vc->cap.grab()) { SetErrorMessage("grab failed"); } } private: VideoCaptureWrap *vc; }; NAN_METHOD(VideoCaptureWrap::Grab) { NanScope(); VideoCaptureWrap *v = ObjectWrap::Unwrap(args.This()); REQ_FUN_ARG(0, cb); NanCallback *callback = new NanCallback(cb.As()); NanAsyncQueueWorker(new AsyncGrabWorker(callback, v)); NanReturnUndefined(); } NAN_METHOD(VideoCaptureWrap::Retrieve) { NanScope(); VideoCaptureWrap *v = ObjectWrap::Unwrap(args.This()); int channel = 0; REQ_FUN_ARG(0, cb); INT_FROM_ARGS(channel, 1); NanCallback *callback = new NanCallback(cb.As()); NanAsyncQueueWorker(new AsyncVCWorker(callback, v, true, channel)); NanReturnUndefined(); }