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