Solved

Video for Windows --> Drawing a Line on the Capture Window

Posted on 2004-04-09
7
646 Views
Last Modified: 2007-12-19
I'd like to ask if anyone  have already done this trick.
I'd like to draw a line on the capture window for my program.
I'd like to draw a small cross on the center of the capture
window.
If I can use a function can anybody share this information(function),
if not can anybody share the procedure on how to do this trick.

Thank you ing advance.

0
Comment
Question by:colossus_21
  • 3
7 Comments
 
LVL 48

Expert Comment

by:AlexFM
ID: 10789937
I have the project which does exactly the same trick. This is MFC application, you you don't use MFC, convert this to API. Appropriate code fragments:

BOOL CVideoCaptureDlg::InitCapture()
{
    m_hCaptureWnd = capCreateCaptureWindow(
        _T(""),
        WS_CHILD,
        0,
        0,
        100,
        100,
        m_hWnd,
        ID_CAPTURE_WND);

        // ... show available drivers in listbox
}


BOOL CVideoCaptureDlg::Connect()
{
    int n = m_list_drivers.GetCurSel();  // driver number

    if ( n < 0 )
    {
        MessageBox("Capture driver is not selected");
        return FALSE;
    }

    if ( ! capDriverConnect(m_hCaptureWnd, n) )
    {
        MessageBox("capDriverConnect failed");
        return FALSE;
    }

    CAPSTATUS CapStatus;

    if ( ! capGetStatus(m_hCaptureWnd, &CapStatus, sizeof (CAPSTATUS)) )
    {
        MessageBox("capGetStatus failed");
        return FALSE;
    }

    ::MoveWindow(m_hCaptureWnd, 0, 0,
                 CapStatus.uiImageWidth, CapStatus.uiImageHeight, FALSE);
    ::ShowWindow(m_hCaptureWnd, SW_SHOW);


    if ( ! capDriverGetCaps(m_hCaptureWnd, &m_DriverCaps, sizeof(CAPDRIVERCAPS)) )
    {
        MessageBox("capDriverGetCaps failed");
        return FALSE;
    }

    if ( ! capSetCallbackOnError(m_hCaptureWnd, ErrorCallback) )
    {
        MessageBox("capSetCallbackOnError failed");
        return FALSE;
    }

    // !!! set frame callback - this is what you need
    if ( ! capSetCallbackOnFrame(m_hCaptureWnd, FrameCallback) )
    {
        MessageBox("capSetCallbackOnFrame failed");
        return FALSE;
    }

    return TRUE;
}

// This function is used to set RGB video format programmatically -
// I need this format to draw in the video frame
BOOL CVideoCaptureDlg::SetVideoFormatRGB()
{
    DWORD size = capGetVideoFormatSize(m_hCaptureWnd);

    if ( size <= 0 )
    {
        AddString("capGetVideoFormatSize failed");
        return FALSE;
    }

    void* pBuffer = new BYTE[size];
    BITMAPINFO* pBitmapInfo = (BITMAPINFO*) pBuffer;

    if ( capGetVideoFormat(m_hCaptureWnd, pBuffer, size) <= 0 )
    {
        delete[] pBuffer;
        AddString("capGetVideoFormat failed");
        return FALSE;
    }

    pBitmapInfo->bmiHeader.biBitCount = 24;
    pBitmapInfo->bmiHeader.biCompression = 0;
    pBitmapInfo->bmiHeader.biSizeImage = pBitmapInfo->bmiHeader.biWidth * pBitmapInfo->bmiHeader.biHeight * 3;

    if ( ! capSetVideoFormat(m_hCaptureWnd, pBitmapInfo, size) )
    {
        delete[] pBuffer;
        AddString("capSetVideoFormat failed");
        return FALSE;
    }

    // keep results in global variables to be available in callback functions
    g_nImageWidth = pBitmapInfo->bmiHeader.biWidth;
    g_nImageHeight = pBitmapInfo->bmiHeader.biHeight;
    g_nBitCount = pBitmapInfo->bmiHeader.biBitCount;
    g_nBitsPerPixel = pBitmapInfo->bmiHeader.biBitCount;

    delete[] pBuffer;
    ...
    return TRUE;
}

This is general stuff, I suppose you have something like tiis in your project. Important thing is capSetCallbackOnFrame and SetVideoFormatRGB which sets well-known RGB video format.

#define LINE_LEN 10

