?? mjpeg2bmp.cpp
字號:
#define INITGUID
#include <windows.h> // For all that Windows stuff
#include <stdlib.h>
#include <stdio.h>
#include <imaging.h>
#if _WIN32_WCE >= 500
#include <GdiPlusEnums.h>
#endif
#define GETZONESONLY
#include "CameraCode.h" // Only needed for ZONE_ constants
#include "StreamFrame.h"
#include "mjpeg2bmp.h"
enum CodecType {eDecoder, eEncoder};
#define NAMEVALENTRY(x) { (LONG)(x), TEXT(#x) }
struct NameValuePair {
LONG pValue;
TCHAR *szName;
};
//void info (const TCHAR* tszFormat, ...);
IImagingFactory *pImagingFactory = NULL;
//----------------------------------------------------------------------
// InitDisplayFrame
//
HRESULT InitDisplayFrame (LPCWSTR pszExt)
{
HRESULT hr;
BOOL fFound = FALSE;
// Get length of search extension
int nLen = pszExt ? lstrlen (pszExt) : 0;
if (FAILED(hr = CoInitializeEx(NULL, COINIT_MULTITHREADED)))
{
DEBUGMSG (ZONE_ERROR, (TEXT("CoInitializeEx failed, hr: 0x%08x\r\n"), hr));
return 1;
}
hr = CoCreateInstance(CLSID_ImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_IImagingFactory,
(void**) &pImagingFactory);
if (FAILED(hr))
return hr;
//
// Query current installed codecs
//
ImageCodecInfo *pCodecInfo;
UINT uCnt = 0;
hr = pImagingFactory->GetInstalledDecoders (&uCnt, &pCodecInfo);
if (SUCCEEDED(hr))
{
DEBUGMSG (ZONE_INIT, (TEXT ("Detected %d decoders\r\n"), uCnt));
for (UINT i = 0; i < uCnt; i++)
{
if (nLen &&
(_wcsnicmp(pCodecInfo[i].FormatDescription, pszExt, nLen) == 0))
fFound = TRUE;
DEBUGMSG (ZONE_INIT, (TEXT("Name >%S<\r\n"), pCodecInfo[i].CodecName));
DEBUGMSG (ZONE_INIT, (TEXT("Desc >%S<\r\n\r\n"), pCodecInfo[i].FormatDescription));
}
CoTaskMemFree ((PVOID)pCodecInfo);
}
// See if we were supposed to find specific support and didn't find it
if (!hr && nLen && !fFound)
{
pImagingFactory->Release();
hr = ERROR_NOT_SUPPORTED;
}
return hr;
}
//----------------------------------------------------------------------
// Frees the imaging library
//
HRESULT ReleaseDisplayFrame ()
{
HRESULT hr = 0;
if (pImagingFactory)
{
pImagingFactory->Release();
pImagingFactory = NULL;
}
return hr;
}
BYTE MJPG2JPGHdr[440] = {
// JPEG file header
0xff,0xd8, // SOI
0xff,0xe0, // APP0
0x00,0x10, // APP0 Hdr size
0x4a,0x46,0x49,0x46,0x00, // ID string
0x01,0x01, // Version
0x00, // Bits per type
0x00, 0x00, // X density
0x00, 0x00, // Y density
0x00, // X Thumbnail size
0x00, // Y Thumbnail size
/* JPEG DHT Segment for YCrCb omitted from MJPG data */
0xFF,0xC4,0x01,0xA2,
0x00,0x00,0x01,0x05,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x01,0x00,0x03,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
0x08,0x09,0x0A,0x0B,0x10,0x00,0x02,0x01,0x03,0x03,0x02,0x04,0x03,0x05,0x05,0x04,0x04,0x00,
0x00,0x01,0x7D,0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,
0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xA1,0x08,0x23,0x42,0xB1,0xC1,0x15,0x52,0xD1,0xF0,0x24,
0x33,0x62,0x72,0x82,0x09,0x0A,0x16,0x17,0x18,0x19,0x1A,0x25,0x26,0x27,0x28,0x29,0x2A,0x34,
0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x53,0x54,0x55,0x56,
0x57,0x58,0x59,0x5A,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x73,0x74,0x75,0x76,0x77,0x78,
0x79,0x7A,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,
0x9A,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,
0xBA,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,
0xDA,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
0xF8,0xF9,0xFA,0x11,0x00,0x02,0x01,0x02,0x04,0x04,0x03,0x04,0x07,0x05,0x04,0x04,0x00,0x01,
0x02,0x77,0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,
0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,0xA1,0xB1,0xC1,0x09,0x23,0x33,0x52,0xF0,0x15,0x62,
0x72,0xD1,0x0A,0x16,0x24,0x34,0xE1,0x25,0xF1,0x17,0x18,0x19,0x1A,0x26,0x27,0x28,0x29,0x2A,
0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x53,0x54,0x55,0x56,
0x57,0x58,0x59,0x5A,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x73,0x74,0x75,0x76,0x77,0x78,
0x79,0x7A,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x92,0x93,0x94,0x95,0x96,0x97,0x98,
0x99,0x9A,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,
0xB9,0xBA,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,
0xD9,0xDA,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,
0xF9,0xFA
};
//----------------------------------------------------------------------
// GetBitMapImage
//
HRESULT GetBitMapImage (PBYTE pData, DWORD dwPreBuff, DWORD dwSize,
IBitmapImage **ppBitmapImage, PBMPFMT pbmpfmt)
{
HRESULT hr;
IImageSink *pImageSink = NULL;
IImageDecoder *pImageDecoder = NULL;
IBitmapImage *pBitmapImage = NULL;
IStream *pStream = NULL;
ImageInfo ii;
LPBYTE pLocal = 0;
if (pImagingFactory == NULL)
return E_NOINTERFACE;
if (*pData == 0)
return 0;
int MjpegHdrSize = *(pData+4);
MjpegHdrSize = MjpegHdrSize << 8;
MjpegHdrSize += *(pData+5)+4;
if (MjpegHdrSize > 100)
return -2;
#if 1
// Slow way copies the data to a seperate heap allocation. This seems to be needed for the
// CreateStreamOnHGlobal method because that method looks at the heap block header to determine
// the size of the data.
// Data is in big endian format
pLocal = (LPBYTE)LocalAlloc (LPTR, dwSize+512);
if (!pLocal)
return -1;
memcpy (pLocal, MJPG2JPGHdr, sizeof (MJPG2JPGHdr));
memcpy (pLocal + sizeof (MJPG2JPGHdr), pData + MjpegHdrSize, dwSize - MjpegHdrSize);
// Create the stream
hr = CreateStreamOnHGlobal(pLocal, TRUE, &pStream);
#endif
#if 0
// This way also copies the data but then uses an custom stream
// interface to expose the data.
pLocal = (LPBYTE)LocalAlloc (LPTR, dwSize+512);
if (!pLocal)
return -1;
memcpy (pLocal, MJPG2JPGHdr, sizeof (MJPG2JPGHdr));
memcpy (pLocal + sizeof (MJPG2JPGHdr), pData + MjpegHdrSize, dwSize - MjpegHdrSize);
// Create the stream
FrameStream *pfs = new FrameStream (pLocal, dwSize + 512);
hr = pfs->QueryInterface (__uuidof(IStream)/*IID_IStream*/, (void **)&pStream);
#endif
#if 0
// Add JPEG header to MJPEG frame data. We need to also remove the MJPEG info at the start of the frame
// Data is in big endian format.
// Expose the data in custom stream interface.
PBYTE pPreBuff = pData + MjpegHdrSize - sizeof (MJPG2JPGHdr);
memcpy (pPreBuff, MJPG2JPGHdr, sizeof (MJPG2JPGHdr));
FrameStream *pfs = new FrameStream (pPreBuff, dwSize + sizeof (MJPG2JPGHdr) - MjpegHdrSize);
hr = pfs->QueryInterface (__uuidof(IStream)/*IID_IStream*/, (void **)&pStream);
#endif
__try
{
if (FAILED(hr))
{
DEBUGMSG (ZONE_ERROR, (TEXT("Create stream failed, hr: 0x%08x\r\n"), hr));
goto finish;
}
// Get the decoder. The system chooses the proper decoder
// from the format of the data in the buffer.
if (FAILED(hr = pImagingFactory->CreateImageDecoder(pStream, DecoderInitFlagBuiltIn1st, &pImageDecoder)))
{
DEBUGMSG (ZONE_ERROR, (TEXT("CreateImageDecoder failed, hr: 0x%08x\r\n"), hr));
goto finish;
}
// Query image info
if (FAILED(hr = pImageDecoder->GetImageInfo(&ii)))
{
DEBUGMSG (ZONE_ERROR, (TEXT("GetImageInfo failed, hr: 0x%08x\r\n"), hr));
goto finish;
}
// Save the width and height
pbmpfmt->nHeight = ii.Height;
pbmpfmt->nWidth = ii.Width;
pbmpfmt->PixelFormat = ii.PixelFormat;
// Create bitmap of the same size
if (FAILED(hr = pImagingFactory->CreateNewBitmap(ii.Width, ii.Height, ii.PixelFormat, &pBitmapImage)))
{
DEBUGMSG (ZONE_ERROR, (TEXT("CreateNewBitmap failed, hr = 0x%08x\r\n"), hr));
goto finish;
}
// Get the "sink" which is needed by the decoder so it can write the data to the bitmap
if (FAILED(hr = pBitmapImage->QueryInterface(IID_IImageSink, (void**)&pImageSink)))
{
DEBUGMSG (ZONE_ERROR, (TEXT("QueryInterface for ImageSink from BitmapImage failed, hr: 0x%08x\r\n"), hr));
goto finish;
}
// Finally, start the conversion
if (FAILED(hr = pImageDecoder->BeginDecode(pImageSink, NULL)))
{
DEBUGMSG (ZONE_ERROR, (TEXT("BeginDecode into Bitmap Image failed, hr = 0x%08d\r\n"), hr));
goto finish;
}
// Loop as necessary
while (E_PENDING == (hr = pImageDecoder->Decode()))
Sleep(100);
if (hr != S_OK)
{
DEBUGCHK ((TEXT("Bad decode hr = %08x\r\n"), hr));
}
// Clean up
hr = pImageDecoder->EndDecode(hr);
if (FAILED(hr))
{
DEBUGMSG (ZONE_DECODING, (TEXT("Decoding failed, hr = 0x%08x\r\n"), hr));
// If fail to decode, release block
if (pLocal)
LocalFree (pLocal);
goto finish;
}
DEBUGMSG (ZONE_DECODING, (TEXT("img size %d\r\n"), dwSize));
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
DEBUGMSG (ZONE_ERROR, (TEXT ("Exception decoding image \r\n")));
}
finish:
if (pImageSink)
pImageSink->Release();
pImageSink = NULL;
if (pImageSink)
pImageSink->Release();
pImageSink = NULL;
if (pImageDecoder)
pImageDecoder->Release();
pImageDecoder = NULL;
if (pStream)
pStream->Release();
pStream = NULL;
if (!FAILED(hr))
*ppBitmapImage = pBitmapImage;
return hr;
}
//----------------------------------------------------------------------
// DisplayFrame
//
HRESULT DisplayFrame (PBYTE pData, DWORD dwPreBuff, DWORD dwSize, HDC hdc, RECT *pRect)
{
HRESULT hr;
IImage *pImage = NULL;
IBitmapImage *pBitmapImage = NULL;
BMPFMT bmpf;
hr = GetBitMapImage (pData, dwPreBuff, dwSize, &pBitmapImage, &bmpf);
__try
{
if (SUCCEEDED(hr))
{
//
// We have a bitmap at this point. Get Image interface and draw
//
if (SUCCEEDED(hr = pBitmapImage->QueryInterface(IID_IImage, (void**)&pImage)))
hr = pImage->Draw (hdc, pRect, NULL);
else
DEBUGMSG (ZONE_ERROR, (TEXT("QueryInterface for Image from BitmapImage failed, hr: 0x%08x\r\n"), hr));
}
else
DEBUGMSG (ZONE_DECODING, (TEXT("Decoding failed, hr = 0x%08x\r\n"), hr));
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
DEBUGMSG (ZONE_ERROR, (TEXT ("Exception decoding image \r\n")));
}
if (pImage)
pImage->Release();
pImage = NULL; // This is already deleted above, but just to make sure...
if (pBitmapImage)
pBitmapImage->Release();
pBitmapImage = NULL;
return hr;
}
//----------------------------------------------------------------------
// DisplayBitmap
//
HRESULT DisplayBitmap (IBitmapImage *pBitmapImage, HDC hdc, RECT *pRect)
{
HRESULT hr;
IImage *pImage = NULL;
__try
{
//
// We have a bitmap at this point. Get Image interface and draw
//
if (SUCCEEDED(hr = pBitmapImage->QueryInterface(IID_IImage, (void**)&pImage)))
hr = pImage->Draw (hdc, pRect, NULL);
else
DEBUGMSG (ZONE_ERROR, (TEXT("QueryInterface for Image from BitmapImage failed, hr: 0x%08x\r\n"), hr));
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
DEBUGMSG (ZONE_ERROR, (TEXT ("Exception decoding image \r\n")));
}
if (pImage)
pImage->Release();
return hr;
}
//----------------------------------------------------------------------
// IsMotionDetected - This routine compares two bitmaps to see if they
// are different above a given threshold.
//
// Code based on a submission by Onkar Singh Parhar.
// (The bugs are mine. DB)
//
BOOL IsMotionDetected (IBitmapImage* pBitmapImage, IBitmapImage* pBitmapImageOld,
PBMPFMT pbmpf, DWORD dwSenstivity)
{
int k = 0;
int red = 0;
int green = 0;
int blue = 0;
int iNoMotionDetectedThreshold = 0;
long MoreThreshCnt=0; // reset the thresh counter
int TreshPerix = 18;
float TreshPerixUnit = ((float)50/24);
PCHAR lpByte1 = NULL;
PCHAR lpByte2 = NULL;
int size1 = NULL;
int size2 = NULL;
int size = NULL;
int bytesPerPixel = 3; // for 24 bits
USHORT pixel = 0;
HRESULT hr = S_OK;
double dSenstivityFactor = 0.006;
RECT rect = {0};
rect.right = pbmpf->nWidth;
rect.bottom = pbmpf->nHeight;
BitmapData lockedBmpData1;
lockedBmpData1.Reserved = 0;
hr = pBitmapImageOld->LockBits(&rect, ImageLockModeRead, pbmpf->PixelFormat, &lockedBmpData1);
BitmapData lockedBmpData2;
lockedBmpData2.Reserved = 0;
hr = pBitmapImage->LockBits(&rect, ImageLockModeRead, pbmpf->PixelFormat, &lockedBmpData2);
if (S_OK != hr)
{
lockedBmpData2 = lockedBmpData1;
}
double grey1 = 0, grey2 = 0;
for (int y=0; y<pbmpf->nHeight; y++)
{
for (int x=0; x<pbmpf->nWidth; x++)
{
BYTE* pPixel = (BYTE*)lockedBmpData1.Scan0+(y*lockedBmpData1.Stride)+(x*3);
blue = *pPixel;
green= *(pPixel+1);
red = *(pPixel+2);
grey1 = ceil(0.212671 * red + 0.715160 * green + 0.072169 * blue);
pPixel = (BYTE*)lockedBmpData2.Scan0+(y*lockedBmpData2.Stride)+(x*3);
blue = *pPixel;
green= *(pPixel+1);
red = *(pPixel+2);
grey2 = ceil(0.212671 * red + 0.715160 * green + 0.072169 * blue);
if (abs((int)(grey1-grey2)) > (int)(TreshPerix))
{
// if diff between this pix in prev and cur frame > TreshPerix
MoreThreshCnt++; // increase motion pixels counters
}
}
}
hr = pBitmapImageOld->UnlockBits(&lockedBmpData1);
hr = pBitmapImage->UnlockBits(&lockedBmpData2);
// Set iNoMotionDetectedThreshold to number of pixels that must change
// in the two frames before motion is said to be detected.
// g_iSenstivity is set by the user,
iNoMotionDetectedThreshold = (int)(dSenstivityFactor*dwSenstivity * pbmpf->nWidth * pbmpf->nHeight);
// See if motion detected
if (MoreThreshCnt > iNoMotionDetectedThreshold)
return TRUE;
// No motion detected
return FALSE;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -