2016년 12월 29일 목요일

C# BeginInvoke 올바른 사용법

BeginInvoke 호출할때 보통 람다식을 사용해서 아래와 같이 쓴다

        private void SetPictureImage(PictureBox picture, Bitmap bitmap)
        {
            Action action = () =>
            {
                if (picture.Image != null) picture.Image.Dispose();
                picture.Image = bitmap;              
            };
            if (this.InvokeRequired) BeginInvoke(action);
            else action();
        }

위 코드의 문제점은 action 이 수행되는 동안 SetPictureImage 함수가 외부 쓰레드에서 호출될때 사용중인 picture, bitmap 변수가 변경될 수 있다는 점이다.

이게 무슨 말이냐면 action 함수 내의 코드와 바깥의 SetPictureImage 함수가 서로 다른 쓰레드에서 호출될 수 있다는 말이다. (InvokeRequired = true 인 경우)
이럴경우 action 함수에서 picture,bitmap 변수를 사용하는 도중 SetPictureImage 함수가 호출되면 picture,bitmap 변수값이 사용도중 바뀌어 에러를 발생시킨다.

이것을 방지하기위해 아래와 같이 action 호출시 변수들을 매개변수로 넘겨주면 버그를 방지할 수 있다.

        private void SetPictureImage(PictureBox picture, Bitmap bitmap)
        {
            Action<PictureBox, Bitmap> action = (picture1, bitmap1) =>
                {
                    if (picture1.Image != null) picture1.Image.Dispose();
                    picture1.Image = bitmap1;
                };
            if (this.InvokeRequired) BeginInvoke(action, picture, bitmap);
            else action(picture, bitmap);
        }

2016년 10월 12일 수요일

리눅스 ffmpeg CUDA 비디오 코덱 연동 빌드 - build ffmpeg with cuda video codec on linux

1. nvidia 드라이버, cuda 툴킷 설치 - /usr/local/cuda
2. cuda video codec 설치 - /home/ubuntu/work/Video_Codec_SDK_7.0.1
3. x264 설치(비교 테스트용) - /home/ubuntu/work/x264/build
4. ffmpeg 빌드(64비트)

./configure --prefix=./build/ --enable-shared --disable-static --enable-cuda --enable-nvenc --enable-nonfree --extra-cflags=-I/usr/local/cuda-8.0/include \
--extra-cflags=-I/home/ubuntu/work/Video_Codec_SDK_7.0.1/Samples/common/inc --arch=x86_6
4 --enable-libx264 --enable-gpl --extra-cflags=-I/home/ubuntu/work/x264/build/include --extra-ldflags=-L/home/ubuntu/work/x264/build/lib

2016년 7월 13일 수요일

소켓 프로그래밍에 대한 조언

언어와 플랫폼을 불문하고 소켓 프로그래밍은 형태가 조금씩 다를뿐이지 내부구현은 완전히 동일하다.
기본적으로 POSIX 소켓 API 로 제공되는 low level API 들이 있고 각 플랫폼마다 이것들을 래핑한 상위 레이어들이 존재하는 형태이다.

응용 프로그램에서는 이러한 low level API를 가지고 개발할 것인지 좀더 편리한 상위 라이브러리를
이용할 것인지 결정해서 개발하면된다.

소켓 프로그래밍을 처음 입문하는 개발자들은 개발에 용이한 상위 라이브러리가 아무래도 많이 끌릴것이다. 심지어 경력 개발자들도 이러한 라이브러리를 이용해서 개발하는것을 선호하기도한다.

개인적으로 소켓 프로그래밍은 반드시 low level API로 개발해야한다고 생각한다. 사실 말이 low level이지 그냥 소켓 API 들이다. C#/Java 등의 언어에서 제공되는 상위 클래스들은 이러한 소켓 API 들을 래핑해서 사용하기 편리하게 만들어주는 역할밖에 하지않는다.

문제는 이러한 라이브러리를 사용해서 개발하다보면 내부구현을 볼 수가 없어서 다양한 상황들이 발생하는 네트워크 프로그래밍에서 올바른 대처를 하기가 어렵다는 점이다. 물론 잘 사용하면 대부분 문제는 없지만 이러한 방법에 길들여지면 소켓 프로그래밍이나 TCP/IP의 기본원리를 이해하기 힘들다는 점도있다.

사실 소켓 프로그래밍을 시작하기 전에 기본적인 TCP/IP 에 대한 이해가 필요하다. 개발을 해가면서 이해하든 미리 공부를 하든 기본적인 TCP/UDP의 동작정도는 알고 시작하는것이 좋다.

