Quick Sign In:  

Forum: VirtualDJ Plugins

Topic: Video plugin for macos (Syphon)
Hello.
I posted the same thing in technical support, but I think the plugin board is more appropriate. If an admin is reading this, please delete the post in the technical one! I can't seem to delete it.

I'm trying to create a simple Syphon sender plugin, as I personally prefer Syphon to NDI.
I've noticed that when I assign this plugin to each deck, the screen turns purple when video is played or scratched. For the master deck, there is no problem.

This problem almost disappears when "videoMicroFrames" is set to "Always". However, I'd like to make it as clean and unaffected by this setting as the official NDI plugin.
This means that OnDraw() should be skipped when the texture is in purple (when a deck doesn't have a microframe?).

I'm a newbie to Objective-C++ and I'm not sure how to identify frames. can anyone help?

info->Flags = VDJFLAG_PROCESSLAST;


HRESULT VDJ_API SyphonSender::OnDraw() {
HRESULT hr;
TVertex *vertices;
void *texture = nullptr;

DrawDeck();

if (VideoWidth != width || VideoHeight != height) {
hr = OnVideoResize(width, height);
}

hr = GetTexture(VdjVideoEngineMetal, &texture, &vertices);
if (hr != S_OK || texture == nullptr) {
return hr;
}

id<MTLTexture> metalTexture = (__bridge id<MTLTexture>)texture;
id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
if (commandBuffer) {
[syphonServer publishFrameTexture:metalTexture
onCommandBuffer:commandBuffer
imageRegion:NSMakeRect(0, 0, VideoWidth, VideoHeight)
flipped:YES];
[commandBuffer commit];
}

return S_OK;
}


This is a very simple OnDraw() function using the latest Syphon framework.
 

Posted Fri 24 May 24 @ 10:13 am
AdionPRO InfinityCTOMember since 2006
Not exactly sure why it's not working like this, but in general if you don't want to draw anything custom, just remove DrawDeck and return E_FAIL instead
 

Posted Fri 24 May 24 @ 11:07 am
Thanks for the answer, I guess I didn't explain it well enough. The video on virtualdj is fine, but the problem is with the screen output to Syphon. It almost produces a purple screen when playing, but only on decks. If you assign the plugin to a master, you won't have this problem at all.
 

Posted Fri 24 May 24 @ 12:15 pm
AdionPRO InfinityCTOMember since 2006
Perhaps there are limitations on the type of textures or the way they are created that can be passed to syphon publishFrameTexture?
 

Posted Fri 24 May 24 @ 12:19 pm
Perhaps this is an issue with syphon. Is there any difference in the handling of texture data when "videoMicroFrames" is "Always" versus "Never"?
 

Posted Fri 24 May 24 @ 12:26 pm
AdionPRO InfinityCTOMember since 2006
Without microFrames you might get a texture directly from the video decoder, which might change the way a program can read back the pixel data to memory.
With microFrames you typically get a mix of 2 frames, which is drawn into a separate buffer, so created differently.
You could of course create such a buffer yourself, draw the texture into that buffer and then pass that newly created texture to syphon
 

Posted Fri 24 May 24 @ 12:31 pm
One of the reasons I've switched to NDI is because I have to basically full screen VDJ's output or else whatever I'm pushing it into just doesn't look good. Things look pixelated or just under scanned.

Not sure if this is what you're talking about but NDI is definitely the better choice for me.
 

Posted Fri 24 May 24 @ 1:04 pm
I'm doing some testing and noticed that the texture is actually a magenta colour before passing it to Syphon, could you help? Below is the simplified code.
Perhaps I should use AnyPtr rather than VdjVideoEngineMetal to get the texture in a different way?

HRESULT VDJ_API SyphonSender::OnDraw() {
HRESULT hr;
TVertex *vertices;
void *texture = nullptr;

hr = DrawDeck();

hr = GetTexture(VdjVideoEngineMetal, &texture, &vertices);

id<MTLTexture> metalTexture = (__bridge id<MTLTexture>)texture;

//Checking the texture.
MTLTextureDescriptor *tempDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:[metalTexture pixelFormat]
width:VideoWidth
height:VideoHeight
mipmapped:NO];
tempDesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;

id<MTLTexture> tempTexture = [metalDevice newTextureWithDescriptor:tempDesc];
id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
id<MTLBlitCommandEncoder> blitEncoder = [commandBuffer blitCommandEncoder];

[blitEncoder copyFromTexture:metalTexture
sourceSlice:0
sourceLevel:0
sourceOrigin:MTLOriginMake(0, 0, 0)
sourceSize:MTLSizeMake(VideoWidth, VideoHeight, 1)
toTexture:tempTexture
destinationSlice:0
destinationLevel:0
destinationOrigin:MTLOriginMake(0, 0, 0)];
[blitEncoder endEncoding];
[commandBuffer commit];
[commandBuffer waitUntilCompleted];

NSUInteger width = [metalTexture width];
NSUInteger height = [metalTexture height];
NSUInteger bytesPerRow = width * 4;
void *textureData = malloc(height * bytesPerRow);
if (textureData == nullptr) {
LogMessage(@"Failed to allocate memory for texture data");
return E_FAIL;
}

[tempTexture getBytes:textureData bytesPerRow:bytesPerRow fromRegion:MTLRegionMake2D(0, 0, width, height) mipmapLevel:0];

bool skipTransmission = true;

for (NSUInteger i = 0; i < 32; i += 4) {
unsigned char r = ((unsigned char*)textureData)[i + 0];
unsigned char g = ((unsigned char*)textureData)[i + 1];
unsigned char b = ((unsigned char*)textureData)[i + 2];
unsigned char a = ((unsigned char*)textureData)[i + 3];

if (r != 255 || g != 0 || b != 255 || a != 255) {
//It's actaully already magenta...
break;
}
}

free(textureData);

 

Posted Mon 27 May 24 @ 4:04 pm
locoDogPRO InfinityModeratorMember since 2013
Mod note, it appears [ i ] even in code blocks is parsed as bbcode
 

Posted Mon 27 May 24 @ 4:26 pm
Any help? Using AnyPtr doesn't seem to make much difference to the result...
 

Posted 20 hours ago