C++中的位图支持

Bitmap Support In C++

本文关键字:支持 位图 C++      更新时间:2023-10-16

下面是我从MSDN示例中截取的一个片段,该示例基本上是以选定的间隔将视频流剪切成小缩略图:

 //-------------------------------------------------------------------
// 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;
}

我希望该方法返回位图数组,而不是将位图放置在Sprite对象中(作为数组传入(。MSDN建议确实存在用于C++的Bitmap类,尽管我似乎不能在这个类中包含对它的引用。我想做的是最终将这个类编译为DLL,并在我的C#项目中使用它,在那里我可以将uri传递给电影,并将其切碎,然后从这些方法中作为位图帧返回。我可以自己处理逻辑,我只需要知道如何使此代码处理并从CreateBitmaps()方法返回帧的Bitmap[]

使用Windows API,您可以创建位图。所以,与其这么做:

pSprite->SetBitmap(pBitmap, m_format);

您应该将指向位图对象的指针作为参数传递给CreateBitmap函数,然后在函数中使用它:

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

在上面的代码中,将*scan0替换为指向以字节为单位的位图数据的指针(我相信您的代码中是pBitmap(,以及m_Format变量中关于高度、宽度、pixelFormat等的其余信息。

这应该对你有用。

注意:请包括所有GDI+标头,因为位图类是其中的一部分。

希望这能有所帮助。

p.S.如果您不喜欢使用GDI+类,可以尝试MSDN作为Windows GDI的一部分提供的位图对象。尽管就我个人而言,我觉得它提供的功能要少得多,而且编写代码需要更长的时间。

编辑:在O.P.之前添加更多内容:

官方的C++语言规范不支持位图。不过它可以支持数组。

常见的方法是找到一个框架,如QT、wxWidgets等,并使用它们的库来显示位图。

更复杂的方法是直接使用Windows API。