여기서 중요한 점은 응용 프로그램과 TCP/IP간의 관계에 대해서 잘 알아야한다는것이다. 
사실 실제적인 데이터 전송과 수신은 TCP/IP가 하는것이지 응용 프로그램이 하는것이 아니다.
응용 프로그램과 TCP/IP는 서로 다른 계층에 존재하고 소켓 API를 통해 서로 데이터를 주고받는데 응용 프로그램의 역할과 TCP/IP의 역할을 잘 알아야 특정한 상황이 발생했을때 이것을 분석해서 원인을 유추하는것이 가능하다.
또한 응용 프로그램간의 프로토콜을 정의하고 구현하는데도 이러한 지식이 필요하다.

마지막으로 한가지 더하자면 통신 프로그램은 아주 정교하게 작성해야한다. TCP 서버/클라이언트 개발자는 잘 알겠지만 통신 상황에서는 너무나도 다양한 케이스들이 발생한다. 대상이 일반 유저라면 생각할 수 있는 거의 모든 경우의 수가 다 발생한다고 보면된다. 
적당히 데이터 주고받는 테스트 정도만 수행하고 릴리즈를 했다간 큰 낭패를 볼 수 있다. 네트워크 상황은 시시각각 변하기때문에 특정 상황에 대한 스냅샷을 잡기가 굉장히 힘들고 이것을 사후에 분석하는것도 어렵기때문에 애초에 robust한 프로그래밍과 테스트가 필요하다.

2016년 7월 4일 월요일

C# 소켓 Select 함수 사용방법 - C# Socket Select

C# 소켓 프로그래밍에서도 기존 POSIX select 함수를 그대로 사용할 수 있다. 방식은 제공되는 Socket 클래스의 Select 정적 멤버함수를 사용하면된다.

< 일반적인 select 사용 >
         try  
         {  
           ArrayList selectList = new ArrayList();  
             
           selectList.Add(mySock);             
   
           if (selectList.Count == 0)  
           {  
             Thread.Sleep(10);  
             return;  
           }  
   
           Socket.Select(selectList, null, null, 1000000);  
   
           foreach (Socket sock in selectList)  
           {                    
             if (sock == mySock)
             {
                 // do something with mySock...
             }
           }            
         }  
         catch (Exception ex)  
         {  
           Trace.WriteLine(ex.ToString());  
         }  

< TCP Connection 타임아웃 >
      
Socket clientSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
clientSock.Blocking = false;
...
public bool Connect(IPAddress serverIP, int serverPort, int timeout) 
{
       try  
       {  
         clientSock.Connect(serverIP, serverPort);        
         return true;  
       }  
       catch (SocketException ex)  
       {          
         if (ex.SocketErrorCode == SocketError.WouldBlock)  
         {  
           ArrayList selectArray = new ArrayList();  
           selectArray.Add(clientSock);  
   
           Socket.Select(null, selectArray, null, timeout * 1000000);  
   
           if (selectArray.Count == 0)  
           {
             Trace.WriteLine(ex.ToString());  
             return false;  
           }
   
           return true;  
         }    
       }  
       catch (Exception ex)  
       {          
         Trace.WriteLine(ex.ToString());  
         return false;  
       }  
}

2016년 6월 20일 월요일

C# 간단한 시리얼 통신 라이브러리 소스코드 - simple c# source code for serial communication

 using System;  
 using System.Collections.Generic;  
 using System.Diagnostics;  
 using System.IO.Ports;  
 using System.Linq;  
 using System.Text;  
 using System.Threading;  
 using System.Threading.Tasks;  
   
 namespace SerialCommLib  
 {        
   public class SerialComm
   {    
     public delegate void DataReceivedHandlerFunc(byte[] receiveData);  
     public DataReceivedHandlerFunc DataReceivedHandler;  
   
     public delegate void DisconnectedHandlerFunc();  
     public DisconnectedHandlerFunc DisconnectedHandler;
   
     private SerialPort serialPort;  
      
     public bool IsOpen   
     {   
       get   
       {   
         if (serialPort != null) return serialPort.IsOpen;  
         return false;  
       }   
     }  
      
     // serial port check
     private Thread threadCheckSerialOpen;  
     private bool isThreadCheckSerialOpen = false;  
   
     public SerialComm()  
     {  
     }  
   
     public bool OpenComm(string portName, int baudrate, int databits, StopBits stopbits, Parity parity, Handshake handshake)  
     {  
       try  
       {  
         serialPort = new SerialPort();  
   
         serialPort.PortName = portName;  
         serialPort.BaudRate = baudrate;  
         serialPort.DataBits = databits;  
         serialPort.StopBits = stopbits;  
         serialPort.Parity = parity;  
         serialPort.Handshake = handshake;  
   
         serialPort.Encoding = new System.Text.ASCIIEncoding();  
         serialPort.NewLine = "\r\n";  
         serialPort.ErrorReceived += serialPort_ErrorReceived;     
         serialPort.DataReceived += serialPort_DataReceived; 
   
         serialPort.Open();  
   
         StartCheckSerialOpenThread();  
         return true;  
       }  
       catch (Exception ex)  
       {  
         Debug.WriteLine(ex.ToString());  
         return false;  
       }  
     }  
   
     public void CloseComm()  
     {  
       try  
       {  
         if (serialPort != null)  
         {  
           StopCheckSerialOpenThread();  
           serialPort.Close();  
           serialPort = null;  
         }  
       }  
       catch (Exception ex)  
       {  
         Debug.WriteLine(ex.ToString());  
       }  
     }  
   
     public bool Send(string sendData)  
     {  
       try  
       {  
         if (serialPort != null && serialPort.IsOpen)  
         {  
           serialPort.Write(sendData);  
           return true;  
         }          
       }  
       catch (Exception ex)  
       {  
         Debug.WriteLine(ex.ToString());  
       }  
       return false;  
     }  
   
     public bool Send(byte[] sendData)  
     {  
       try  
       {  
         if (serialPort != null && serialPort.IsOpen)  
         {  
           serialPort.Write(sendData, 0, sendData.Length);  
           return true;  
         }  
       }  
       catch (Exception ex)  
       {  
         Debug.WriteLine(ex.ToString());  
       }  
       return false;  
     }  
   
     public bool Send(byte[] sendData, int offset, int count)  
     {  
       try  
       {  
         if (serialPort != null && serialPort.IsOpen)  
         {  
           serialPort.Write(sendData, offset, count);  
           return true;  
         }  
       }  
       catch (Exception ex)  
       {  
         Debug.WriteLine(ex.ToString());  
       }  
       return false;  
     }  
   
     private byte[] ReadSerialByteData()  
     {  
       serialPort.ReadTimeout = 100;  
       byte[] bytesBuffer = new byte[serialPort.BytesToRead];  
       int bufferOffset = 0;  
       int bytesToRead = serialPort.BytesToRead;  
   
       while (bytesToRead > 0)  
       {  
         try  
         {  
           int readBytes = serialPort.Read(bytesBuffer, bufferOffset, bytesToRead - bufferOffset);  
           bytesToRead -= readBytes;  
           bufferOffset += readBytes;  
         }  
         catch (TimeoutException ex)  
         {  
           Debug.WriteLine(ex.ToString());  
         }  
       }  
   
       return bytesBuffer;  
     }  
   
     private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)  
     {  
       try  
       {  
         byte[] bytesBuffer = ReadSerialByteData();  
         string strBuffer = Encoding.ASCII.GetString(bytesBuffer);  

         if (DataReceivedHandler != null)  
           DataReceivedHandler(bytesBuffer);  
   
         Debug.WriteLine("received(" + strBuffer.Length + ") : " + strBuffer);     
       }  
       catch (Exception ex)  
       {  
         Debug.WriteLine(ex.ToString());  
       }  
     }  
   
     private void serialPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)  
     {  
       Debug.WriteLine(e.ToString());  
     }  
      
     private void StartCheckSerialOpenThread()  
     {   
       isThreadCheckSerialOpen = true;  
       threadCheckSerialOpen = new Thread(new ThreadStart(ThreadCheckSerialOpen));  
       threadCheckSerialOpen.Start();  
     }  
   
     private void StopCheckSerialOpenThread()  
     {  
       if (isThreadCheckSerialOpen)  
       {  
         isThreadCheckSerialOpen = false;  
         if (Thread.CurrentThread != threadCheckSerialOpen)  
           threadCheckSerialOpen.Join();
       }  
     }  
   
     private void ThreadCheckSerialOpen()  
     {  
       while (isThreadCheckSerialOpen)  
       {  
         Thread.Sleep(100);  
   
         try  
         {  
           if (serialPort == null || !serialPort.IsOpen)  
           {  
             Debug.WriteLine("seriaport disconnected");  
             if (DisconnectedHandler != null)  
               DisconnectedHandler();  
             break;  
           }  
         }  
         catch (Exception ex)  
         {  
           Debug.WriteLine(ex.ToString());  
         }  
       }  
     }  
   }  
 }  
   


< SerialComm 사용 >

using System.IO.Ports;

using SerialCommLib;
...
SerialComm serial = new SerialComm();
serial.DataReceivedHandler = DataReceivedHandler;
serial.DisconnectedHandler = DisconnectedHandler;
...
serial.OpenComm("COM3", 9600, 8, StopBits.One, Parity.None, Handshake.None);
...
serial.CloseComm();

private void DataReceivedHandler(byte[] receiveData)
{
    // do something with receiveData here
}

private void DisconnectedHandler()
{
    Console.WriteLine("serial disconnected");
}

* 라이브러리 사용은 시리얼 데이터 수신과 연결종료 이벤트 핸들러를 등록해서 콜백으로 받아서 처리하는 방식으로 간단하게 사용할 수 있다.

C# SerialPort 클래스는 이벤트 수신 방식과 쓰레드 방식 두 가지로 사용할 수 있는데 쓰레드 방식보다 이벤트 수신 방식이 더 간단하고 직관적이다.
SerialPort 클래스의 Read 계열 메소드는 블러킹 방식으로 동작하기때문에 데이터 수신 이벤트 발생시 반드시 BytesToRead 에 명시된 모든 바이트를 읽어서 수신버퍼를 비워줘야한다.


2016년 2월 4일 목요일

OpenCV sample build

cmake -G "Visual Studio 11 2012" -DBUILD_EXAMPLES=1

* samples 아래에 있는 소스들 솔루션/프로젝트 파일 만들 수 있다.

2016년 1월 28일 목요일

ffmpeg 비디오 필터 사용 소스코드 - ffmpeg video filter sample source code

뮤텍스 소스

< VideoFilter.h >
 #ifndef __VIDEO_FILTER_H__  
 #define __VIDEO_FILTER_H__  
   
 extern "C" {  
 #include "libavfilter/avfiltergraph.h"  
 #include "libavfilter/buffersink.h"  
 #include "libavfilter/buffersrc.h"  
 }  
   
 #include "Mutex.h"  
   
 struct VideoFilterParam {  
      int width;  
      int height;  
      AVPixelFormat pix_fmt;  
      AVRational time_base;  
      AVRational sample_aspect_ratio;  
 };  
   
 class VideoFilter   
 {  
 public:  
      VideoFilter();  
      virtual ~VideoFilter();  
   
      int initFilter(struct VideoFilterParam &param, int vflip, int hflip, int rotate);  
      void freeFilter();  
   
      int processFilter(AVFrame *newFrame, AVFrame *frame);  
   
      int checkFilter(struct VideoFilterParam &param);  
   
 protected:  
      static void initFilter();  
   
 protected:  
      AVFilterGraph*          m_pFilterGraph;  
      AVFilterContext*     m_pBufferSinkCtx;  
      AVFilterContext*     m_pBufferSrcCtx;       
      AVFrame*               m_pFrame;  
   
      int                    m_nWidth;  
      int                    m_nHeight;  
      AVPixelFormat     m_nPixelFormat;  
      AVRational          m_timeBase;  
      AVRational          m_sampleAspectRatio;  
   
      static MUTEX     m_hMutex;  
      static bool          m_bInit;  
 };  
   
 #endif  
   

< VideoFilter.cpp >
 #include "VideoFilter.h"  
 #include "GlobalEnv.h"  
 #include "CommonType.h"  
   
 bool VideoFilter::m_bInit = false;  
 MUTEX VideoFilter::m_hMutex = PTHREAD_MUTEX_INITIALIZER;  
   
 VideoFilter::VideoFilter() : m_pFilterGraph(NULL), m_pBufferSrcCtx(NULL), m_pBufferSinkCtx(NULL), m_pFrame(NULL)  
 {  
      initFilter();  
      m_nWidth = m_nHeight = 0;  
      m_nPixelFormat = AV_PIX_FMT_NONE;  
      m_timeBase.den = m_timeBase.num = 0;  
      m_sampleAspectRatio.den = m_sampleAspectRatio.num = 0;  
 }  
   
 VideoFilter::~VideoFilter()  
 {  
      freeFilter();  
 }  
   
 void VideoFilter::initFilter()  
 {  
      MUTEX_LOCK(&m_hMutex);  
   
      if (!m_bInit) {  
           avfilter_register_all();  
           m_bInit = true;  
      }  
   
      MUTEX_UNLOCK(&m_hMutex);  
 }  
   
 int VideoFilter::initFilter(struct VideoFilterParam &param, int vflip, int hflip, int rotate)  
 {  
      freeFilter();  
   
      char args[128];  
   snprintf(args, sizeof(args),  
       "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",  
       param.width, param.height, param.pix_fmt,   
                param.time_base.num, param.time_base.den,   
       param.sample_aspect_ratio.num, param.sample_aspect_ratio.den);  
   
      m_pFrame = av_frame_alloc();  
      m_pFilterGraph = avfilter_graph_alloc();  
   
      char errbuf[128];  
      int err = avfilter_graph_create_filter(&m_pBufferSrcCtx, avfilter_get_by_name("buffer"), "buffer1", args, NULL, m_pFilterGraph);       
      if (err < 0) {  
           av_strerror(err, errbuf, sizeof(errbuf));  
           DXPRINTF("avfilter_graph_create_filter failed, err : %s\n", errbuf);  
           return -1;  
      }  
   
      err = avfilter_graph_create_filter(&m_pBufferSinkCtx, avfilter_get_by_name("buffersink"), "buffersink1", NULL, NULL, m_pFilterGraph);  
      if (err < 0) {  
           av_strerror(err, errbuf, sizeof(errbuf));  
           DXPRINTF("avfilter_graph_create_filter failed, err : %s\n", errbuf);  
           return -1;  
      }  
   
      AVFilterContext *vflipCtx = NULL;  
      AVFilterContext *hflipCtx = NULL;  
      AVFilterContext *rotateCtx = NULL;  
      AVFilterContext *prevCtx = m_pBufferSrcCtx;  
   
      if (vflip > 0) {  
           err = avfilter_graph_create_filter(&vflipCtx, avfilter_get_by_name("vflip"), "vflip1", NULL, NULL, m_pFilterGraph);  
           if (err < 0) {  
                av_strerror(err, errbuf, sizeof(errbuf));  
                DXPRINTF("avfilter_graph_create_filter failed, err : %s\n", errbuf);  
                return -1;  
           }  
           err = avfilter_link(prevCtx, 0, vflipCtx, 0);  
           if (err < 0) {  
                av_strerror(err, errbuf, sizeof(errbuf));  
                DXPRINTF("avfilter_link failed, err : %s\n", errbuf);  
                return -1;  
           }  
           prevCtx = vflipCtx;  
      }  
   
      if (hflip > 0) {  
           err = avfilter_graph_create_filter(&hflipCtx, avfilter_get_by_name("hflip"), "hflip1", NULL, NULL, m_pFilterGraph);  
           if (err < 0) {  
                av_strerror(err, errbuf, sizeof(errbuf));  
                DXPRINTF("avfilter_graph_create_filter failed, err : %s\n", errbuf);  
                return -1;  
           }  
           err = avfilter_link(prevCtx, 0, hflipCtx, 0);  
           if (err < 0) {  
                av_strerror(err, errbuf, sizeof(errbuf));  
                DXPRINTF("avfilter_link failed, err : %s\n", errbuf);  
                return -1;  
           }  
           prevCtx = hflipCtx;  
      }  
   
      if (rotate) {  
           snprintf(args, sizeof(args), "PI*2/360*%d", rotate);  
           err = avfilter_graph_create_filter(&rotateCtx, avfilter_get_by_name("rotate"), "rotate1", args, NULL, m_pFilterGraph);  
           if (err < 0) {  
                av_strerror(err, errbuf, sizeof(errbuf));  
                DXPRINTF("avfilter_graph_create_filter failed, err : %s\n", errbuf);  
                return -1;  
           }  
           err = avfilter_link(prevCtx, 0, rotateCtx, 0);  
           if (err < 0) {  
                av_strerror(err, errbuf, sizeof(errbuf));  
                DXPRINTF("avfilter_link failed, err : %s\n", errbuf);  
                return -1;  
           }  
           prevCtx = rotateCtx;  
      }  
   
      err = avfilter_link(prevCtx, 0, m_pBufferSinkCtx, 0);  
      if (err < 0) {  
           av_strerror(err, errbuf, sizeof(errbuf));  
           DXPRINTF("avfilter_link failed, err : %s\n", errbuf);  
           return -1;  
      }  
   
      err = avfilter_graph_config(m_pFilterGraph, NULL);  
      if (err < 0) {  
           av_strerror(err, errbuf, sizeof(errbuf));  
           DXPRINTF("avfilter_graph_config failed, err : %s\n", errbuf);  
           return -1;  
      }  
   
      m_nWidth = param.width;  
      m_nHeight = param.height;  
      m_nPixelFormat = param.pix_fmt;  
      m_timeBase.den = param.time_base.den;  
      m_timeBase.num = param.time_base.num;  
      m_sampleAspectRatio.den = param.sample_aspect_ratio.den;  
      m_sampleAspectRatio.num = param.sample_aspect_ratio.num;  
   
      return 0;  
 }  
   
 void VideoFilter::freeFilter()  
 {  
      avfilter_graph_free(&m_pFilterGraph);  
      av_frame_free(&m_pFrame);  
   
      m_nWidth = m_nHeight = 0;  
      m_nPixelFormat = AV_PIX_FMT_NONE;  
      m_timeBase.den = m_timeBase.num = 0;  
      m_sampleAspectRatio.den = m_sampleAspectRatio.num = 0;  
 }  
   
 AVFrame* copyFrame(AVFrame *frame)  
 {  
      AVFrame *new_frame = avcodec_alloc_frame();  
      if (new_frame) {  
           if (av_image_alloc(new_frame->data, new_frame->linesize,  
                frame->width, frame->height, (AVPixelFormat)frame->format, 1) > 0)   
           {  
                av_image_copy(new_frame->data, new_frame->linesize,  
                     (const uint8_t **)frame->data, frame->linesize, (AVPixelFormat)frame->format,  
                     frame->width, frame->height);  
   
                new_frame->width = frame->width;  
                new_frame->height = frame->height;  
                new_frame->pict_type = frame->pict_type;  
                new_frame->format = frame->format;  
   
                return new_frame;  
           }  
           else  
           {  
                av_free(new_frame->data[0]);  
                av_free(new_frame);  
           }  
      }  
   
      return NULL;  
 }  
   
 int VideoFilter::processFilter(AVFrame *newFrame, AVFrame *frame)  
 {  
      if (!m_pFilterGraph) return -1;  
   
      int ret = av_buffersrc_add_frame_flags(m_pBufferSrcCtx, frame, AV_BUFFERSRC_FLAG_KEEP_REF);  
      if (ret >= 0) {  
           while (1) {  
                ret = av_buffersink_get_frame(m_pBufferSinkCtx, m_pFrame);  
                if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) break;  
                if (ret < 0) break;  
        
                newFrame = copyFrame(m_pFrame);  
                av_frame_unref(m_pFrame);  
           }  
      }  
      return 0;  
 }  
   
 int VideoFilter::checkFilter(struct VideoFilterParam &param)  
 {  
      if (m_nWidth != param.width || m_nHeight != param.height ||   
           m_nPixelFormat != param.pix_fmt ||  
           m_timeBase.den != param.time_base.den || m_timeBase.num != param.time_base.num ||  
           m_sampleAspectRatio.den != param.sample_aspect_ratio.den ||   
           m_sampleAspectRatio.num != param.sample_aspect_ratio.num)   
      {  
           return -1;  
      }  
   
      return 0;  
 }  
   

< VideoFilter 사용 >

AVCodecContext *pCodecCtx;
...
struct VideoFilterParam param;
param.width = pCodecCtx->width;
param.height = pCodecCtx->height;
param.pix_fmt = pCodecCtx->pix_fmt;
param.time_base.den = pCodecCtx->time_base.den;
param.time_base.num = pCodecCtx->time_base.num;
param.sample_aspect_ratio.den = pCodecCtx->sample_aspect_ratio.den;
param.sample_aspect_ratio.num = pCodecCtx->sample_aspect_ratio.num;
...
VideoFilter *filter = new VideoFilter();
...
filter->initFilter(param, 1, 1, 30);    // 상하반전, 좌우반전, 30도 회전
...
if (filter->checkFilter(param) < 0) {
    filter->freeFilter();
 
    param.width = pCodecCtx->width;
    param.height = pCodecCtx->height;
    param.pix_fmt = pCodecCtx->pix_fmt;
    param.time_base.den = pCodecCtx->time_base.den;
    param.time_base.num = pCodecCtx->time_base.num;
    param.sample_aspect_ratio.den = pCodecCtx->sample_aspect_ratio.den;
    param.sample_aspect_ratio.num = pCodecCtx->sample_aspect_ratio.num;
}  
filter->processFilter(newFrame, frame);   // newFrame은 처리결과, frame은 디코딩된 프레임
...
filter->freeFilter();