扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
// MovieGrabberDLL.cpp : 定义 DLL 应用程序的入口点。
//
#include "stdafx.h"
#include "MovieGrabberDLL.h"
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
...{
switch (ul_reason_for_call)
...{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

/**//**
* 抓取视频的截图
* @param aPath 视频文件的位置
* @return
*/
MOVIEGRABBERDLL_API HANDLE GrabMovieFrame(LPCTSTR aPath,int grayColorCountThreshold)
...{
HRESULT hr;
// 定义IMediaDet接口实例
CComPtr< IMediaDet > pDet;
hr = pDet.CoCreateInstance(__uuidof(MediaDet));
if (FAILED(hr))
return NULL;
// 将影片文件名转换成BSTR类型
CComBSTR openBSTR(aPath);
// 设置IMediaDet接口的文件关联
hr = pDet->put_Filename(openBSTR);
if (FAILED(hr))
return NULL;
// 从影片中检索视频流和音频流
long lStreams;
hr = pDet->get_OutputStreams(&lStreams);
if (FAILED(hr))
return NULL;
// 取出影片的视频流,因为帧的信息是保存在视频流中的
bool bFound = false;
for (int i=0; i<lStreams; i++)
...{
GUID major_type;
hr = pDet->put_CurrentStream(i);
if (SUCCEEDED(hr))
hr = pDet->get_StreamType(&major_type);
if (FAILED(hr))
break;
if (major_type == MEDIATYPE_Video)
...{
bFound = true;
break;
}
}
if (!bFound)
return NULL;
long width = 0, height = 0; // 存储位图的宽和高(单位:象素)
AM_MEDIA_TYPE mt;
hr = pDet->get_StreamMediaType(&mt);
if (SUCCEEDED(hr))
...{
if ((mt.formattype == FORMAT_VideoInfo) &&
(mt.cbFormat >= sizeof(VIDEOINFOHEADER)))
...{
// 得到VIDEOINFOHEADER结构指针,VIDEOINFOHEADER结构包含一些与视频
// 有关的信息,其中含有BITMAPINFORHEADER结构
VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)(mt.pbFormat);
width = pVih->bmiHeader.biWidth;
height = pVih->bmiHeader.biHeight;
if(height < 0 ) height *= -1;
}
else
hr = VFW_E_INVALIDMEDIATYPE;
MyFreeMediaType(mt); // 释放AM_MEDIA_TYPE结构
}
if (FAILED(hr))
return NULL;
return (HANDLE)LookforSuitableMovieFrame(pDet,width,height,grayColorCountThreshold);
}

/**//**
* 写入合适视频帧截图到磁盘
* @param pDet DirectShow的IMediaDet接口
* @param width 截图的长
* @param height 截图的宽
* @param grayColorCountThreshold 灰度颜色个数阈值
*/
HBITMAP LookforSuitableMovieFrame(IMediaDet* pDet,int width,int height,int grayColorCountThreshold)
...{
long size;
double time = 0.0;
double totaltime;
// 获取整个视频的时间长度
pDet->get_StreamLength(&totaltime);
// 每1秒,截取视频截图
for(time=0.0; time <totaltime; time+= 1.0) 
...{
// 获取bitmap的buffer大小
HRESULT hr = pDet->GetBitmapBits(time, &size, 0, width, height);
if (SUCCEEDED(hr)) 
...{
char *pBuffer = new char[size];
if (!pBuffer)
return NULL;
hr = pDet->GetBitmapBits(time, 0, pBuffer, width, height);
if (SUCCEEDED(hr))
...{
// Find the address of the start of the image data.
void *pData = pBuffer + sizeof(BITMAPINFOHEADER);
if(IsSuitableMovieFrame(pData,width,height,grayColorCountThreshold))
...{
BITMAPINFOHEADER *bmih = (BITMAPINFOHEADER*)pBuffer;
HDC hdcDest = GetDC(0);
BITMAPINFO bmi;
ZeroMemory(&bmi, sizeof(BITMAPINFO));
CopyMemory(&(bmi.bmiHeader), bmih, sizeof(BITMAPINFOHEADER));
HBITMAP hBitmap = CreateDIBitmap(hdcDest, bmih, CBM_INIT,
pData, &bmi, DIB_RGB_COLORS);
delete[] pBuffer;
return hBitmap;
}
}
delete[] pBuffer;
}
}
return NULL;
}

/**//**
* 检测一个位图是否是合适的视频截图
* @param pData 位图的点色数组
* @param width 位图的长
* @param height 位图的宽
* @param grayColorCountThreshold 灰度颜色个数阈值
*/
bool IsSuitableMovieFrame(void* pData,int width,int height,int grayColorCountThreshold)
...{
BYTE* pixels = (BYTE*)pData;
int numGrayColor = 0;
int size = width*height;
int graycolor;
int i,j;
int* appearedcolors = new int[grayColorCountThreshold];
int numappearedcolors = 0;
for(i=0;i<size; i++) 
...{
// 计算当前点的灰度值,采用的RGB转换灰度的公式是GRAY = (R+G+B)/3
graycolor = (pixels[i*3] +pixels[i*3+1]+pixels[i*3+2])/3;
// 检测该灰度色是否之前出现过
for(j=0;j<numappearedcolors; j++) 
...{
if(graycolor == appearedcolors[j])
break;
}
if(j == numappearedcolors) // 如果是新的灰度颜色值
...{
numappearedcolors++;
if(numappearedcolors == grayColorCountThreshold) // 如果灰度颜色个数满足阈值
...{
delete[] appearedcolors;
return true; // 返回信息,合适
}
else
...{
appearedcolors[j] = graycolor; // 记录下该灰度颜色值
}
}
}
delete[] appearedcolors;
return false; // 返回信息,不合适
}
void MyFreeMediaType(AM_MEDIA_TYPE& mt)
...{
if(mt.cbFormat != 0)
...{
CoTaskMemFree((PVOID)mt.pbFormat);
mt.cbFormat = 0;
}
if (mt.pUnk != NULL)
...{
mt.pUnk->Release();
mt.pUnk = NULL;
}
}如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。