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.
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; }
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 );
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 ); }
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 ); }
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.