2012년 11월 2일 금요일

ffmpeg deblocking filter disable 시키기

h264.c

static int decode_slice_header(H264Context *h, H264Context *h0){
...
...

    h->deblocking_filter = 1;
    h->slice_alpha_c0_offset = 52;
    h->slice_beta_offset = 52;
    if( h->pps.deblocking_filter_parameters_present ) {
        tmp= get_ue_golomb_31(&s->gb);
        if(tmp > 2){
            av_log(s->avctx, AV_LOG_ERROR, "deblocking_filter_idc %u out of range\n", tmp);
            return -1;
        }
        h->deblocking_filter= tmp;
        if(h->deblocking_filter < 2)
            h->deblocking_filter^= 1; // 1<->0

        if( h->deblocking_filter ) {
            h->slice_alpha_c0_offset += get_se_golomb(&s->gb) << 1;
            h->slice_beta_offset     += get_se_golomb(&s->gb) << 1;
            if(   h->slice_alpha_c0_offset > 104U
               || h->slice_beta_offset     > 104U){
                av_log(s->avctx, AV_LOG_ERROR, "deblocking filter parameters %d %d out of range\n", h->slice_alpha_c0_offset, h->slice_beta_offset);
                return -1;
            }
        }
    }
h->deblocking_filter = 0;    // turn off deblocking filter
    if(   s->avctx->skip_loop_filter >= AVDISCARD_ALL
       ||(s->avctx->skip_loop_filter >= AVDISCARD_NONKEY && h->slice_type_nos != AV_PICTURE_TYPE_I)
       ||(s->avctx->skip_loop_filter >= AVDISCARD_BIDIR  && h->slice_type_nos == AV_PICTURE_TYPE_B)
       ||(s->avctx->skip_loop_filter >= AVDISCARD_NONREF && h->nal_ref_idc == 0))
        h->deblocking_filter= 0;
...
...

* 디블러킹 필터를 끄면 화질 열화현상이 발생하지만 약 20% 정도의 성능개선 효과를 볼 수 있다. 작은 화면을 플레이할때는 화질 열화현상이 눈에 잘 띄지않아서 경우에 따라 적용해봄직 하다.

2012년 10월 8일 월요일

DirectDraw Surface 에 Win32 GDI 함수로 그리기 - Drawing on DirectDraw Surface with Win32 GDI API


void drawSurface(RECT *rectTarget, IDirectDrawSurface7 *lpSurface)
{
HDC hdc;
hr=lpSurface->GetDC(&hdc);

int targetWidth = rectTarget->right-rectTarget->left;
int targetHeight = rectTarget->bottom-rectTarget->top;

HDC hMemDC;

hMemDC = CreateCompatibleDC(hdc);

HBITMAP hbmMem = CreateCompatibleBitmap(hdc, targetWidth, targetHeight);
SelectObject(hMemDC, hbmMem);
 .....
 .....
 TextOut(hMemDC, ....);
 .....
 TransparentBlt(hMemDC, ...);
 .....
 Rectangle(hMemDC, ...);
 ....
 ....

DeleteObject(hbmMem);
DeleteDC(hMemDC);

lpSurface->ReleaseDC(hdc);
}


* lpSurface->GetDC()/lpSurface->ReleaseDC() 하면서 lpSurface 는 lock/unlock 이 된다. 
따라서 위 함수 내부에서 DirectDraw Blt 함수가 호출되어서는 안된다.

* Win32 GDI 함수는 기본적으로 DirectDraw 계열 함수보다 훨씬 느리기때문에 위 함수를
사용할때는 두 개의 Surface를 두고 Blt 하는 Double-buffering 방식으로 구현하는것이 좋다.

2012년 9월 4일 화요일

ffmpeg audio encoding/decoding

< Encoder.h >
 #ifndef __ENCODER_H__  
 #define __ENCODER_H__  
 #include <windows.h>  
 extern "C" {  
 #include "libavcodec\avcodec.h"  
 }  
 class Encoder  
 {  
 public:  
      Encoder();  
      virtual ~Encoder();  
      static void initCodec();  
      virtual void close();  
      virtual int encodeFrame(AVFrame *frame) = 0;  
      AVFrame* frame() { return m_pFrame; }  
      unsigned char* outBuf() { return m_pOutBuf; }  
      int outBufSize() { return m_nOutBufSize; }  
 protected:  
      int prepareOpen(enum AVCodecID codecId);  
 protected:  
      AVCodec*          m_pCodec;  
      AVCodecContext*     m_pCodecCtx;  
      AVPacket          m_avPacket;  
      AVFrame*          m_pFrame;  
      unsigned char*     m_pOutBuf;  
      int                    m_nOutBufSize;  
      int                    m_nOutBufMaxSize;  
      static HANDLE     m_hMutexInit;  
      static bool          m_bInit;  
      static int          m_nCPU;  
 };  
 #endif  

< Encoder.cpp >
 #include "Encoder.h"  
 #include "GlobalEnv.h"  
 #include "FFMPEGUtil.h"  
 bool Encoder::m_bInit = false;  
 int Encoder::m_nCPU = 1;  
 HANDLE Encoder::m_hMutexInit = CreateMutex(NULL, FALSE, NULL);  
 Encoder::Encoder() : m_pCodec(NULL), m_pCodecCtx(NULL), m_pFrame(NULL)   
 {  
      initCodec();  
      m_pOutBuf = NULL;  
      m_nOutBufMaxSize = m_nOutBufSize = 0;  
 }  
 Encoder::~Encoder()  
 {  
      close();  
 }  
 void Encoder::initCodec()  
 {  
      WaitForSingleObject(m_hMutexInit, INFINITE);  
      if (!m_bInit) {  
           InitFFmpegLib();  
           SYSTEM_INFO sysinfo;  
           GetSystemInfo(&sysinfo);  
           m_nCPU = sysinfo.dwNumberOfProcessors;  
           m_bInit = true;  
      }  
      ReleaseMutex(m_hMutexInit);  
 }  
 int Encoder::prepareOpen(enum AVCodecID codecId)  
 {  
      av_init_packet(&m_avPacket);  
      m_pCodec = avcodec_find_encoder(codecId);  
      if (!m_pCodec) {  
           DXPRINTF("avcodec_find_encoder failed to find codec %d\n", codecId);  
           return -1;  
      }  
      m_pCodecCtx = avcodec_alloc_context3(m_pCodec);  
      if (!m_pCodecCtx) {  
           DXPRINTF("avcodec_alloc_context3 failed\n");  
           return -1;  
      }  
      m_pFrame = avcodec_alloc_frame();  
      if (!m_pFrame) {  
           DXPRINTF("avcodec_alloc_frame failed\n");            
           return -1;  
      }  
      return 0;  
 }  
 void Encoder::close()  
 {  
      if (m_pCodecCtx) {  
           avcodec_close(m_pCodecCtx);  
           av_free(m_pCodecCtx);  
           m_pCodecCtx = NULL;  
      }  
      avcodec_free_frame(&m_pFrame);  
      if (m_pOutBuf) {  
           delete[] m_pOutBuf;  
           m_pOutBuf = NULL;  
      }  
      m_nOutBufMaxSize = m_nOutBufSize = 0;  
 }  

< AudioEncoder.h >
 #ifndef __AUDIO_ENCODER_H__  
 #define __AUDIO_ENCODER_H__  
 #include "Encoder.h"  
 class AudioEncoder : public Encoder  
 {  
 public:  
      AudioEncoder();  
      virtual ~AudioEncoder();  
      int open(enum AVCodecID codec_id, int bit_rate, int sample_rate, int channels, int channel_layout, enum AVSampleFormat sample_fmt);  
      virtual void close();  
      virtual int encodeFrame(AVFrame *frame);  
      int prepareAudioFrame(unsigned short *pData, int size, int nb_samples);  
 };  
 #endif  

< AudioEncoder.cpp >
 #include "AudioEncoder.h"  
 #include "GlobalEnv.h"  
 /* check that a given sample format is supported by the encoder */  
 static int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt)  
 {  
   const enum AVSampleFormat *p = codec->sample_fmts;  
   while (*p != AV_SAMPLE_FMT_NONE) {  
     if (*p == sample_fmt)  
       return 1;  
     p++;  
   }  
   return 0;  
 }  
 /* just pick the highest supported samplerate */  
 static int select_sample_rate(AVCodec *codec)  
 {  
   const int *p;  
   int best_samplerate = 0;  
   if (!codec->supported_samplerates)  
     return 44100;  
   p = codec->supported_samplerates;  
   while (*p) {  
     best_samplerate = FFMAX(*p, best_samplerate);  
     p++;  
   }  
   return best_samplerate;  
 }  
 /* select layout with the highest channel count */  
 static int select_channel_layout(AVCodec *codec)  
 {  
   const uint64_t *p;  
   uint64_t best_ch_layout = 0;  
   int best_nb_channels  = 0;  
   if (!codec->channel_layouts)  
     return AV_CH_LAYOUT_STEREO;  
   p = codec->channel_layouts;  
   while (*p) {  
     int nb_channels = av_get_channel_layout_nb_channels(*p);  
     if (nb_channels > best_nb_channels) {  
       best_ch_layout  = *p;  
       best_nb_channels = nb_channels;  
     }  
     p++;  
   }  
   return best_ch_layout;  
 }  
 AudioEncoder::AudioEncoder() : Encoder()  
 {       
 }  
 AudioEncoder::~AudioEncoder()  
 {  
 }  
 int AudioEncoder::open(AVCodecID codec_id, int bit_rate, int sample_rate, int channels, int channel_layout, AVSampleFormat sample_fmt)  
 {  
      int err;  
      char errbuf[128];  
      err = prepareOpen(codec_id);  
      if (err < 0) return -1;  
      m_pCodecCtx->bit_rate = bit_rate;  
      m_pCodecCtx->sample_rate = sample_rate == 0 ? select_sample_rate(m_pCodec) : sample_rate;  
      m_pCodecCtx->channel_layout = channel_layout == 0 ? select_channel_layout(m_pCodec) : channel_layout;  
      m_pCodecCtx->channels = channels == 0 ? av_get_channel_layout_nb_channels(m_pCodecCtx->channel_layout) : channels;  
      m_pCodecCtx->sample_fmt = sample_fmt;  
      if (!check_sample_fmt(m_pCodec, m_pCodecCtx->sample_fmt)) {  
           DXPRINTF("failed to open audio encoder, Encoder does not support sample format %s\n",  
                av_get_sample_fmt_name(m_pCodecCtx->sample_fmt));  
           return -1;  
      }  
      if (err=avcodec_open2(m_pCodecCtx, m_pCodec, NULL) < 0) {  
           av_strerror(err, errbuf, sizeof(errbuf));  
           DXPRINTF("avcodec_open2 %s open failed, err: %d %s\n", avcodec_get_name(codec_id), err, errbuf);  
           return -1;  
      }  
      DXPRINTF("audio encoder opened %s\n", avcodec_get_name(codec_id));  
      return 0;  
 }  
 void AudioEncoder::close()  
 {  
      Encoder::close();  
 }  
 int AudioEncoder::prepareAudioFrame(unsigned short *pData, int size, int nb_samples)  
 {  
      int err;  
      char errbuf[128];  
      avcodec_get_frame_defaults(m_pFrame);  
      m_pFrame->nb_samples = nb_samples == 0 ? m_pCodecCtx->frame_size : nb_samples;  
      m_pFrame->format = m_pCodecCtx->sample_fmt;  
      err = avcodec_fill_audio_frame(m_pFrame, m_pCodecCtx->channels, m_pCodecCtx->sample_fmt,  
           (const uint8_t *)pData, size, 0);  
      if (err < 0) {  
           av_strerror(err, errbuf, sizeof(errbuf));  
           DXPRINTF("avcodec_fill_audio_frame failed, err : %d %s\n", err, errbuf);  
           return -1;  
      }  
      return 0;  
 }  
 int AudioEncoder::encodeFrame(AVFrame *frame)  
 {  
      int err;  
      char errbuf[128];  
      av_init_packet(&m_avPacket);  
      m_avPacket.data = NULL;  
      m_avPacket.size = 0;  
      int got_output;  
      err = avcodec_encode_audio2(m_pCodecCtx, &m_avPacket, frame, &got_output);  
      if (err < 0) {  
           av_strerror(err, errbuf, sizeof(errbuf));  
           DXPRINTF("avcodec_encode_audio2 failed, err : %d %s\n", err, errbuf);  
           return -1;  
      }  
      if (got_output) {            
           if (m_avPacket.size > 0) {  
                if (m_nOutBufMaxSize < m_avPacket.size) {  
                     if (m_pOutBuf) delete[] m_pOutBuf;  
                     m_pOutBuf = new unsigned char[m_avPacket.size];  
                     m_nOutBufMaxSize = m_avPacket.size;  
                }  
                memcpy(m_pOutBuf, m_avPacket.data, m_avPacket.size);                 
           }  
           m_nOutBufSize = m_avPacket.size;  
           av_free_packet(&m_avPacket);  
      }  
      return got_output == 1 ? 0 : -1;  
 }  

< AudioEncoder 사용 >
 AudioEncoder*     m_pEncoder = new AudioEncoder();  
 m_pEncoder->open(AV_CODEC_ID_PCM_MULAW, 64000, 8000, 1, AV_CH_LAYOUT_MONO, AV_SAMPLE_FMT_S16);  
 ...  
 m_pEncoder->prepareAudioFrame((unsigned short*)pData, size, nb_samples);  
 int ret = m_pEncoder->encodeFrame(m_pEncoder->frame());
if (ret > 0) {  
   fwrite(m_pEncoder->outBuf(), m_pEncoder->outBufSize(), 1, fp);  
 } 
 ...  
 m_pEncoder->close();  
 delete m_pEncoder;  

< Decoder.h >
 #ifndef __DECODER_H__  
 #define __DECODER_H__  
 #include <windows.h>  
 extern "C" {  
 #include "libavcodec\avcodec.h"  
 }  
 #define MAX_DECODE_BUFFER_SIZE               (1024*1024)  
 class Decoder  
 {  
 public:  
      Decoder();  
      virtual ~Decoder();  
      static void initCodec();  
      virtual int open(enum AVCodecID codecId, int channel);  
      virtual int open(AVCodecContext *codec, int channel);  
      virtual void close();  
      virtual int decodeFrame(unsigned char *inBuf, int inLen, AVFrame *frame) = 0;  
      void flush();  
      enum AVCodecID codecID();  
      AVFrame* frame() { return m_pFrame; }  
      int width();  
      int height();  
      enum AVPixelFormat pixelFormat();  
 protected:  
      virtual int open(enum AVCodecID codecId, AVCodecContext *codec, int channel) = 0;  
      int prepareOpen(enum AVCodecID codecId, AVCodecContext *codec);  
      void prepareDecBuffer(unsigned char *inBuf, int inLen);  
 protected:  
      AVCodec*          m_pCodec;  
      AVCodecContext*     m_pCodecCtx;  
      AVFrame*          m_pFrame;  
      AVPacket          m_avPacket;  
      unsigned char*     m_pDecBuffer;  
      int                    m_nDecBufferSize;  
      bool               m_bCodecCtxAlloc;  
      static HANDLE     m_hMutexInit;  
      static bool          m_bInit;  
      static int          m_nCPU;  
      // dump  
      FILE               *m_pFile;  
 };  
 #endif  

