Using a Callback Function

This example demonstrates how to use a FrameQueueSink with a FrameQueueSinkListener-derived class to process images using a callback function.

The program can be found in the %TOPLEVEL%\Samples\VC\Callback directory. In order to run the program, open the solution file Callback.sln in this directory and select Build -> Build Callback in the menu. Then the program can be executed by selecting Debug -> Start.

Introduction

This example uses a function called setupDeviceFromFile. The source code for this function can be found at %TOPLEVEL%\Samples\VC\Common\CmdHelper.h. This function asks the user to select the desired video capture device, video norm, video format and input channel. The selected settings are saved, so that you do not have to re-select them every time you run the program.

The following code demonstrates how to setup the FrameQueueSink that receives a callback whenever an image was captured.

sink_listener    listener_instance;
// Create a FrameTypeInfoArray data structure describing the allowed color formats.
FrameTypeInfoArray acceptedTypes = FrameTypeInfoArray::createRGBArray();
// Create the frame sink
tFrameQueueSinkPtr pSink = FrameQueueSink::create( listener_instance, acceptedTypes );
// Apply the sink to the grabber.
grabber.setSinkType( pSink );

The program derives a class called sink_listener from FrameQueueSinkListener.

In the method overriding FrameQueueSinkListener::sinkConnected, FrameQueueSink::allocAndQueueBuffers is used to add a number of buffers to the input queue of the sink.

virtual void    sinkConnected( FrameQueueSink& sink, const FrameTypeInfo& frameType )
{
    UNREFERENCED_PARAMETER( frameType );

    sink.allocAndQueueBuffers( 10 );
}

In the implementation of FrameQueueSinkListener::framesQueued, the oldest filled buffer is retrieved from the queue by calling FrameQueueSink::popOutputQueueBuffer. The contents of that buffer is saved in a BMP file using the saveImage method.

//////////////////////////////////////////////////////////////////////////
/*! The framesQueued() method calls the saveImage method to save the image buffer to disk.
*/
virtual void    framesQueued( FrameQueueSink& sink )
{
    tFrameQueueBufferPtr buffer = sink.popOutputQueueBuffer();
    unsigned int frame_number = buffer->getFrameMetaData().mediaSampleDesc.FrameNumber;
    std::cout << "Buffer " << frame_number << " processed in sink_listener::framesQueued()." << std::endl;
    saveImage( buffer, frame_number );
    Sleep( 250 );       // induce a high latency penalty
}

For this example, we do not want to re-queue the processed buffer, since we want to process a fixed amount of images. Instead, we add a Sleep(250) to simulate expensive processing, so that images accumulate in the copied (output) queue of the sink during the run of the program.

The main() function stops the image acquisition once all enqueued input buffers have been filled by the sink:

grabber.startLive();                // Start the grabber.
while( pSink->getInputQueueSize() != 0 ) // we have to wait until all 10 queued buffers have been drained
{
    Sleep( 100 );
}
grabber.stopLive();                    // Stop the grabber.

It then uses FrameQueueSink::popAllOutputQueueBuffers to obtain all buffers for which framesQueued has not been called, and saves all of them as well:

// Save the buffers for which CListener::frameReady() has not been called.
// Since sink_listener::framesQueued() calls Sleep(100)

tFrameQueueBufferList remaining_buffers = pSink->popAllOutputQueueBuffers();
for( size_t i = 0; i < remaining_buffers.size(); i++ )
{
    unsigned int frame_number = remaining_buffers[i]->getFrameMetaData().mediaSampleDesc.FrameNumber;
    std::cout << "Buffer " << frame_number << " processed in main()." << std::endl;
    listener_instance.saveImage( remaining_buffers[i], frame_number );
}

<< Programmer's Guide