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:
//-------------------------------------------------------------------
// 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.
精彩评论