2011년 7월 29일 금요일

ActiveX 확실히 제거하는법

보통 익스플로러에서 도구 -> 추가기능관리 -> (화면왼쪽아래 콤보박스) 모든 추가 기능 -> 더블클릭 -> 제거
하는데 더 확실한 방법

탐색기에서
C:\WINDOWS\Downloaded Program Files
폴더에 들어가면 설치된 엑티브엑스들 볼수있음. 선택->우클릭->제거

IIS 설치후 ASP.NET 엑세스 권한 설정

IIS 설치후 asp.net(asmx) 스크립트 엑세스 권한 없는경우 .net framework 디렉토리에서
아래 실행

aspnet_regiis -ga ASPNET

관련링크 : http://msdn.microsoft.com/ko-kr/library/k6h9cz8h(v=vs.80).aspx

2011년 7월 19일 화요일

.NET MySQL Connector/Net - "out of sync with server" Exception 문제

linux mysql-5.0.77 서버 설치된 환경에서 윈도우 C# 으로 만든 클라이언트 접속시
Connector/Net 6.4.3 으로 접속시도하면 아래 Exception 발생

out of sync with server

=> Connector/Net 6.3.7 설치하면 해결

출처 : http://bugs.mysql.com/bug.php?id=61806

2011년 7월 8일 금요일

ffmpeg 비디오 디코더(decoder) API 사용법 - how to use ffmpeg video decoder API

#define FFMPEG_0_8   // ffmpeg-1.0 이전 버전

extern "C" {
#include "libavcodec\avcodec.h"
}

#define VIDEO_CODEC_H264 0
#define VIDEO_CODEC_MPEG4 1

// 코덱관련 변수들 선언
class VideoDecoder {
    AVCodec *m_pCodec;
    AVCodecContext *m_pCodecContext;
    AVFrame *m_pPicture;
    AVPacket m_avPacket;
...
};

static HANDLE hMutex;
static int g_numCPU = 1;

< 디코더 초기화 - initialize decoder >

void VideoDecoder::initCodec()
{
    static int init = 0;    // 코덱 초기화는 프로그램 돌때 한번만 해주면됨
    if (init == 0) {
        SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
g_numCPU = sysinfo.dwNumberOfProcessors;    // cpu 코어 갯수

#ifdef FFMPEG_0_8
avcodec_init();
#endif
avcodec_register_all();

        hMutex = CreateMutex(NULL, FALSE, NULL);
        init = 1;
    }
}

< 디코더 열기 - open decoder >

int VideoDecoder::openDecoder(int codec)
{
WaitForSingleObject(hMutex, INFINITE);    // 뮤텍스 처리 (thread-safe 하지않음)

av_init_packet(&m_avPacket);
if (codec == VIDEO_CODEC_H264)
m_pCodec = avcodec_find_decoder(CODEC_ID_H264); else if (codec == VIDEO_CODEC_MPEG4)
m_pCodec = avcodec_find_decoder(CODEC_ID_MPEG4);
else {
ReleaseMutex(hMutex);
return -1;
}

#ifdef FFMPEG_0_8
m_pCodecContext = avcodec_alloc_context();
#else
    m_pCodecContext = avcodec_alloc_context3(m_pCodec);
#endif

//m_pCodecContext->thread_type = FF_THREAD_FRAME; m_pCodecContext->thread_type = FF_THREAD_SLICE;
m_pCodecContext->thread_count = g_numCPU;

m_pPicture = avcodec_alloc_frame();

if (codec == VIDEO_CODEC_H264) // MPEG4('mp4v') 일때 영상깨짐 {
if (m_pCodec->capabilities&CODEC_CAP_TRUNCATED)
m_pCodecContext->flags |= CODEC_FLAG_TRUNCATED; }

#ifdef FFMPEG_0_8
if (avcodec_open(m_pCodecContext, m_pCodec) < 0) {
#else
    if (avcodec_open2(m_pCodecContext, m_pCodec, NULL) < 0)
#endif
  ReleaseMutex(hMutex);
  return -1;
 }

ReleaseMutex(hMutex);
    return 0;
}

< 디코더 닫기 - close decoder >

int VideoDecoder::closeDecoder()
{
WaitForSingleObject(hMutex, INFINITE);

if (m_pCodecContext)
  avcodec_close(m_pCodecContext);

av_free(m_pCodecContext);
av_free(m_pPicture);

ReleaseMutex(hMutex);

return 0;
}

< 디코더 사용 - decode >

int VideoDecoder::Decode(char *inBuf, int inLen)
{
int retLen, got_picture;


    char *buf = (char *)malloc(inLen+FF_INPUT_BUFFER_PADDING_SIZE);
    memset(&buf[inLen], 0, FF_INPUT_BUFFER_PADDING_SIZE);
    memcpy(buf, inBuf, inLen);
    m_avPacket.data = (uint8_t *)buf;
    m_avPacket.size = inLen;

retLen = avcodec_decode_video2(m_pCodecContext, m_pPicture, &got_picture, &m_avPacket);    // 디코딩 => m_pPicture->data[0], data[1], data[2] 이 각각 YCbCr 값을 가짐 (YUV420)
if (retLen < 0) {
  goto exit;
 }

if (!got_picture) {    // 한 프레임을 만들지 못함 -> 한 프레임을 잘라서 주지 못할경우 여기에 대한 처리가 필요
  goto exit;
}
...
exit:

    if (buf)
        free(buf);

    return retLen;
}

사용법은 클래스 생성후 initCodec()(프로그램 실행처음 한번만 하면됨) -> openDecoder() -> Decode() -> closeDecoder() 해주면 된다.

ffmpeg 디코더 라이브러리 => ffmpeg 디코더 참고소스

ffmpeg 스케일러(scaler) 사용법 - how to use ffmpeg scaler

< VideoScaler.h >

#ifndef __VIDEO_SCALER_H__
#define __VIDEO_SCALER_H__

extern "C" {
#include "libavcodec\avcodec.h"
#include "libswscale\swscale.h"
}

#include "FFMPEGUtil.h"

class VideoScaler
{
public:
VideoScaler();
virtual ~VideoScaler();

int resetScaler(int srcWidth, int srcHeight, AVPixelFormat pixFmtSrc,
int targetWidth, int targetHeight, AVPixelFormat pixFmtDst);
void freeScaler();
int processScaler(AVFrame *frame);

int srcWidth() { return m_nSrcWidth; }
int srcHeight() { return m_nSrcHeight; }
int targetWidth() { return m_nTargetWidth; }
int targetHeight() { return m_nTargetHeight; }
int bitCount() { return GetBitPerPixel(m_pixFmtDst); }

AVPixelFormat srcPixFormat() { return m_pixFmtSrc; }
AVPixelFormat dstPixFormat() { return m_pixFmtDst; }

unsigned char* picture() { return m_pPicture; }
int size() { return m_nTargetWidth*m_nTargetHeight*(GetBitPerPixel(m_pixFmtDst)>>3); }

protected:
struct SwsContext* m_pScaler;
AVPixelFormat m_pixFmtSrc;
AVPixelFormat m_pixFmtDst;
int m_nSrcWidth, m_nSrcHeight;
int m_nTargetWidth, m_nTargetHeight;
unsigned char *m_pPicture;
};

#endif

< VideoScaler.cpp >

#include "VideoScaler.h"

VideoScaler::VideoScaler()
{
m_pScaler = NULL;
m_nSrcWidth = m_nSrcHeight = 0;
m_nTargetWidth = m_nTargetHeight = 0;
m_pPicture = NULL;
m_pixFmtSrc = m_pixFmtDst = AV_PIX_FMT_NONE;
}

VideoScaler::~VideoScaler()
{
freeScaler();
}

int VideoScaler::resetScaler(int srcWidth, int srcHeight, AVPixelFormat pixFmtSrc,
int targetWidth, int targetHeight, enum AVPixelFormat pixFmtDst)
{
if (srcWidth <= 0 || srcHeight <= 0) return -1;
if (targetWidth <= 0 || targetHeight <= 0) return -1;
if (pixFmtSrc == AV_PIX_FMT_NONE || pixFmtDst == AV_PIX_FMT_NONE) return -1;

if (m_pPicture) {
delete[] m_pPicture;
m_pPicture = NULL;
}

if (m_pScaler) {
sws_freeContext(m_pScaler);
m_pScaler = NULL;
}

int flags = SWS_BILINEAR;
//int flags = SWS_FAST_BILINEAR;
m_pScaler = sws_getContext(srcWidth, srcHeight, pixFmtSrc,
targetWidth, targetHeight, pixFmtDst, flags, NULL, NULL, NULL);

m_nSrcWidth = srcWidth;
m_nSrcHeight = srcHeight;
m_nTargetWidth = targetWidth;
m_nTargetHeight = targetHeight;

m_pixFmtSrc = pixFmtSrc;
m_pixFmtDst = pixFmtDst;

m_pPicture = new unsigned char[size()];

return 0;
}

void VideoScaler::freeScaler()
{
if (m_pScaler) {
sws_freeContext(m_pScaler);
m_pScaler = NULL;
}
if (m_pPicture) {
delete[] m_pPicture;
m_pPicture = NULL;
}

m_nSrcWidth = m_nSrcHeight = 0;
m_nTargetWidth = m_nTargetHeight = 0;
m_pixFmtSrc = m_pixFmtDst = AV_PIX_FMT_NONE;
}

int VideoScaler::processScaler(AVFrame *frame)
{
unsigned char *ptr = m_pPicture;

unsigned char *src_buf[4];
src_buf[0] = frame->data[0];
src_buf[1] = frame->data[1];
src_buf[2] = frame->data[2];
src_buf[3] = NULL;

int src_stride[4];
src_stride[0] = frame->linesize[0];
src_stride[1] = frame->linesize[1];
src_stride[2] = frame->linesize[2];
src_stride[3] = 0;

unsigned char *dst_buf[4];
dst_buf[0] = ptr;
dst_buf[1] = NULL;
dst_buf[2] = NULL;
dst_buf[3] = NULL;

int pitch = m_nTargetWidth * (GetBitPerPixel(m_pixFmtDst) >> 3);
int dst_stride[4];
dst_stride[0] = pitch;
dst_stride[1] = pitch;
dst_stride[2] = pitch;
dst_stride[3] = pitch;

int ret = -1;
if (m_pScaler) {
ret = sws_scale(m_pScaler, src_buf, src_stride, 0, m_nSrcHeight, dst_buf, dst_stride);
#if 0
FILE *fp = fopen("d:\\test.ppm", "wb");
fprintf(fp, "P6\n%d %d\n255\n", m_nTargetWidth, m_nTargetHeight);
fwrite(ptr, m_nTargetWidth*m_nTargetHeight*(m_nBitCount/8), 1, fp);
fclose(fp);
#endif
}

return ret;
}

< FFMPEGUtil.cpp >

int GetBitPerPixel(AVPixelFormat pix_fmt)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
return av_get_bits_per_pixel(desc);
}

< 사용 >
...
m_pScaler = new VideoScaler();
...
int scaleFrame(AVFrame *frame, int targetWidth, int targetHeight, AVPixelFormat pix_fmt)
{
if (frame->width != m_pScaler->srcWidth() || frame->height != m_pScaler->srcHeight() || 
targetWidth != m_pScaler->targetWidth() || targetHeight != m_pScaler->targetHeight() ||
frame->format != m_pScaler->srcPixFormat() || pix_fmt != m_pScaler->dstPixFormat()) 
{
if (m_pScaler->resetScaler(frame->width, frame->height, (AVPixelFormat)frame->format,
targetWidth, targetHeight, pix_fmt) < 0) 
{
printf("failed to reset scaler\n");
return -1;
}
}

if (m_pScaler->processScaler(frame) < 0) {
printf("failed to process scale\n");
return -1;
}
    ...
    doSomething(m_pScaler->picture(), m_pScaler->size());
}

VC++에서 ffmpeg 연동시 에러처리


libavutil/common.h:165: error: ‘UINT64_C’ was not declared in this scope
위와 같은 에러를 만나면 common.h 소스에 아래 코드추가
#ifndef INT64_C
#define INT64_C(c) (c ## LL)
#define UINT64_C(c) (c ## ULL)
#endif

DirectDraw를 이용한 YUV -> RGB 고속 변환출력 - YUV -> RGB Converting by using DirectDraw

< DirectDraw YUV Surface 생성 - creating directdraw surfaces >

DDPIXELFORMAT g_ddpfFormats[] = 
{{sizeof(DDPIXELFORMAT), DDPF_FOURCC,MAKEFOURCC('Y','V','1','2'),0,0,0,0,0}}; 
...
IDirectDraw7 *pDD;
IDirectDrawSurface7 *lpPrimary;
IDirectDrawClipper      *lpClipper;
IDirectDrawSurface7   *lpYUVBuffer;
int g_width, g_height;

initDraw(HWND hWnd, int width, int height)
{
HRESULT hr;

g_width = width;
g_height = height;

hr = DirectDrawCreateEx(NULL, (void **)&pDD, IID_IDirectDraw7, NULL);
if (FAILED(hr)) {
TRACE("failed to create directdraw device (hr:0x%x)\n", hr);
return -1;
}

hr = pDD->SetCooperativeLevel(hWnd, DDSCL_NORMAL);
if(FAILED(hr)) {
TRACE("failed to SetCooperativeLevel (hr:0x%x)\n", hr);
return -1;
}


DDSURFACEDESC2 ddsd;

/* creating primary surface (RGB32) */
ZeroMemory( &ddsd, sizeof( ddsd ) );
ddsd.dwSize         = sizeof( ddsd );
ddsd.dwFlags        = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;

if (hr=pDD->CreateSurface(&ddsd, &lpPrimary, NULL ) != DD_OK)
{
TRACE("failed to create create primary surface (hr:0x%x)\n", hr);
        return -1;
}

/* creating clipper */
hr = pDD->CreateClipper(0, &lpClipper, NULL);
if (hr != DD_OK)
{
TRACE("failed to create create clipper (hr:0x%x)\n", hr);
pDD->Release();
return -1;
}
hr = lpClipper->SetHWnd(0, hWnd);
if (hr != DD_OK)
{
TRACE("failed to clippter sethwnd (hr:0x%x)\n", hr);
lpClipper->Release();
lpPrimary->Release();
pDD->Release();
return -1;
}

hr = lpPrimary->SetClipper(lpClipper);
if (hr != DD_OK)
{
TRACE("failed to set clipper (hr:0x%x)\n", hr);
lpClipper->Release();
lpPrimary->Release();
pDD->Release();
return -1;
}


/* creating yuv420 surface */
ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
ddsd.dwWidth = width;
ddsd.dwHeight = height;

memcpy(&ddsd.ddpfPixelFormat, &g_ddpfFormats[0], sizeof(DDPIXELFORMAT));

if ((hr=pDD->CreateSurface(&ddsd, &lpYUVBuffer, NULL)) != DD_OK)
{
TRACE("failed to create yuv buffer surface\n");
return -1;
}
...
}


< Primary Surface 로 변환해서 출력 - yuv surface -> primary surface blt >

int draw(RECT *rectTarget, AVFrame *pPicture)
{
HRESULT hr;

int w = g_width;
int h = g_height;
...
DDSURFACEDESC2 ddsd;

ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
if ((hr=lpYUVBuffer->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL)) == DD_OK)
{
LPBYTE lpSurf = (LPBYTE)ddsd.lpSurface;
LPBYTE ptr = lpSurf;
int t_stride = pPicture->linesize[0];
int i;
for (i=0; i < h; i++) {
memcpy(ptr+i*ddsd.lPitch, pPicture->data[0]+i*t_stride, w);
}
ptr += ddsd.lPitch*h;
for (i=0; i < h/2; i++) {
memcpy(ptr+i*ddsd.lPitch/2, pPicture->data[2]+i*t_stride/2, w/2);
}
ptr += ddsd.lPitch*h/4;
for (i=0; i < h/2; i++) {
memcpy(ptr+i*ddsd.lPitch/2, pPicture->data[1]+i*t_stride/2, w/2);
}

lpYUVBuffer->Unlock(NULL);
}

RECT rectSrc;
rectSrc.top = 0;
rectSrc.left = 0;
rectSrc.right = w;
rectSrc.bottom = h;

hr = lpPrimary->Blt(rectTarget, lpYUVBuffer, &rectSrc, DDBLT_ASYNC, NULL);
}

< ddraw resource release >


void release()
{
if (pDD != NULL)
{
pDD->Release();
pDD = NULL;
}

if (lpPrimary != NULL)
{
lpPrimary->Release();
lpPrimary = NULL;
}

if (lpYUVBuffer != NULL)
{
lpYUVBuffer->Release();
lpYUVBuffer = NULL;
}
}



위 소스에서 AVFrame 은 ffmpeg 에서 사용하는 구조체이고 data[0], data[2], data[1] 는 각각 yuv(yuv420) 값을 가진다.
분리된(non-interleaved) yuv 값을 가진 버퍼를 yuv surface에 memcpy 로 적절하게 복사한 다음 primary surface 로 blt 하면 하드웨어 가속기를 이용한 고속복사를 통해 영상 이미지를 출력할 수 있다.
여기서 primary surface의 픽셀포멧은 RGB32 인데 다른 픽셀포멧의 surface 에다 blt 시켜서 변환시킬수도 있을것같다.

윈도우에서 리얼타임(realtime) 구현

네트웍으로 수신되는 라이브 비디오 영상을 플레이하는 플레이어를 개발하는 경우 정확하게  33ms 마다 한 프레임을 그려줘야하는데 directshow 를 쓰지않고 win32 쓰레드로 구현하는 경우 정확하게 33ms 를 지키기가 어렵다. Sleep() 함수의 경우 틱값이 10ms 이기 때문에 거의 무용지물에 가깝고 네트웍 트래픽 상태가 않좋다면 다 채널 영상의 경우 제멋데로 플레이가 되는것을 볼 수 있다. 윈도우 타이머에 관한 모든 방법을 다 사용해봤는데 윈도우 멀티미디어 타이머를 사용하는 아래 방법이 가장 적절한 방법이었고 HD 다채널(9채널이상) 상황에서도 타이밍이 정확하게 동작하는 것을 볼수 있었다.


static void CALLBACK TimeProc(UINT _timerId, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2)
{
// KLog log;
CstreamMedia* rtspClient = (CstreamMedia*)dwUser;
    rtspClient->tcount++;

if (rtspClient->frameQueue.count >= MAX_TIMER_Q_COUNT)
rtspClient->timerCount = rtspClient->timerCountOrg/2;
else if (rtspClient->frameQueue.count <= MIN_TIMER_Q_COUNT)
rtspClient->timerCount = rtspClient->timerCountOrg;

if (rtspClient->tcount >= rtspClient->timerCount) {
//log.WriteFileLog("[%s] q count: %d\n", rtspClient->szURL, rtspClient->frameQueue.count);
SetEvent(rtspClient->hTimerEvent);
rtspClient->tcount = 0;
}
}

