2012년 9월 4일 화요일
DirectDraw Surface Transparent Blt
void CopySurface(IDirectDrawSurface7 *lpSurfaceDst, RECT &rectTarget, IDirectDrawSurface7 *lpSurfaceSrc, RECT &rectSrc)
{
DDBLTFX ddbltfx;
ZeroMemory(&ddbltfx, sizeof(ddbltfx));
ddbltfx.dwSize = sizeof(ddbltfx);
DDCOLORKEY colorKey = {RGB(0,0,0), RGB(0,0,0)}; // Transparent Color - black
ddbltfx.ddckSrcColorkey = colorKey;
DWORD flags = DDBLT_ASYNC | DDBLT_KEYSRCOVERRIDE;
HRESULT hr = lpSurfaceDst->Blt(&rectTarget, lpSurfaceSrc, &rectSrc, flags, &ddbltfx);
if (FAILED(hr)) {
TRACE("[%s] hr:0x%x\n", __FUNCTION__, hr);
}
}
라벨:
directdraw
DirectDraw Surface 알파블랜딩 - DirectDraw Surface Alpha Blending
HBITMAP m_hbm;
BITMAP m_bmpInfo;
...
< 비트맵 로드 - bitmap load >
m_hbm = (HBITMAP) LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(123), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
GetObject(m_hbm, sizeof(m_bmpInfo), &m_bmpInfo);
< 알파블랜딩 - alpha blending >
void drawBitmapAlpha(RECT *rectTarget, IDirectDrawSurface7 *lpSurface)
{
HDC hdc;
if (lpSurface->GetDC(&hdc) != DD_OK || m_hbm == NULL)
return;
/* calculate bitmap size */
int targetWidth = rectTarget->right-rectTarget->left;
int targetHeight = rectTarget->bottom-rectTarget->top;
int cx = rectTarget->left+targetWidth/2;
int cy = rectTarget->top+targetHeight/2;
int bmpWidth = m_bmpInfo.bmWidth;
int bmpHeight = m_bmpInfo.bmHeight;
POINT pt;
pt.x = cx-bmpWidth/2;
pt.y = cy-bmpHeight/2;
HDC hMemDC, hAlphaDC;
BOOL ret;
hMemDC = CreateCompatibleDC(hdc); // create bitmap dc
hAlphaDC = CreateCompatibleDC(hdc); // create alpha dc
HBITMAP hbmAlpha = CreateCompatibleBitmap(hdc, bmpWidth, bmpHeight);
SelectObject(hMemDC, m_hbm);
SelectObject(hAlphaDC, hbmAlpha);
// copy src image to alpha dc
ret = BitBlt(hAlphaDC, 0, 0, bmpWidth, bmpHeight, hdc, pt.x, pt.y, SRCCOPY);
if (!ret) {
TRACE("[%s] BitBlt failed, err:%d\n", __FUNCTION__, GetLastError());
}
// copy bitmap image to alpha dc with transparent
ret = TransparentBlt(hAlphaDC, 0, 0, bmpWidth, bmpHeight, hMemDC, 0, 0, m_bmpInfo.bmWidth, m_bmpInfo.bmHeight, RGB(0, 0, 0));
if (!ret) {
TRACE("[%s] TransparentBlt failed, err:%d\n", __FUNCTION__, GetLastError());
}
BLENDFUNCTION bf;
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = 100;
bf.AlphaFormat = 0;
// alpha blend alpha dc to dest dc
ret = AlphaBlend(hdc, pt.x, pt.y, bmpWidth, bmpHeight, hAlphaDC, 0, 0, bmpWidth, bmpHeight, bf);
if (!ret) {
TRACE("[%s] AlphaBlend failed, err:%d\n", __FUNCTION__, GetLastError());
}
DeleteObject(hbmAlpha);
DeleteDC(hAlphaDC);
DeleteDC(hMemDC);
lpSurface->ReleaseDC(hdc);
}
라벨:
directdraw
2012년 6월 20일 수요일
vc++ 프로젝트 배포를 위한 manifest와 dll 링크
vc++ 로 작성된 프로젝트를 배포하다보면 타겟 PC에서
"응용 프로그램 구성이 올바르지 않기 때문에 이 응용 프로그램을 시작하지 못했습니다"
라는 메시지를 출력하면서 실행에 실패하는 경우가 있다. 이것은 dll dependency 에 따른 dll 이 타겟 PC 에 존재하지 않거나 dll 버전이 맞지 않아서 생기는 현상이다.
이 문제를 해결하기 위해서는 올바른 dll 들을 같이 묶어서 배포해야한다.
올바른 버전의 dll 을 찾아내려면 manifest 파일을 봐야하는데 vc++ 프로젝트 속성에 디폴트로 embed manifest 로 되어있다. 따라서 manifest 정보를 보려면 프로젝트 output 파일(exe/dll/ocx)을 텍스트 에디터로 직접 열어서 manifest 정보를 보거나 xxx.intermediate.manifest 파일을 열어봐야한다.
manifest 정보를 보면 대게 아래와 같이 나오는데
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level='asInvoker' uiAccess='false' />
</requestedPrivileges>
</security>
</trustInfo>
<dependency>
<dependentAssembly>
<assemblyIdentity type='win32' name='Microsoft.VC90.CRT' version='9.0.21022.8' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />
</dependentAssembly>
</dependency>
<dependency>
<dependentAssembly>
<assemblyIdentity type='win32' name='Microsoft.VC90.MFC' version='9.0.21022.8' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />
</dependentAssembly>
</dependency>
</assembly>
위와 같이 manifest 정보가 구성되어있을때 Microsoft.VC90.CRT 와 Microsoft.VC90.MFC 두개의 dll 들을 찾아야 하는데 이것은 각각 msvcr90.dll 과 mfc90.dll 이다.
어느 dll 인지 찾으려면 dependency walker 를 이용하면된다. 해당 dll 파일을 찾으려면
C:\Program Files\Microsoft Visual Studio 9.0\VC\redist\x86
아래를 뒤져서 파일을 찾으면 되는데 경우에 따라 dll 버전이 또 다를수 있다. (속성->버전정보)
이럴 경우
C:\WINDOWS\WinSxS
아래를 뒤져서 정확히 버전이 일치하는 dll 파일을 찾아야한다.
"응용 프로그램 구성이 올바르지 않기 때문에 이 응용 프로그램을 시작하지 못했습니다"
라는 메시지를 출력하면서 실행에 실패하는 경우가 있다. 이것은 dll dependency 에 따른 dll 이 타겟 PC 에 존재하지 않거나 dll 버전이 맞지 않아서 생기는 현상이다.
이 문제를 해결하기 위해서는 올바른 dll 들을 같이 묶어서 배포해야한다.
올바른 버전의 dll 을 찾아내려면 manifest 파일을 봐야하는데 vc++ 프로젝트 속성에 디폴트로 embed manifest 로 되어있다. 따라서 manifest 정보를 보려면 프로젝트 output 파일(exe/dll/ocx)을 텍스트 에디터로 직접 열어서 manifest 정보를 보거나 xxx.intermediate.manifest 파일을 열어봐야한다.
manifest 정보를 보면 대게 아래와 같이 나오는데
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level='asInvoker' uiAccess='false' />
</requestedPrivileges>
</security>
</trustInfo>
<dependency>
<dependentAssembly>
<assemblyIdentity type='win32' name='Microsoft.VC90.CRT' version='9.0.21022.8' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />
</dependentAssembly>
</dependency>
<dependency>
<dependentAssembly>
<assemblyIdentity type='win32' name='Microsoft.VC90.MFC' version='9.0.21022.8' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />
</dependentAssembly>
</dependency>
</assembly>
위와 같이 manifest 정보가 구성되어있을때 Microsoft.VC90.CRT 와 Microsoft.VC90.MFC 두개의 dll 들을 찾아야 하는데 이것은 각각 msvcr90.dll 과 mfc90.dll 이다.
어느 dll 인지 찾으려면 dependency walker 를 이용하면된다. 해당 dll 파일을 찾으려면
C:\Program Files\Microsoft Visual Studio 9.0\VC\redist\x86
아래를 뒤져서 파일을 찾으면 되는데 경우에 따라 dll 버전이 또 다를수 있다. (속성->버전정보)
이럴 경우
C:\WINDOWS\WinSxS
아래를 뒤져서 정확히 버전이 일치하는 dll 파일을 찾아야한다.
2012년 6월 8일 금요일
H.264 RFC3984 NAL 패킷처리 - H.264 RFC3984 NAL Packet Handling
class RTPSource
{
uint8_t* fFrameBuf; // 프레임 버퍼 - 한개 프레임 될때까지 채움
int fFrameBufPos; // 프레임 버퍼 인덱스 - 현재 프레임 버퍼 사이즈
FrameHandlerFunc fFrameHandlerFunc; // 콜백함수 - 한개 프레임이 완성되면 호출
void* fFrameHandlerFuncData; // 콜백함수 데이터
uint8_t* fExtraData; // SPS/PPS 정보
unsigned fExtraDataSize;
...
}
int trimStartCode(uint8_t *buf, int len)
{
uint8_t *ptr = buf;
if (len < 4) return 0;
// trying to find 0x00 0x00 ... 0x01 pattern
// find first 0x00 0x00 bytes
if (ptr[0] == 0x00 && ptr[1] == 0x00) {
// find first 0x01
while (*ptr == 0x00 && ptr < buf+len-1)
ptr++;
if (*ptr != 0x01) { // error - invalid stream
DPRINTF("invalid stream, 0x%02x\n", *ptr);
ptr = buf;
} else {
ptr++;
}
}
return ptr-buf;
}
void RTPSource::copyToFrameBuffer(uint8_t *buf, int len)
{
if (fFrameBufPos+len >= FRAME_BUFFER_SIZE) {
DPRINTF("RTP Frame Buffer overflow %s\n", fCodecName);
fFrameBufPos = 0;
}
memmove(&fFrameBuf[fFrameBufPos], buf, len);
fFrameBufPos += len;
}
void RTPSource::resetFrameBuf()
{
fFrameBufPos = 0;
}
uint64_t RTPSource::getMediaTimestamp(uint32_t timestamp)
{
uint64_t msec = 1000;
uint64_t time_msec = timestamp*msec/fTimestampFrequency;
return time_msec;
}
void H264RTPSource::putStartCode()
{
fFrameBuf[fFrameBufPos++] = 0x00;
fFrameBuf[fFrameBufPos++] = 0x00;
fFrameBuf[fFrameBufPos++] = 0x00;
fFrameBuf[fFrameBufPos++] = 0x01;
}
void H264RTPSource::processFrame(RTPPacketBuffer *packet)
{
uint8_t *buf = (uint8_t *)packet->payload();
int len = packet->payloadLen();
int offset = trimStartCode(buf, len);
buf = &buf[offset];
len -= offset;
uint8_t *buf_ptr = buf;
bool isCompleteFrame = false;
uint32_t media_timestamp = getMediaTimestamp(packet->timestamp());
uint8_t nalUnitType = (buf[0]&0x1F);
if (RTSPCommonEnv::nDebugFlag&DEBUG_FLAG_RTP_PAYLOAD)
DPRINTF("nal_type: %d, size: %d\n", nalUnitType, len);
if (!fIsStartFrame) {
if (fExtraData) {
putStartCode();
copyToFrameBuffer(fExtraData, fExtraDataSize);
}
fIsStartFrame = true;
}
switch (nalUnitType)
{
case 28: { // FU-A
uint8_t startBit = buf[1]&0x80;
uint8_t endBit = buf[1]&0x40;
if (startBit) {
buf_ptr++; len--;
buf[1] = (buf[0]&0xE0) + (buf[1]&0x1F);
putStartCode();
} else {
buf_ptr += 2; len -= 2;
}
copyToFrameBuffer(buf_ptr, len);
isCompleteFrame = (endBit != 0);
break;
}
case 5: { // IDR-Picture
putStartCode();
copyToFrameBuffer(buf_ptr, len);
isCompleteFrame = true;
break;
}
case 7: { // SPS
putStartCode();
copyToFrameBuffer(buf_ptr, len);
isCompleteFrame = false;
break;
}
case 8: { // PPS
putStartCode();
copyToFrameBuffer(buf_ptr, len);
isCompleteFrame = false;
break;
}
case 24: { // STAP-A
buf_ptr++; len--;
while (len > 3)
{
uint16_t staplen = (buf_ptr[0]<<8) | (buf_ptr[1]);
if (staplen > len) {
DPRINTF("STAP-A process error, staplen: %d, len\n", staplen, len);
break;
}
buf_ptr += 2; len -= 2;
nalUnitType = buf_ptr[0]&0x1F;
putStartCode();
copyToFrameBuffer(buf_ptr, staplen);
buf_ptr += staplen; len -= staplen;
if (fFrameHandlerFunc)
fFrameHandlerFunc(fFrameHandlerFuncData, fFrameType, media_timestamp, fFrameBuf, fFrameBufPos);
resetFrameBuf();
}
break;
}
default:
putStartCode();
copyToFrameBuffer(buf_ptr, len);
isCompleteFrame = true;
break;
}
if (isCompleteFrame) {
if (fFrameHandlerFunc)
fFrameHandlerFunc(fFrameHandlerFuncData, fFrameType, media_timestamp, fFrameBuf, fFrameBufPos);
resetFrameBuf();
}
}
base64 디코딩 - base64 decoding
int b64_decode( char *dest, char *src )
{
const char *dest_start = dest;
int i_level;
int last = 0;
int b64[256] = {
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 00-0F */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 10-1F */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* 20-2F */
52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, /* 30-3F */
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* 40-4F */
15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* 50-5F */
-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, /* 60-6F */
41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* 70-7F */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 80-8F */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 90-9F */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* A0-AF */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* B0-BF */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* C0-CF */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* D0-DF */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* E0-EF */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 /* F0-FF */
};
for( i_level = 0; *src != '\0'; src++ )
{
int c;
c = b64[(unsigned int)*src];
if( c == -1 )
{
continue;
}
switch( i_level )
{
case 0:
i_level++;
break;
case 1:
*dest++ = ( last << 2 ) | ( ( c >> 4)&0x03 );
i_level++;
break;
case 2:
*dest++ = ( ( last << 4 )&0xf0 ) | ( ( c >> 2 )&0x0f );
i_level++;
break;
case 3:
*dest++ = ( ( last &0x03 ) << 6 ) | c;
i_level = 0;
}
last = c;
}
*dest = '\0';
return dest - dest_start;
}
2012년 6월 5일 화요일
TCP 소켓 Connection 타임아웃 주기(윈도우/리눅스 공통) - TCP Socket Connection Timeout
TCP 소켓통신에서 서버로 연결할때 상대서버가 동작하지 않거나 연결에 문제가 생겼을때
connect 함수에서 블러킹이 걸려 한참 동안 빠져나오지 못할때가 있다.
이런 현상을 방지하려면 소켓을 non-blocking 으로 만든다음 타임아웃을 주고 connect 후
select 함수에서 연결결과를 감지하면 된다.
#ifdef WIN32 #include <WinSock2.h> #include <ws2tcpip.h> #define closeSocket closesocket #define EWOULDBLOCK WSAEWOULDBLOCK #define EINPROGRESS WSAEWOULDBLOCK #define EINTR WSAEINTR #else #include <sys/socket.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <arpa/inet.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #define closeSocket close #define WSAGetLastError() errno #include <ctype.h> #include <stdlib.h> #endif #ifdef WIN32 #define WS_VERSION_CHOICE1 0x202/*MAKEWORD(2,2)*/ #define WS_VERSION_CHOICE2 0x101/*MAKEWORD(1,1)*/ int initializeWinsockIfNecessary(void) { /* We need to call an initialization routine before * we can do anything with winsock. (How fucking lame!): */ static int _haveInitializedWinsock = 0; WSADATA wsadata; if (!_haveInitializedWinsock) { if ((WSAStartup(WS_VERSION_CHOICE1, &wsadata) != 0) && ((WSAStartup(WS_VERSION_CHOICE2, &wsadata)) != 0)) { return 0; /* error in initialization */ } if ((wsadata.wVersion != WS_VERSION_CHOICE1) && (wsadata.wVersion != WS_VERSION_CHOICE2)) { WSACleanup(); return 0; /* desired Winsock version was not available */ } _haveInitializedWinsock = 1; } return 1; } #else #define initializeWinsockIfNecessary() 1 #endif int makeSocketNonBlocking(int sock) { #ifdef WIN32 unsigned long arg = 1; return ioctlsocket(sock, FIONBIO, &arg) == 0; #else int curFlags = fcntl(sock, F_GETFL, 0); return fcntl(sock, F_SETFL, curFlags|O_NONBLOCK) >= 0; #endif } static int reuseFlag = 1; int setupStreamSock(short port, int makeNonBlocking) { if (!initializeWinsockIfNecessary()) { socketErr("[%s] Failed to initialize 'winsock': ", __FUNCTION__); return -1; } int newSocket = socket(AF_INET, SOCK_STREAM, 0); if (newSocket < 0) { DPRINTF("%s:%d\n",__FUNCTION__,__LINE__); socketErr("[%s] unable to create stream socket: ", __FUNCTION__); return newSocket; } if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseFlag, sizeof reuseFlag) != 0) { socketErr("[%s] setsockopt(SO_REUSEADDR) error: ", __FUNCTION__); closeSocket(newSocket); return -1; } struct sockaddr_in c_addr; memset(&c_addr, 0, sizeof(c_addr)); c_addr.sin_addr.s_addr = INADDR_ANY; c_addr.sin_family = AF_INET; c_addr.sin_port = htons(port); if (bind(newSocket, (struct sockaddr*)&c_addr, sizeof c_addr) != 0) { socketErr("[%s] bind() error (port number: %d): ", __FUNCTION__, port); closeSocket(newSocket); return -1; } if (makeNonBlocking) { if (!makeSocketNonBlocking(newSocket)) { socketErr("[%s] failed to make non-blocking: ", __FUNCTION__); closeSocket(newSocket); return -1; } } return newSocket; } int connectToServer(char *svrIP, int svrPort) { int sock = setupStreamSocket(0, 1); int ret, err; struct sockaddr_in svr_addr; memset(&svr_addr, 0, sizeof(svr_addr)); svr_addr.sin_addr.s_addr = inet_addr(svrIP); svr_addr.sin_family = AF_INET; svr_addr.sin_port = htons(svrPort); fd_set set; FD_ZERO(&set); timeval tvout = {2, 0}; // 2 seconds timeout FD_SET(sock, &set);if ((ret=connect(sock, (struct sockaddr *)&svr_addr, sizeof(svr_addr))) != 0) { err = WSAGetLastError(); if (err != EINPROGRESS && err != EWOULDBLOCK) { printf("connect() failed : %d\n", err); return -1; } if (select(sock+1, NULL, &set, NULL, &tvout) <= 0) { printf("select/connect() failed : %d\n", WSAGetLastError()); return -1; } err = 0; socklen_t len = sizeof(err); if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*)&err, &len) < 0 || err != 0 ) { printf("getsockopt() error: %d\n", err); return -1; } }return 0; }
c# 소스코드
라벨:
socket
2012년 5월 23일 수요일
vc++ 디버그 모드로 빌드된 파일 배포
vc++ (vs2008 sp1 기준) shared dll 옵션과 디버그 모드로 빌드된 dll/ocx/exe 등의 파일을
아무것도 설치되지않은 타겟 머신에 실행하려면,
C:\Program Files\Microsoft Visual Studio 9.0\VC\redist\Debug_NonRedist\x86
아래에 있는 dll 들이 필요하다. 하지만 위 dll 들을 빌드된 파일과함께 같은 폴더에 넣어도
exe 파일을 실행시키면
"응용 프로그램 구성이 올바르지 않기 때문에 이 응용 프로그램을 시작하지 못했습니다"
메시지박스가 뜬다.
dependency walker 로 보면 dll 들이 모두 정상적으로 로드되는 것처럼 보이는데
이것은 vs2008 sp1 에서 사용하는 dll 버전이 맞지 않아서이다.
이럴 경우 stdafx.h 파일의 제일 위에
#define _BIND_TO_CURRENT_VCLIBS_VERSION 1
정의를 넣고 다시 빌드하면 타겟 머신에서 실행된다.
< 출처 - http://blog.kalmbach-software.de/2009/05/27/deployment-of-vc2008-apps-without-installing-anything/ >
아무것도 설치되지않은 타겟 머신에 실행하려면,
C:\Program Files\Microsoft Visual Studio 9.0\VC\redist\Debug_NonRedist\x86
아래에 있는 dll 들이 필요하다. 하지만 위 dll 들을 빌드된 파일과함께 같은 폴더에 넣어도
exe 파일을 실행시키면
"응용 프로그램 구성이 올바르지 않기 때문에 이 응용 프로그램을 시작하지 못했습니다"
메시지박스가 뜬다.
dependency walker 로 보면 dll 들이 모두 정상적으로 로드되는 것처럼 보이는데
이것은 vs2008 sp1 에서 사용하는 dll 버전이 맞지 않아서이다.
이럴 경우 stdafx.h 파일의 제일 위에
#define _BIND_TO_CURRENT_VCLIBS_VERSION 1
정의를 넣고 다시 빌드하면 타겟 머신에서 실행된다.
< 출처 - http://blog.kalmbach-software.de/2009/05/27/deployment-of-vc2008-apps-without-installing-anything/ >
피드 구독하기:
글 (Atom)