简体   繁体   English

Bitmap 支持 C++

[英]Bitmap Support In C++

Below is a snippet I've taken from an MSDN example that basically chops a video stream in to small thumbnails at selected intervals:下面是我从 MSDN 示例中截取的片段,该示例基本上以选定的间隔将视频 ZF7B44CFFAFD5C52223D5498196C8A2E7BZ 切成小缩略图:

 //-------------------------------------------------------------------
// 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, 
        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.我希望该方法返回一个位图数组,而不是将位图放置在 Sprite 对象中(作为数组传入)。 MSDN suggests Bitmap class does exist for C++ though I can't seem to include a reference to it for this class. MSDN 建议 Bitmap class 确实存在于 C++ 虽然我似乎无法包含对这个 ZA2F2ED4F8EBC21CBB4DC20 的引用。 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. 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.我可以自己处理逻辑,我只需要知道如何处理此代码并从CreateBitmaps()方法返回帧的Bitmap[]

Edit: Before OP Added more content:编辑:在 OP 之前添加了更多内容:

The official C++ language specification does not support bitmaps.官方 C++ 语言规范不支持位图。 It can support arrays though.它可以支持 arrays。

The common method is to find a framework, such as QT, wxWidgets, etc., and use their libraries for displaying bitmaps.常用的方法是找一个框架,比如QT,wxWidgets等,用它们的库来展示位图。

A more complex method is to use the Windows API directly.更复杂的方法是直接使用 Windows API。

Using the Windows API, you can create a Bitmap.使用 Windows API,您可以创建 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:您应该将指向 Bitmap object 的指针作为参数传递给 CreateBitmap function,然后在 ZC194F14507ZC14Z 中使用它

  *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.在上面,将 *scan0 替换为指向 bitmap 数据的指针(我相信您的代码是 pBitmap)和来自 m_Format 变量的有关高度、宽度、像素格式等信息的 rest。

This should work for you.这应该适合你。

Note: Please include all the GDI+ headers as Bitmap class is a part of it.注意:请包含所有 GDI+ 头文件,因为 Bitmap class 是其中的一部分。

Hope this helps.希望这可以帮助。

PS If you are averse to using the GDI+ classes, you can try the bitmap object which MSDN offers as part of Windows GDI. PS如果您不喜欢使用 GDI+ 类,您可以尝试 MSDN 作为 Windows GDI 的一部分提供的 bitmap object。 Though personally, I feel that it offers a lot less functionality and it takes longer to code.虽然就个人而言,我觉得它提供的功能少了很多,而且编码时间也更长。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM