📄 mainframe.cpp
字号:
//-----------------------------------------------------------------------------
// (c) 2002 by Basler Vision Technologies
// Section: Vision Components
// Project: BCAM
// $Header: MainFrame.cpp, 7, 26.09.2002 18:37:40, Nebelung, H.$
//-----------------------------------------------------------------------------
/**
\file MainFrame.cpp
\brief Implementation of the CMainFrame class.
*/
#include "stdafx.h"
#include <float.h>
#include <math.h>
#include <vfw.h>
#include "resource.h"
#include "MainFrame.h"
#include <BvcDib.h>
//! The frame rate as stored in the AVI file = RATE / SCALE
const int RATE = 30;
//! The frame rate as stored in the AVI file = RATE / SCALE
const int SCALE = 1;
//! Number of Delta frames per key frame
/*! Delta frames contain only differences to the previous frames.
Key frames are stored fully and serve as re-synchronization point
Storing delta frames shrinks the file size and costs computing power
In addition single-stepping backwards does take pretty long.
If #DELTA_FRAMES_PER_KEY_FRAME == 0 alle frames are stored
as key frames.
*/
const int DELTA_FRAMES_PER_KEY_FRAME = 0;
//! Number of frames which will be stored at maximum
const unsigned long MAX_NUM_FRAMES = 200;
//! Stores an additional text stream including a time stamp
const bool STORE_TEXT_STREAM = true;
//! Number of characters in the comment attached to each frame
const int TEXT_SIZE = 25;
//! Hight of the comment as shown in the AVI file
const int TEXT_HEIGHT = 20;
//! Topple image before saving so they are bottom up instead of top down.
/*! Most compression implementations and also some AVI viewers cannot deal with
top down images. On the other hand doe toppeling make things slower
*/
const bool TOPPLE_IMAGE = true;
//! Show a list box and let the user choose a compression format
/*! This option is available only if #TOPPLE_IMAGE == true
*/
const bool COMPRESS_IMAGE = true;
//! Pre-allocates the avi file
/*! Since the compression factor is unknown this daoe not make sense
together with #COMPRESS_IMAGE == true
*/
const bool PRE_ALLOCATE_FILE = false;
/*!
Creates the window and initializes all GUI objects.
*/
LRESULT CMainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
try
{
// create command bar window
HWND hWndCmdBar = m_CmdBar.Create(m_hWnd, rcDefault, NULL, ATL_SIMPLE_CMDBAR_PANE_STYLE);
// attach menu
m_CmdBar.AttachMenu(GetMenu());
// load command bar images
m_CmdBar.LoadImages(IDR_MAINFRAME);
// remove old menu
SetMenu(NULL);
HWND hWndToolBar = CreateSimpleToolBarCtrl(m_hWnd, IDR_MAINFRAME, FALSE, ATL_SIMPLE_TOOLBAR_PANE_STYLE);
CreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE);
AddSimpleReBarBand(hWndCmdBar);
AddSimpleReBarBand(hWndToolBar, NULL, TRUE);
// Create Status Bar
CreateSimpleStatusBar("");
m_StatusBar.SubclassWindow(m_hWndStatusBar);
int arrParts[] =
{
ID_STATUS_PANE,
ID_DEFAULT_PANE,
ID_FRAME_COUNTER_PANE,
ID_FPS_PANE
};
m_StatusBar.SetPanes(arrParts, sizeof(arrParts) / sizeof(int), false);
CString StatusPaneText;
StatusPaneText.LoadString(ID_STATUS_PANE);
m_StatusBar.SetPaneText(ID_STATUS_PANE, (LPCSTR)StatusPaneText);
// create view window
m_hWndClient = m_view.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, WS_EX_CLIENTEDGE);
m_view.ReleaseBitmap();
UIAddToolBar(hWndToolBar);
UISetCheck(ID_VIEW_TOOLBAR, 1);
UISetCheck(ID_VIEW_STATUS_BAR, 1);
// register object for message filtering and idle updates
CMessageLoop* pLoop = _Module.GetMessageLoop();
ATLASSERT(pLoop != NULL);
pLoop->AddMessageFilter(this);
pLoop->AddIdleHandler(this);
}
CATCH_MSGBOX( "CMainFrame::OnCreate" )
return 0;
}
/*!
Called it the user wants to start a live grab.
Opens the driver, initilizes the camera and enqueues #NUM_BUFFERS grab commands.
When the grab commands are finished they turn up in the #GrabThreadProc.
*/
LRESULT CMainFrame::OnGrabLive(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
try
{
// Check for a camera
if(CBcam::DeviceNames().size() == 0)
{
MessageBox("No camera present", _T("Error"), MB_OK | MB_ICONEXCLAMATION);
return 0;
}
// ask the user for a filename
CFileDialog dlg(FALSE, _T("avi"), m_AviFilename, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T("AVI Files (*.avi)\0*.avi\0All Files (*.*)\0*.*\0"), m_hWnd);
if(dlg.DoModal() == IDOK)
{
m_AviFilename = dlg.m_szFileName;
}
// Show the filename in the caption framecounter
CString Buffer;
Buffer.Format("StoreAVI - %s", m_AviFilename);
SetWindowText(Buffer);
// Get the devicename of the first camera
CString DeviceName = *(CBcam::DeviceNames().begin());
ATLTRACE(_T("Devicename = %s\n"), DeviceName);
// Open the driver
m_Bcam.Open( DeviceName );
// Parameter set for the fastest monochrome format (valid assumption anly for Basler cameras)
const DCSVideoFormat VideoFormat = DCS_Format7;
const DCSVideoMode VideoMode = DCS_Mode0;
const DCSColorCode ColorCode = DCSColor_Mono8;
m_Bcam.SetVideoMode(VideoFormat, VideoMode);
m_Bcam.FormatSeven[VideoMode].ColorCoding = ColorCode;
// Check if the camera sends Bayer8 data instead of Mono8
m_IsBayerImage = false;
// Is it a Basler camera? - Check the vendor_id
CString NodeID = m_Bcam.Info.NodeId();
if(NodeID.Find("0x003053") == 0)
{
// Is it a color camera? - check for the letter 'c' in the modelname
CString ModelName = m_Bcam.Info.ModelName();
if(ModelName.Find("c") >= 0)
m_IsBayerImage = true;
}
// Set Area Of Interest to maximum
CSize ImageSize = m_Bcam.FormatSeven[VideoMode].MaxSize();
ImageSize.cx = ImageSize.cx & ~3; // Beware : Windows Bitmaps have to have a DWORD alligned width :-(
CPoint AoiPosition(0,0);
CSize AoiSize(ImageSize);
m_Bcam.FormatSeven[VideoMode].Position = AoiPosition;
m_Bcam.FormatSeven[VideoMode].Size = AoiSize;
// Set full speed
unsigned long BytePerPacketMax = m_Bcam.FormatSeven[VideoMode].BytePerPacket.Max();
m_Bcam.FormatSeven[VideoMode].BytePerPacket = BytePerPacketMax;
// Create suitable bitmaps
for(int i=0; i<NUM_BUFFERS; ++i)
m_ptrBitmaps[i].Create(AoiSize, 8, CDib::TopDown, CDib::Monochrome);
// Allocate Resources
m_Bcam.AllocateResources(NUM_BUFFERS, AoiSize.cx * AoiSize.cy );
// Start the grab thread
if ( ! m_GrabThread.Create(&GrabThreadProc, this, THREAD_PRIORITY_HIGHEST) )
{
throw BcamException(::GetLastError(), "CMainFrame::OnGrabLive : Create Grab Thread");
}
// reset the frame counter
m_FrameCounter = 0;
// Indicate that we're grabbing live now
m_LiveGrabbing = true;
m_StopWatch.Start();
// Enqueue Grab commands
for(i=0; i<NUM_BUFFERS; ++i)
{
m_Bcam.GrabImageAsync((char*)m_ptrBitmaps[i]->GetPixels(), AoiSize.cx * AoiSize.cy, (void*)i, USE_ONESHOT);
}
// Switch on the camera (in case we're using ContinuousShot)
if(!USE_ONESHOT)
m_Bcam.ContinuousShot = true;
}
CATCH_MSGBOX( "CMainFrame::OnGrabLive" );
return 0;
}
/*!
Waits on the completion port for finished commands to show up.
- In case of a a finished grab command a #WM_GRAB_FINISHED message is send to the GUI thread
causing the #OnGrabFinished method to be fired.
- In case a #NotifyQuit message turns up a #WM_GRAB_STOPPED message is send to the GUI thread
causing the #OnGrabStopped method to be fired.
- If an error occurs a #WM_ERROR message is send to the GUI thread
causing the #OnError method to be fired.
*/
DWORD CMainFrame::GrabThreadProc(void* pParameter)
{
CMainFrame* This = (CMainFrame*) pParameter; // instance pointer
// Handle for the AVI file
PAVIFILE hAviFile = NULL;
// Handle for the raw video stream
PAVISTREAM hVideoStream = NULL;
// Handle for the raw video stream
PAVISTREAM hTextStream = NULL;
// Buffer to hold the toppled image in case this is required
CDibPtr ptrToppledImage;
try
{
// Initilaize the operating system's AVI support
// Use explicit CoInitilize to force the thread in the MTA
HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED);
if (hr != AVIERR_OK)
throw BcamException(hr, "CMainFrame::GrabThreadProc");
AVIFileInit();
/**************************************/
// Open an AVI file to store the video
// For some reason AVIFileOpen will not shrink the file even with OF_CREATE set
::DeleteFile( (LPCTSTR)This->m_AviFilename );
hr = AVIFileOpen(
&hAviFile,
(LPCTSTR)This->m_AviFilename,
OF_WRITE | OF_CREATE,
NULL); // use handler determined from file extension....
if (hr != AVIERR_OK)
throw BcamException(hr, "CMainFrame::GrabThreadProc");
/**************************************/
// Create a raw video stream in the file
AVISTREAMINFO StreamInfo;
::ZeroMemory(&StreamInfo, sizeof(StreamInfo));
StreamInfo.fccType = streamtypeVIDEO; // stream type
StreamInfo.fccHandler = 0; // No compressor
StreamInfo.dwScale = SCALE;
StreamInfo.dwRate = RATE;
// compressing the image and pre-allocating for (uncompressed) video data does
// not make sense
assert(!PRE_ALLOCATE_FILE || (PRE_ALLOCATE_FILE && !COMPRESS_IMAGE));
if(PRE_ALLOCATE_FILE)
{
StreamInfo.dwSuggestedBufferSize = MAX_NUM_FRAMES * This->m_ptrBitmaps[0]->GetTotalPixelBytes();
StreamInfo.dwSampleSize = This->m_ptrBitmaps[0]->GetTotalPixelBytes();
}
SetRect(&StreamInfo.rcFrame, 0, 0, // rectangle for stream
(int) This->m_ptrBitmaps[0]->GetSize().cx,
(int) This->m_ptrBitmaps[0]->GetSize().cy);
hr = AVIFileCreateStream(hAviFile, // file pointer
&hVideoStream, // returned stream pointer
&StreamInfo); // stream header
if (hr != AVIERR_OK)
throw BcamException(hr, "CMainFrame::GrabThreadProc");
/**************************************/
// Make a compressed stream from the raw stream
// Most compressors don't like top down images :-)
assert(!COMPRESS_IMAGE || (COMPRESS_IMAGE && TOPPLE_IMAGE));
if(COMPRESS_IMAGE && TOPPLE_IMAGE)
{
// Handle for the raw video stream
PAVISTREAM hCompressedVideoStream = NULL;
AVICOMPRESSOPTIONS CompressionOptions;
AVICOMPRESSOPTIONS FAR * pCompressionOptions[1] = {&CompressionOptions};
::ZeroMemory(&CompressionOptions, sizeof(CompressionOptions));
// Let the user choose the compression format (this will show a message box!)
if (!AVISaveOptions(NULL, 0, 1, &hVideoStream, (LPAVICOMPRESSOPTIONS FAR *) &pCompressionOptions))
throw BcamException(E_FAIL, "CMainFrame::GrabThreadProc");
hr = AVIMakeCompressedStream(
&hCompressedVideoStream,
hVideoStream,
&CompressionOptions,
NULL);
if (hr != AVIERR_OK)
throw BcamException(hr, "CMainFrame::GrabThreadProc");
// We need only the handle of the compressed stream so close the handle
// of the raw stream
AVIStreamClose(hVideoStream);
hVideoStream = hCompressedVideoStream;
}
/**************************************/
// Set the stream format (= the format of the DIBs)
unsigned long BitmapInfoBytes;
BITMAPINFO *pBitmapInfo;
This->m_ptrBitmaps[0]->GetBitmapInfo(&pBitmapInfo, &BitmapInfoBytes);
// See TopDown discussion in the CDib class' header
if(!TOPPLE_IMAGE && (This->m_ptrBitmaps[0]->GetOrientation() == CDib::TopDown))
{
pBitmapInfo->bmiHeader.biHeight = -pBitmapInfo->bmiHeader.biHeight;
}
else
{
ptrToppledImage = This->m_ptrBitmaps[0]->Clone(true); // Topple
}
hr = AVIStreamSetFormat(hVideoStream, 0,
pBitmapInfo,
BitmapInfoBytes);
free(pBitmapInfo);
if (hr != AVIERR_OK)
throw BcamException(hr, "CMainFrame::GrabThreadProc");
/**************************************/
// Create an additional text stream for comments
// The MS Media Player V6.4 will show that
if(STORE_TEXT_STREAM)
{
::ZeroMemory(&StreamInfo, sizeof(StreamInfo));
StreamInfo.fccType = streamtypeTEXT;
StreamInfo.fccHandler = mmioFOURCC('D', 'R', 'A', 'W');
StreamInfo.dwScale = SCALE;
StreamInfo.dwRate = RATE;
StreamInfo.dwSuggestedBufferSize = TEXT_SIZE;
SetRect(&StreamInfo.rcFrame, 0, (int) This->m_ptrBitmaps[0]->GetSize().cy,
(int) This->m_ptrBitmaps[0]->GetSize().cx,
(int) This->m_ptrBitmaps[0]->GetSize().cy + TEXT_HEIGHT);
hr = AVIFileCreateStream(hAviFile, &hTextStream, &StreamInfo);
if (hr != AVIERR_OK)
throw BcamException(hr, "CMainFrame::GrabThreadProc");
DWORD TextFormat;
TextFormat = sizeof(TextFormat);
hr = AVIStreamSetFormat(hTextStream, 0, &TextFormat, sizeof(TextFormat));
if (hr != AVIERR_OK)
throw BcamException(hr, "CMainFrame::GrabThreadProc");
}
/**************************************/
// Wait for images and process them
unsigned long RunningIndex = 0;
for(;;)
{
FunctionCode_t FunctionCode;
unsigned long ErrorCode;
void *pContext;
// Wait for things to show up at the driver's completion port
This->m_Bcam.WaitForCompletion(&FunctionCode, &ErrorCode, &pContext, INFINITE);
if(ErrorCode)
throw BcamException(ErrorCode, "CMainFrame::GrabThreadProc");
switch(FunctionCode)
{
case AsyncGrabImage:
{
// Stop the watch and restart it again immediately
float ElapsedTime = (float)This->m_StopWatch.Stop(true);
// Identify the image
unsigned int BufferIndex = *(unsigned int*)&pContext;
// Make sure only MAX_NUM_FRAMES are stored (for the sake of your hard disk :-)
if(RunningIndex < MAX_NUM_FRAMES)
{
LPBYTE pSrc = (unsigned char*)This->m_ptrBitmaps[BufferIndex]->GetPixels();
LPBYTE pDst = pSrc;
if(TOPPLE_IMAGE && (This->m_ptrBitmaps[0]->GetOrientation() == CDib::TopDown))
{
// Topple the data only without telling the image
// thus don't use CDib's topple method
CSize ImageSize;
This->m_ptrBitmaps[0]->GetSize(&ImageSize);
DWORD WidthBytes = This->m_ptrBitmaps[0]->GetWidthBytes();
pDst = (unsigned char*)ptrToppledImage->GetPixels();
for( int i = 0, m = abs(ImageSize.cy) - 1; i < abs(ImageSize.cy); i++, m-- )
{
memcpy(pDst + m * WidthBytes, pSrc + i * WidthBytes, WidthBytes);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -