簡體   English   中英

Bitmap 支持 C++

[英]Bitmap Support In C++

下面是我從 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;
}

我希望該方法返回一個位圖數組,而不是將位圖放置在 Sprite 對象中(作為數組傳入)。 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. 我可以自己處理邏輯,我只需要知道如何處理此代碼並從CreateBitmaps()方法返回幀的Bitmap[]

編輯:在 OP 之前添加了更多內容:

官方 C++ 語言規范不支持位圖。 它可以支持 arrays。

常用的方法是找一個框架,比如QT,wxWidgets等,用它們的庫來展示位圖。

更復雜的方法是直接使用 Windows API。

使用 Windows API,您可以創建 Bitmap。 所以,而不是這樣做:

pSprite->SetBitmap(pBitmap, m_format);

您應該將指向 Bitmap object 的指針作為參數傳遞給 CreateBitmap function,然后在 ZC194F14507ZC14Z 中使用它

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

在上面,將 *scan0 替換為指向 bitmap 數據的指針(我相信您的代碼是 pBitmap)和來自 m_Format 變量的有關高度、寬度、像素格式等信息的 rest。

這應該適合你。

注意:請包含所有 GDI+ 頭文件,因為 Bitmap class 是其中的一部分。

希望這可以幫助。

PS如果您不喜歡使用 GDI+ 類,您可以嘗試 MSDN 作為 Windows GDI 的一部分提供的 bitmap object。 雖然就個人而言,我覺得它提供的功能少了很多,而且編碼時間也更長。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM