leadedge / ofxNDI

An Openframeworks addon to allow sending and receiving images over a network using the NewTek Network Device Protocol.
GNU General Public License v3.0
134 stars 48 forks source link

from @leadedge testing branch, now compiling and running on linux #14

Closed dropmeaword closed 4 years ago

dropmeaword commented 4 years ago
dropmeaword commented 4 years ago

One remark, I have an application with two NDI streams and I see that the library loads twice because having two senders now, also means having two dynloaders. Not sure how much of a problem this could be as I don't have extensive experience with the NDI library, but perhaps the dynloader should be a singleton to make sure that only one instance of the library ever gets loaded.

leadedge commented 4 years ago

I need to examine each of these things one at a time rather than pulling the changes. Did you change what I had done or what you already had? I saw you had removed "m_bWasLoaded" guard against reloading and it is never done twice, so I removed it. For each sender or receiver you need to create a new object. Are you creating two senders with the same object? I would rather leave out the platforms file if it works without it. Is there a problem if it is left out?

dropmeaword commented 4 years ago

I pulled from leadedge/ofxNDI testing and started working from there all over again after our last exchange.

ofxNDIplatforms is technically not really needed, but I think it was a good idea in the first place, to keep consistency with OF. Also Linux is never just one platform, it might be linux ARM, linux intel, and a very long etc. So I think that given that you want to keep the thing partly OF independant it is good to have something to interface the OF compile and the non-OF compile.

I also used that header to create defines to redirect the cout output if it's in OF. I would personally prefer to not have cout in my OF application, as I typically disable the log when running my app as a service.

I have two senders for two different ofTextures with two different resolutions.

I also noticed that sending via NDI an ofTexture is not really working for me, it's fine however if I first render the texture onto an FBO.

leadedge commented 4 years ago

OK good, I will look at it again. I will be busy for a day or so but will do it as quickly as possible. I used cout just for the sake of replacing ofLog. It's only needed to warn if the runtime library is not there. Originally it was a messagebox which opens the runtime download. Is there such a thing for Linux?

The dlls can be re-distributed, so if the loader looks for them it saves the user from installing anything if you prefer.

Do you have -

ofxNDIsender sender-1;
ofxNDIsender sender-2;

I can't see how the library can be loaded more than once for each one. Or is there only one of these and two senders created from it? Each one has local variables that the class manages. It's more important for a receiver.

For your texture send are you using SendImage(ofTexture or SendImage(ofFbo Does the function fail or is it just black?

dropmeaword commented 4 years ago

@leadedge in Linux you can also do a popup, would that be a GNOME popup or a pop up in any other of the hundreds of desktop environments? ;) It's not really the typical thing to do at all in Linux, printing to terminal does the job.

dropmeaword commented 4 years ago

This is the line that prevents me from sending my camera capture in a texture over to NDI. ofxNDI absolutely expects all images to be GL_RGBA, is this a requirement on NewTek's library?

if (tex.getTextureData().glInternalFormat != GL_RGBA)

leadedge commented 4 years ago

NDI formats are described in NDIlib_FourCC_video_type_e which is in "Processing.NDI.structs.h". All types are 4 bytes per pixel. The sender is set up to provide a pixel image that NDI expects to be NDIlib_FourCC_type_RGBA. All the fbo and pbo buffers are allocated as RGBA. So if the actual data was RGB it would not work. I suppose the test here should be the actual pixel storage format rather than internal format, but Openframeworks only provides glInternalFormat as far as I am aware. I will explore this later before changing anything.

leadedge commented 4 years ago

I restored ofxNDIplatforms.h and went through the whole thing to make sure all the platform defines are up to date, at the same time adding your recent changes. I removed cout from everywhere for Windows. All printf statements are generally for debugging and can be removed if you prefer. For the dynamic loader, guard against repeat load is simply done by checking if the library pointer has been initialised. The extra flag and function isn't needed. I can't see how the library would be loaded more than once in any case. I have been previously advised to remove "using namespace std" for the Spout project and so prefer to follow that advice. For ofxNDIutils, there is some argument whether to use <stdint.h> or <cstdint>, which includes stdint.h. Did you find a problem with <cstdint>? There was not much change otherwise so hopefully this will be close.

Edit: github had a problem with "cstdint" with < > around it unless marked up as code.

dropmeaword commented 4 years ago

@leadedge yes, about the pixel format the change in my repo is not safe. better that it stays on my dev branch for my own use. About stdint vs. cstdint, I have no strong argument for one or the other, i just needed one to remove the unsigned __int32 that were used in the utils functions. as that didn't seem to be a cross-platform way of defining known-size integers.

leadedge commented 4 years ago

OK let's go with <cstdint>. If somebody finds a problem they will say so. GL_RGB should be OK. I understand that it's an internal format and OpenGL will fill the 4th byte with 255 for the actual format. I will check it out further when I can.

magdesign commented 4 years ago

It does not build on RPi: error: ‘glClearTexImage’ was not declared in this scope error: ‘sprintf_s’ was not declared in this scope

/home/pvj/openFrameworks/addons/ofxNDI/example-receiver/src/ofApp.cpp: In member function ‘virtual void ofApp::setup()’: /home/pvj/openFrameworks/addons/ofxNDI/example-receiver/src/ofApp.cpp:88:91: error: ‘glClearTexImage’ was not declared in this scope glClearTexImage(ndiTexture.getTextureData().textureID, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); ^ /home/pvj/openFrameworks/addons/ofxNDI/example-receiver/src/ofApp.cpp: In member function ‘void ofApp::ShowInfo()’: /home/pvj/openFrameworks/addons/ofxNDI/example-receiver/src/ofApp.cpp:174:172: error: ‘sprintf_s’ was not declared in this scope sprintf_s(str, 256, "[%s] (%dx%d/%4.2fp)", ndiReceiver.GetSenderName().c_str(), ndiReceiver.GetSenderWidth(), ndiReceiver.GetSenderHeight(), ndiReceiver.GetSenderFps()); ^ /home/pvj/openFrameworks/addons/ofxNDI/example-receiver/src/ofApp.cpp:178:82: error: ‘sprintf_s’ was not declared in this scope sprintf_s(str, 256, "Connecting to [%s]", ndiReceiver.GetSenderName().c_str()); ^ /home/pvj/openFrameworks/addons/ofxNDI/example-receiver/src/ofApp.cpp:187:54: error: ‘sprintf_s’ was not declared in this scope sprintf_s(str, 256, "%d network sources", nsenders); ^ /home/pvj/openFrameworks/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk:221: recipe for target 'obj/linuxarmv6l/Release/src/ofApp.o' failed make[1]: *** [obj/linuxarmv6l/Release/src/ofApp.o] Error 1 make[1]: Leaving directory '/home/pvj/openFrameworks/addons/ofxNDI/example-receiver' /home/pvj/openFrameworks/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk:124: recipe for target 'Release' failed make: *** [Release] Error 2

dropmeaword commented 4 years ago

@magdesign I see that you are trying to compile the example, I haven't touched that as I have never even tried to compile it. What branch are you compiling from? You are comenting on this pull request, so I am assuming you are compiling from the testing branch inleadedge/ofxNDI or is your upstream IDArnhem/ofxNDI? Please clarify.

leadedge commented 4 years ago

OK there might still be a chance though. glClearTexImage just clears the texture to black and is only really needed for very slow frame rates such as the Newtek Test Patterns. It seems that sprintf_s is Microsoft only. The only way to resolve it in the short term is to replace it with sprintf. But it looks like it is only the example code that's a problem and only 5 errors show up.

Edit: just remove these lines to see if you can get it to compile.

magdesign commented 4 years ago

@dropmeaword : compiling the actual testing branch on RPI 3 B+, Debian Stretch, OF 10.1 @leadedge: when you say just remove these lines, jest uncomment them in example-receiver/src/ofApp.cpp on line 174...?

Sorry I have no idea of C, for me its magic ;-)

leadedge commented 4 years ago

You are doing well so far. Just put // in front of the lines that you want to disable, or in this case just delete them. If it doesn't compile, again post the result here. It might be close to working.

magdesign commented 4 years ago

In example-sender uncommented following:

