Skip to content

Commit 48cea07

Browse files
committed
create capturing API for streaming/etc.
1 parent 85d261e commit 48cea07

File tree

5 files changed

+153
-105
lines changed

5 files changed

+153
-105
lines changed

CMakeLists.txt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,18 @@ elseif (MSVC)
370370
set(BZC_PROJECT_INCLUDES ${CMAKE_SOURCE_DIR}/data/windows ${BZC_PROJECT_INCLUDES})
371371
endif ()
372372

373-
set(BZC_PROJECT_SRCS ${BZC_PROJECT_SRCS} ${BZC_PLATFORM_SRCS} ${BZC_RESOURCES_DATA})
373+
if (MSVC AND BONZOMATIC_NDI)
374+
set(BZC_CAPTURE_SRCS
375+
${CMAKE_SOURCE_DIR}/src/capturing/Capture_NDI.cpp
376+
)
377+
else ()
378+
set(BZC_CAPTURE_SRCS
379+
${CMAKE_SOURCE_DIR}/src/capturing/Capture_Dummy.cpp
380+
)
381+
endif ()
382+
source_group("Bonzomatic\\Capture" FILES ${BZC_CAPTURE_SRCS})
383+
384+
set(BZC_PROJECT_SRCS ${BZC_PROJECT_SRCS} ${BZC_PLATFORM_SRCS} ${BZC_RESOURCES_DATA} ${BZC_CAPTURE_SRCS})
374385

375386
set(BZC_PROJECT_INCLUDES ${CMAKE_SOURCE_DIR}/src ${BZC_PROJECT_INCLUDES})
376387

src/Capture.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Capture
2+
{
3+
void LoadSettings(jsonxx::Object & o);
4+
bool Open(RENDERER_SETTINGS & settings);
5+
void CaptureFrame();
6+
void Close();
7+
}

src/capturing/Capture_Dummy.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include "jsonxx.h"
2+
#include "Renderer.h"
3+
4+
namespace Capture
5+
{
6+
void LoadSettings(jsonxx::Object & o)
7+
{
8+
}
9+
bool Open(RENDERER_SETTINGS & settings)
10+
{
11+
return true;
12+
}
13+
void CaptureFrame()
14+
{
15+
}
16+
void Close()
17+
{
18+
}
19+
}

src/capturing/Capture_NDI.cpp

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#include <Processing.NDI.Lib.h>
2+
#include <string>
3+
#include "jsonxx.h"
4+
#include "Renderer.h"
5+
6+
namespace Capture
7+
{
8+
std::string sNDIConnectionString;
9+
float fNDIFrameRate = 60.0;
10+
std::string sNDIIdentifier;
11+
bool bNDIProgressive = true;
12+
bool bNDIEnabled = true;
13+
unsigned int * pBuffer[2] = { NULL, NULL };
14+
unsigned int nBufferIndex = 0;
15+
NDIlib_video_frame_t pNDIFrame;
16+
NDIlib_send_instance_t pNDI_send;
17+
18+
void LoadSettings(jsonxx::Object & o)
19+
{
20+
if (o.has<jsonxx::Object>("ndi"))
21+
{
22+
if (o.get<jsonxx::Object>("ndi").has<jsonxx::Boolean>("enabled"))
23+
bNDIEnabled = o.get<jsonxx::Object>("ndi").get<jsonxx::Boolean>("enabled");
24+
if (o.get<jsonxx::Object>("ndi").has<jsonxx::String>("connectionString"))
25+
sNDIConnectionString = o.get<jsonxx::Object>("ndi").get<jsonxx::String>("connectionString");
26+
if (o.get<jsonxx::Object>("ndi").has<jsonxx::String>("identifier"))
27+
sNDIIdentifier = o.get<jsonxx::Object>("ndi").get<jsonxx::String>("identifier");
28+
if (o.get<jsonxx::Object>("ndi").has<jsonxx::Number>("frameRate"))
29+
fNDIFrameRate = o.get<jsonxx::Object>("ndi").get<jsonxx::Number>("frameRate");
30+
if (o.get<jsonxx::Object>("ndi").has<jsonxx::Boolean>("progressive"))
31+
bNDIProgressive = o.get<jsonxx::Object>("ndi").get<jsonxx::Boolean>("progressive");
32+
}
33+
}
34+
bool Open(RENDERER_SETTINGS & settings)
35+
{
36+
if (bNDIEnabled)
37+
{
38+
if (!NDIlib_initialize())
39+
{
40+
printf("[Capture] Cannot initialize NDI");
41+
return false;
42+
}
43+
44+
NDIlib_send_create_t pNDICreateDesc;
45+
sNDIIdentifier = "BONZOMATIC" + (sNDIIdentifier.length() ? (" - " + sNDIIdentifier) : "");
46+
pNDICreateDesc.p_ndi_name = sNDIIdentifier.c_str();
47+
pNDICreateDesc.p_groups = NULL;
48+
pNDICreateDesc.clock_video = true;
49+
pNDICreateDesc.clock_audio = false;
50+
51+
pNDI_send = NDIlib_send_create(&pNDICreateDesc);
52+
if (!pNDI_send)
53+
{
54+
printf("[Capture] Cannot create NDI source");
55+
return false;
56+
}
57+
58+
NDIlib_metadata_frame_t pNDIConnType;
59+
pNDIConnType.length = sNDIConnectionString.length();
60+
pNDIConnType.timecode = NDIlib_send_timecode_synthesize;
61+
pNDIConnType.p_data = (char*)sNDIConnectionString.c_str();
62+
63+
NDIlib_send_add_connection_metadata(pNDI_send, &pNDIConnType);
64+
65+
pNDIFrame.xres = settings.nWidth;
66+
pNDIFrame.yres = settings.nHeight;
67+
pNDIFrame.FourCC = NDIlib_FourCC_type_BGRA;
68+
pNDIFrame.frame_rate_N = fNDIFrameRate * 100;
69+
pNDIFrame.frame_rate_D = 100;
70+
pNDIFrame.picture_aspect_ratio = settings.nWidth / (float)settings.nHeight;
71+
pNDIFrame.frame_format_type = bNDIProgressive ? NDIlib_frame_format_type_progressive : NDIlib_frame_format_type_interleaved;
72+
pNDIFrame.timecode = NDIlib_send_timecode_synthesize;
73+
pBuffer[0] = new unsigned int[settings.nWidth * settings.nHeight * 4];
74+
pBuffer[1] = new unsigned int[settings.nWidth * settings.nHeight * 4];
75+
pNDIFrame.p_data = NULL;
76+
pNDIFrame.line_stride_in_bytes = settings.nWidth * 4;
77+
}
78+
return true;
79+
}
80+
void CaptureFrame()
81+
{
82+
if (pBuffer[0] && pBuffer[1])
83+
{
84+
pNDIFrame.p_data = (unsigned char*)pBuffer[ nBufferIndex ];
85+
nBufferIndex = (nBufferIndex + 1) & 1;
86+
if (Renderer::GrabFrame( pNDIFrame.p_data ))
87+
{
88+
unsigned int * p = (unsigned int *)pNDIFrame.p_data;
89+
for(int i=0; i < pNDIFrame.xres * pNDIFrame.yres; i++)
90+
p[i] = (p[i] & 0x00FF00) | ((p[i] >> 16) & 0xFF) | ((p[i] & 0xFF) << 16) | 0xFF000000;
91+
NDIlib_send_send_video_async(pNDI_send, &pNDIFrame);
92+
}
93+
}
94+
}
95+
void Close()
96+
{
97+
if (pBuffer[0] && pBuffer[1])
98+
{
99+
NDIlib_send_send_video_async(pNDI_send, NULL); // stop async thread
100+
101+
delete[] pBuffer[0];
102+
delete[] pBuffer[1];
103+
NDIlib_send_destroy(pNDI_send);
104+
NDIlib_destroy();
105+
}
106+
}
107+
}

