// 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...{ 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 ...{ // 获取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 ...{ // 计算当前点的灰度值,采用的RGB转换灰度的公式是GRAY = (R+G+B)/3 graycolor = (pixels[i*3] +pixels[i*3+1]+pixels[i*3+2])/3; // 检测该灰度色是否之前出现过 for(j=0;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; } }
|