line 53:

 //strcpy_s(senderName, 256, "Openframeworks NDI Sender"); // Set the sender name
(btw. tried to replace strcpy_s with strncpy but this throws some -fpermissive errors)

line 163: //sprintf_s(str, 256, "Sending as : [%s] (%dx%d)", senderName, senderWidth, senderHeight);

line 166: //sprintf_s(str, 256, "fps: %3.3d (%4.2f)", (int)ofGetFrameRate(), ndiSender.GetFps());

then following error came up: https://gist.github.com/magdesign/d6630d2ae6ced09edcf7ab0972801f05

Thought this could be of Missing GL support on RPi since I was compiling on terminal, so enabled the fake GL driver, bootet into xwindow system, make clean and tried compiling there, got the same error.

So enabled the full GL driver, started compiling and yes, we came further but stuck here now:

/home/pvj/openFrameworks/addons/ofxNDI/src/ofxNDIreceiver.cpp: In member function ‘bool ofxNDIreceiver::GetPixelData(ofTexture&)’:
/home/pvj/openFrameworks/addons/ofxNDI/src/ofxNDIreceiver.cpp:501:105: error: ‘GL_BGRA’ was not declared in this scope
   texture.loadData((const unsigned char *)videoData, (int)texture.getWidth(), (int)texture.getHeight(), GL_BGRA);
magdesign commented 4 years ago

and for example-receiver (under xwindow with GL enabled), also uncommented all the sprintf_s stuff, then got following error:

/home/pvj/openFrameworks/addons/ofxNDI/example-receiver/src/ofApp.cpp: In member function ‘virtual void ofApp::setup()’:
/home/pvj/openFrameworks/addons/ofxNDI/example-receiver/src/ofApp.cpp:88:91: error: ‘glClearTexImage’ was not declared in this scope
  glClearTexImage(ndiTexture.getTextureData().textureID, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
leadedge commented 4 years ago

@magdesign - I forgot about the sender name. You will need to change that one rather than removing it - strcpy(senderName, "Openframeworks NDI Sender"); Remove the entire glClearTexImage line. It isn't important. It looks like all the extensions needed for the PBO stuff and for GL_BGRA are not supported. There is a test for these but it's too complicated right now. Meanwhile if you have bypassed the PBO problem, just change GL_BGRA to GL_RGBA. Maybe work on the sender until you get it to compile. It looks like it's getting closer. @dropmeaword - I have already removed <xmmintrin.h>

dropmeaword commented 4 years ago

@leadedge I will sync with your testing branch, yesterday I was working on something else and this change slipped. Shall we close this PR then?

leadedge commented 4 years ago

It should be ready now. If you are happy with it we can close. I have a few other things to do at the moment too. @magdesign - how are you going?

magdesign commented 4 years ago

I am now stuck in error: ‘GL_PIXEL_UNPACK_BUFFER_ARB’ and other GL_Pixel errors. Weird that I can not fix it anymore with activating the Full GL driver.

magdesign commented 4 years ago

but nevermind, I think to get this running on a RPi is quite tricky.

leadedge commented 4 years ago

From what you posted before, I think what this means is that Raspberry PI doesn't support PBO (pixel buffer) functions. These are used for a very fast "streaming" copy where the data is copied via GPU using two buffers. This is asynchronous and doesn't hold the the rest of the program up.. It's actually easy to fix by disabling all of this and just using memcpy instead. I have some things to do over the next day or two , but I will make a temporary change so that you can try it. @dropmeaword if you can download the repo first it would be good. You just need to put your RGB fix back in.

leadedge commented 4 years ago

@magdesign - I have disabled all the pbo functions for a sender. I researched this a little and it seems that pbo is only supported with OpenGL ES 3.0 and it looks like you have 2.0. Hopefully it will now compile. If there are any other errors I will keep going until it does or we hit a brick wall.

There is an addition to ofxNDIsender() that should print the target detected. If it shows "TARGET_LINUX_ARM" in the console window that's a start. But I am not sure yet how to detect the version of OpenGL ES.

@dropmeaword - I created a release in case you have not downloaded the current testing repo. It's also backed up as a zip file.

magdesign commented 4 years ago

uncommented in src/ofApp.cpp all lines with:

glClearTexImage
sprintf_s

added to example folders:

Makefile
config.make

changed in src/ofxNDIreceiver.cpp:

GL_BGRA to GL_RGBA

now stuck at NDIlib_v4 error:

/home/pvj/openFrameworks/addons/ofxNDI/src/ofxNDIdynloader.h:15:9: error: ‘NDIlib_v4’ does not name a type
 typedef NDIlib_v4* (*NDIlib_v4_load_)(void);
         ^~~~~~~~~
/home/pvj/openFrameworks/addons/ofxNDI/src/ofxNDIdynloader.cpp: In member function ‘const NDIlib_v4* ofxNDIdynloader::Load()’:
/home/pvj/openFrameworks/addons/ofxNDI/src/ofxNDIdynloader.cpp:165:52: error: ‘endl’ was not declared in this scope
     OUTS << "NDI runtime location " << ndi_path << endl;
                                                    ^~~~
/home/pvj/openFrameworks/addons/ofxNDI/src/ofxNDIdynloader.cpp:165:52: note: suggested alternative:
In file included from /usr/include/c++/6/iostream:39:0,
                 from /home/pvj/openFrameworks/addons/ofxNDI/src/ofxNDIdynloader.h:20,
                 from /home/pvj/openFrameworks/addons/ofxNDI/src/ofxNDIdynloader.cpp:41:
/usr/include/c++/6/ostream:590:5: note:   ‘std::endl’
     endl(basic_ostream<_CharT, _Traits>& __os)
     ^~~~
/home/pvj/openFrameworks/addons/ofxNDI/src/ofxNDIdynloader.cpp:176:5: error: ‘NDIlib_v4_load_’ was not declared in this scope
     NDIlib_v4_load_ lib_load = reinterpret_cast<NDIlib_v4_load_>(dlsym(m_hNDILib, "NDIlib_v4_load"));
     ^~~~~~~~~~~~~~~
/home/pvj/openFrameworks/addons/ofxNDI/src/ofxNDIdynloader.cpp:179:10: error: ‘lib_load’ was not declared in this scope
     if (!lib_load)
          ^~~~~~~~
/home/pvj/openFrameworks/addons/ofxNDI/src/ofxNDIdynloader.cpp:190:25: error: ‘lib_load’ was not declared in this scope
     p_NDILib = lib_load(); // this loads the library and returns a pointer to the dynamic binding

Downloaded the Linux SDK from Newtek, where would I have to place libndi.so.4.1.3 from the SDK?

leadedge commented 4 years ago

1) Change "endl" to "std::endl;"