< Decoder.cpp >
 #include "Decoder.h"  
 #include "GlobalEnv.h"  
 #include "FFMPEGUtil.h"  
 bool Decoder::m_bInit = false;  
 int Decoder::m_nCPU = 1;  
 HANDLE Decoder::m_hMutexInit = CreateMutex(NULL, FALSE, NULL);  
 Decoder::Decoder() : m_pCodec(NULL), m_pCodecCtx(NULL), m_pFrame(NULL), m_bCodecCtxAlloc(false), m_pFile(NULL)  
 {  
      initCodec();  
      m_pDecBuffer = new unsigned char[MAX_DECODE_BUFFER_SIZE];  
      m_nDecBufferSize = MAX_DECODE_BUFFER_SIZE;  
 }  
 Decoder::~Decoder()  
 {  
      if (m_pDecBuffer) {  
           delete[] m_pDecBuffer;  
           m_pDecBuffer = NULL;  
      }  
 }  
 void Decoder::initCodec()  
 {  
      WaitForSingleObject(m_hMutexInit, INFINITE);  
      if (!m_bInit) {  
           InitFFmpegLib();  
           SYSTEM_INFO sysinfo;  
           GetSystemInfo(&sysinfo);  
           m_nCPU = sysinfo.dwNumberOfProcessors;  
           m_bInit = true;  
      }  
      ReleaseMutex(m_hMutexInit);  
 }  
 int Decoder::open(AVCodecID codecId, int channel)  
 {  
      return open(codecId, NULL, channel);  
 }  
 int Decoder::open(AVCodecContext *codec, int channel)  
 {  
      return open(codec->codec_id, codec, channel);  
 }  
 int Decoder::prepareOpen(enum AVCodecID codecId, AVCodecContext *codec)  
 {  
      av_init_packet(&m_avPacket);  
      m_pCodec = avcodec_find_decoder(codecId);  
      if (!m_pCodec) {  
           DXPRINTF("avcodec_find_decoder failed to find codec %d\n", codecId);  
           return -1;  
      }  
      if (codec) {  
           m_pCodecCtx = codec;  
           m_bCodecCtxAlloc = false;  
      } else {  
           m_pCodecCtx = avcodec_alloc_context3(m_pCodec);  
           if (!m_pCodecCtx) {  
                DXPRINTF("avcodec_alloc_context3 failed\n");  
                return -1;  
           }  
           m_bCodecCtxAlloc = true;  
      }  
      m_pFrame = avcodec_alloc_frame();  
      if (!m_pFrame) {  
           DXPRINTF("avcodec_alloc_frame failed\n");            
           return -1;  
      }  
      return 0;  
 }  
 void Decoder::close()  
 {  
      if (m_bCodecCtxAlloc) {  
           if (m_pCodecCtx)  
                avcodec_close(m_pCodecCtx);  
           av_free(m_pCodecCtx);  
           m_bCodecCtxAlloc = false;  
      }  
      m_pCodecCtx = NULL;  
      avcodec_free_frame(&m_pFrame);  
      if (m_pFile) {  
           fclose(m_pFile);  
           m_pFile = NULL;  
      }  
 }  
 enum AVCodecID Decoder::codecID()  
 {  
      if (m_pCodecCtx)  
           return m_pCodecCtx->codec_id;  
      return AV_CODEC_ID_NONE;  
 }  
 int Decoder::width()  
 {  
      if (m_pCodecCtx)  
           return m_pCodecCtx->width;  
      return 0;  
 }  
 int Decoder::height()  
 {  
      if (m_pCodecCtx)  
           return m_pCodecCtx->height;  
      return 0;  
 }  
 enum AVPixelFormat Decoder::pixelFormat()  
 {  
      if (m_pCodecCtx)  
           return m_pCodecCtx->pix_fmt;  
      return AV_PIX_FMT_NONE;  
 }  
 void Decoder::prepareDecBuffer(unsigned char *inBuf, int inLen)  
 {  
      if (inLen+FF_INPUT_BUFFER_PADDING_SIZE > m_nDecBufferSize) {  
           delete[] m_pDecBuffer;  
           m_pDecBuffer = new unsigned char[inLen+FF_INPUT_BUFFER_PADDING_SIZE];  
           m_nDecBufferSize = inLen+FF_INPUT_BUFFER_PADDING_SIZE;  
      }  
      memset(&m_pDecBuffer[inLen], 0, FF_INPUT_BUFFER_PADDING_SIZE);  
      memcpy(m_pDecBuffer, inBuf, inLen);  
      av_init_packet(&m_avPacket);  
      m_avPacket.data = m_pDecBuffer;  
      m_avPacket.size = inLen;  
 }  
 void Decoder::flush()  
 {  
      if (m_pCodecCtx)  
           avcodec_flush_buffers(m_pCodecCtx);  
 }  

< AudioDecoder.h>
 #ifndef __AUDIO_DECODER_H__  
 #define __AUDIO_DECODER_H__  
 #include "Decoder.h"  
 extern "C" {  
 #include "libswresample\swresample.h"  
 #include "libavutil\opt.h"  
 }  
 class AudioDecoder : public Decoder  
 {  
 public:  
      AudioDecoder();  
      virtual ~AudioDecoder();  
      virtual void close();  
      virtual int decodeFrame(unsigned char *inBuf, int inLen, AVFrame *frame);  
      unsigned char* outBuf() { return m_pOutBuf; }  
      int outBufSize() { return m_nOutBufSize; }  
      void setExtraData(unsigned char *extradata, int extradatasize);  
 protected:  
      virtual int open(enum AVCodecID codecId, AVCodecContext *codec, int channel);  
      int initResampler(uint64_t channel_layout, int sample_rate, enum AVSampleFormat sample_fmt);  
      int checkResampler();  
 protected:  
      struct SwrContext*     m_pSwrCtx;  
      unsigned char*     m_pOutBuf;  
      int                    m_nOutBufSize;  
      int                    m_nOutBufMaxSize;  
      unsigned char*     m_pExtraData;  
      int                    m_nExtraDataSize;  
 };  
 #endif  

< AudioDecoder.cpp >
 #include "AudioDecoder.h"  
 #include "GlobalEnv.h"  
 AudioDecoder::AudioDecoder() : Decoder(),  
 m_pSwrCtx(NULL), m_pOutBuf(NULL), m_nOutBufSize(0), m_nOutBufMaxSize(0), m_pExtraData(NULL), m_nExtraDataSize(0)  
 {  
 }  
 AudioDecoder::~AudioDecoder()  
 {  
 }  
 int AudioDecoder::open(enum AVCodecID codecId, AVCodecContext *codec, int channel)  
 {  
      int err;  
      char errbuf[128];  
      err = prepareOpen(codecId, codec);  
      if (err < 0) return -1;  
      if (m_bCodecCtxAlloc) {  
           m_pCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;  
           m_pCodecCtx->channels = channel;  
           if (codecId == AV_CODEC_ID_PCM_MULAW) {  
                m_pCodecCtx->sample_fmt = AV_SAMPLE_FMT_U8;  
           } else if (codecId == AV_CODEC_ID_AAC) {  
                if (m_pExtraData) {  
                     m_pCodecCtx->extradata = m_pExtraData;  
                     m_pCodecCtx->extradata_size = m_nExtraDataSize;  
                }  
                m_pCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16;  
           } else {  
                m_pCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16;  
           }  
      }  
      if (err=avcodec_open2(m_pCodecCtx, m_pCodec, NULL) < 0) {  
           av_strerror(err, errbuf, sizeof(errbuf));  
           DXPRINTF("avcodec_open2 %s open failed, err: %d %s\n", avcodec_get_name(codecId), err, errbuf);  
           goto exit;  
      }  
      int channel_layout = m_pCodecCtx->channel_layout;  
      if (channel_layout == 0) {  
           channel_layout = av_get_default_channel_layout(m_pCodecCtx->channels);  
      }  
      err = initResampler(channel_layout, m_pCodecCtx->sample_rate, m_pCodecCtx->sample_fmt);  
      if (err < 0) goto exit;  
      DXPRINTF("audio decoder opened %s\n", avcodec_get_name(codecId));  
 exit:  
      return err;  
 }  
 int AudioDecoder::initResampler(uint64_t channel_layout, int sample_rate, enum AVSampleFormat sample_fmt)  
 {  
      int err;  
      char errbuf[128];  
      if (m_pSwrCtx) {  
           swr_free(&m_pSwrCtx);  
           m_pSwrCtx = NULL;  
      }  
      m_pSwrCtx = swr_alloc();  
      av_opt_set_int(m_pSwrCtx, "in_channel_layout", channel_layout, 0);  
      av_opt_set_int(m_pSwrCtx, "in_sample_rate", sample_rate, 0);  
      av_opt_set_sample_fmt(m_pSwrCtx, "in_sample_fmt", sample_fmt, 0);  
      av_opt_set_int(m_pSwrCtx, "out_channel_layout", channel_layout, 0);  
      av_opt_set_int(m_pSwrCtx, "out_sample_rate", sample_rate, 0);  
      av_opt_set_sample_fmt(m_pSwrCtx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);  
      err = swr_init(m_pSwrCtx);  
      if (err < 0) {  
           av_strerror(err, errbuf, sizeof(errbuf));  
           DXPRINTF("swr_init failed, err: %d %s\n", err, errbuf);  
           return err;  
      }  
      return 0;  
 }  
 void AudioDecoder::close()  
 {  
      Decoder::close();  
      if (m_pSwrCtx) {  
           swr_free(&m_pSwrCtx);  
           m_pSwrCtx = NULL;  
      }  
      if (m_pExtraData) {  
           delete[] m_pExtraData;  
           m_pExtraData = NULL;  
           m_nExtraDataSize = 0;  
      }  
      if (m_pOutBuf) {  
           delete[] m_pOutBuf;  
           m_pOutBuf = NULL;  
           m_nOutBufMaxSize = m_nOutBufSize = 0;  
      }  
      if (m_pFile) {  
           fclose(m_pFile);  
           m_pFile = NULL;  
      }  
 }  
 int AudioDecoder::decodeFrame(unsigned char *inBuf, int inLen, AVFrame *frame)  
 {  
      if (!m_pCodecCtx || !inBuf || inLen <= 0) return 0;  
      int retLen = 0, got_frame;  
      prepareDecBuffer(inBuf, inLen);  
      __try  
      {  
           retLen = avcodec_decode_audio4(m_pCodecCtx, m_pFrame, &got_frame, &m_avPacket);  
      }  
      __except (EXCEPTION_EXECUTE_HANDLER)  
      {  
           GlobalEnv::WriteLogFile("[%s] avcodec_decode_audio4 crashed, (exception code : 0x%x)",   
                __FUNCTION__, GetExceptionCode());  
      }  
      if (retLen <= 0) {  
           DXPRINTF("audio decode error : %d\n", retLen);  
           return retLen;  
      }  
      int out_size = av_samples_get_buffer_size(NULL, m_pCodecCtx->channels, m_pFrame->nb_samples,  
           m_pCodecCtx->sample_fmt, 1);  
      if (out_size > m_nOutBufMaxSize) {  
           if (m_pOutBuf) delete[] m_pOutBuf;  
           m_pOutBuf = new unsigned char[out_size];  
           m_nOutBufMaxSize = out_size;  
      }  
      if (m_pSwrCtx) {  
           // audio resampling  
           if (checkResampler() < 0) return -1;  
           __try  
           {  
                retLen = swr_convert(m_pSwrCtx, &m_pOutBuf, out_size,   
                     (const uint8_t **)m_pFrame->extended_data, m_pFrame->nb_samples);  
           }  
           __except (EXCEPTION_EXECUTE_HANDLER)  
           {  
                GlobalEnv::WriteLogFile("[%s] swr_convert crashed, (exception code : 0x%x)",  
                     __FUNCTION__, GetExceptionCode());  
           }  
      } else {  
           if (m_pFrame->channels == 1) {  
                memcpy(m_pOutBuf, m_pFrame->extended_data[0], out_size);  
           } else {  
                uint8_t *data0 = m_pFrame->extended_data[0];  
                uint8_t *data1 = m_pFrame->extended_data[1];  
                int c = 0;  
                for (int i=0; i<out_size/2; i+=2) {  
                     m_pOutBuf[c++] = data0[i]; m_pOutBuf[c++] = data0[i+1];  
                     m_pOutBuf[c++] = data1[i]; m_pOutBuf[c++] = data1[i+1];  
                }  
                out_size = c;  
           }  
      }  
      out_size = retLen*m_pCodecCtx->channels*av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);  
      m_nOutBufSize = out_size;  
      if (m_pFile)  
           fwrite(m_pOutBuf, m_nOutBufSize, 1, m_pFile);  
      return retLen;  
 }  
 void AudioDecoder::setExtraData(unsigned char *extradata, int extradatasize)  
 {  
      if (m_pExtraData) {  
           delete[] m_pExtraData;  
           m_pExtraData = NULL;  
           m_nExtraDataSize = 0;  
      }  
      if (extradata == NULL || extradatasize <= 0)  
           return;  
      m_pExtraData = new unsigned char[extradatasize];  
      memset(m_pExtraData, 0, extradatasize);  
      memcpy(m_pExtraData, extradata, extradatasize);  
      m_nExtraDataSize = extradatasize;  
 }  
 int AudioDecoder::checkResampler()  
 {  
      int err;  
      int64_t channel_layout = 0;  
      int64_t sample_rate = 0;  
      int64_t sample_fmt = -1;  
      av_opt_get_int(m_pSwrCtx, "in_channel_layout", 0, &channel_layout);  
      av_opt_get_int(m_pSwrCtx, "in_sample_rate", 0, &sample_rate);  
      av_opt_get_int(m_pSwrCtx, "in_sample_fmt", 0, &sample_fmt);  
      if ((m_pCodecCtx->channel_layout != 0) && (channel_layout != m_pCodecCtx->channel_layout) ||  
           sample_rate != m_pCodecCtx->sample_rate ||  
           sample_fmt != m_pCodecCtx->sample_fmt) {  
           err = initResampler(m_pCodecCtx->channel_layout, m_pCodecCtx->sample_rate, m_pCodecCtx->sample_fmt);  
           if (err < 0)   
                return err;  
      }  
      return 0;  
 }  

< AudioDecoder 사용 >
 AudioDecoder *m_pDecoder = new AudioDecoder();  
 m_pDecoder->open(codec_id, channel);  
 ...  
 int ret = m_pDecoder->decodeFrame(pData, size, m_pDecoder->frame());  
 if (ret > 0) {  
   fwrite(m_pDecoder->outBuf(), m_pDecoder->outBufSize(), 1, fp);  
 }  
 ...  
 m_pDecoder->close();  
 delete m_pDecoder;  

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 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);
}

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 파일을 찾아야한다.


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# 소스코드

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/ >


2012년 5월 18일 금요일

ANSI <-> UTF-8 <-> Unicode 변환


int UnicodetoUTF8( LPWSTR pUniStr, int iLength, LPBYTE pUtf8Str )
{
WCHAR wChar;
BYTE szBytes[4] = { 0 };
int nbytes;
int i, j;
int iTotelLen = 0;

for( i = 0; i < iLength; i++ )
{
wChar = pUniStr[i];

if( 0x80 > wChar )
{
nbytes = 1;
szBytes[0] = (BYTE)wChar;
}
else if( 0x800 > wChar )
{
nbytes = 2;
szBytes[1] = ( wChar & 0x3f ) | 0x80;
szBytes[0] = ( ( wChar << 2 ) & 0xcf00 | 0xc000) >> 8;
}
else
{
nbytes = 3;
szBytes[2] = ( wChar & 0x3f ) | 0x80;
szBytes[1] = ( ( wChar << 2 ) & 0x3f00 | 0x8000) >> 8;
szBytes[0] = ( ( wChar << 4 ) & 0x3f0000 | 0xe00000) >> 16;
}

for( j = 0; j < nbytes; j++ )
{
pUtf8Str[iTotelLen] = szBytes[j];
iTotelLen++;
}
}

pUtf8Str[iTotelLen] = '\0';

return iTotelLen;
}

int Utf8ToUnicode( LPBYTE pUtf8Str, LPWSTR pUniStr )
{
int iIndex = 0;
int iCount = 0;
WCHAR wChar;

while( 0 != pUtf8Str[iIndex] )
{
if( ( 0xE0 == ( pUtf8Str[iIndex] & 0xE0 ) ) )
{
wChar = ( ( pUtf8Str[iIndex] & 0x0f ) << 12 ) |
( ( pUtf8Str[iIndex+1]&0x3F ) << 6 ) |
( pUtf8Str[iIndex+2] & 0x3F );

iIndex += 3;
}
else if( 0xC0 == ( pUtf8Str[iIndex] & 0xC0 ) )
{
wChar = ( ( pUtf8Str[iIndex] & 0x1F ) << 6 ) |
( pUtf8Str[iIndex+1] & 0x3F );

iIndex += 2;
}
else
{
wChar = pUtf8Str[iIndex] & 0x7F;

iIndex++;
}

pUniStr[iCount] = wChar;

iCount++;
}

pUniStr[iCount] = 0;

return iCount;
}