LRESULT CALLBACK FrameCallback(HWND hWnd, LPVIDEOHDR lpVHdr)
{
    if ( g_nBitCount != 24 )   // only RGB format !
        return 0;

    if ( ! g_hFrameBitmap )
        CreateGraphicObjects(hWnd);

    if ( ! g_hFrameBitmap )   // failed
        return 0;

    HPEN hOldPen = (HPEN)SelectObject(g_hFrameDC, g_hWhitePen);       // global pen handle created in initialization code
    HBRUSH hOldBrush = (HBRUSH)SelectObject(g_hFrameDC, g_hBrush);// global brush handle created in initialization code

    // copy video frame to bitmap bits
    SetBitmapBits(g_hFrameBitmap, g_nImageWidth*g_nImageHeight*3, lpVHdr->lpData);

    // draw something
    MoveToEx(g_hFrameDC, g_nImageWidth/2 - LINE_LEN, g_nImageHeight/2, NULL);
    LineTo(g_hFrameDC, g_nImageWidth/2 + LINE_LEN + 1, g_nImageHeight/2);
    MoveToEx(g_hFrameDC, g_nImageWidth/2, g_nImageHeight/2 - LINE_LEN, NULL);
    LineTo(g_hFrameDC, g_nImageWidth/2, g_nImageHeight/2 + LINE_LEN + 1);

    SelectObject(g_hFrameDC, g_hBlackPen);

    MoveToEx(g_hFrameDC, g_nImageWidth/2 - LINE_LEN, g_nImageHeight/2 - 1, NULL);
    LineTo(g_hFrameDC, g_nImageWidth/2 + LINE_LEN + 1, g_nImageHeight/2 - 1);
    MoveToEx(g_hFrameDC, g_nImageWidth/2 - 1, g_nImageHeight/2 - LINE_LEN, NULL);
    LineTo(g_hFrameDC, g_nImageWidth/2 - 1, g_nImageHeight/2 + LINE_LEN + 1);

    SelectObject(g_hFrameDC, hOldBrush);
    SelectObject(g_hFrameDC, hOldPen);

    // copy bitmap bits back to video frame    
    GetBitmapBits(g_hFrameBitmap, g_nImageWidth*g_nImageHeight*3, lpVHdr->lpData);

    return 0;
}


#define WIDTHBYTES(bits) ((((bits) + 31) / 32) * 4)

void CreateGraphicObjects(HWND hWnd)
{
    HDC hDC = ::GetDC(hWnd);
    g_hFrameDC = CreateCompatibleDC(hDC);
    ::ReleaseDC(hWnd, hDC);

    LPBITMAPINFO lpbi;

    lpbi = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER) + (256 * sizeof(RGBQUAD))];
    lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    lpbi->bmiHeader.biWidth = g_nImageWidth;
    lpbi->bmiHeader.biHeight = g_nImageHeight;
    lpbi->bmiHeader.biPlanes = 1;
    lpbi->bmiHeader.biBitCount = 24;
    lpbi->bmiHeader.biCompression = BI_RGB;
    lpbi->bmiHeader.biSizeImage = WIDTHBYTES((DWORD)g_nImageWidth * 8) * g_nImageHeight;
    lpbi->bmiHeader.biXPelsPerMeter = 0;
    lpbi->bmiHeader.biYPelsPerMeter = 0;
    lpbi->bmiHeader.biClrUsed = 0;
    lpbi->bmiHeader.biClrImportant = 0;

    BYTE* pBits;

    g_hFrameBitmap = CreateDIBSection(
        NULL,                       // DC - we don't need it here
        lpbi,                       // BITMAPINFOHEADER pointer
        DIB_RGB_COLORS,             // palette is in BITMAPINFO, contains RGBQUAD entries (doesn't matter for RGB)
        (void **)&pBits,             // output pointer to bitmap bits
        NULL,
        0 );

    delete[] lpbi;

    SelectObject(g_hFrameDC, (HBITMAP)g_hFrameBitmap);
}

g_hFrameBitmap is 24 bpp DIB selected in memory DC g_hFrameDC. Each frame is copied to this bitmap bits, after this lines (and some other stuff in my project) are drawn in this DC, and bitmap bits are copied back to video frame.
0
 
LVL 1

Expert Comment

by:ppk1981
ID: 10789955
Hi,

if you can get the window handles of your programs windows, but not others......

You can call "GetDC" function to get the "display device context" handle for the client area of that window.
And can draw anything...

check this link..
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/devcons_4esj.asp

To draw line you can use "Line Functions"

--> MoveToEx
--> LineTo

check this link....

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/linecurv_8bn7.asp

If you are using win32 i.e WinMain()
Then in the WM_PAINT Message of "Window Procedure" you have to call line functions.

praveen
0
 
LVL 48

Accepted Solution

by:
AlexFM earned 250 total points
ID: 10790673
By the way, you can draw line manually setting pixel values in lpVHdr->lpData array. Drawing horizontal line may be done using memset, drawing of vertical line may be done in loop calculating every pixel address.

LRESULT CALLBACK FrameCallback(HWND hWnd, LPVIDEOHDR lpVHdr)
{
    // change pixels here directly setting them using lpVHdr->lpData array.
    // Each pixel gets 3 bytes (assuming video format is RGB).
    // If you know image size, you have enough information to do this.

    // Example:
    memset(lpVHdr->lpData, 0, 300);   // first 100 pixels in the video capture imahe will be black
}

Which approach to use - it depends on complexity of graphics overlay you want to draw. Simple line may be drawn by direct pixel access. Complicated overlay is better to draw using device context.
0
 
LVL 48

Expert Comment

by:AlexFM
ID: 10992840
I think my answer is OK.
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Excel/Word Add-in in what language? 5 143
Would like to move button in a function 3 84
How to print into std::string like sprintf using C++11? 12 118
Need some help with mailto 16 33
Errors will happen. It is a fact of life for the programmer. How and when errors are detected have a great impact on quality and cost of a product. It is better to detect errors at compile time, when possible and practical. Errors that make their wa…
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

749 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question