开发者

Bitmap Support In C++

开发者 https://www.devze.com 2023-03-16 15:57 出处:网络
Below is a snippet I\'ve taken from an MSDN example that basically chops a video stream in to small thumbnails at selected intervals:

Below is a snippet I've taken from an MSDN example that basically chops a video stream in to small thumbnails at selected intervals:

 //-------------------------------------------------------------------
// CreateBitmaps
//
// Creates an array of thumbnails from the video file.
//
// pRT:      Direct2D render target. Used to create the bitmaps.
// count:    Number of thumbnails to create.
// pSprites: An array of Sprite objects to hold the bitmaps.
//
// Note: The caller allocates the sprite objects.
//-------------------------------------------------------------------

HRESULT ThumbnailGenerator::CreateBitmaps(
ID2D1RenderTarget *pRT, 
DWORD count, 
Sprite pSprites[]
)
{
HRESULT hr = S_OK;
BOOL bCanSeek = 0;

LONGLONG hnsDuration = 0;
LONGLONG hnsRangeStart = 0;
LONGLONG hnsRangeEnd = 0;
LONGLONG hnsIncrement = 0;

hr = CanSeek(&bCanSeek);

if (FAILED(hr)) { return hr; }

if (bCanSeek)
{
    hr = GetDuration(&hnsDuration);

    if (FAILED(hr)) { return hr; }

    hnsRangeStart = 0;
    hnsRangeEnd = hnsDuration;

    // We have the file duration , so we'll take bitmaps from
    // several positions in the file. Occasionally, the first frame 
    // in a video is black, so we don't start at time 0.

    hnsIncrement = (hnsRangeEnd - hnsRangeStart) / (count + 1);

}

// Generate the bitmaps and invalidate the button controls so
// they will be redrawn.
for (DWORD i = 0; i < count; i++)
{
    LONGLONG hPos = hnsIncrement * (i + 1);

    hr = CreateBitmap(
        pRT, 
        hPos, 
        &pSprites[i]
    );
}

return hr;
}


//
/// Private methods
//

//-------------------------------------------------------------------
 // CreateBitmap
 //
// Creates one video thumbnail.
//
// pRT:      Direct2D render target. Used to create the bitmap.
// hnsPos:   The seek position.
// pSprite:  A Sprite object to hold the bitmap.
//-------------------------------------------------------------------

HRESULT ThumbnailGenerator::CreateBitmap(
ID2D1RenderTarget *pRT, 
LONGLONG& hnsPos, 
Sprite *pSprite
)
{
HRESULT     hr = S_OK;
DWORD       dwFlags = 0;

BYTE        *pBitmapData = NULL;    // Bitmap data
DWORD       cbBitmapData = 0;       // Size of data, in bytes
LONGLONG    hnsTimeStamp = 0;
BOOL        bCanSeek = FALSE;       // Can the source seek?  
DWORD       cSkipped = 0;           // Number of skipped frames

IMFMediaBuffer *pBuffer = 0;
IMFSample *pSample = NULL;
ID2D1Bitmap *pBitmap = NULL;

hr = CanSeek(&bCanSeek);
if (FAILED(hr)) 
{ 
    return hr; 
}

if (bCanSeek && (hnsPos > 0))
{
    PROPVARIANT var;
    PropVariantInit(&var);

    var.vt = VT_I8;
    var.hVal.QuadPart = hnsPos;

    hr = m_pReader->SetCurrentPosition(GUID_NULL, var);

    if (FAILED(hr)) { goto done; }

}


// Pulls video frames from the source reader.

// NOTE: Seeking might be inaccurate, depending on the container
//       format and how the file was indexed. Therefore, the first
//       frame that we get might be earlier than the desired time.
//       If so, we skip up to MAX_FRAMES_TO_SKIP frames.

while (1)
{
    IMFSample *pSampleTmp = NULL;

    hr = m_pReader->ReadSample(
        (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, 
        0,开发者_如何学C 
        NULL, 
        &dwFlags, 
        NULL, 
        &pSampleTmp
        );

    if (FAILED(hr)) { goto done; }

    if (dwFlags & MF_SOURCE_READERF_ENDOFSTREAM)
    {
        break;
    }

    if (dwFlags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)
    {
        // Type change. Get the new format.
        hr = GetVideoFormat(&m_format);

        if (FAILED(hr)) { goto done; }
    }

    if (pSampleTmp == NULL)
    {
        continue;
    }

    // We got a sample. Hold onto it.

    SafeRelease(&pSample);

    pSample = pSampleTmp;
    pSample->AddRef();

    if (SUCCEEDED( pSample->GetSampleTime(&hnsTimeStamp) ))
    {
        // Keep going until we get a frame that is within tolerance of the
        // desired seek position, or until we skip MAX_FRAMES_TO_SKIP frames.

        // During this process, we might reach the end of the file, so we
        // always cache the last sample that we got (pSample).

        if ( (cSkipped < MAX_FRAMES_TO_SKIP) && 
             (hnsTimeStamp + SEEK_TOLERANCE < hnsPos) )  
        {
            SafeRelease(&pSampleTmp);

            ++cSkipped;
            continue;
        }
    }

    SafeRelease(&pSampleTmp);

    hnsPos = hnsTimeStamp;
    break;
 }

 if (pSample)
 {
    UINT32 pitch = 4 * m_format.imageWidthPels; 

    // Get the bitmap data from the sample, and use it to create a
    // Direct2D bitmap object. Then use the Direct2D bitmap to 
    // initialize the sprite.

    hr = pSample->ConvertToContiguousBuffer(&pBuffer);

    if (FAILED(hr)) { goto done; }

    hr = pBuffer->Lock(&pBitmapData, NULL, &cbBitmapData);

    if (FAILED(hr)) { goto done; }

    assert(cbBitmapData == (pitch * m_format.imageHeightPels));

    hr = pRT->CreateBitmap( 
        D2D1::SizeU(m_format.imageWidthPels, m_format.imageHeightPels),
        pBitmapData,
        pitch,
        D2D1::BitmapProperties( 
            // Format = RGB32
            D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE) 
            ),
        &pBitmap
        );

    if (FAILED(hr)) { goto done; }

    pSprite->SetBitmap(pBitmap, m_format);
    }
    else
    {
    hr = MF_E_END_OF_STREAM;
    }

done:

if (pBitmapData)
{
    pBuffer->Unlock();
}
SafeRelease(&pBuffer);
SafeRelease(&pSample);
SafeRelease(&pBitmap);

return hr;
}

Instead of the bitmaps being placed inside the Sprite objects (passed in as an array), I want the method to return an array of Bitmaps. MSDN suggests Bitmap class does exist for C++ though I can't seem to include a reference to it for this class. What I want to do is compile this class as a DLL eventually and use it in my C# project where I can pass a uri to a movie and have it chopped up and returned as Bitmap frames from these methods. I can take care of the logic myself, I just need to know how I could make this code handle and return a Bitmap[] of the frames from the CreateBitmaps() method.


Using the Windows API, you can create a Bitmap. So, instead of doing:

pSprite->SetBitmap(pBitmap, m_format);

You should pass a pointer to a Bitmap object as a parameter to the CreateBitmap function and then use this in the function:

  *pBitmap =  new Bitmap(INT width, INT height, INT stride, PixelFormat format, BYTE *scan0);

In the above, replace *scan0 with the pointer to the bitmap data in bytes (which I believe in your code is pBitmap) and the rest of the information regarding the height, width, pixelFormat etc, from the m_Format variable.

This should work for you.

Note: Please include all the GDI+ headers as Bitmap class is a part of it.

Hope this helps.

P.S. If you are averse to using the GDI+ classes, you can try the bitmap object which MSDN offers as part of Windows GDI. Though personally, I feel that it offers a lot less functionality and it takes longer to code.


Edit: Before O.P. Added more content:

The official C++ language specification does not support bitmaps. It can support arrays though.

The common method is to find a framework, such as QT, wxWidgets, etc., and use their libraries for displaying bitmaps.

A more complex method is to use the Windows API directly.

0

精彩评论

暂无评论...
验证码 换一张
取 消