Capturing to User-allocated Memory Buffers

This example demonstrates how to wrap user-allocated memory buffers into FrameQueueBuffer objects and then use the FrameSnapSink to directly capture image data into them.

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

Opening a Device

The example program uses the setupDeviceFromFile function from %TOPLEVEL%\Samples\VC\Common\CmdHelper.h. This function displays the device selection dialog and saves the selected device in a configuration file, that is loaded when the function is called again.

Grabber grabber;
if( !setupDeviceFromFile( grabber ) )
{
    return -1;
}

Determine the Required Buffer Size

To find out the required size for the user-allocated buffers, we setup a FrameSnapSink with the desired color format (in this case eY800 ) and call Grabber::prepareLive. After this call, we can retrieve the sink format by calling FrameSnapSink::getOutputFrameType.

// Create a FrameSnapSink with an image buffer format to eY800.
// eY800 means monochrome, 8 bits (1 byte) per pixel.
tFrameSnapSinkPtr pSink = FrameSnapSink::create( eY800 );
// Set the sink.
grabber.setSinkType( pSink );
// Prepare the live mode, to get the output size of the sink.
if( !grabber.prepareLive( false ) )
{
    std::cerr << "Could not render the VideoFormat into a eY800 sink.";
    return -1;
}
// Retrieve the output type and dimension of the sink
// The dimension of the sink could be different from the VideoFormat, when
// you use filters.
FrameTypeInfo info;
pSink->getOutputFrameType( info );

Wrapping User-Allocated Buffers into FrameQueueBuffers

Now that we found the sink format, we can create buffers with the appropriate size. FrameTypeInfo::buffersize contains the number of bytes for one image.

Each memory buffer is allocated using new, but this could be easily substituted with pointers to other places, like third-party library buffers.

A FrameQueueBuffer object is created for each buffer by calling createFrameQueueBuffer, passing in the pointer the the memory buffer.

// Declare an array of 5 pointers to user buffers
BYTE* pBuf[5] = {};
tFrameQueueBufferList lst;
for( int i = 0; i < 5; ++i )
{
    // Create buffer
    pBuf[i] = new BYTE[info.buffersize];
    // Create a FrameQueueBuffer that objects that wraps the memory of our user buffer
    tFrameQueueBufferPtr ptr;
    Error err = createFrameQueueBuffer( ptr, info, pBuf[i], info.buffersize, NULL );
    if( err.isError() ) {
        std::cerr << "Failed to create buffer due to " << err.toString() << "\n";
        return -1;
    }
    lst.push_back( ptr );
}

Snapping and Saving Images

After the list of FrameQueueBuffers has been created, the program snaps five images into the buffers by calling FrameSnapSink::snapSequence. If the images were captured successfully, they are saved to the disk.

// Start live mode for fast snapping. The live video will not be displayed,
// because false is passed to startLive().
grabber.startLive( false );

// Snap 5 images. The list of buffers we pass to snapSequence will be filled
// with the next 5 images the sink receives
Error err = pSink->snapSequence( lst, lst.size() );
if( err.isError() ) {
    std::cerr << "Failed to snap into buffers due to " << err.toString() << "\n";
    return -1;
}

// Stop the live video.
grabber.stopLive();

// Close the device.
grabber.closeDev();
// Save the five captured images to bitmap files.
for( int idx = 0; idx < 5; ++idx )
{
    wchar_t buf[MAX_PATH] = {};
    swprintf_s( buf, L"file%d.bmp", idx );
    saveToFileBMP( *(lst[idx]), buf );
}

Cleanup

The FrameQueueBuffers and the memory buffers have independent object lifetimes. Since the buffer FrameQueueBuffer objects contain a pointer to the memory buffers, they have to be destroyed first.

<< Programmer's Guide