Last active
October 21, 2019 04:52
-
-
Save prisonerjohn/c1879fb72aaf87f6a4f0021e1e1c70a4 to your computer and use it in GitHub Desktop.
Sensing Machines NDI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "ofApp.h" | |
void ofApp::setup() | |
{ | |
ofBackground(0); | |
ofSetFrameRate(60); | |
ofSetWindowShape(640, 480); | |
// Start a router to kick things off | |
// (otherwise the receivers don't work...) | |
ndiRouter.setup("Router " + (int)ofRandom(255), "ofxNDI"); | |
ndiSources = ofxNDI::listSources(); | |
// Setup parameters and gui. | |
useGrabber.set("Use Grabber", false); | |
refreshSources.set("Refresh Sources"); | |
refreshSources.addListener(this, &ofApp::doRefreshSources); | |
recvChannel.set("Recv Channel", 0, 0, 15); | |
setupSource.set("Setup Source"); | |
setupSource.addListener(this, &ofApp::doSetupSource); | |
sendChannel.set("Send Channel", 1, 0, 15); | |
setupDestination.set("Setup Destination"); | |
setupDestination.addListener(this, &ofApp::doSetupDestination); | |
sendVideo.set("Send Video", true); | |
guiPanel.setup("NDI Filter", "settings.json"); | |
guiPanel.add(useGrabber); | |
guiPanel.add(refreshSources); | |
guiPanel.add(recvChannel); | |
guiPanel.add(setupSource); | |
guiPanel.add(sendChannel); | |
guiPanel.add(setupDestination); | |
guiPanel.add(sendVideo); | |
} | |
void ofApp::update() | |
{ | |
if (useGrabber && grabber.isInitialized()) | |
{ | |
grabber.update(); | |
if (grabber.isFrameNew() && sendVideo) | |
{ | |
if (!filterImage.isAllocated()) | |
{ | |
filterImage.allocate(grabber.getWidth(), grabber.getHeight(), OF_IMAGE_COLOR_ALPHA); | |
} | |
filterImage.setFromPixels(grabber.getPixels()); | |
} | |
} | |
else if (ndiReceiver && ndiReceiver->isConnected()) | |
{ | |
ndiRecvVideo->update(); | |
if (ndiRecvVideo->isFrameNew()) | |
{ | |
ndiRecvVideo->decodeTo(ndiPixels); | |
if (!filterImage.isAllocated()) | |
{ | |
filterImage.allocate(ndiPixels.getWidth(), ndiPixels.getHeight(), OF_IMAGE_COLOR_ALPHA); | |
} | |
if (sendChannel == 1) | |
{ | |
// Invert image. | |
ofPixels& filterPixels = filterImage.getPixels(); | |
for (int row = 0; row < ndiPixels.getHeight(); row++) | |
{ | |
for (int col = 0; col < ndiPixels.getWidth(); col++) | |
{ | |
ofColor pixVal = ndiPixels.getColor(col, row); | |
filterPixels.setColor(col, row, pixVal.getInverted()); | |
} | |
} | |
filterImage.update(); | |
} | |
else if (sendChannel == 2) | |
{ | |
// Threshold image. | |
ofPixels& filterPixels = filterImage.getPixels(); | |
for (int row = 0; row < ndiPixels.getHeight(); row++) | |
{ | |
for (int col = 0; col < ndiPixels.getWidth(); col++) | |
{ | |
int pixVal = ndiPixels.getColor(col, row).getBrightness(); | |
if (pixVal < 127) | |
{ | |
filterPixels.setColor(col, row, ofColor(0)); | |
} | |
else | |
{ | |
filterPixels.setColor(col, row, ofColor(255)); | |
} | |
} | |
} | |
filterImage.update(); | |
} | |
else | |
{ | |
filterImage.setFromPixels(ndiPixels); | |
} | |
} | |
} | |
if (sendVideo && filterImage.isAllocated() && ndiSendVideo) | |
{ | |
// Send filter image. | |
ndiSendVideo->send(filterImage.getPixels()); | |
} | |
} | |
void ofApp::draw() | |
{ | |
if (filterImage.isAllocated()) | |
{ | |
filterImage.draw(0, 0); | |
} | |
int label = 1; | |
for (auto &s : ndiSources) | |
{ | |
ofDrawBitmapString(ofToString(label) + ":" + s.p_ndi_name + "(" + s.p_url_address + ")", 10, label * 20); | |
++label; | |
} | |
guiPanel.draw(); | |
} | |
void ofApp::doRefreshSources() | |
{ | |
ndiSources = ofxNDI::listSources(); | |
ofLogNotice(__FUNCTION__) << ndiSources.size() << " sources found"; | |
for (int i = 0; i < ndiSources.size(); i++) | |
{ | |
ofLogNotice(__FUNCTION__) << i << ": " << ndiSources[i].p_ndi_name << " / " << ndiSources[i].p_url_address; | |
} | |
} | |
void ofApp::doSetupSource() | |
{ | |
// Close video grabber (in case it was open). | |
grabber.close(); | |
// Clear old NDI source. | |
if (ndiReceiver) | |
{ | |
ndiRecvVideo.reset(); | |
ndiReceiver.reset(); | |
} | |
// Clear filter image. | |
filterImage.clear(); | |
if (useGrabber) | |
{ | |
// Setup video grabber. | |
grabber.setup(640, 480); | |
return; | |
} | |
// Generate source name. | |
std::string sourceName = "NDI-" + ofToString(recvChannel, 2, '0'); | |
ofLogNotice(__FUNCTION__) << "Connect to source " << recvChannel << ": " << sourceName; | |
ndiSources = ofxNDI::listSources(); | |
int matchIdx = -1; | |
for (int i = 0; i < ndiSources.size(); i++) | |
{ | |
if (ndiSources[i].p_ndi_name.find(sourceName) != std::string::npos) | |
{ | |
// Found a match! | |
matchIdx = i; | |
break; | |
} | |
} | |
if (matchIdx == -1) | |
{ | |
ofLogWarning(__FUNCTION__) << "No match found for source " << sourceName; | |
return; | |
} | |
// Create new NDI source. | |
ndiReceiver = std::make_shared<ofxNDIReceiver>(); | |
ndiReceiver->setup(ndiSources[recvChannel]); | |
ndiRecvVideo = std::make_shared<ofxNDIRecvVideoFrameSync>(); | |
ndiRecvVideo->setup(*ndiReceiver.get()); | |
} | |
void ofApp::doSetupDestination() | |
{ | |
if (ndiSender) | |
{ | |
// Clear old NDI destination. | |
ndiSender.reset(); | |
ndiSendVideo.reset(); | |
} | |
std::string destinationName = "NDI-" + ofToString(sendChannel, 2, '0'); | |
int matchIdx = -1; | |
ndiSources = ofxNDI::listSources(); | |
for (int i = 0; i < ndiSources.size(); i++) | |
{ | |
if (ndiSources[i].p_ndi_name.find(destinationName) != std::string::npos) | |
{ | |
// Found a match! | |
matchIdx = i; | |
break; | |
} | |
} | |
if (matchIdx != -1) | |
{ | |
ofLogWarning(__FUNCTION__) << "Destination name " << destinationName << " already in use!"; | |
return; | |
} | |
// Create new NDI destination. | |
ndiSender = std::make_shared<ofxNDISender>(); | |
if (ndiSender->setup(destinationName)) | |
{ | |
ndiSendVideo = std::make_shared<ofxNDISendVideo>(); | |
ndiSendVideo->setup(*ndiSender.get()); | |
ndiSendVideo->setAsync(true); | |
ndiSources = ofxNDI::listSources(); | |
} | |
else | |
{ | |
ofLogError(__FUNCTION__) << "Could not set up NDI destination " << destinationName; | |
ndiSender.reset(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "ofMain.h" | |
#include "ofxGui.h" | |
#include "ofxNDI.h" | |
#include "ofxNDIRouter.h" | |
#include "ofxNDIReceiver.h" | |
#include "ofxNDIRecvStream.h" | |
#include "ofxNDISender.h" | |
#include "ofxNDISendStream.h" | |
class ofApp : public ofBaseApp | |
{ | |
public: | |
void setup(); | |
void update(); | |
void draw(); | |
//void keyPressed(int key); | |
//void keyReleased(int key); | |
//void mouseMoved(int x, int y); | |
//void mouseDragged(int x, int y, int button); | |
//void mousePressed(int x, int y, int button); | |
//void mouseReleased(int x, int y, int button); | |
//void mouseEntered(int x, int y); | |
//void mouseExited(int x, int y); | |
//void windowResized(int w, int h); | |
//void dragEvent(ofDragInfo dragInfo); | |
//void gotMessage(ofMessage msg); | |
void doRefreshSources(); | |
void doSetupSource(); | |
void doSetupDestination(); | |
ofVideoGrabber grabber; | |
ofxNDIRouter ndiRouter; | |
std::vector<ofxNDI::Source> ndiSources; | |
std::shared_ptr<ofxNDIReceiver> ndiReceiver; | |
std::shared_ptr<ofxNDIRecvVideoFrameSync> ndiRecvVideo; | |
std::shared_ptr<ofxNDISender> ndiSender; | |
std::shared_ptr<ofxNDISendVideo> ndiSendVideo; | |
ofPixels ndiPixels; | |
ofImage filterImage; | |
ofParameter<bool> useGrabber; | |
ofParameter<void> refreshSources; | |
ofParameter<int> recvChannel; | |
ofParameter<void> setupSource; | |
ofParameter<int> sendChannel; | |
ofParameter<void> setupDestination; | |
ofParameter<bool> sendVideo; | |
ofxPanel guiPanel; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "ofApp.h" | |
void ofApp::setup() | |
{ | |
ofSetWindowShape(640, 480); | |
// Set parameters and GUI. | |
guiPanel.setup("NDI Recv", "settings.json"); | |
} | |
void ofApp::update() | |
{ | |
ndiGrabber.update(); | |
} | |
void ofApp::draw() | |
{ | |
// Draw grabber. | |
ndiGrabber.draw(0, 0); | |
guiPanel.draw(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "ofMain.h" | |
#include "ofxGui.h" | |
#include "ofxNDI.h" | |
class ofApp : public ofBaseApp | |
{ | |
public: | |
void setup(); | |
void update(); | |
void draw(); | |
ofxNDIGrabber ndiGrabber; | |
ofxPanel guiPanel; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "ofApp.h" | |
void ofApp::setup() | |
{ | |
ofSetWindowShape(640, 480); | |
// Start video grabber. | |
grabber.setup(640, 480); | |
// Allocate threshold image (same size as video, single channel). | |
thresholdImg.allocate(640, 480, OF_IMAGE_COLOR); | |
// Set up NDI senders. | |
ndiSender.setMetaData("NDI Sender", "Sender", "ofxNDI", "1.0.0", "", "", ""); | |
// Set parameters and GUI. | |
thresholdVal.set("Threshold Val", 127, 0, 255); | |
sendGrabber.set("Send Grabber", true); | |
sendThreshold.set("Send Threshold", false); | |
guiPanel.setup("NDI Send", "settings.json"); | |
guiPanel.add(thresholdVal); | |
guiPanel.add(sendGrabber); | |
guiPanel.add(sendThreshold); | |
} | |
void ofApp::update() | |
{ | |
grabber.update(); | |
if (grabber.isFrameNew()) | |
{ | |
// Threshold video image. | |
// Use references (&) when getting the ofPixels objects to | |
// avoid unnecessary copies. | |
ofPixels& videoPix = grabber.getPixels(); | |
ofPixels& thresholdPix = thresholdImg.getPixels(); | |
for (int row = 0; row < videoPix.getHeight(); row++) | |
{ | |
for (int col = 0; col < videoPix.getWidth(); col++) | |
{ | |
int pixVal = videoPix.getColor(col, row).getBrightness(); | |
if (pixVal < thresholdVal) | |
{ | |
thresholdPix.setColor(col, row, ofColor(0)); | |
} | |
else | |
{ | |
thresholdPix.setColor(col, row, ofColor(255)); | |
} | |
} | |
} | |
thresholdImg.update(); | |
if (sendGrabber) | |
{ | |
// Send grabber pixels. | |
ndiSender.send(grabber.getPixels()); | |
} | |
else if (sendThreshold) | |
{ | |
// Send threshold pixels. | |
ndiSender.send(thresholdPix); | |
} | |
} | |
} | |
void ofApp::draw() | |
{ | |
thresholdImg.draw(0, 0); | |
guiPanel.draw(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "ofMain.h" | |
#include "ofxGui.h" | |
#include "ofxNDI.h" | |
class ofApp : public ofBaseApp | |
{ | |
public: | |
void setup(); | |
void update(); | |
void draw(); | |
ofVideoGrabber grabber; | |
ofImage thresholdImg; | |
ofxNDISender ndiSender; | |
ofParameter<int> thresholdVal; | |
ofParameter<bool> sendGrabber; | |
ofParameter<bool> sendThreshold; | |
ofxPanel guiPanel; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment