Skip to content

Instantly share code, notes, and snippets.

@prisonerjohn
Last active October 21, 2019 04:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save prisonerjohn/c1879fb72aaf87f6a4f0021e1e1c70a4 to your computer and use it in GitHub Desktop.
Save prisonerjohn/c1879fb72aaf87f6a4f0021e1e1c70a4 to your computer and use it in GitHub Desktop.
Sensing Machines NDI
#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();
}
}
#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;
};
#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();
}
#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;
};
#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();
}
#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