2) I understand that ".so" files are the Linux equivalent of Windows dll files. We are loading the library dynamically so it has to be found at the expected place. That is set up when you install the NDI runtime. I assume it exists for Linux. Is there a "Redist" folder in the SDK? Otherwise the NDI SDK documentation should show the download location.

3) I am not sure what the typedef problem is. I compared with the code reference - https://raw.githubusercontent.com/Palakis/obs-ndi/master/src/obs-ndi.cpp and the only difference I can see is "const" - typedef const NDIlib_v4* (*NDIlib_v4_load_)(void); you could try that. @dropmeaword - can you help with this?

leadedge commented 4 years ago

For the typedef error - Remove the "#include "Processing.NDI.Lib.h" line -

#include <string>
#include <vector>
#include <iostream> // for cout
// #include "Processing.NDI.Lib.h" // NDI SDK

Move it to the start -

#include "ofxNDIplatforms.h"
#include "Processing.NDI.Lib.h" // NDI SDK

See if that solves it.

leadedge commented 4 years ago

@magdesign - I have restored the PBO functions in preparation for commit to the master branch. There is an Openframeworks define "TARGET_RASPBERRY_PI" and if this is defined for your system they could be conditionally removed for Raspberry PI. @dropmeaword - I am closing this now since you have it working. TODO is OSX compatibility.

magdesign commented 4 years ago

sorry for my absence. I am still not able to compile on RPi, but I think it will not run on an ARM processor anyway. Thanks for your great effort so far!

leadedge commented 4 years ago

No problems. Sorry I can't help without a setup to work with.