C++中的位图支持
Bitmap Support In C++
下面是我从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。
相关文章:
- C / C++ 移位/偏移/向左或向右移动位图?
- 如何在快板的屏幕中显示子位图的绘制?
- CreateDIBSection为同一图像返回不一致的位图位值
- C++ 位图中的 ttc 字体
- 使用 GDI+ 旋转位图,然后转换为 HDC
- 难以从 CImageList 设置菜单项位图
- 如何将位图拉伸到父面板(wxWidgets 自定义)
- 如何使用 freetype2 访问单色位图中的像素状态
- 将位图 (bmp) 转换为具有透明度的 png (Windows c++)
- 安卓工作室 |CPP 文件错误错误: 位图库中对"AndroidBitmap_unlockPixels"的未定义引用
- 位图到垫子/2D 数组
- Gdiplus位图没有Alpha通道
- 如何从路径字符串加载Gdiplus::位图
- 在C++中使用Gdiplus创建透明位图
- 用C++压缩内存中的位图
- C++gdi::内存中的位图到PNG图像
- LoadImage 函数不适用于 ImageMagick 创建的位图图像
- (位图)LoadImage() 返回 NULL,GetLastError() 返回 0
- 将Qt qml文件转换为位图图像
- C++中的位图支持