//char* UTF8ToANSI(char *pszCode)
int UTF8ToANSI(char *pszCode, char *pszAnsi)
{
BSTR    bstrWide;
//char*   pszAnsi;
int     nLength;

nLength = MultiByteToWideChar(CP_UTF8, 0, pszCode, lstrlen(pszCode) + 1, NULL, NULL);
bstrWide = SysAllocStringLen(NULL, nLength);

MultiByteToWideChar(CP_UTF8, 0, pszCode, lstrlen(pszCode) + 1, bstrWide, nLength);

nLength = WideCharToMultiByte(CP_ACP, 0, bstrWide, -1, NULL, 0, NULL, NULL);
//pszAnsi = new char[nLength];

WideCharToMultiByte(CP_ACP, 0, bstrWide, -1, pszAnsi, nLength, NULL, NULL);
SysFreeString(bstrWide);
//return pszAnsi;
return nLength;
}


char * ANSIToUTF8(char * pszCode)
{
int nLength, nLength2;
BSTR bstrCode;
char *pszUTFCode = NULL;

nLength = MultiByteToWideChar(CP_ACP, 0, pszCode, lstrlen(pszCode), NULL, NULL);
bstrCode = SysAllocStringLen(NULL, nLength);
MultiByteToWideChar(CP_ACP, 0, pszCode, lstrlen(pszCode), bstrCode, nLength);


nLength2 = WideCharToMultiByte(CP_UTF8, 0, bstrCode, -1, pszUTFCode, 0, NULL, NULL);
pszUTFCode = (char*)malloc(nLength2+1);
WideCharToMultiByte(CP_UTF8, 0, bstrCode, -1, pszUTFCode, nLength2, NULL, NULL);

return pszUTFCode;
}

< 출처 - http://blog.kangsoo.com/14http://skorea.tistory.com/43 >

2012년 4월 27일 금요일

ffmpeg 스케일러와 DirectDraw 를 이용한 YUV -> RGB 고속변환 출력 - YUV -> RGB Converting by ffmpeg and DirectDraw

YUV420->RGB32 변환출력의 경우 보통 이전에 포스팅된 YUV->RGB 변환방식을 사용하면된다. YUV420 버퍼를 YUV 평면에 그데로 복사하고 primary 평면에 blt 를 하면 yuv->rgb 변환과 스케일링을 동시에 고속으로 수행할 수 있다.

이번에 사용하는 방법은 YUV420 버퍼를 일반 RGB32 offscreen 평면에 스케일링한 후에  primary 평면에 blt 하는 방법이다.
이 방식은 기존 YUV->RGB 변환 방식과 성능이 동일하게 나오지만 비디오카드의 하드웨어 가속기를 사용하지않기 때문에 다른 프로세스가 하드웨어 가속기를 점유하고 있을경우에도 문제없이 사용할수 있다.

ffmpeg 스케일러 사용법과 DirectDraw 사용방법은 이전 포스팅 참조

< DirectDraw 평면 생성 >
...

ZeroMemory( &ddsd, sizeof( ddsd ) );
ddsd.dwSize         = sizeof( ddsd );
ddsd.dwFlags        = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;

ddsd.dwWidth        = targetWidth;
ddsd.dwHeight       = targetHeight;

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

// 스케일러 생성
sws = sws_getContext(srcWidth, srcHeight, PIX_FMT_YUV420P, targetWidth, targetHeight, PIX_FMT_RGB32, SWS_BILINEAR, NULL, NULL, NULL);
...

< primary 평면에 출력 >

int VideoDDraw::draw(AVFrame *pPicture, RECT *rectTarget)
...
ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
if ((hr=lpBackBuffer->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL)) == DD_OK)
{
        // offscreen 평면에 복사 (스케일링과 동시에 복사)
LPBYTE lpSurf = (LPBYTE)ddsd.lpSurface;
LPBYTE ptr = lpSurf;
unsigned char *src_buf[4];
src_buf[0] = pPicture->data[0];
src_buf[1] = pPicture->data[1];
src_buf[2] = pPicture->data[2];
src_buf[3] = NULL;

int src_stride[4];
src_stride[0] = pPicture->linesize[0];
src_stride[1] = pPicture->linesize[1];
src_stride[2] = pPicture->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 dst_stride[4];
dst_stride[0] = ddsd.lPitch;
dst_stride[1] = ddsd.lPitch;
dst_stride[2] = ddsd.lPitch;
dst_stride[3] = ddsd.lPitch;

        // 스케일링(변환된 데이터가 들어감)
sws_scale(sws, src_buf, src_stride, 0, h, dst_buf, dst_stride);

lpBackBuffer->Unlock(NULL);
}
...
// primary 평면에 blt
hr = lpPrimary->Blt(rectTarget, lpBackBuffer, &rectSrc, DDBLT_ASYNC, NULL);

2012년 3월 15일 목요일

윈도우 file descriptor -> HANDLE 변환 - converting file descriptor to HANDLE

int fd = open(file_name,O_RDWR);
HANDLE hFile = (void *)_get_osfhandle(fd);
...
ReadFile();
WriteFile();
...
close(fd);

2012년 3월 2일 금요일

자기 ip 알아내기 - obtaining host ip address

struct hostent *fHost;
char fMyIpAddr[64];

void getMyIP()
{
        char buffer[1024];

if (gethostname(buffer, sizeof(buffer)) == SOCKET_ERROR) {
printf("%s gethostname error !!!\r\n", __FUNCTION__);
return;
}

fHost = gethostbyname(buffer);
if (fHost == NULL) {
printf("%s gethostbyname error !!!\r\n", __FUNCTION__);
return;
}

sprintf(fMyIpAddr, "%d.%d.%d.%d", 
((struct in_addr *)(fHost->h_addr))->S_un.S_un_b.s_b1,
((struct in_addr *)(fHost->h_addr))->S_un.S_un_b.s_b2,
((struct in_addr *)(fHost->h_addr))->S_un.S_un_b.s_b3,
((struct in_addr *)(fHost->h_addr))->S_un.S_un_b.s_b4
);

}

