原先的编码太慢了,jpg编码要800ms,解码要1000ms,疯了。
于是开始用Imagefactory,经测试320x240的图片jpg编码67ms,解码38ms,太帅了,差距竟然这么大,经过的过程见:
http://topic.csdn.net/u/20121009/00/a4c385d9-62a4-48d7-ba03-a48495ecd068.html
代码如下:
将如下文件放到StdAfx.h中:
#include <imaging.h>
#include <initguid.h>
#include <imgguids.h>
其中imgguids.h要加防止重编译宏,原因见:
http://topic.csdn.net/u/20121011/12/0d353742-82bb-4089-8e40-16d9db489bf7.html?1158181987
.h文件:
#ifndef _JPG_IMGFAC_LIB_H_
#define _JPG_IMGFAC_LIB_H_
void ConvBmp2jpg(char *bmpbuf, int bmpsize, char *jpgbuf, int *jpgsize);
void ConvJpg2bmp(char *jpgbuf, int jpgsize, char *bmpbuf, int *bmpsize);
BOOL CreateStreamOnBuffer(const char * pBuffer, DWORD bufsize, IStream ** ppStream);
BOOL GetEnCodecCLSID(IImagingFactory* pImagingFactory,WCHAR * wszMimeType ,CLSID * pclsid );
#endif
.cpp文件:
#include "StdAfx.h"
#include "jpgimgfaclib.h"
DEFINE_GUID(IID_IImagingFactory, 0x327abda7,0x072b,0x11d3,0x9d,0x7b,0x00,0x00,0xf8,0x1e,0xf3,0x2e);
DEFINE_GUID(CLSID_ImagingFactory, 0x327abda8,0x072b,0x11d3,0x9d,0x7b,0x00,0x00,0xf8,0x1e,0xf3,0x2e);
void ConvBmp2jpg(char *bmpbuf, int bmpsize, char *jpgbuf, int *jpgsize)
{
HRESULT hr;
IImagingFactory * pImagingFactory = NULL ; //Image工厂接口对象
IStream *pStream = NULL; // 流接口对象
IStream *pOutStream = NULL; // 流接口对象
LARGE_INTEGER liTemp = {0};
STATSTG stats={0};
IImageSink *pImageSink = NULL; //Image Sink接口对象
IImageDecoder *pImageDecoder = NULL; //解码器接口对象
IImageEncoder *pImageEncoder = NULL; //编码器接口对象
CLSID clsidEncoder; //编码器CLSID
TCHAR *tszMime = L"image/jpeg"; //指定转换后,图象文件的格式
// tszMime = L"image/bmp"; //指定转换后,图象文件的格式
//初始化COM环境
if (FAILED(hr = CoInitializeEx(NULL, COINIT_MULTITHREADED)))
{
TRACE(L"COINIT_MULTITHREADED ERROR");
return;
}
//得到Image工厂接口对象
hr = CoCreateInstance(CLSID_ImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_IImagingFactory,
(void**) &pImagingFactory);
if (FAILED(hr))
{
TRACE(L"IMAGE FACTORY CREATED ERROR");
goto finish;
}
if (FAILED(hr = CreateStreamOnBuffer(bmpbuf, bmpsize, &pStream)))
{
goto finish;
}
//根据编码器类型名称得到编码器CLSID
if (!GetEnCodecCLSID(pImagingFactory,tszMime, &clsidEncoder ))
{
goto finish;
}
if (FAILED(hr = CreateStreamOnHGlobal(NULL,TRUE,&pOutStream)))
{
goto finish;
}
//创建编码器接口,并关联到输出流中
if (FAILED(hr = pImagingFactory->CreateImageEncoderToStream(&clsidEncoder, pOutStream, &pImageEncoder)))
{
goto finish;
}
//创建解码器接口
if (FAILED(hr = pImagingFactory->CreateImageDecoder(pStream, DecoderInitFlagBuiltIn1st, &pImageDecoder)))
{
goto finish;
}
//得到编码器接口的sink对象。此ImageSink接口作为一个槽或者管道来理解;
//是用于负责pImageEncoder和pImageDecoder之间的传输
if (FAILED(hr = pImageEncoder->GetEncodeSink(&pImageSink)))
{
goto finish;
}
//开始解码
if (FAILED(hr = pImageDecoder->BeginDecode(pImageSink, NULL)))
{
goto finish;
}
//循环解码,直到结束
for(;;)
{
//解码
hr = pImageDecoder->Decode();
//继续解码后面的部分
if (E_PENDING == hr)
{
Sleep(500);
}
//失败
else if (FAILED(hr))
{
//终止解码
pImageDecoder->EndDecode(hr);
goto finish;
}
else
{
//解码成功
break;
}
}
//结束解码
pImageDecoder->EndDecode(hr);
//释放pImageSink对象
pImageSink->Release();
pImageSink = NULL;
//结束编码,此时就已经完成了文件格式的转换
pImageEncoder->TerminateEncoder();
pOutStream->Stat(&stats, 0);
*jpgsize = (int)stats.cbSize.QuadPart;
pOutStream->Seek(liTemp, STREAM_SEEK_SET, NULL);
pOutStream->Read(jpgbuf, (unsigned long)stats.cbSize.QuadPart, NULL);
finish:
//释放pStream对象
if (pStream)
pStream->Release();
if (pOutStream)
pOutStream->Release();
//释放pImageSink对象
if (pImageSink)
pImageSink->Release();
//释放pImageDecoder对象
if (pImageDecoder)
pImageDecoder->Release();
//释放pImageEncoder对象
if (pImageEncoder)
pImageEncoder->Release();
//释放IImagingFactory接口对象
if (pImagingFactory)
pImagingFactory->Release();
//释放程序占用的COM资源
CoUninitialize();
}
//虽然是到Stream,但转换出来是完整的图像文件,可能需要用完整的图像文件获取图像参数之类的
void ConvJpg2bmp(char *jpgbuf, int jpgsize, char *bmpbuf, int *bmpsize)
{
HRESULT hr;
IImagingFactory * pImagingFactory = NULL ; //Image工厂接口对象
IStream *pStream = NULL; // 流接口对象
IStream *pOutStream = NULL; // 流接口对象
LARGE_INTEGER liTemp = {0};
STATSTG stats={0};
IImageSink *pImageSink = NULL; //Image Sink接口对象
IImageDecoder *pImageDecoder = NULL; //解码器接口对象
IImageEncoder *pImageEncoder = NULL; //编码器接口对象
CLSID clsidEncoder; //编码器CLSID
TCHAR *tszMime = L"image/bmp"; //指定转换后,图象文件的格式
// tszInFileName = L"\\1.jpg"; //指定待转换的图象文件
// tszOutFileName = L"\\11.bmp"; //指定转换后的图象文件
// tszMime = L"image/bmp"; //指定转换后,图象文件的格式
//初始化COM环境
if (FAILED(hr = CoInitializeEx(NULL, COINIT_MULTITHREADED)))
{
TRACE(L"COINIT_MULTITHREADED ERROR");
return;
}
//得到Image工厂接口对象
hr = CoCreateInstance(CLSID_ImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_IImagingFactory,
(void**) &pImagingFactory);
if (FAILED(hr))
{
TRACE(L"IMAGE FACTORY CREATED ERROR");
goto finish;
}
if (FAILED(hr = CreateStreamOnBuffer(jpgbuf, jpgsize, &pStream)))
{
goto finish;
}
//根据编码器类型名称得到编码器CLSID
if (!GetEnCodecCLSID(pImagingFactory,tszMime, &clsidEncoder ))
{
goto finish;
}
if (FAILED(hr = CreateStreamOnHGlobal(NULL,TRUE,&pOutStream)))
{
goto finish;
}
//创建编码器接口,并关联到输出流中
if (FAILED(hr = pImagingFactory->CreateImageEncoderToStream(&clsidEncoder, pOutStream, &pImageEncoder)))
{
goto finish;
}
//创建解码器接口
if (FAILED(hr = pImagingFactory->CreateImageDecoder(pStream, DecoderInitFlagBuiltIn1st, &pImageDecoder)))
{
goto finish;
}
//得到编码器接口的sink对象。此ImageSink接口作为一个槽或者管道来理解;
//是用于负责pImageEncoder和pImageDecoder之间的传输
if (FAILED(hr = pImageEncoder->GetEncodeSink(&pImageSink)))
{
goto finish;
}
//开始解码
if (FAILED(hr = pImageDecoder->BeginDecode(pImageSink, NULL)))
{
goto finish;
}
//循环解码,直到结束
for(;;)
{
//解码
hr = pImageDecoder->Decode();
//继续解码后面的部分
if (E_PENDING == hr)
{
Sleep(500);
}
//失败
else if (FAILED(hr))
{
//终止解码
pImageDecoder->EndDecode(hr);
goto finish;
}
else
{
//解码成功
break;
}
}
//结束解码
pImageDecoder->EndDecode(hr);
//释放pImageSink对象
pImageSink->Release();
pImageSink = NULL;
//结束编码,此时就已经完成了文件格式的转换
pImageEncoder->TerminateEncoder();
pOutStream->Stat(&stats, 0);
*bmpsize = (int)stats.cbSize.QuadPart;
pOutStream->Seek(liTemp, STREAM_SEEK_SET, NULL);
pOutStream->Read(bmpbuf, (unsigned long)stats.cbSize.QuadPart, NULL);
finish:
//释放pStream对象
if (pStream)
pStream->Release();
if (pOutStream)
pOutStream->Release();
//释放pImageSink对象
if (pImageSink)
pImageSink->Release();
//释放pImageDecoder对象
if (pImageDecoder)
pImageDecoder->Release();
//释放pImageEncoder对象
if (pImageEncoder)
pImageEncoder->Release();
//释放IImagingFactory接口对象
if (pImagingFactory)
pImagingFactory->Release();
//释放程序占用的COM资源
CoUninitialize();
}
/*
*函数介绍:将文件加载到内存流中
*入口参数:pBuffer:表示要打开的文件
*出口参数: ppStream : 表示内存流,将文件中的内容输出到此内存流中
*返回值:S_OK :表示成功,否则失败
*/
BOOL CreateStreamOnBuffer(const char * pBuffer, DWORD bufsize, IStream ** ppStream)
{
HGLOBAL hg = NULL;
BYTE* pbLocked = NULL;
//分配内存
hg = GlobalAlloc(GMEM_MOVEABLE, bufsize);
if (NULL == hg)
{
goto error;
}
//得到已经分配的内存指针
pbLocked = (BYTE*) GlobalLock(hg);
if (NULL == pbLocked)
{
goto error;
}
//读取文件内容到内存中
memcpy(pbLocked, pBuffer, bufsize);
//解锁已经分配全局内存,对应GlobalLock(hg)
GlobalUnlock(hg);
//创建Stream对象
CreateStreamOnHGlobal(hg, TRUE, ppStream);
return TRUE;
error: //错误处理,并释放内存
if (pbLocked)
GlobalUnlock(hg);
if (hg)
GlobalFree(hg);
return TRUE;
}
/*
*函数介绍:根据编码器类型名称,得到指定的编码器CLSID
*入口参数:pImagingFactory: Image工厂接口对象
wszMimeType : Image编码格式名称
*出口参数:pclsid :编码器的CLSID
*返回值:TRUE : 成功; FALSE: 失败
*/
BOOL GetEnCodecCLSID(IImagingFactory* pImagingFactory,WCHAR * wszMimeType ,CLSID * pclsid )
{
UINT uiCount;
ImageCodecInfo * codecs;
HRESULT hr;
BOOL fRet = FALSE;
//枚举系统已经安装的编码器
hr = pImagingFactory->GetInstalledEncoders(&uiCount, &codecs);
//查找制定编码器的CLSID
for (UINT i = 0; i < uiCount; i++)
{
if (wszMimeType && !wcscmp(wszMimeType, codecs[i].MimeType))
{
*pclsid = codecs[i].Clsid;
fRet = TRUE;
break;
}
}
//释放内存
CoTaskMemFree(codecs);
//
return fRet;
}