OpenNI 1.5.4
NiRecordRaw.cpp - sample program

Source file: Click the following link to view the source code file:

This section describes an OpenNI sample program for recording raw data, and then playing it back. Recording raw data may be useful for middleware developers who produce a custom type of data that isn't defined by OpenNI. In addition, recording raw data may also be useful for middleware developers who save additional debugging information in the ONI file. This additional data may be used in conjunction with the standard OpenNI data types such as depth output data stored in the file. In this case, each frame of debugging information will match a depth frame.

In this sample, the raw data is artificial data that the application itself synthesizes.

Declaration of File Paths

In the following definitions, SAMPLE_XML_PATH is for the path to an OpenNI XML script input file for building a stored production graph. The <i>production graph</i> is a network of <i>production nodes</i> and is the principal OpenNI object model. See @ref prod_graph for more about production graph. RECORDING_FILE_NAME is the OpenNI output file to store the recording.
@code 
    #define SAMPLE_XML_PATH "../../../../Data/SamplesConfig.xml"
    #define RECORDING_FILE_NAME "recordingWithRaw.oni"
@endcode            

Macro Declarations

At the top of the program are two macro utility declarations, both of which call OpenNI methods. They are described below. However, for the sake of conciseness, the rest of this documentation skips calls to these macros.

The CHECK_RC_ERR() macro checks whether the most recent OpenNI operation for creating a production graph actually created a production graph or not. If no production graph was created (indicated by the <code>XN_STATUS_NO_NODE_PRESENT</code> return code), the @ref xn::xnGetStatusString "xnGetStatusString()" method converts an error list to a  error string for printing. Either way, this macro then calls the <code>CHECK_RC()</code> macro described above.
@code 
    #define CHECK_RC_ERR(rc, what, error) \
      ...           
@endcode    

Main Program - Declaration Block

The declaration block at the top of the main program declares an OpenNI status flag for collecting return values from method calls.
@code 
    XnStatus nRetVal = XN_STATUS_OK;
@endcode

Main Program

@subsection recraw_record Recording Data

    In the following, the @ref xn::xnLogInitFromXmlFile() function initializes the log from an XML file. 
    @code 
        nRetVal = xnLogInitFromXmlFile(SAMPLE_XML_PATH);
    @endcode

    The following initalizes the @ref xn::Context object. This is a workspace where the application builds an OpenNI production graph. The <i>production graph</i> is a network of <i>production nodes</i> and is the principal OpenNI object structure.
    @code 
        Context context;
        nRetVal = context.Init();
    @endcode

    The following statement initializes a Recorder object. This object records to a specified destination medium the frames of data from each node that was added to the Recorder node. 
    @code 
        nRetVal = recorder.Create(context);
    @endcode

    The following call specifies to where the recorder must send its recording. 

    @note Disk files are the only medium that this installation currently supports.

    @code 
        nRetVal = recorder.SetDestination(XN_RECORD_MEDIUM_FILE, RECORDING_FILE_NAME);
    @endcode        

    The following code creates a mock node. This is to simulate an actual node when recording or playing data from a recording. A mock node does not contain any logic for generating data. Instead, it allows an outside component &ndash; such as an application or a real node &ndash; to feed it configuration changes and data. 
    @code 
        MockRawGenerator rawGenerator;
        nRetVal = rawGenerator.Create(context, "MockRaw");
    @endcode        

    The following statements set properties of the @ref xn::MockRawGenerator "rawGenerator" node. It creates a string property named Type and assigns it the value "ReverseT", creates an integer property named X and assigns it the value 5.  This depends on the middleware developer that is using this feature. It could be any parameter that the middleware code might later need for debugging purposes or for custom data types.
    @code 
        nRetVal = rawGenerator.SetStringProperty("Type", "ReverseT");
        nRetVal = rawGenerator.SetIntProperty("X", 5);
    @endcode

    The following statement adds the node to the recording setup, and starts recording it.
    @code 
        nRetVal = recorder.AddNodeToRecording(rawGenerator);
    @endcode

    The following example shows that properties can also be set after the node has been added to the recording. 
    @code 
        nRetVal = rawGenerator.SetIntProperty("Y", 8);
    @endcode

    The following main application loop sets artificial data in the rawGenerator node. The parameters to the SetData() call, in order, are nFrameID and nTimestamp, both generated from the loop counter - abd then the nDataSize and a pointer to the data buffer.         
    @code 
        XnChar buff[20];
        for (XnUInt32 i = 1; i <= 10; i++)
        {
            for (XnUInt32 j = 0; j < 20; j++)
            {
                buff[j] = i;
            }
            nRetVal = rawGenerator.SetData(1000 * i, i, sizeof(buff), buff);nRetVal = recorder.Record();
    @endcode

    In the above, the @ref xn::Recorder::Record() "Record()" method records one frame of data from each node added to the recorder. To record continually, the recorder node must be called repeatedly for each frame.

    On completion of the loop, the following code removes the node from the Recorder object and so stops recording the node output. The code then releases the @ref xn::Recorder "Recorder" and  @ref xn::MockRawGenerator "MockRawGenerator" nodes. Releasing the nodes unreferences them, decreasing their reference counts by 1. If a node's reference count reaches zero, it will be destroyed. 
    @code 
        nRetVal = recorder.RemoveNodeFromRecording(rawGenerator);
           ...
        recorder.Release();
           ...
        rawGenerator.Release();
    @endcode

    This completes the recording example. All recorded data has been recorded in the file whose name is given in RECORDING_FILE_NAME.

@subsection recraw_play Plays Back Recorded Data

    The application now builds a production graph to play back the data recorded above 

    The following statement gets a handle to an existing production node instance using that instance name. It is already known that there exists a node with the instance name "MockRaw".  
    @code 
        nRetVal = context.GetProductionNodeByName("MockRaw", rawGenerator);
    @endcode

    The following code replays a recorded file of a session of OpenNI data generation exactly as it was recorded. the @ref xn::Player node is for playing a saved recording of an OpenNI data generation session. The RECORDING_FILE_NAME string contains the file name, as above. 
    @code 
        Player player;
        nRetVal = context.OpenFileRecording(RECORDING_FILE_NAME, player);
    @endcode            

    The following statement specifies whether the player will automatically rewind to the beginning of the recording after reaching the end of the recording.
    @code 
        nRetVal = player.SetRepeat(FALSE);
    @endcode

    @code 
        nRetVal = context.GetProductionNodeByName("MockRaw", rawGenerator);
    @endcode

    The following program loop waits for available data from any generator node and prints it out. The @ref xn::Context::WaitAnyUpdateAll() "WaitAnyUpdateAll()" method updates all generator nodes in the context that have new data available, first waiting for any of the nodes to have new data available. The application can then get the data (for example, using a metadata <code>GetData()</code> method). This method has a timeout.         
    @code 
        while ((nRetVal = context.WaitAnyUpdateAll()) != XN_STATUS_EOF)
        {
            CHECK_RC(nRetVal, "Read data from file");
            pData = (const XnChar*)rawGenerator.GetData();
            nSize = rawGenerator.GetDataSize();
            for (XnUInt32 i = 0; i < nSize; i++)
            {
                printf("%d ", pData[i]);
            }
            printf("\n");
        }
    @endcode

    On completion of the loop, the following code removes the node from the Player  object and and so stops playing the recording. All other objects are also released. See ealier for a more detailed description of Release().
    @code 
        player.Release();
        rawGenerator.Release();
        recorder.Release();
        context.Release();
    @endcode