DWORD WINAPI timerThread( LPVOID lpParam )
{
CstreamMedia* rtspClient = (CstreamMedia*)lpParam;
int sleepTime = 33;
int count = 0;

long last_time = 0, curr_time = 0, diff_time;

KLog log;

if (rtspClient->videoFps > 0)
sleepTime = 1000/rtspClient->videoFps;

err("timerThread begin\n");

    TIMECAPS tc;
    UINT wTimerRes;

    // 타이머의 최소/최대 해상도를 얻어옵니다.
    if (timeGetDevCaps (&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
        // 에러발생
        return -1;
    }

if (timeBeginPeriod(1) != TIMERR_NOERROR) {
log.WriteFileLog("TIMERR_NOERROR\n");
}

// 1ms의 타이머 이벤트를 시작합니다.
    UINT interval = 1;  // 단위: ms

    DWORD timerID = timeSetEvent (1, 1, TimeProc, (DWORD)rtspClient, TIME_PERIODIC);
    if (timerID == NULL) {
        // 에러발생
        return -1;
    }

//log.WriteFileLog("tcount: %d\n", tcount);

SetEvent(rtspClient->hTimerThreadReady);

while (rtspClient->m_recvThreadFlag)
{
Sleep(1);
}

// 타이머를 해제 합니다.
    if (timeKillEvent (timerID) != TIMERR_NOERROR) {
        // 에러발생
        return -1;
    }

timeEndPeriod(1);

rtspClient->frameQueue.reset();

err("timerThread end\n");

return 0;
}

간단히 설명하면

1. timeBeginPeriod(1) 해서 윈도우 틱값을 1ms 로 변경.
2. timeSetEvent 함수로 1ms 마다 주기적으로 TimeProc 콜백함수를 호출하도록 등록.
3. TimeProc 함수에서 tcount 값을 1씩 증가.
4. TimeProc 함수에서 tcount 값이 원하는 시간값(33)이 되면 SetEvent 함수로 실제 일을 하는 (decoding/draw) 쓰레드(WaitForSingleObject로 기다리는)를 깨워줌.

위 코드를 조금만 수정하면 리얼타임에 관련된 코드에 적용가능할듯 합니다.

msys/minGW ffmpeg 빌드후 VC++에서 static 링크 에러처리

"error LNK2019: unresolved external symbol __imp____lc_codepage referenced in function _mbrlen libmingwex.a
error LNK2001: unresolved external symbol __imp____lc_codepage libmingwex.a



< 해결방법 (출처 : http://ffmpeg.arrozcru.org/forum/viewtopic.php?f=1&t=891) >

 1. Make sure you have got VS2005 or VS2008 in your path.

2. Go to mingw/lib where you have libmingwex.a

3. use command "lib -remove:mbrtowc.o libmingwex.a"

4. use command "lib -remove:wcrtomb.o libmingwex.lib" note the ending .lib

5. link with libmingwex.lib and 

VC++ win32 프로젝트에서 메모리 릭(memory leak) 위치 출력

디버그 모드로 하고 메모리릭 의심되는 위치마다 아래 코드 삽입


#ifdef _DEBUG
//#define _CRTDBG_MAP_ALLOC
//#define _CRTDBG_MAP_ALLOC_NEW
#include <crtdbg.h>
   #ifndef DBG_NEW
      #define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
      #define new DBG_NEW
   #endif
#endif

주로 library 프로젝트에서 메모리 릭 발생시 디버그 창에 그냥 헥사코드만 찍어주는데
위 코드 삽입하면 위치까지 출력해줌

WinSock 헤더와 링크

winsock 헤더위치 => C:\Program Files\Microsoft SDKs\Windows\v7.0\Include\WinSock.h
winsock 링크 => #pragma comment(lib, "wsock32.lib")

DirectShow Media Type guid 모아놓은 파일위치

C:\Program Files\Microsoft SDKs\Windows\v7.0\Include\uuids.h

ActiveX 에러 로그 보기

도구 -> 인터넷옵션 -> 설정 -> 파일보기

해서 해당 파일 텍스트 에디터로 보면됨.

javascript 에서 ActiveX 메소드/프로퍼티 엑세스할때 경고 메시지박스 뜨는것 막기

< 액티브액스에 IObjectSafety 인터페이스 추가 >
=> ie에서 스크립트가 activex object 메소드/프로퍼티 액세스할때 메시지박스 뜨는것 막아줌
=> 출처 : http://ancdesign.tistory.com/18

[ActiveXCtrl.h]

#include <objsafe.h>

class ActiveXCtrl
{
...
// IObjectSafety
DECLARE_INTERFACE_MAP()

BEGIN_INTERFACE_PART(ObjSafe, IObjectSafety)
STDMETHOD_(HRESULT, GetInterfaceSafetyOptions) (
/* [in] */ REFIID riid,
/* [out] */ DWORD __RPC_FAR *pdwSupportedOptions,
/* [out] */ DWORD __RPC_FAR *pdwEnabledOptions
);

STDMETHOD_(HRESULT, SetInterfaceSafetyOptions) (
/* [in] */ REFIID riid,
/* [in] */ DWORD dwOptionSetMask,
/* [in] */ DWORD dwEnabledOptions
);
END_INTERFACE_PART(ObjSafe);
...
};

[ActiveXCtrl.cpp]

// Interface map for IObjectSafety

BEGIN_INTERFACE_MAP( CActiveXCtrl, COleControl )
INTERFACE_PART(CActiveXCtrl, IID_IObjectSafety, ObjSafe)
END_INTERFACE_MAP()

/////////////////////////////////////////////////////////////
// IObjectSafety member functions

ULONG FAR EXPORT CActiveXCtrl::XObjSafe::AddRef()
{
METHOD_PROLOGUE(CActiveXCtrl, ObjSafe)
return pThis->ExternalAddRef();
}

ULONG FAR EXPORT CActiveXCtrl::XObjSafe::Release()
{
METHOD_PROLOGUE(CActiveXCtrl, ObjSafe)
return pThis->ExternalRelease();
}

HRESULT FAR EXPORT CActiveXCtrl::XObjSafe::QueryInterface(
REFIID iid, void FAR* FAR* ppvObj)
{
METHOD_PROLOGUE(CActiveXCtrl, ObjSafe)
return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
}

const DWORD dwSupportedBits =
INTERFACESAFE_FOR_UNTRUSTED_CALLER |
INTERFACESAFE_FOR_UNTRUSTED_DATA;
const DWORD dwNotSupportedBits = ~ dwSupportedBits;

HRESULT STDMETHODCALLTYPE
CActiveXCtrl::XObjSafe::GetInterfaceSafetyOptions(
/* [in] */ REFIID riid,
/* [out] */ DWORD __RPC_FAR *pdwSupportedOptions,
/* [out] */ DWORD __RPC_FAR *pdwEnabledOptions)
{
METHOD_PROLOGUE(CActiveXCtrl, ObjSafe)

HRESULT retval = ResultFromScode(S_OK);

// does interface exist?
IUnknown FAR* punkInterface;
retval = pThis->ExternalQueryInterface(&riid, (void * *)&punkInterface);
if (retval != E_NOINTERFACE) { // interface exists
punkInterface->Release(); // release it--just checking!
}

// we support both kinds of safety and have always both set,
// regardless of interface
*pdwSupportedOptions = *pdwEnabledOptions = dwSupportedBits;

return retval; // E_NOINTERFACE if QI failed
}

HRESULT STDMETHODCALLTYPE
CActiveXCtrl::XObjSafe::SetInterfaceSafetyOptions(
/* [in] */ REFIID riid,
/* [in] */ DWORD dwOptionSetMask,
/* [in] */ DWORD dwEnabledOptions)
{
METHOD_PROLOGUE(CActiveXCtrl, ObjSafe)

// does interface exist?
IUnknown FAR* punkInterface;
pThis->ExternalQueryInterface(&riid, (void**)&punkInterface);
if (punkInterface) { // interface exists
punkInterface->Release(); // release it--just checking!
}
else { // interface doesn't exist
return ResultFromScode(E_NOINTERFACE);
}

// can't set bits we don't support
if (dwOptionSetMask & dwNotSupportedBits) {
return ResultFromScode(E_FAIL);
}

// can't set bits we do support to zero
dwEnabledOptions &= dwSupportedBits;
// (we already know there are no extra bits in mask )
if ((dwOptionSetMask & dwEnabledOptions) != dwOptionSetMask) {
return ResultFromScode(E_FAIL);
}

// don't need to change anything since we're always safe
return ResultFromScode(S_OK);
}
//---------------------------------------------------------------------------------------

DirectShow 링크 에러관련 체크

에러 메시지: error LNK2019: unresolved external symbol "public: __thiscall CTransInPlaceFilter::CTransInPlaceFilter(wchar_t const *,struct IUnknown *,struct _GUID const &,long *,bool)" (??0CTransInPlaceFilter@@QAE@PB_WPAUIUnknown@@ABU_GUID@@PAJ_N@Z) referenced in function "public: __thiscall CVideoFrameFilter::CVideoFrameFilter(wchar_t *,struct IUnknown *,long *)" (??0CVideoFrameFilter@@QAE@PA_WPAUIUnknown@@PAJ@Z)
=> 위와같은 링크에러시 BaseClasses와 필터 프로젝트의 속성에서 Character Set(예: Use Multi-Byte Character Set)이 서로 맞는지 확인.

에러 메시지: error LNK2001: unresolved external symbol "class CFactoryTemplate * g_Templates" (?g_Templates@@3PAVCFactoryTemplate@@A)
=> 위와같은 링크에러 발생시 아래 코드 추가 (출처 : http://www.vbforums.com/archive/index.php/t-296274.html)

extern "C"
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());

return AfxDllGetClassObject(rclsid, riid, ppv);
}

extern "C"
STDAPI DllCanUnloadNow(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());

return AfxDllCanUnloadNow();
}