src/main.cpp

Lines changed: 8 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,10 @@
1010
#include "Misc.h"
1111
#include "UniConversion.h"
1212
#include "jsonxx.h"
13+
#include "Capture.h"
1314

1415
#ifdef WIN32
1516
#include <windows.h>
16-
#ifdef BONZOMATIC_ENABLE_NDI
17-
#include <Processing.NDI.Lib.h>
18-
#endif
1917
#endif
2018

2119
void ReplaceTokens( std::string &sDefShader, const char * sTokenBegin, const char * sTokenName, const char * sTokenEnd, std::vector<std::string> &tokens )
@@ -131,14 +129,6 @@ int main()
131129
float fFFTSmoothingFactor = 0.9f; // higher value, smoother FFT
132130
float fFFTSlightSmoothingFactor = 0.6f; // higher value, smoother FFT
133131

134-
#ifdef BONZOMATIC_ENABLE_NDI
135-
std::string sNDIConnectionString;
136-
float fNDIFrameRate = 60.0;
137-
std::string sNDIIdentifier;
138-
bool bNDIProgressive = true;
139-
bool bNDIEnabled = true;
140-
#endif // BONZOMATIC_ENABLE_NDI
141-
142132
char szConfig[65535];
143133
FILE * fConf = fopen("config.json","rb");
144134
if (fConf)
@@ -205,21 +195,12 @@ int main()
205195
midiRoutes.insert( std::make_pair( it->second->number_value_, it->first ) );
206196
}
207197
}
208-
#ifdef BONZOMATIC_ENABLE_NDI
209-
if (o.has<jsonxx::Object>("ndi"))
210-
{
211-
if (o.get<jsonxx::Object>("ndi").has<jsonxx::Boolean>("enabled"))
212-
bNDIEnabled = o.get<jsonxx::Object>("ndi").get<jsonxx::Boolean>("enabled");
213-
if (o.get<jsonxx::Object>("ndi").has<jsonxx::String>("connectionString"))
214-
sNDIConnectionString = o.get<jsonxx::Object>("ndi").get<jsonxx::String>("connectionString");
215-
if (o.get<jsonxx::Object>("ndi").has<jsonxx::String>("identifier"))
216-
sNDIIdentifier = o.get<jsonxx::Object>("ndi").get<jsonxx::String>("identifier");
217-
if (o.get<jsonxx::Object>("ndi").has<jsonxx::Number>("frameRate"))
218-
fNDIFrameRate = o.get<jsonxx::Object>("ndi").get<jsonxx::Number>("frameRate");
219-
if (o.get<jsonxx::Object>("ndi").has<jsonxx::Boolean>("progressive"))
220-
bNDIProgressive = o.get<jsonxx::Object>("ndi").get<jsonxx::Boolean>("progressive");
221-
}
222-
#endif // BONZOMATIC_ENABLE_NDI
198+
Capture::LoadSettings( o );
199+
}
200+
if ( !Capture::Open( settings ) )
201+
{
202+
printf("Initializing capture system failed!\n");
203+
return 0;
223204
}
224205

225206
Renderer::Texture * texFFT = Renderer::Create1DR32Texture( FFT_SIZE );
@@ -302,59 +283,6 @@ int main()
302283
static float fftDataIntegrated[FFT_SIZE];
303284
memset(fftDataIntegrated, 0, sizeof(float) * FFT_SIZE);
304285

