File: Modules.Exporter.txt

package info (click to toggle)
openni 1.5.4.0%2Bdfsg-8
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 45,580 kB
  • sloc: cpp: 116,706; ansic: 58,807; sh: 10,287; cs: 7,698; java: 7,402; python: 1,547; makefile: 492; xml: 167
file content (409 lines) | stat: -rw-r--r-- 14,435 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
/**
@page modules_exporter Creating a Node Exporter

Once you have completed your node implementation class, you must create 
a node exporter class to export your new node to OpenNI. The node 
exporter is a factory that allows (i) enumerating existing nodes, (ii) 
creating new nodes, and (iii) destroying nodes. 

Creating a node exporter is done by defining a new class that inherits 
from @ref xn::ModuleExportedProductionNode. 

@section modules_exporter_desc Node Description

Each node implementation has a description. The description contains the 
following information: 

- Node Type (Depth Generator / Device / Hands Generator, etc.)
- Vendor Name
- Node Name (to distinguish two products from the same vendor)
- Version

This description should be unique to each node implementation.

@section modules_exporter_enum Enumeration

The enumeration process is where production graphs are created. When an 
application asks for a node of a specific type, OpenNI enumerates the 
node exporters which declared this type. The node exporter is 
responsible of returning the list of production graphs that can be 
created in order to have such a node. Of course, each such production 
graph will have your node implementation as its root. 

The enumeration process is the opportunity to:
- Check if a specific hardware is attached and ready for operation. For 
  example, an exporter of a device node will usually 
  - Query the operating system to find out if a specific USB device is 
    connected right now. 
  - Check if this hardware is not already in use by another software 
    component, and so cannot be used. 
  - If more than one device is connected, it can return two different 
    production graph alternatives, one for each such device. 
- Check that a valid license exists to use the node implementation.
- Enumerate nodes from another type that are required for this node 
  implementation to function. 

A production graph alternative is represented by a @ref xn::NodeInfo 
object. It contains a description of the node (must be the same as the 
description returned by the @ref 
xn::ModuleExportedProductionNode::GetDescription() method), an optional 
creation info and a list of dependent nodes (through which the entire 
graph can be described). 

Adding production graphs to the list is usually done using the @ref 
xn::NodeInfoList::Add() method. 

Note that one of the returned production graph alternatives might be 
used later on to create the production graph, so it's important that 
this alternative will fully describe the exact instance to be created. 
If two alternatives only differ in the way the root node (your node 
implementation) is created, the difference can be described in the 
<i>creation info</i> member. 

If the node implementation depends on exactly one input node, it can use 
the @ref xn::Context::AutoEnumerateOverSingleInput() utility method. 

If no production graphs alternatives are currently available, besides 
returning an empty list, it is also advised to return a return value 
other than XN_STATUS_OK. This return value will be added to the 
EnumerationErrors object, so that the application can later on check why 
a specific node failed to enumerate. 

@note Current OpenNI interface can not pass state while enumerating. 
This causes a problem if production graph cycles might occur (for 
example, if a depth generator enumerates for depth generator, or if a 
hands generator enumerates for user generator which itself enumerates 
for hands generator). Right now, the best solution is to use a static 
boolean inside your Enumerate() implementation, to recognize if the 
method is called recursively, and if so, return nothing. 

@section modules_exporter_create Creating the Node

Once enumeration is complete, the application can choose one of the 
returned production graphs alternatives and ask OpenNI to create it. 
OpenNI assures the node exporter that all needed nodes in the production 
graphs will be created before calling to 
xn::ModuleExportedProductionNode::Create(), so that the exporter can 
take those nodes and use them. In addition to the information found in 
the NodeInfo object (needed nodes, creation info), OpenNI passes to the 
exporter an instance name (the name that this node will have in OpenNI 
context), and a configuration dir (taken from the module registration -- 
see @ref modules_registration). 

The exporter should create the node implementation it exports, and 
return a pointer to it to OpenNI. 

@section modules_exporter_destroy Destroying the Node

Once OpenNI determines that the node is no longer needed, it will 
request the exporter to destroy it by calling <code>@ref 
xn::ModuleExportedProductionNode::Destroy()</code>. OpenNI ensures that 
a node is destroyed before any of the nodes on which it depends in the 
production graph are destroyed. 

@section modules_exporter_ex1 Example A: Exporter for a node which requires a physical device

Let's take for example a device node that represents some USB physical 
device. The enumeration uses the operating system to find out which 
devices are connected right now, obtains the path to each device node, 
and creates a production graph for each device node. The exporter places 
the device path in the creation info. This allows easy access to the 
device path so the exporter knows which is the correct device to connect 
to. 

The Create() method takes the creation info and passes it to the device 
node constructor. 

@code
class MyDevice : public virtual xn::ModuleDevice
{
public:
	MyDevice(const XnChar* strDevicePath);
	...
};

class MyDeviceExporter : public virtual xn::ModuleExportedProductionNode
{
public:
	virtual void GetDescription(XnProductionNodeDescription* pDescription) 
	{
		pDescription->Type = XN_NODE_TYPE_DEVICE;
		strcpy(pDescription->strVendor, "New Devices Inc.");
		strcpy(pDescription->strName, "MyDevice");
		pDescription->Version.nMajor = 1;
		pDescription->Version.nMinor = 0;
		pDescription->Version.nMaintenance = 0;
		pDescription->Version.nBuild = 7;
	}

	virtual XnStatus EnumerateProductionTrees(Context& context, NodeInfoList& TreesList, EnumerationErrors* pErrors) 
	{
		XnStatus nRetVal = XN_STATUS_OK;

		XnProductionNodeDescription description;
		GetDescription(&description);
		
		// find which USB device are connected
		const XnUSBConnectionString* astrDevicePaths;
		XnUInt32 nCount;

		nRetVal = xnUSBEnumerateDevices(MY_VENDOR_ID, MY_PRODUCT_ID, astrDevicePaths, &nCount);
		XN_IS_STATUS_OK(nRetVal);
		
		if (nCount == 0)
		{
			// no device was found. return an error
			return XN_STATUS_DEVICE_NOT_CONNECTED;
		}

		// add a production graph alternative for each connected device
		for (XnUInt32 i = 0; i < nCount; ++i)
		{
			nRetVal = TreesList.Add(description, astrDevicePaths[i], NULL);
			XN_IS_STATUS_OK(nRetVal);
		}

		xnUSBFreeDevicesList(astrDevicePaths);

		return (XN_STATUS_OK);
	}

	virtual XnStatus Create(Context& context, const XnChar* strInstanceName, const XnChar* strCreationInfo, 
							NodeInfoList* pNeededTrees, const XnChar* strConfigurationDir, ModuleProductionNode** ppInstance) 
	{
		*ppInstance = new MyDevice(strCreationInfo);
		if (*ppInstance == NULL)
		{
			return XN_STATUS_ALLOC_FAILED;
		}

		return XN_STATUS_OK;
	}

	virtual void Destroy(ModuleProductionNode* pInstance) 
	{
		delete pInstance;
	}
};
@endcode

@section modules_exporter_ex2 Example B: Exporter for a node which requires one input node

For example, if you want to build a hands generator that works over an 
RGB image map. The exporter must declare that the node needs an image 
generator as input. 

@code
class MyHandsGenerator : public virtual xn::ModuleHandsGenerator
{
public:
	MyHandsGenerator(ImageGenerator imageGen);
	...
};

class MyHandsExporter : public virtual xn::ModuleExportedProductionNode
{
public:
	virtual void GetDescription(XnProductionNodeDescription* pDescription) 
	{
		pDescription->Type = XN_NODE_TYPE_DEVICE;
		strcpy(pDescription->strVendor, "New Algorithms Inc.");
		strcpy(pDescription->strName, "MyHandsGenerator");
		pDescription->Version.nMajor = 1;
		pDescription->Version.nMinor = 0;
		pDescription->Version.nMaintenance = 0;
		pDescription->Version.nBuild = 7;
	}

	virtual XnStatus EnumerateProductionTrees(Context& context, NodeInfoList& TreesList, EnumerationErrors* pErrors) 
	{
		XnStatus nRetVal = XN_STATUS_OK;

		XnProductionNodeDescription description;
		GetDescription(&description);

		return context.AutoEnumerateOverSingleInput(
			TreesList,			// the list to be filled
			description,		// our description
			NULL,				// creation info. Not needed in this example.
			XN_NODE_TYPE_IMAGE, // type of the single input required
			pErrors,			// the EnumerationErrors object
			NULL				// query. Not needed in this example.
			);
	}

	virtual XnStatus Create(Context& context, const XnChar* strInstanceName, const XnChar* strCreationInfo, 
							NodeInfoList* pNeededTrees, const XnChar* strConfigurationDir, ModuleProductionNode** ppInstance) 
	{
		XnStatus nRetVal = XN_STATUS_OK;
		
		// take the first needed node
		NodeInfoList::Iterator it = pNeededTrees->Begin();
		if (it == pNeededTrees->End())
		{
			xnLogError("MyHandsGenerator", "Got a production graph different from the one returned in Enumerate()!");
			return XN_STATUS_ERROR;
		}

		NodeInfo imageInfo = *it;

		// make sure its of the right type and that this is the only one
		if (imageInfo.GetDescription().Type != XN_NODE_TYPE_IMAGE || ++it != pNeededTrees->End())
		{
			xnLogError("MyHandsGenerator", "Got a production graph different from the one returned in Enumerate()!");
			return XN_STATUS_ERROR;
		}

		// OpenNI assures us the image node is already created
		ImageGenerator image;
		nRetVal = imageInfo.GetInstance(image);
		XN_IS_STATUS_OK(nRetVal);

		*ppInstance = new MyHandsGenerator(image);
		if (*ppInstance == NULL)
		{
			return XN_STATUS_ALLOC_FAILED;
		}

		return XN_STATUS_OK;
	}

	virtual void Destroy(ModuleProductionNode* pInstance) 
	{
		delete pInstance;
	}
};
@endcode

@section modules_exporter_ex3 Example C: Exporter for a node which requires two different nodes

Let's take for example a hands generator that needs both RGB information 
and depth information of the scene. The exporter will create production 
graph alternatives that require both an ImageGenerator node and a 
DepthGenerator node. 

@code
class MyHandsGenerator : public virtual xn::ModuleHandsGenerator
{
public:
	MyHandsGenerator(ImageGenerator& imageGen, DepthGenerator& depthGen);
	...
};

class MyHandsExporter : public virtual xn::ModuleExportedProductionNode
{
public:
	virtual void GetDescription(XnProductionNodeDescription* pDescription) 
	{
		pDescription->Type = XN_NODE_TYPE_DEVICE;
		strcpy(pDescription->strVendor, "New Algorithms Inc.");
		strcpy(pDescription->strName, "MyHandsGenerator");
		pDescription->Version.nMajor = 1;
		pDescription->Version.nMinor = 0;
		pDescription->Version.nMaintenance = 0;
		pDescription->Version.nBuild = 7;
	}

	virtual XnStatus EnumerateProductionTrees(Context& context, NodeInfoList& TreesList, EnumerationErrors* pErrors) 
	{
		XnStatus nRetVal = XN_STATUS_OK;

		XnProductionNodeDescription description;
		GetDescription(&description);

		// find production graph alternatives for image
		NodeInfoList imageList;
		nRetVal = context.EnumerateProductionTrees(XN_NODE_TYPE_IMAGE, NULL, imageList, pErrors);
		XN_IS_STATUS_OK(nRetVal);

		// find production graph alternatives for depth
		NodeInfoList depthList;
		nRetVal = context.EnumerateProductionTrees(XN_NODE_TYPE_DEPTH, NULL, depthList, pErrors);
		XN_IS_STATUS_OK(nRetVal);

		// now for each combination, we create one alternative
		for (NodeInfoList::Iterator imageIt = imageList.Begin(); imageIt != imageList.End(); ++imageIt)
		{
			for (NodeInfoList::Iterator depthIt = depthList.Begin(); depthIt != depthList.End(); ++depthIt)
			{
				// create needed nodes list
				NodeInfoList neededNodes;

				nRetVal = neededNodes.AddNodeFromAnotherList(imageIt);
				XN_IS_STATUS_OK(nRetVal);

				nRetVal = neededNodes.AddNodeFromAnotherList(depthIt);
				XN_IS_STATUS_OK(nRetVal);

				nRetVal = TreesList.Add(
					description,	// our description
					NULL,			// creation info. not needed in this example
					&neededNodes	// needed nodes list
					);
				XN_IS_STATUS_OK(nRetVal);
			}
		}

		return XN_STATUS_OK;
	}

	virtual XnStatus Create(Context& context, const XnChar* strInstanceName, const XnChar* strCreationInfo, 
							NodeInfoList* pNeededTrees, const XnChar* strConfigurationDir, ModuleProductionNode** ppInstance) 
	{
		XnStatus nRetVal = XN_STATUS_OK;
		
		// take the first needed node
		NodeInfoList::Iterator it = pNeededTrees->Begin();
		if (it == pNeededTrees->End())
		{
			xnLogError("MyHandsGenerator", "Got a production graph different from the one returned in Enumerate()!");
			return XN_STATUS_ERROR;
		}

		NodeInfo imageInfo = *it;

		// take the second needed node
		++it;
		if (it == pNeededTrees->End())
		{
			xnLogError("MyHandsGenerator", "Got a production graph different from the one returned in Enumerate()!");
			return XN_STATUS_ERROR;
		}

		NodeInfo depthInfo = *it;

		// make sure types are correct and that no more nodes were received
		if (imageInfo.GetDescription().Type != XN_NODE_TYPE_IMAGE || 
			depthInfo.GetDescription().Type != XN_NODE_TYPE_DEPTH ||
			++it != pNeededTrees->End())
		{
			xnLogError("MyHandsGenerator", "Got a production graph different from the one returned in Enumerate()!");
			return XN_STATUS_ERROR;
		}

		// OpenNI assures us the nodes are already created
		ImageGenerator image;
		nRetVal = imageInfo.GetInstance(image);
		XN_IS_STATUS_OK(nRetVal);

		DepthGenerator depth;
		nRetVal = depthInfo.GetInstance(depth);
		XN_IS_STATUS_OK(nRetVal);

		*ppInstance = new MyHandsGenerator(image, depth);
		if (*ppInstance == NULL)
		{
			return XN_STATUS_ALLOC_FAILED;
		}

		return XN_STATUS_OK;
	}

	virtual void Destroy(ModuleProductionNode* pInstance) 
	{
		delete pInstance;
	}
};
@endcode

*/