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

timecode #42

Closed moebiussurfing closed 10 months ago

moebiussurfing commented 1 year ago

Hello @leadedge , do you now if the ndi libraries support timecode?

leadedge commented 1 year ago

The NDI video frame structure allows for a timecode, but this is not set from a timing source. The timecode value is set to the default (synthesised for us).

moebiussurfing commented 1 year ago

Thanks!

So I’m trying to sync a tracker with an ndi feed. Right now the ndi feed comes in after the tracking data. I’d like to keep a timecode referenced buffer of tracking data, check the ndi frame timecode, find that frames tracking data from the buffer, and reemit them both in sync.

Do you think this is possible?

leadedge commented 1 year ago

I think this could be done. A timecode is available from each received video frame. I have not studied the details of timecodes, but in this plugin you would retrieve it in ofxReceiveImage.cpp > ReceiveImage at line 1139 as the "timecode of the frame in 100-nanosecond intervals".

int64_t timecode = video_frame.timecode;

For a receiver, there is also "video_frame.timestamp" generated by the SDK when the frame is produced by the sender and this is documented in "Processing.NDI.structs.h". The SDK documentation explains more about the timecode value, time since epoch etc..

eduardfrigola commented 9 months ago

Hi @leadedge,

I'm involved in a project where accessing timestamp and timecode information is essential. In using the ofxNDI addon for openFrameworks, I noticed that the various ReceiveImage methods (whether they take a buffer, texture, or FBO) do not inherently provide this data.

To work around this, I've experimented by modifying these methods, such as changing ReceiveImage(ofPixels &buffer) to ReceiveImage(ofPixels &buffer, int64_t &timestamp). This allows the optional retrieval of timestamp information along with the video data. While this modification meets my immediate needs, it made me wonder about the broader utility of such a feature in the addon.

Do you think it would be beneficial to integrate optional timecode and timestamp retrieval capabilities into the ReceiveImage methods? This addition could be designed to maintain backward compatibility, ensuring it doesn't disrupt existing implementations. If you see merit in this suggestion, I would be glad to open a new issue to discuss these enhancements in more detail.

Thank you for considering this proposal.

Best regards, Eduard

leadedge commented 9 months ago

Thanks Eduard,

I am sure that somebody like @moebiussurfing would be very interested.

This project is actually a double wrapper. The ofxNDIsend / ofxNDIreceive classes can be used independently of Openframeworks, so that would be something to consider.

Initially I would see some additional function like "GetTimeCode", that works in the same way as "GetMetadataString".

Right now I am knee deep, or more likely neck deep, in several other things so can't do anything immediately but I would be interested to have a look at what you have done.

eduardfrigola commented 9 months ago

Hi @leadge, I needed timestamp and not timecode for my use case. So I just added timestamp retrieval the same way you implemented timecode information in a pull request.

My use case is receiving 120fps NDI frames from a camera, and storing it in a pool where I can retrieve the frames based on the timestamp information to create timed video effects.

My implementation is as follows:

int64_t t1;
        int64_t t2;
        int64_t t3;

        int numframes = 0;
        if (ndiReceiver.ReceiveImage(pix1)) {
            t1 = ndiReceiver.GetVideoTimestamp();
            ndiTex1.loadData(pix1);
            output = &ndiTex1;
            timestamp1 = t1;
        }
        if (ndiReceiver.ReceiveImage(pix2)) {
            t2 = ndiReceiver.GetVideoTimestamp();
            ndiTex2.loadData(pix2);
            output2 = &ndiTex2;
            timestamp2 = t2;
        }
        if (ndiReceiver.ReceiveImage(pix3)) {
            t3 = ndiReceiver.GetVideoTimestamp();
            ndiTex3.loadData(pix3);
            output3 = &ndiTex3;
            timestamp3 = t3;
        }

I wanted to update the receiver example to retreive that information, but last commit seems the example is gone, and there is a non-working sender-reveiver example (does not have sources inside src/ folder, and does not have a receiver implemented inside the code. Or I amb missing something.

Thanks for all your efforts on improving the library!

Eduard

leadedge commented 9 months ago

I have modified the separate sender and receiver to make them a single project. Documentation is still not updated. The sender-receiver example has a define in ofApp.h #define BUILDRECEIVER. Enable the define for a receiver and disable for a sender.

I will put the sender-receiver-example source in a "src" folder. Meanwhile it's outside that but still in the sender-receiver folder. Copy those files to your Openframeworks src folder.

Tomorrow I will add "GetVideoTimestamp()" and test it with the receiver example and come back.