305-
// if we want to do some sort of frame capturing code
306-
// (for e.g. sending frames through the network)
307-
// we'd do it here, and then below.
308-
309-
#ifdef BONZOMATIC_ENABLE_NDI
310-
NDIlib_video_frame_t pNDIFrame;
311-
NDIlib_send_instance_t pNDI_send;
312-
unsigned int * pBuffer[2] = { NULL, NULL };
313-
unsigned int nBufferIndex = 0;
314-
if (bNDIEnabled)
315-
{
316-
if (!NDIlib_initialize())
317-
{
318-
printf("Cannot run NDI.");
319-
return 0;
320-
}
321-
322-
NDIlib_send_create_t pNDICreateDesc;
323-
sNDIIdentifier = "BONZOMATIC" + (sNDIIdentifier.length() ? (" - " + sNDIIdentifier) : "");
324-
pNDICreateDesc.p_ndi_name = sNDIIdentifier.c_str();
325-
pNDICreateDesc.p_groups = NULL;
326-
pNDICreateDesc.clock_video = TRUE;
327-
pNDICreateDesc.clock_audio = FALSE;
328-
329-
pNDI_send = NDIlib_send_create(&pNDICreateDesc);
330-
if (!pNDI_send)
331-
{
332-
printf("Cannot create NDI source");
333-
return 0;
334-
}
335-
336-
NDIlib_metadata_frame_t pNDIConnType;
337-
pNDIConnType.length = sNDIConnectionString.length();
338-
pNDIConnType.timecode = NDIlib_send_timecode_synthesize;
339-
pNDIConnType.p_data = (CHAR*)sNDIConnectionString.c_str();
340-
341-
NDIlib_send_add_connection_metadata(pNDI_send, &pNDIConnType);
342-
343-
pNDIFrame.xres = settings.nWidth;
344-
pNDIFrame.yres = settings.nHeight;
345-
pNDIFrame.FourCC = NDIlib_FourCC_type_BGRA;
346-
pNDIFrame.frame_rate_N = fNDIFrameRate * 100;
347-
pNDIFrame.frame_rate_D = 100;
348-
pNDIFrame.picture_aspect_ratio = settings.nWidth / (float)settings.nHeight;
349-
pNDIFrame.frame_format_type = bNDIProgressive ? NDIlib_frame_format_type_progressive : NDIlib_frame_format_type_interleaved;
350-
pNDIFrame.timecode = NDIlib_send_timecode_synthesize;
351-
pBuffer[0] = new unsigned int[settings.nWidth * settings.nHeight * 4];
352-
pBuffer[1] = new unsigned int[settings.nWidth * settings.nHeight * 4];
353-
pNDIFrame.p_data = NULL;
354-
pNDIFrame.line_stride_in_bytes = settings.nWidth * 4;
355-
}
356-
#endif // BONZOMATIC_ENABLE_NDI
357-
358286
bool bShowGui = true;
359287
Timer::Start();
360288
float fNextTick = 0.1;
@@ -534,33 +462,9 @@ int main()
534462

535463
Renderer::EndFrame();
536464

537-
#ifdef BONZOMATIC_ENABLE_NDI
538-
if (pBuffer[0] && pBuffer[1])
539-
{
540-
pNDIFrame.p_data = (BYTE*)pBuffer[ nBufferIndex ];
541-
nBufferIndex = (nBufferIndex + 1) & 1;
542-
if (Renderer::GrabFrame( pNDIFrame.p_data ))
543-
{
544-
unsigned int * p = (unsigned int *)pNDIFrame.p_data;
545-
for(int i=0; i < settings.nWidth * settings.nHeight; i++)
546-
p[i] = (p[i] & 0x00FF00) | ((p[i] >> 16) & 0xFF) | ((p[i] & 0xFF) << 16) | 0xFF000000;
547-
NDIlib_send_send_video_async(pNDI_send, &pNDIFrame);
548-
}
549-
}
550-
#endif // BONZOMATIC_ENABLE_NDI
465+
Capture::CaptureFrame();
551466
}
552467

553-
#ifdef BONZOMATIC_ENABLE_NDI
554-
if (pBuffer[0] && pBuffer[1])
555-
{
556-
NDIlib_send_send_video_async(pNDI_send, NULL); // stop async thread
557-
558-
delete[] pBuffer[0];
559-
delete[] pBuffer[1];
560-
NDIlib_send_destroy(pNDI_send);
561-
NDIlib_destroy();
562-
}
563-
#endif // BONZOMATIC_ENABLE_NDI
564468

565469
delete surface;
566470

0 commit comments

Comments
 (0)