에러 메시지: error LNK2019: unresolved external symbol __imp__timeGetTime@0 referenced in function "void __stdcall DbgInitialise(struct HINSTANCE__ *)" (?DbgInitialise@@YGXPAUHINSTANCE__@@@Z)
=> 프로젝트 속성 additional dependencies에 winmm.lib 추가

에러 메시지: regsvr32 로 dll 등록시 "g_hInst != 0 ...baseclasses\dllsetup.cpp" 메시지 박스 뜰때
=> 아래 코드추가 (출처 : http://social.msdn.microsoft.com/forums/en-US/windowsdirectshowdevelopment/thread/15323770-9485-4284-8487-017845f592c0/)

extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);

BOOL WINAPI DllMain(HANDLE hDllHandle, DWORD dwReason, LPVOID lpReserved)

{
return DllEntryPoint(reinterpret_cast<HINSTANCE>(hDllHandle), dwReason, lpReserved);
}

ffdshow setting 값 변경 등

ffmpeg-mt 에서 비디오 디코더 h264 로 설정하는법
=> 윈도 레지스트리 HKCU\Software\GNU\ffdshow에 값:h264 데이터:21 써주면 됨.

ffdshow 레지스트리 디폴트값 수정위치
=> src/settings/TglobalSettings.cpp

void TglobalSettingsDecVideo::reg_op_codec(TregOp &t,TregOp *t2)
void TglobalSettingsDecAudio::reg_op_codec(TregOp &t,TregOp *t2)
에서 _reg_op_codec() 함수 마지막 인자값이 디폴트

프로그램에서 ffdshow 클래스 생성 실패 때문에 수정한 곳
=> TffdshowDec::NonDelegatingQueryInterface(REFIID riid,void **ppv)
에서 whitelist, blacklist 체크하는 부분 막아줌

ActiveX 등 Component 등록여부 확인

윈도우 레지스트리 에디터에서 해당 component guid 등록되었나 확인

HKLM\SOFTWARE\Classes\CLSID\XXXX-XXX...

VC++ 에서 문자열 관련 함수들 찾기

unicode<->multibyte 문자열 관련 함수 vc\include\tchar.h

.NET Framework 버전 확인

윈도우 레지스트리 에디트에서

HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP

확인할것

__RPC__out_xcount_part 에러처리

syntax error : identifier '__RPC__out_xcount_part' => directx include 버전문제