2012년 2월 16일 목요일

win32 shutdown 함수 사용법 - how to use win32 shutdown function

shutdown 함수는 tcp 소켓통신에서 송신/수신 채널만을 닫을때 쓰는 함수이다.
select 함수를 쓰는 구조에서 소켓통신을 종료할때 closesocket(close) 을 바로 호출하면
select 함수에서 오류가 발생하고 소켓 전체적으로 문제가 발생한다. 이때 shutdown 함수를
호출해서 통신하는 상대방에게 FIN 패킷을 전달하여 상대방 recv 함수에서 0를 리턴하게
하여 상대방쪽에서 closesocket(close) 시켜 정상적으로 tcp 소켓을 닫을때 주로 사용한다.
이때 MS 의 페이크가 있는데 리눅스와 윈도우의 shutdown 함수의 인수는 서로 반대의 의미
를 가진다. 즉,
linux                                   windows
shutdown(SHUT_RD)  => shutdown(SD_SEND)
shutdown(SHUT_WR) => shutdown(SD_RECEIVE)

tcp 통신중 상대방에게 FIN 메시지를 전달해서 상대방으로 하여금 closesocket(close) 함수를
호출하도록 유도하려면 shutdown(SD_SEND) 함수를 호출

2012년 2월 10일 금요일

mingw64 를 이용한 ffmpeg/x264 x64 빌드 및 VC++ 링크 - building x64 ffmpeg/x264 with mingw64 and link in VC++


< ffmpeg && x264 x64 빌드 >
1. http://www.drangon.org/mingw/ 에서 mingw64 툴체인/소스 다운로드 및 설치
=> 툴체인: mingw-w64-bin-x86_64-20111106 *** 툴체인 mingw-w64-bin-x86_64-20120127 로 하면 mingw64 소스빌드 안됨 !!!
=> mingw64 소스: mingw-w64-v2.0.1 (소스 빌드하고 싶을때만)
2. msys 설치
3. ffmpeg 빌드
./configure --enable-memalign-hack
*** pr.exe, yasm.exe, pkg-config.exe(libglib-2.0_0.dll, intl.dll, libiconv-2.dll) 등 필요한것들 msys/bin 밑으로 복사
make

4. x264 빌드
./configure --cross-prefix=x86_64-w64-mingw32- --host=x86_64-pc-mingw32
endian test failed => configure 파일에서 endian test 하는 부분 전부 주석처리

x86_64-w64-mingw32-ar: command not found
x86_64-w64-mingw32-ranlib: command not found
=> mingw64/bin 아래에 ar.exe,ranlib.exe 복사본만들어서 파일 이름 위와같이 변경

dumpbin /headers libavcodec.lib | more => x64 빌드되었는지 확인
for /R %f in (*.obj *.lib) do @echo %f && dumpbin /headers %f | findstr /c:"machine (x86)"

5. mingw64 툴체인 디렉토리에서 libmingwex.a, libgcc.a 복사 링크
6. unresolved external symbol __mingw_raise_matherr 등 => libdummy.a 링크로 해결
7.
libavformat.a(tcp.o) : error LNK2001: unresolved external symbol gai_strerrorA
libavformat.a(udp.o) : error LNK2001: unresolved external symbol gai_strerrorA
=> config.h 에
#define HAVE_GETADDRINFO 1 -> 0 수정

8. VC++ 디버그 모드 빌드시 에러처리
libmingwex.a(lib64_libmingwex_a-wassert.o) : error LNK2005: _wassert already defined in MSVCRTD.lib(MSVCR90D.dll)
=> ar -d libmingwex.a lib64_libmingwex_a-wassert.o

소스수정으로 해결하는 방법
=> 툴채인 mingw-w64-bin-x86_64-20111106 버전으로 할것 !!!
=> mingw-w64-crt\misc\wassert.c 에서 __wassert() => ___wassert() 변경

*** .a 파일의 object member 보기
dumpbin /list libmingwex.a

*** dummy.c (libdummy.a) 소스 (6번 unresolved external symbol 에러해결)


int mingw_app_type = 0;
void __mingw_raise_matherr (int typ, const char *name, double a1, double a2,
   double rslt)
{
}

typedef int HMODULE;
HMODULE __mingw_get_msvcrt_handle(void)
{
return 0;
}

2012년 1월 21일 토요일

윈도우 7, 2008 서버에서 오류보고창 뜨는것 막기 - disable wer(window error reporting) dialog in windows 7 and windows 2008 server

윈7, 2008 서버 등에서 응용프로그램이 오류로 인해 비정상 종료될때 오류보고 다이얼로그창이 항상 뜬다. 경우에 따라 이 기능을 제거해야할때가 있다. 예를 들어 특정 프로세스가 종료되었는지 모니터링을 해야하는 경우 사용자가 오류보고 창의 닫기버튼을 클릭해야 프로세스가 종료가 된다. 이럴때 프로세스가 비정상 종료되었음에도 모니터링 프로세스는 이것을 자동으로 감지할수가 없다. 이때 아래 과정을 통해 오류보고창을 완전히 막아버릴수 있다.

시작 -> gpedit.msc 실행

컴퓨터 구성 -> 관리 템플릿 -> windows 구성 요소 -> windows 오류보고

-> 오류에 대해 사용자 인터페이스 표시 안 함 더블클릭

사용(E) 선택 -> 확인