2015년 8월 11일 화요일

DBCP validationQuery 설정

* 참고 사이트: http://linuxism.tistory.com/579
* 참고 사이트: Configuring the High Concurrency JDBC Connection Pool
* 참고 사이트: DBCP 설정 정리

에러 메시지 일부분
 - is longer than the server configured value of 'wait_timeout'.

원인 
 - 마지막으로 DB에 커넥션을 맺은후 사용이 없다 보니 데이터 베이스 커넥션이 끝겼다. 

해결책
 - 특정 시간마다 커넥션을 확인 하는 셋팅을 지정한다. 

적용 코드
 - MySQL
  • validationQuery="select 1"

 - 오라클의 경우
  • validationQuery="select 1 from dual"


상세 설명
mysql wait_timeout 설정(기본값 28800 , 8시간) 에 의해 커넥션이 연결된 이후 해당커넥션의 close 없이 8시간이 지나면 해당 커넥션을 종료 시키게 된다.
문제는 이렇게 종료된 커넥션을 dbcp의 connection pool 에선 여전히 가지고 있는 상태라는 것이다.이런 상황에서 DB 관련 프로그램이 호출되면 커넥션 관련 에러가 발생된다.
해결방법은 java에서 DB를 사용하기 전에 해당 connection 이 정상적인지 검사를 하도록 하는 것이다. 이 옵션이 validationQuery 파라미터이다.

* 추가 작업
 - timeBetweenEvctionRunsMillis - 사용되지 않는 커넥션을 추출하는 쓰레드의 실행 주기를 지정
    이값을 알맞게 지정해서 사용되지 않는 커넥션을 제거하는것이 좋다 보통 10~20분 단위 검사

 - testWhileIdle - true 일 경우 비활성화 커넥션을 추출할때 커넥션이 유효한지 여부를 검사해서 유효하지 않으면 제거


추가 적용 코드
  • validationQuery="select 1"
  • testWhileIdle="true"   
  • timeBetweenEvictionRunsMillis="30000"
 - testWhileIdle:컨넥션이 놀고 있을때, validationQuery 를 이용해서 유효성 검사를 할지 여부.
 - timeBetweenEvictionRunsMillis:해당 밀리초마다 validationQuery 를 이용하여 유효성 검사 진행.

* 더 추가 작업
 - 이렇게 설정하면 컨넥션을 풀에서 가져 올때도, validationQuery를 통해서 유효성 검사를 진행하게 되는데
 - 퍼포먼스가 문제 될거라고 생각된다면 testOnBorrow( default : true ) 값을 false 로 추가해주면 된다.
 - testOnBorrow : true일 경우 커넥션을 가져올 때 커넥션이 유효한지의 여부를 검사.

웹 프로젝트에 UTF-8 인코딩 설정




Tomcat 및 서블릿 컨테이너 설정 추가

$CATALINA_HOME/conf/server.xml
또는 이클립스 IDE > Servers 폴더 > server.xml 수정.
Connector 에 URIEncoding="UTF-8" 을 추가

web.xml 에 인코딩 필터 추가

     <!-- Encoding filter : UTF-8 -->  
     <filter>  
         <filter-name>EncodingFilter</filter-name>  
         <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>  
         <init-param>  
             <param-name>encoding</param-name>  
             <param-value>UTF-8</param-value>  
         </init-param>  
     </filter>  
     <filter-mapping>  
         <filter-name>EncodingFilter</filter-name>  
         <url-pattern>/*</url-pattern>  
     </filter-mapping>  


JSP 파일에 내용 추가 (2가지 중 아무거나 가능)

1. jsp 파일: <%@ page contentType="text/html; charset=utf-8" %>
2. web.xml: jsp 2.1 부터 JSP의 모든 페이지의 인코딩을 web.xml에 설정 가능
     <!-- All jsp page encoding setting -->  
     <jsp-config>  
         <jsp-property-group>  
             <description>jsp page encoding</description>  
             <display-name>Encoding</display-name>  
             <url-pattern>*.jsp</url-pattern>  
             <el-ignored>false</el-ignored>  
             <page-encoding>UTF-8</page-encoding>  
             <scripting-invalid>false</scripting-invalid>  
             <is-xml>false</is-xml>  
         </jsp-property-group>  
     </jsp-config>  



blogspot tips

code formatting

web.xml sample

 <?xml version="1.0" encoding="UTF-8"?>  
 <web-app xmlns="http://java.sun.com/xml/ns/javaee"  
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"  
   version="2.5">  
   
   <!-- JDBC 연결을 위한 정보 -->  
   <resource-ref>  
     <description>OracleDatasource</description>  
     <res-ref-name>jdbc/myoracle</res-ref-name>  
     <res-type>javax.sql.DataSource</res-type>  
     <res-auth>Container</res-auth>  
   </resource-ref>  
   
   <context-param>  
     <param-name>ds</param-name>  
     <param-value>jdbc/myoracle</param-vlaue>  
   </context-param>  
   
   <!-- Filter 설정 (Encoding Filter) -->  
   <filter>  
     <filter-name>Encoding Filter</filter-name>  
     <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>  
     <init-param>  
       <param-name>encoding</param-name>  
       <param-value>UTF-8</param-value>  
     </init-param>  
   </filter>  
   
   <filter-mapping>  
     <filter-name>Encoding Filter</filter-name>  
     <servlet-name>action</servlet-name>  
   </filter-mapping>  
   
   <!-- servlet 설정 -->  
   <servlet>  
     <servlet-name>action</servlet-name>  
     <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>  
     <init-param>  
       <param-name>config</param-name>  
       <param-value>/WEB-INF/struts-config.xml</param-value>  
     </init-param>  
     <init-param>  
       <param-name>debug</param-name>  
       <param-value>3</param-value>  
     </init-param>  
     <init-param>  
       <param-name>detail</param-name>  
       <param-value>3</param-value>  
     </init-param>  
     <load-on-startup>0</load-on-startup>  
   </servlet>  
   
   <servlet-mapping>  
     <servlet-name>action</servlet-name>  
     <url-pattern>*.do</url-pattern>  
   </servlet-mapping>  
   
   <!-- 세션 기간 설정 -->  
   <session-config>  
     <session-timeout>30</session-timeout>  
   </session-config>  
   
   <!-- 시작페이지 설정 -->  
   <welcome-file-list>  
     <welcome-file>index.jsp</welcome-file>  
   </welcome-file-list>  
   
   <!-- 존재하지 않는 페이지, 404에러시 처리 페이지 설정 -->  
   <error-page>  
     <error-code>404</error-code>  
     <location>/404.jsp</location>  
   </error-page>  
   
   <!-- 500에러시 처리 페이지 설정 -->  
   <error-page>  
     <error-code>500</error-code>  
     <location>/500.jsp</location>  
   </error-page>  
   
   <!-- NullpointException발생시 처리 페이지 설정 -->  
   <error-page>  
     <exception-type>java.lang.NullPointerException</exception-type>  
     <location>/null.jsp</location>  
   </error-page>  
   
   <!-- 태그 라이브러리 설정 (JSTL"coreTag"을(를) 사용)-->  
   <jsp-config>  
     <taglib>  
       <taglib-url>http://java.sun.com/jsp/jstl/core</taglib-url>  
       <taglib-location>/WEB-INF/tld/c.tld</taglib-location>  
     </taglib>  
   </jsp-config>  
 </web-app>  
   

A web.xml Deployment Descriptor Elements

web.xml elements order ?

2010년 6월 11일 금요일

아이폰의 성공 비결

1. 스마트폰 개발을 위해 지난 4년간 내로라하는 우수 인력 100여명을 투입해서 아이폰 한 종류만 만들었다. 타 업체는 매년 수십종의 휴대폰을 내놓음.

2. 제품 개발의 일관성과 책임성 : 톱 매니지먼트가 직접 제품을 기획한 후 디자인 및 개발 전과정을 직접 지휘했다는 점이 완성도 높은 제품 출시를 가능하게 했다는 설명

3. '뉴톤', '아이팟폰' 등 실패작에서 사용했던 기술이 지금의 아이폰의 바탕을 이룸.

4. 무엇보다 가장 큰 성공이유 : 애플 CEO가 스티브 잡스라서ㅋㅋㅋ(스티브 잡스는 UX 전공자가 아니면서도 현존하는 최고의 UX 디자이너)

 

* 다변하는 모바일 생태계에서 기업이 생존하기 위한 조건 : 일관성(coherence)

 - 서로 다른 것들이 잘 뭉쳐서 전체를 구성하는 것

 - 마치 소설에서 '기승전결'을 따라가며 이야기가 변하지만 주제의 일관성만은 헤치지 않는 것처럼.

 - 다만 표준화와 규격화를 지향하는 '획일적 일관성(consistency)은 버려야 한다.

 - 심리스 UX를 구현하기 위한 '은은한 일관성'이 필요하다.

 - 애플 TV와 아이팟의 조작매뉴얼은 방식이 완전히 다르지만 말로 설명할 수 없는 애플 UX만의 냄새가 난다. 우리도 그것을 만들 수 있어야만 성공할 수 있다.

 

원문 주소 : http://www.zdnet.co.kr/Contents/2010/03/11/zdnet20100311161544.htm

 

2010년 5월 4일 화요일

드럼이란

* 드럼

  • 드럼은 영어로 북을 뜻하는 것으로 서양의 타악기 중의 하나이다.
  • 음악 그룹에서의 드럼은 일반적으로 여러 개의 북과 심벌즈로 이루어진 드럼셋을 의미한다.
  • 드럼셋은 사이드(크래시) 심벌, 탑(라이드) 심벌, 탐탐, 하이햇 심벌, 스네어 심벌, 플로어 탐, 스네어 드럼, 베이스 드럼(대고)로 일반적으로 구성된다.
  • 드럼 연주자를 지칭하는 말로도 쓰인다.
  • 드럼통은 둥근 원통을 이야기한다.

 

 

출처 : 위키백과

처음에 익혀야 할 기타코드

* 처음에 외워야 할 기타코드는 개방현을 이용한 메이저코드, 마이너코드, 세븐스 코드 정도다.(개방현이란 자판에서 아무것도 잡지 않은 기타줄을 말한다.)

 

* 기본적으로 외워야 할 코드

  • 메이저 코드 : C   D   E    F   G   A   B
  • 마이너 코드 : Cm Dm Em Fm Gm Am Bm
  • 세븐스 코드 : C7  D7  E7 F7  G7  A7  B7
  • 그   외 코드 : F#  F#m F#7

 

출처 : 해브원 블로그

기본음계에 대해

* 다장조 온음과 반음 관계에 대해서

  • 도     레     미     파     솔      라     시      도
  •    온음  온음  반음  온음  온음   온음  반음
  • 도와 도#의 관계는 반음 관계.
  • 도# = 레b

 

* 기타 자판과 음계

  • 도 레 미 파 솔 라 시 도
  • C  D  E  F  G  A  B  C

 

* 기타의 줄은 6개, 가장 두꺼운 쇠줄(6번)이 가장 윗 줄이다.

* 6번줄부터 1번줄까지 미라레솔시미로 맞춰져 있다.

 

출처 : 해브원 블로그

통기타 연주법에 대해

1. 스트로크

  •  통기타의 가장 기초가 되는 주법
  • 코드를 잡고 여러 개의 줄을 동시에 쳐주는 것을 말함
  • 기타 반주 그 자체로 볼 수 있음

2. 아르페지오

  • 우리말로 분산화음을 말하며 스트로크와는 달리 기본적으로 코드를 잡고 여러 줄을 치는 것이 아니라 한 음 한 음 팅겨주는 주법을 말함(엄밀히 말하면 핑거링 주법에 속한다고 볼 수도 있음)
  • 좀 조용하고 분위기 있는 음율에 많이 사용됨

3. 핑거링

  • 핑거스타일 주법으로 표현되기도 함
  • 피크를 사용하기보다 손가락을 이용하며, 주로 반주용이 아닌 하나의 곡을 연주하는 것을 말함.
  • 노래가 주가 되는 것이 아니라 기타연주 자체가 주가 되는 주법
  • 코타로 오시오나 유투브에서 정성하군 영상 참조

 

 

출처 : 해브원 블로그

2010년 4월 24일 토요일

유니버셜 디자인

< 유니버셜 디자인 >

 

1. 개념

  • Design for all people
  • 유니버셜 디자인은 "평생 디자인"이라고도 부르는 디자인계의 최신 주제(2010.4.)
  • 장애인, 노인, 어린이 등 약자가 사용할 수 있는 환경과 상품 창조를 만드는 디자인을 말하고, 신체적인 약함뿐 아니라 상황이나 나이에 따라 일어날 수 있는 특정 부분의 불리한 점을 보완하는 것이 "유니버셜 디자인"이다.
  • '더 편하게, 더 안전하게, 더 풍요롭게'를 외치는 소비자 중심의 생활 디자인이 지금 세계 디자이너가 추구하는 디자인의 중심이다.

 

2. 배경

  • 20세기 들어서 장애인, 고령자 등이 늘면서, 그들이 일상 생활을 자유롭게 보낼 수 있는 베리어 프리(barrier free) 개념이 등장했다.
  • 1980년 미국의 건축가이자 공업 디자이너인 론 메이스는 베리어 프리 개념을 뛰어넘는 남녀노소 누구나 사는데 불편함이 없는 디자인을 해야한다고 주장했고, 이 때 유니버셜 디자인이라는 개념이 생겨났다.
  • 유니버셜 디자인은 장애의 개념을 좀더 넓힌 디자인으로 정상인뿐 아니라 일시적 장애를 포함한 모든 장애를 어린이와 노인이 사용할 수 있는 환경과 상품창조를 추구하고, 이론적으로 생각하는 신체적 능력의 부족함만이 아니라, 상황이나 나이에 따라 모든 사람이 가지고 있는 특정부분의 취약성 모두를 장애의 개념으로 본다.

 

3. 원리

  • 기능적 자원성이 높은 디자인(Supportive Design)
    • 기능상 필요한 도움을 제공해야 하며 사용자에게 불필요한 어떤 부담도 야기시켜서는 안된다. 조명의 경우 밝기가 적절치 않으면 시각의 정확성이 떨어지며
  • 수용가능한 디자인(Adaptable Design)
    • 상품이나 환경이 상황에 따라 조절가능함으로써 다양한 요구를 충족시킬 수 있는 유통성을 지녀야 한다. 특히 오랜 시간 다양한 형태로 작업하는 사무환경에서는 인간공학적인 방법으로 이러한 특성의 디자인이 연구되어야 한다.
    • 변화 가능한 형태의 작업대나 높이조절이 가능한 책상과 스탠드, 다양한 서체와 글자의 크기조절이 가능한 컴퓨터 프로그램들이 이러한 사례이다.
    • 이러한 상품은 시각장애자와 노인들에게도 매우 유용하다.
  • 접근 가능한 디자인(Accessible Design)
    • 접근 가능성이란 장애물이 제거된 상태이다.
    • 보도블럭을 휠체어 사용자와 자전거를 타는 사람, 환자들이 편리하게 다닐 수 있도록 고려하고 아울러 시각장애자들에게도 도움이 되도록 색채와 패턴, 적절한 배치와 질감있는 재료를 사용해 시각장애로 인한 사고를 가능한 줄이는 것 등이 이러한 것들이다.
  • 안전한 디자인(Safely-oriental Design)
    • 대조적인 색채와 패턴으로 레벨차를 표시하거나 모서리를 둥글게 처리한 것 등 안전한 디자인은 보다 개성적이며 예반적이다. 또한 안전성은 심리적인 건강함, 소속감, 자기가치등을 포함한다.
    • 장애자가 정상정적인 활동을 유지할 수 있도록 고려된 공간은 개인에게 도립심을 부여함으로써 심리적인 건강을 유지시켜 준다.

 

 

< 7가지 원칙 >

  • 공평한 사용(Equitable)
    • 누구라도 차별감이나 불안감, 열등감을 느끼지 않고 공평하게 사용 가능한가?
  • 사용상의 융통성(Flexiblility in Use)
    • 서두르거나, 다양한 생활환경 조건에서도 정확하고 자유롭게 사용 가능한가?
  • 간단하고 직관적인 사용(Simple and Intutive)
    • 직감적으로 사용방법을 간단히 알 수 있도록 간결하고, 사용 시 피드백이 있는가?
  • 쉽게 인지할 수 있는 정보(Perceptive Information)
    • 정보구조가 간단하고, 복수의 전달수단을 통해 정보입수가 가능한가?
  • 오류에 대한 포용력(Tolerance for Error)
    • 사고를 방지하고, 잘못된 명령에도 원래 상태로 쉽게 복귀가 가능한가?
  • 적은 물리적 노력(Low Physical Effort)
    • 무의미한 반복동작이나, 무리한 힘을 들이지 않고 자연스런 자세로 사용이 가능한가?
  • 접근과 사용을 위한 충분한 공간(Size and Space for Approach and Use)
    • 이동이나 수납이 용이하고, 다양한 신체조건의 사용자와 도우미가 함께 사용이 가능한가?

 

 이와 같은 유니버셜 디자인은 제품이나 환경시설 외에 모든 산업을 대상으로 할 만큼 대단히 광범위하며, 근래 고령화의 급진전에 따른 고령친화산업(실버산업)의 부각은 기업에 있어서 새로운 비즈니스 창출 및 참여라는 기회를 제공하고 있습니다. 본격적인 고령사회의 도래와 와 국제화, 정보통신기술의 고도화 등에 동반하여 사회, 경제구조의 변혁, 가치관의 다양화 등이 한층 진전될 것으로 예측되는 향후 사회에 있어서 유니버셜 디자인은 더불어 사는 사회를 형성해가기 위해 필연적인 대안이라고 할 수 있습니다.

 

 

출처 : Our Blog, UDRC 유니버셜 디자인 연구센터

2010년 4월 20일 화요일

Qt4를 이용한 C++ GUI 프로그래밍-Chapter 01

(1) Hello Qt

  • 예제

1 #include <QApplication>
2 #include <QLabel>

3 int main(int argc, char *argv[])
4 {
5     QApplication app(argc, argv);
6     QLabel *label = new QLabel("Hello Qt!");
7     label->show();
8     return app.exec();
9 }

  • Qt의 모든 클래스는 자신의 이름과 똑같은 이름으로 된 헤더파일 내에 정의되어 있다.
  • 5번째 줄 : 응용 프로그램 차원의 자원을 관리하기 위해 QApplication 객체를 생성한다.
    • QApplication은 GUI 응용 프로그램 제어 흐름과 주요 설정 사항을 관리하는 클래스로서, 메인 이벤트 루프를 갖고 있으며, 응용 프로그램의 초기화와 종료화 그리고 시스템 차원의 설정사항과 응용 프로그램 차원의 설정사항을 다룬다.
    • Qt를 사용하는 GUI 응용 프로그램에는 하나의 QApplication 객체만이 존재할 수 있으며, 전역 포인터인 qApp 나 QCoreApplication::instance()를 통해 이 객체에 접근할 수 있다.(자세한 것은 Qt 어시스턴트 참조)
  • 명령행으로부터 입력되는 인자 중에서 Qt가 자체적으로 인식하는 것이 있기 때문에, QApplication을 생성할 때는 생성자에 argc와 argv를 넘겨줘야 한다.
  • 6번째 줄 : "Hello Qt"라는 문자열을 출력하는 QLabel 위젯을 생성하고 있다.
  • Qt와 유닉스에서 통용되는 위젯(Widget)이란 용어는 유저 인터페이스 상에 자리잡은 각각의 비주얼한 요소를 일컫는 말이다. '윈도우 가젯'이란 말에서 유래된 이 용어는, 윈도우에서 사용되는 용어인 '컨트롤'이나 '컨테이너'와 그 의미하는 바가 동일한데, 이를 테면 버튼, 메뉴, 스크롤 바, 프레임 등이 바로 위젯인 것이다. 하지만 Qt는 어떠한 위젯이라도 윈도우가 될 수 있다는 특징이 있다.
  • 7번째 줄 : 이 레이블이 화면에 보이게 만들고 있다. 모든 위젯은 항상 화면에 보이지 않는 상태로 생성되는데, 이러한 방침은 화면에 보이기 이전에 위젯에 필요한 모든 조치가 취해질 수 있게 하기 위한 것으로서, 이를 통해 불필요한 화면의  깜빡임을 막을 수 있게 된다.(화면 깜빡임의 다른 방법은 더블 버퍼링으로 5장에서 다룬다.)
  • 8번 줄 : 응용 프로그램의 제어를 Qt에게 넘겨주고 있다. 이렇게 되면 프로그램은 마우스 클릭이나 키보드 입력과 같은 사용자의 액션을 기다리는 일종의 대기모드인 이벤트 루프에 진입하게 된다. 사용자의 액션은 이벤트('메시지'라고도 함)를 발생시키게 되는데, 프로그램은 보통 이러한 이벤트에 대해 몇 가지 함수를 실행함으로써 반응하게 된다. 예를 들어, 사용자가 어떤 위젯을 클릭하면 '마우스 버튼의 누름'과 '마우스 버튼의 뗌'을 의미하는 이벤트가 생성된다.
  • main() 함수의 끝부분에서는 좀 더 간략함을 위해 QLabel 객체에 대한 delete 호출을 생략하고 있다. 프로그램이 종료되면 운영체제는 그 프로그램이 사용한 모든 메모리를 회수하기 때문에, 이 정도 크기의 작은 프로그램에서 발생하는 메모리 누수는 아무런 해가 되지 않는다.
  • 프로그램을 실행시키려면 먼저 컴퓨터에 Qt 4.3.2이상의 Qt 4가 설치되어 있어야 함.
  • 그리고 Qt의 bin 디렉토리가 PATH 환경변수에 설정되어 있어야 함.(부록 A 참조, 윈도우는 Qt 설치시 자동으로 등록됨.)
    • 1 # vi hello.cpp
      2 # qmake -project
      3 # qmake hello.pro
      4 # make
      5 # ./hello
    • 1 : chapter01의 hello 예제 파일 소스임.
    • 2 : 플랫폼에 독립적인 프로젝트 파일(hello.pro)이 생성됨.
    • 3 : 이전 단계에서 생성된 플랫폼 독립적인 프로젝트 파일로부터 특정 플랫폼을 위한 makefile이 생성됨.
    • 4 : 프로그램이 만들어 진다.
    • 5 : 만들어진 프로그램을 실행

 

  • ### 윈도우 비쥬얼 스튜디오 프로젝트 파일 만드는 법 ###
    • # qmake -tp vc hello.pro

 

 

(2) Signal / Slot

  • 시그널은 함수와 연결될 수 있어서, 시그널이 발생하면 그와 연결된 함수가 자동으로 실행되는데, 이처럼 시그널의 발생에 의해 자동으로 호출되는 함수를 슬롯이라고 한다.
  • SIGNAL()과 SLOT()은 시그널과 슬롯을 연결하는 데 사용하는 매크로이다.
  • ex) QObject::connect( button, SIGNAL(clicked()), &app, SLOT(quit()));

 

(3) Widget

  • QWidget은 어떤 응용프로그램의 메인 윈도우가 될 수 있다.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         

 

 

(4) Reference Document

 

 

end

2010년 4월 19일 월요일

Qt4를 이용한 C++ GUI 프로그래밍-시작하기

* Qt(큐트)

  • 소스 코드 한 벌만으로 다양한 운영체제 환경에서 실행 가능한 어플리케이션을 만들 수 있도록 해주는 크로스 플랫폼 응용프로그램 프레임워크
  • 노르웨이에 있는 트롤테크에서 처음 개발되었고, 2008년 노키아가 인수하여 현재 모바일 및 데스크톱 소프트웨어에 관한 노키아의 플랫폼 소프트웨어 전략의 핵심 역할을 하고 있음.(2008년?)
  • Write Once, Compile Anywhere : 소스 코드는 한 벌만 만들고 이를 원하는 운영체제 환경에서 컴파일하기만 하면 해당 환경에서 실행될 수 있는 이미지가 만들어진다.(윈도우, 리눅스, 맥 OS 지원, 임베디드 리눅스, 윈도우 CE 지원)
  • Qt로 만들어진 제품들 : 구글 어스, 얻도비 포토샵 앨범, 스카이프, 메스메티카,  KDE, KOffice
  • 오픈 소스로 배포되고 있음

 

* Qt 라이선스

  • 오픈 소스 에디션
    • GNU GPL 사용에 대한 요구사항이 포함됨
    • 소스를 보고, 수정하고, 배포하는 권리를 부여함.
  • 상용 에디션
    • 만든 응용 프로그램을 상용 라이선스 조건을 적용하고자 할 경우 사용
    • 자신만의 조건 하에 판매하고 배포할 수 있음.

 

* Qt 설치하기(부록 A)

  • Qt 다운로드 하기
  • 책 예제 다운 받기
  • Qt/윈도우 설치(MinGW C++ 설치 필수)
  • Qt/맥 설치(Xcode Tools 먼저 설치 필수)
  • Qt/X11 설치
    • # cd /tmp
    • # gunzip qt-x11-opensource-src-4.3.2.tar.gz
    • # tar xvf qt-x11-opensource-src-4.3.2.tar
    • # cd /tmp/qt-x11-opensource-src-4.3.2
    • # ./configure
    • # make
    • # make install or sudo make install
    • 환경 변수 설정(.profile)
      PATH=/usr/local/Trolltech/Qt-4.3.2/bin:$PATH
      export PATH

 

2010년 4월 14일 수요일

linux 2.6 device model

* 5 component for device model

  • the device model core -> defines a set of structures and functions
    • 'include/linux/device.h', 'drivers/base/*.c'
  • the generic bus drivers
    • bus / struct bus_type / bus_register(), bus_unregister()
  • the bus  controller drivers
    • device / struct device / device_register(), device_unregister()
  • the device drivers
    • driver / sturce device_driver / driver_register(), driver_unregister()
  • the class drivers
    • class / struct class / class_register(), class_unregister()

 

* Device Model Core

  • 'struct bus_type' : Represents busses(PCI, USB, I2C, etc.)
  • 'struct device' : Represents devices(Intel AC97 audio controller, Intel PRO/100 ethernet controller, a PS/2 mouse, etc.)
  • 'struct device_driver' : Represents kernel drivers that handle devices
  • 'struct class ' : Represents a class of devices(sound, input, graphics, etc.)
  • 'include/linux/device.h', 'drivers/base/*.c'

 

* device_register() : 한 device에 대해 맞는 driver들을 검색

* driver_register() : 한 driver에 대해 맞는 device들을 검색

 

* Generic Bus Drivers

  • kernel이 지원하는 모든 bus마다 generic bus driver가 있다. Generic bus driver는 sturct bus_type을 allocate하고 bus_register()를 써서 kernel의 bus type list에 register한다.
  • bus_type structure
    • name (string)
    • !klist_devices (klist)
    • !klist_driver (klist)
    • match (fp)
    • suspend (fp)
    • resume (fp)
  • klist_devices는 이 bus에 존재하는 device들의 list, Bus controller driver가 device_register()를 호출함에 의해 update 됨.
  • Bus controller driver는 system initialization 시 bus를 scan해서 어떤 device들이 있는지 check한 뒤 각 device마다 device_register()를 호출해서 klist_devices를 scan해서 맞는 driver (match() 이용)를 찾는다. 그런 뒤 device를 klist_devices에 update한다.
  • Bus controller driver는 또한 gadget이 hot plugged 되었을 때(어떤 device인지 확인한 뒤) device_register()를 호출해서 klist_drivers를 scan해서 각 device 마다 맞는 driver( match() 이용 )를 찾는다. 그런뒤 device를 klist_devices에 update 한다.
  • klist_driver는 이 bus에 존재하는 device들을 handle할 수 있는 driver들의 list, Device driver가 스스로 initialization 할 때, driver_register()를 호출하여 자신을 등록함으로써 갱신된다.
  • Device Driver가 kernel에 inserted 되면, 이 driver는 driver_register()를 호출하여 해당 bus에 대해 klist_devices를 scan하여 이 driver가 다룰 수 있는 device들을 찾는다. 그런 뒤 driver를 klist_drivers에 update 한다.
  • match()에 의해 device와 driver가 associated 되는 것을 binding이라고 한다.
  • ex) 'drivers/net/phy/mdio_bus.c'
  • struct bus_type mdio_bus_type = {
    . name = "mdio_bus",
    .match = mdio_bus_match,
    .suspend = mdio_bus_suspend,
    .resume = mdio_bus_resume,
    };

 

* '!' is internal to the device motel core and should not be touched by the bus controller driver directly.

 

* Bus Controller Drivers

  • Bus의 device driver다. 따라서, 여느 device drivers와 마찬가지로 자신을 driver_register()로 등록함. 그러나 추가적으로 자신이 다루는 bus 상에 있는 devices를 detect하여 device_register()를 이용해 등록한다. bus_type 구조체의 klist_devices list에.
  • 새로운 Linux device driver model에서 모든 device는 bus 상에 존재하므로, 결국 bus controller driver가 모든 device를 등록한다. struct device 형태로. bus_type 구조체의 klist_devices list에.
  • device
    • bus_id (string)
    • bus (bus_type)
    • parent (device)
    • !driver(device_driver)
  • 'drivers/net/gianfar_mii.c'

 

* Device Drivers

  • 모든 device driver는, driver_register()를 호출해 bus_type 구조체의 klist_driver list에 자기 자신을 등록한다. 그 다음에 device model core가 이 driver를 한 device와 binding을 시도함.
  • 한 device가 registered 되면 (이는 곧 이 device를 handle할 수 있는 drivers가 klist_drivers에 등록된다는 말이므로) 한 특정 driver에 의해 handled 될 수 있는데, 그 driver의 probe member가 하는 일이 바로 그 특정 device 하나를 위해 이 driver의 한 instance를 생성해내는 (그리고 그 device를 초기화하는) 일이다.
  • device_driver
    • bus (bus_type)
    • probe (fp)
    • remove (fp)
    • suspend (fp)
    • resume (fp)
  • bus는 이 driver가 등록될 klist_drivers를 가진 bus_type 구조체에 대한 pointer.
  • probe는, 이 driver가 지원하는 device가 detected (이는 곧 device를 지원하는 drivers를 klist_drivers에서 찾아내는 일을 한 것 즉, binded) 될 때마다 불리는 callback function. 이 함수는 driver 자신을 각 device 당 하나 씩 instantiate한 뒤 그 device를 initialize 한다.
  • remove는 이 driver를 그 device로부터 unbind하기 위해 불리는 callback function. Unbinding은 device가 physically removed 되거나 driver가 unloaded 되거나 system이 shutdown 될 때 일어난다.
  • 'drivers/net/phy/'

 

* Class Drivers

  • Class driver는 그것이 표현하는 device class들에 대해 struct class를 instantiate하여  class_register()를 통해 device model core에 등록한다.
  • Devices를 적당한 class에 추가하는 것은 각 해당 device driver의 책임이다.
  • class
    • name (string)
    • !devices (list)
  • devices는 이 class에 속한 device들의 list이다. 이 list는 device driver들에 의해 갱신된다. (그 device driver들이 자기 자신들을 각 device들에 대해 instantiate할 때).

 

* Conclusion

  • 결국 이런 data structure들이 있음으로 해서, device들이 어떻게 tree 구조를 이루고 있는지 알 수 있고, 어떤 종류의 device들이 system에 존재하는지도 알 수 있다.
  • 그 효과는 더 나은 power management, 그리고 system에 연결된 devices에 대한 더 나은 통찰.

 

출처 : 블로그

 

 

I2C

I2C(Inter-Integrated Circuit,아이 스퀘어 씨)

  • 필립스에서 개발한 직렬 컴퓨터 버스
  • 마더보드, 임베디드 시스템, 휴대전화 등에 저속의 주변 기기를 연결하기 위해 사용됨.
  • I2C는 풀업 저항이 연결된 직렬 데이터(SDA)와 직렬 클럭(SCL)이라는 두 개의 양방향 오픈 컬렉터 라인을 사용한다. 최대 전압은 +5V이며, 일반적으로 +3.3V 시스템이 사용되지만 다른 전압도 가능하다.
  • I2C 레퍼런스 디자인은 7bit의 주소 공간을 가지며, 이 중 16개는 예약되어 있으므로, 동일한 버스에 최대 112개의 노드를 연결할 수 있다. 가장 일반적으로 사용되는 I2C 버스의 모드는 표준 모드인 100kbit/s와 저속 모드인 10kbit/s가 사용된다. 최신 리비전의 I2C는 보다 빠르게 동작하며, fast mode인 400kbit/s와 고속 모드인 3.4Mbit/s를 지원한다. 최대 1008 노드까지 연결 가능한 10bit 주소 지정 등의 확장된 기능등을 지원한다.
  • 응용 영역
    • 사용자 설정값을 저장하기 위해 NVRAM에 접근하는 경우
    • 저속의 디지털-아날로그 변환 회로에 접근하는 경우
    • 저속의 아날로그-디지털 변환 회로에 접근하는 경우
    • 모니터의 명암, 대비, 색상 등을 변경하는 경우
    • 지능형 스피커의 볼륨값을 변경하는 경우
    • 휴대전화 같은 장치에 포함된 발광 다이오드를 제어하는 경우
    • 중앙 처리 장치 온도나 팬 속도와 같은 하드웨어 모니터링 정보나 진단 센서 정보를 읽는 경우
    • 실시간 클럭 값을 읽는 경우
    • 시스템 요소의 전원을 제어하는 경우
  • I2C의 장점은 특히 마이크로컨트롤러에서 단지 2개의 일반 목적 입출력 핀(GPIO)과 소프트웨어만을 이용하여 여러 장치들을 제어할 수 있다는 점이다
  • 주변장치들은 시스템이 동작 중일 때도 I2C 버스에 추가/제거될 수 있으며, 이것은 핫 스왑이 필요한 요소들을 이용하는 응용에 적합하다.
  • I2C는 엑세스 버스, VESA 디스플레이 데이터 채널 (DDC) 인터페이스, 시스템 과리 버스(SMBus), IPMI 프로토콜 중의 하나인 지능형 플랫폼 관리 버스(IPMB)의 기본 기술이다. 이러한 것들은 전압과 클럭 주파수 범위에서 차이가 있으며, 인터럽트 라인을 가질 수 있다.
  • I2C 버스의 설계상 장점 : 노이즈에 강하여 신뢰성이 높고, 매우 적은 전력을 사용하며, 다양한 온다환경에서도 잘 동작할 뿐만 아니라, 다양한 전압레벨을 지원한다.

 

* I2C에서 ACK의 역할

  • Write 시 정상 수신 신호
  • Read 시 송신 완료 신호
  • Write, Read 모두 ACK 신호는 Slave에서 발생시킴

 

* I2C의 정의

  • 1980년대 필립스에서 개발된 버스 표준안
  • 2개의 전송 라인을 이용한 양방향 통신 지원(SDA, SCL)
  • 현재 세계에서 가장 많이 쓰이는 임베디드 표준안
  • Multi-master capable bus with arbitration feature
  • Master-Slave communication supported
  • Each IC on the bus is identified by its own address code

 

* I2C의 장점

  • 단순한 하드웨어 구성
  • 단순한 프로토콜로 구성
  • 장치의 연결과 제거가 용이함
  • Simpler PCB
  • Fast enough for all "Human Interfaces" applications(Display, Switches, Keyboard)
  • Large number of I2C devices

 

* I2C Signals

 (1) Control Signal

  • SCL highdptj SDA transition으로 판정
  • Start / Stop bit
    • Start : SDA low 이동 후 SCL low 이동
    • Stop : SCL high 이동 후 SDA high 이동

 (2) Data Signal

  • SCL이 pulse 안에서 SDA 데이터의 이동으로 0/1 구분
  • SCL pulse 안에서...
    • SDA pulse 존재하면 : 1
    • SDA pulse 존재하지 않으면 : 0

 (3) ACK / NAK Signal

  • 9번째 data 신호로 판명
    • ACK : 0
    • NAK : 1

 

 

The image shows a simplified equivalent circuit diagram for an I2C connection between two devices (master or slave). It shows all factors which are relevant for I2C.

 

VCC I2C supply voltage, typically ranging from 1.2 V to 5.5 V
GND Common ground
SDA Serial data (I2C data line)
SCL Serial clock (I2C clock line)
Rp Pull-up resistance (a.k.a. I2C termination)
Rs Serial resistance
Cp Wire capacitance
Cc Cross channel capacitance

 

 

출처 : 위키 백과, 다음 블로그, 네이버 블로그, I2C bus(영문)

2010년 4월 13일 화요일

latency

latency : 지연 (또는 대기) 시간

 

1. 네트워크에서의 latency는 delay와 비슷한 말로서, 하나의 데이터 패킷을 한 지점에서 다른 지점으로 보내는데 소요되는 시간을 표현한 것이다. 그러나 일부에서는 (예를 들어 AT&T 등에서는), 패킷 하나를 보내고 그것이 송신자에게 되돌아올 때까지의 왕복에 걸리는 시간을 latency라고 부르기도 한다. latency는 한 지점에서 다른 지점 사이에 (지연시간이 전혀 없이) 데이터가 즉시 전송되어야만 하는 것으로 가정한다. 네트워크에서 latency를 일으키는 요인은 다음과 같다.

  • 전달 지연 : 이것은 단순히 하나의 패킷이 한 지점에서 다른 지점으로 광속으로 이동하는데 걸리는 시간이다.
  • 전송 지연 : (광케이블, 무선 또는 그 밖의 어떤 것이라도) 매체 그 차제에서 약간의 지연이 생긴다. 또 패킷의 크기에 따라서도 왕복하는데 지연이 생길 수 있는데, 그 이유는 패킷이 클수록 수신하고 반환하는데 시간이 더 걸리기 때문이다.
  • 라우터 및 기타 처리 지연 :  게이트웨이 노드들 시험하고, 또 어쩌면 패킷 내의 헤더를 변경 (예를 들어, TTL 필드 내에 있는  카운트의 값을 변경하는 등) 하는 데에도 시간이 걸린다.
  • 다른 컴퓨터 및 저장장치 지연 : 네트웍 내 행로 양단에서, 패킷은 스위치 브리지와 같은 중간 장비들에서 하드디스크와 같은 저장장치에 액세스하기 쉽다 (그러나백본 통계에서, 이러한 종류의 지연은 십중팔구 고려되지 않는다). 

 

2. 컴퓨터 시스템에서의 latency는 종종 응답시간을 늦추는 지연이나 대기를 의미하는데 사용된다. 컴퓨터 latency에 기여하는 명확한 요인들로는, 마이크로프로세서와 입출력장치들 간의 데이터 속도가 맞지 않거나, 데이터 버퍼링이 불충분한 것 등이 포함된다. 컴퓨터 내에서, latnecy는 prefeching이나 멀티 스레딩, 또는 다중 스레드의 실행에 걸친 병렬 처리의 사용 등

과 같은 기술에 의해 제거되거나 감추어질 수 있다.

 

3. 입체 시야와 머리 추적 장치 등이 제공되는 헬멧을 설명하는 3차원 모의실험에서, latency는 컴퓨터가 머리의 움직임을 감지하는 때부터 적절한 이미지가 나타나는데 까지 걸리는 시간을 말한다.

 

출처 : 텀즈

2010년 4월 10일 토요일

리눅스 사운드 프로그래밍

< 음악이 생겨라 (Let There Be Music) >

 

by Shuveb Hussain

한글 번역 전정호

이 글은 한글번역판을 요약한 것입니다.

 

*** 사운드 카드 프로그래밍 ***

 

 (1) 샘플링

  • 음을 녹음할 때 음질을 선택한다.
  • 음질을 결정하는 중요한 요소 중 하나가 샘플링 빈도(sampling rate)이다.
  • 음은 시간에 따라 진동수가 바뀌는 파장일 뿐이다.
  • 음을 녹음하려면 일정 간격으로 음의 진동수를 기록한다. 이 간격을 샘플링 빈도라고 한다.
  • 샘플링 빈도가 높을수록 음질이 좋아진다. 예를 들어, CD의 샘플링 빈도는 초당 44100번, 즉 44.1kHz이다.
  • PCM(Pulse Code Modulation, 펄스 코드 변조)이라고 하는 이 작업은 ADC(Analogue to Digital Converter, 아날로그-디지털 변환기)가 한다.

 

 

 (2) 비트와 채널

  • 음을 샘플링할 때, 샘플당 일정 수의 비트를 사용하고, 이런 채널을 여러 개 사용한다. 샘플링하는 자료의 비트 개수를 샘플링 정밀도(resolution)라고 한다.
  • 가장 흔한 형식은 8비트 양수 바이트 혹은 16비트이다.
  • 채널별로 자료를 분리한다. 예를 들어, CD 음악에는 왼쪽, 오른쪽(스테레오) 두 채널이 있다.
  • 8비트 정밀도로 CD음질을 녹음할 때 초당 필요한 크기를 계산해보면 :
  •        2        x       44100      =      88200 bytes
    (채널 개수) x (샘플링 빈도) = (초당 필요한 크기)

  • 이제 이론은 충분하니 실제 프로그램을 시작하자.

 

 

 (3) 사운드 카드를 프로그래밍 하기

  • 사운드 카드를 프로그래밍하는 방법이 몇가지 있다.
  •  초기 리눅스 드라이버가 만들어지던 때 두 그룹이 있었다.
    • Open Sound System(OSS)은 많은 장치 드라이버를 작성한 그룹으로 심지어 하드웨어 사양을 공개하지 않거나 비밀유지동의(non-disclusure agreement)를 하지않은 개발자에게 사양을 공개하지 않는 사운드 카드 제조사의 이진모듈도 포함하였다. 하드웨어 제조자가 개인에게 사양을 알려주려고하지 않았기 때문에 OSS는 4Front Technologies란 회사를 만들었다.
    • ALSA(Advanced Linux Sound Architecture)는 제조사가 사양을 공개한 사운드 카드 드라이버만 작성했다. ALSA는 2.6-test 커널에 포함되어 있다.
  • ALSA는 OSS 에뮬레이션 계층을 제공하기 때문에 OSS로 작성한 프로그램은 OSS와 ALSA 시스템에서 모두 동작한다. 간단하고 대다수의 시스템에 설치되어 있기 때문에 이 글은 OSS 프로그래밍을 다룰 것이다.

 

  • 유닉스/리눅스는 모든 장치 드라이버마다 (보통 /dev 디렉토리에) 파일 시스템 인터페이스가 있다. 이 장치파일을 open, read, write, lseek, close와 같은 파일관련 시스템 호출에 사용한다. 장치파일을 장치드라이버가 요청을 기다리는 파일시스템상의 훅(hook)이라고 보면 된다.예를 들어, /dev/hda1 파일은 primary master IDE 하드디스크의 첫번째 파티션에 대한 인터페이스이다. open 시스템호출을 사용하여 파일을 열면 일반파일과 같이 파일핸드(file handle)을 얻을 수 있다. 파일핸들을 읽으면 실제로 파티션의 첫번째 섹터에 있는 자료를 읽게 된다. 또, 앞으로 lseek하면 파일포인터(file pointer)를 앞으로 이동한다. 섹터를 건너뛰으려면 섹터 크기만큼 앞으로 lseek한다. 위험하므로 하드디스크 장치 파일을 수정하지는 마라. 파티션에 값을 쓰면 파티션이 망가질 수 있다. 하드웨어 장치는 보통 root만 직접 접근할 수 있다.

 (4) 코드

  • 이제 코드로 넘어가자. 이 코드는 root가 아니어도 문제없이 실행되야 한다. 파일장치를 접근하는데 문제가 있다면 root로 su하고 chmod하여 접근 권한을 푼다. 물론 리눅스에서 작동하는 사운드카드를 사용해야 한다. 직접 코드를 입력하지 않고 여기에서 다운받을 수 있다. demo.pcm 파일도 같이 다운받아야 한다.

 

/*
 * oss.c는 사운드카드에서 raw PCM 22KHz 샘플음을 낸다
 *
 * 중요 - 프로그램을 실행하기전에 현재 디렉토리에 demo.pcm 파일이 있는지 확인하라.
 */

#include < sys/types.h >
#include < sys/stat.h >
#include < sys/soundcard.h >
#include < sys/ioctl.h >
#include < unistd.h >
#include < fcntl.h >
#include < errno.h >
#include < stdlib.h >

#define SECONDS 5 //재생 시간 (초)

int main()
{
    int fd;
    int handle = -1;
    int channels = 1;         // 0=모노 1=스테레오
    int format = AFMT_U8;
    int rate = 22000;
    unsigned char* data;

   /* 사운드카드에 해당하는 파일에 쓰기위해(write) 파일을 연다(open). DSP = Digital Signal Processor */
    if ( (handle = open("/dev/dsp",O_WRONLY)) == -1 )
    {
  perror("open /dev/dsp");
  return -1;
    }

   /* 재생하려는 음이 스테레오라고 사운드카드에 알린다. 0=모노 1=스테레오 */
    if ( ioctl(handle, SNDCTL_DSP_STEREO,&channels) == -1 )
    {
  perror("ioctl stereo");
  return errno;
    }

    /* 자료 형식을 사운드카드에게 알린다 */
    if ( ioctl(handle, SNDCTL_DSP_SETFMT,&format) == -1 )
    {
  perror("ioctl format");
  return errno;
    }

    /* DSP 재생율(playback rate), 즉 raw PCM 음의 샘플링 빈도를 지정한다. */
    if (ioctl(handle, SNDCTL_DSP_SPEED,&rate) == -1 )
    {
  perror("ioctl sample rate");
  return errno;
    }

    // 빈도 * 5 초 * 두 채널
    data = malloc(rate*SECONDS*(channels+1));

    if((fd=open("demo.pcm",O_RDONLY))==-1)
    {
  perror("open file");
  exit(-1);
    }

    /* demo 파일에 저장된 정보를 읽어서 할당한 메모리에 저장한다 */
    read(fd,data,rate*SECONDS*(channels+1));
    close(fd);

    /* 읽은 내용을 사운드카드에 쓴다(write)! 그러면 재생이 된다. */
    write(handle, data, rate*SECONDS*(channels+1));

    if (ioctl(handle, SNDCTL_DSP_SYNC) == -1)
    {
  perror("ioctl sync");
  return errno;
     }

    free(data); //좋다. 마무리.
    close(handle);

    printf("===Done===\n");
    return 0;
}


 

(5) 코드 설명

  • 이 프로그램은 raw PCM, 22KHz, stereo 자료파일을 5초간 연주한다. 프로그램은 크게 3가지 작업을 한다.
    • sound 장치 열기(open)
    • 재생을 위한 파라미터 설정
    • 장치에 자료 쓰기(write)
  • open() / write() / close() 시스템 호출은 일반 파일과 동일하다.
  • ioctl()(Input/Output ConTroL) 시스템 호출을 사용하여 재생에 사용할 파라미터를 설정한다. ioctl() 시스템 호출은 입출력 장치와 통신하거나 파라미터를 설정할 때 사용한다. 또 시스템 호출의 개수를 줄이기 위한 편법으로 사용되기도 한다. 그래서 흔히 프로그래머의 다용도칼이라고 부른다. 함수의 원형
  • int ioctl( int fd, int command, ... );

    • fd : 장치의 파일 기술자(file descriptor)
    • command : 장치에 대한 요청/명령
    • ... : command에 따라 달라진다.
  • ioctl(handle, SNDCTL_DSP_SPEED, &rate)
    • DSP 재생을 설정한다. rate는 장치 드라이버로 전달되는 실제 재생율이다.
  • 예제 프로그램에는 3가지 ioctl()이 있다.
    • 재생에 사용할 채널 개수(channels)를 설정
    • PCM 형식(format)을 설정
    • 재생율(sampling rate)을 설정
  • 이것으로 장치에 필요한 정보는 충분하고, 다음은 장치파일에 PCM 자료를 직접 쓰면(write) 재생이 된다. 마지막 ioctl()은 장치를 비우고(flush), 그 다음 PCM 자료를 저장하기 위해 할당한 메모리를 해제한다. 이게 끝이다.

 

 

(6) 음악 저장 형식

  • 방금 전에 5초짜리 22KHz 음악을 재생하기 위해 raw PCM 자료 220KB가 필요했다.
    • 22,000 x  5  x   2    = 220,000 bytes
    • (샘플   x 초 x 채널 = 데이터 크기)
    • CD 음질로 1분을 재생하기 위해 필요한 크기는 :
      • 44,100 x 60 x 2 = 5292000 bytes, 약 5 MB!
  • 음악 CD는 raw PCM 형식으로 자료를 저장한다. 그러나 컴퓨터는 음악을 효율적으로 저장하고 (인터넷으로) 전송하기 위해 음악을 압축하여 크기를 줄이고 재생시 다시 압축을 푼다. 어떤 음악이던 관계없이 샘플링률은 고정되어 있다. 아무 소리가 없는 몇 초간을 샘플링 했다고 생각해 보자. 같은 시간의 시끄러운 락 음악과 동일한 크기가 필요하다.
  • raw 음악파일은 자료반복이 매우 적기 때문에 일반적인 압축방법으로는 잘 압축되지 않는다. 음악은 다른 기술을 사용하여 압축한다. 가장 일반적인 방법은 사림이 귀로 들을 수 없는 부분을 제거하거나 음악 특성에 따라 압축한다. 음악을 좋아하는 사람들에게 가장 대중적인 형식은 분명 MP3다. 현재 MP3에는 특허문제가 걸려 있기 때문에, 오픈소스 공동체에서는 Ogg Vorbis 형식을 반긴다. 두 형식 모두 크기가 비슷하게 줄어들며 음질의 손실을 최소화한다.

 

 

 (7) Ogg Vorbis 파일을 재생하는 방법

  • 사운드 카드가 어떻게 raw 음악 자료를 재생하는지 알았으니, Ogg Vorbis 파일을 재생하는 방법을 알아보자. Ogg Vorbis 파일을 재생하려면 먼저 복호화(decode), 즉 raw PCM 자료로 변환해야 한다.
  • libvorbisfile이 이 작업을 한다. 이 라이브러리는 매우 낮은 수준을 다루지만 더 세밀한 조절이 가능한 libvorbis 라이브러리보다 높은 수준에서 변환을 한다. 이제 문제가 간단해진다 : Ogg Vorbis 파일에서 읽은 자료를 라이브러리로 넘기고, 라이브러리가 변환된 raw PCM 자료를 사운드 카드로 직접 보낸다. 소스는 여기에
  • #include < sys/types.h >
    #include < sys/stat.h >
    #include < sys/soundcard.h >
    #include < sys/ioctl.h >
    #include < unistd.h >
    #include < fcntl.h >
    #include < errno.h >
    #include < stdlib.h >

    #include "vorbis/codec.h"
    #include "vorbisfile.h"

    int setup_dsp(int fd,int rate, int channels);

    char pcmout[4096]; // 변환한 PCM 자료를 저장할 4KB 버퍼
    int dev_fd;

    int main(int argc, char **argv)
    {
     OggVorbis_File vf;
     int eof=0;
     int current_section;
     FILE *infile,*outfile;

     if(argc<2)
     {
      printf("supply file arguement");
      exit(0);
     }

     if ( (dev_fd = open("/dev/dsp",O_WRONLY)) == -1 )
    {
      perror("open /dev/dsp");
      return -1;
     }

     infile=fopen(argv[1],"r");

     if(infile==NULL)
     {
      perror("fopen");
      exit(-1);
     }  

    if(ov_open(infile, &vf, NULL, 0) < 0)
    {
      fprintf(stderr,"Input does not appear to be an Ogg bitstream.");
      exit(1);
     }

     char **ptr=ov_comment(&vf,-1)->user_comments;
     vorbis_info *vi=ov_info(&vf,-1);

     while(*ptr)
     {
      fprintf(stderr,"%s",*ptr);
      ++ptr;
     }

     fprintf(stderr,"Bitstream is %d channel, %ldHz",vi->channels,vi->rate);
     fprintf(stderr,"Decoded length: %ld samples",(long)ov_pcm_total(&vf,-1));
     fprintf(stderr,"Encoded by: %s",ov_comment(&vf,-1)->vendor);

     if(setup_dsp(dev_fd,vi->rate,vi->channels-1))
     {
      printf("dsp setup error.aborting");
      exit(-1);
     }

     int count=0;

     while(!eof)
     {
          long ret=ov_read(&vf,pcmout,sizeof(pcmout),0,2,1,&current_section);
          if (ret == 0)
          {
        /* EOF */
      eof=1;
          }
          else if (ret < 0)
          {
            /* 자료에 오류가 있다.  (프로그램에) 중요하다면 보고하지만,
      이 프로그램은 하지 않는다. */
           }
          else   {
      printf("Writing %d bytes for the %d time.",ret,++count);
      write(dev_fd,pcmout,ret);
          }
     }

     ov_clear(&vf);
     fclose(infile);
     
    if (ioctl(dev_fd, SNDCTL_DSP_SYNC) == -1)
    {
          perror("ioctl sync");
      return errno;
     }

     close(dev_fd);
     fprintf(stderr,"Done.");

     return(0);
    }


    int setup_dsp(int handle,int rate, int channels)
    {
        int format;

        if ( ioctl(handle, SNDCTL_DSP_STEREO,&channels) == -1 )
        {
      perror("ioctl stereo");
      return errno;
        }

         format=AFMT_U8;

         if ( ioctl(handle, SNDCTL_DSP_SETFMT,&format) == -1 )
        {
      perror("ioctl format");
      return errno;
        }
     
        if ( ioctl(handle, SNDCTL_DSP_SPEED,&rate) == -1 )
       {
      perror("ioctl sample rate");
      return errno;
        }

         return 0;
    }

 

  • 다음과 같이 컴파일 한다.
  • gcc oggplay.c -oggplay -lvorbisfile -I/path/to/vorbis/header/files -L/path/to/vorbis/lib/files

  • 라이브러리파일과 헤더파일이 /usr/lib 이나 /usr/include 같은 일반적인 위치에 있다면 -l 과 -L 명령행 옵션이 필요없다. 모든 대중적인 배포본에 vorbisfile 라이브러리가 포함되있다. 만약 시스템에 설치가 안되있다면 여기에서 다운받을 수 있다. 또, Ogg Vorbis 사이트는 여기다. 프로그램을 컴파일하려면 (개발용) 헤더파일이 필요하다.

  • setup_dsp 함수는 dsp 장치를 열고(open), 세가지 중요한 파라미터인 채널, 형식, 재생율을 지정한다. 음악 재생을 위해 가장 중요한 세가지 파라미터를 기억하라. main 함수는 오류검사외에, 쉘 아규먼트로 준 Ogg Vorbis 파일을 열고, 파일에 저장된 설명과 파일정보를 출력한다. ov_open() 라이브러리함수가 채우는 구조체에 저장된 샘플링 빈도와 채널 정보를 setup_dsp 함수에 넘긴다. 그후 프로그램은 Ogg Vorbis 파일 내용을 변환하여 버퍼에 넣는 반복문을 실행한다. 반복문은 버퍼에 저장한 raw PCM 자료를 앞에서 설정한 dsp 장치에 쓴다. 파일이 끝날때까지 반복한 후, 마지막으로 정리하고 종료한다. 간단하지 않는가? 쉽고 직관적으로 변환해준 libvorbisfile에게 감사하다.
  • Ogg Vorbis 파일을 변환하려면 libvorbisfile을 사용하면 된다. MP3 파일을 변환하여 재생하고 싶다면 여러 라이브러리를 선택할 수 있다. 많이 사용하는 라이브러리중에 영상과 음악을 모두 변환할 수 있는 smpeg 라이브러리가 있다. 또, libmad 라이브러리도 찾았다. 나는 smpeg의 음악 변환 기능만 사용하기로 했다. 관심이 있다면 smpeg의 MPEG 영상 변환 기능도 살펴보길 바란다. 라이브러리 사용법을 설명하는 샘플 프로그램 plaympeg도 포함되있다. 영상을 보여주기위해 smpeg은 매우 사용하기 쉽고 기능이 많은 그래픽 프로그래밍 라이브러리인 SDL을 사용한다. 이외에도 MP3를 변환하는 라이브러리는 많지만, 많은 리눅스 배포본에 smpeg이 포함되있기때문에 smpeg을 선택했다. 많이 사용하는 gtv MPEG 영상플레이어도 smpeg 패키지에 포함되있다.

 

 (8) MP3 파일 연주하는 프로그램 예제

  • smpeg 라이브러리가 변환한 MP3 자료를 직접 사운드 카드로 보낸다. 직접 PCM을 다룰 필요가 없다. 소스 다운로드
  • #include < stdio.h >
    #include < stdlib.h >
    #include < string.h >
    #include < signal.h >
    #include < unistd.h >
    #include < errno.h >
    #include < sys/types.h >
    #include < sys/stat.h >
    #include < sys/ioctl.h >
    #include < sys/time.h >

    #include "smpeg.h"

    void usage(char *argv0)
    {
        printf("Hi,%s This is the normal useage.",argv0);
    }

    int main(int argc, char *argv[])
    {

        int volume;
        SMPEG *mpeg;
        SMPEG_Info info;
       
        volume = 100; //Volume level

        /* 아규먼트가 없으면 사용법만 출력한다 */
        if (argc == 1)
        {
             usage(argv[0]);
             return(0);
        }

        mpeg = SMPEG_new(argv[1], &info;, 1);

        if ( SMPEG_error(mpeg) )
        {
                fprintf(stderr, "%s: %s", argv[1], SMPEG_error(mpeg));
                SMPEG_delete(mpeg);
        }

        SMPEG_enableaudio(mpeg, 1);
       SMPEG_setvolume(mpeg, volume);

        /* 음악에 대한 정보를 출력한다 */
        if ( info.has_audio )
        {
                printf("%s: MPEG audio stream", argv[1]);
         
                if ( info.has_audio )
                    printf("Audio %s", info.audio_string);

                 if ( info.total_size )
      printf("Size: %d", info.total_size);
             

                  if ( info.total_time )
      printf("Total time: %f", info.total_time);

                   /* 재생하고 재생이 끌날때까지 기다린다 */
      SMPEG_play(mpeg);  

      while(SMPEG_status(mpeg)==SMPEG_PLAYING);

            SMPEG_delete(mpeg); //구조체 반환
       }

       return(0);
    }

  • 여기에 있는 smpeg을 설치한후 프로그램을 컴파일한다. smpeg을 설치하기위해서 미리 SDL을 설치해야 한다. 컴파일할때 헤더파일과 라이브러리파일 경로를 컴파일러에게 알려줘야 한다. 쉽게 하려고 smpeg 패키지는 smpeg-config라는 간단한 도구를 제공한다. 다음과 같이 프로그램을 컴파일한다:
  • gcc playmp3.c `smpeg-config --cflags --libs` -I/usr/include/SDL

  • smpeg-config 명령어를 감싸는 따옴표문자를 주의하라. 보통 backqoute라고 부르며, US식 키보드에서 틸데(~) 문자와 같이 있다. 쉘에서 이 문자는 안에 있는 명령어의 출력을 그 자리에 대신한다. 그냥 smpeg-config 명령만 실행해보면 내가 무슨 말을 하는지 알 것이다. -I/usr/include/SDL 명령행 옵션을 -I < 실제 SDL 경로 >로 수정하라. SDL 함수를 사용하지 않아도, smpeg.h가 내부적으로 SDL 헤더파일을 사용하므로 SDL 헤더파일 경로를 지정해야 한다. RPM 사용자는 프로그램을 컴파일하기위해 smpeg과 smpeg-devel 패키지를 설치해야 한다.
  • SMPEG_new 라이브러리함수는 필요한 내부 객체를 할당하고, MP3 파일에 대한 정보를 SMPEG_info 구조체에 채운다. 프로그램은 이 정보를 출력하고, SMPEG_play를 호출하여 재생을 시작한다. 함수는 즉시 반환되기때문에 다른 작업을 하면서 MP3를 연주하는 프로그램에 유용하다. 이 프로그램에서는 따로 할 일이 없기때문에 재생이 끝날 때까지 기다린다. SMPEG_delete는 그동안 라이브러리가 할당한 모든 메모리를 반환하고, 마친다

 

 글이 여러분의 프로그래밍 작업에 조금이나마 도움이 되길 바란다. 의견을 듣고 싶다. 잘못된 점을 알려주거나 제안을 바란다. shuveb@shuvebhussain.org로 내게 연락할 수 있다.

 

참고로 테스트를 해봤는데 PCM RAW파일로만 가능한다. ^^ 형식이 그렇네. mp3나 다른 형식의 파일을 받아서 cool edit로 변환해 주었다. 쿠울~~~ 에디터 ㄱㄱ 그리고 역시나 속도 그런거 잘 맞춰줘야 한다는 ^^

 

출처 : http://www.whiterabbitpress.com/lg/issue97tag/shuveb.html

 

출처 : 한국어 출처, 원문(영어)

2010년 4월 9일 금요일

리눅스 멀티미디어 프로그래밍

1. Linux용 멀티미디어 환경

 (1) 사운드

  •  기본적으로 리눅스에서는 커널 차원에서 사운드 드라이버를 지원한다.
  • 리눅스 지원 사운드 드라이버
    • 리눅스 커널과 함께 배포된 것(OSS/Free)
    • 상업용 드라이버 OSS
    • 무료로 배포되고 있는 ALSA
  • 커널 표준 사운드 드라이버
    • OSS/Free라고도 불리우며 4Front Technologies 사에서 OSS 개발을 하고 있는 Hanu Savolainen씨가 대부분을 개발했다. 지금도 OSS에서 무상 드라이버를 기부하여 이에 대응하는 사운드 카드는 점점 늘어가고 있다.
  • OSS(Open Sound System)
    • 미국의 4Front Technologes라는 회사가 개발하여 배포하고 있는 사운드 드라이버로 자유롭게 사용할 수 있는 것과 상업용이 있다.
  • ALSA(Advanced Linux Sound Architecture)
    • Jaroslav Kysela(체코 거주)가 메인 프로그래머로서 활동하고 있는 ALSA Project에서 제작, 배포하고 있는 자유 Linux용 사운드 드라이버, GPL에 의한 재배포가 가능함, 커널 표준 드라이버나 OSS 드라이버와의 호환성이 있어, 이들 드라이버용으로 작성된 프로그램의 대부분이 ALSA 드라이버에서 그대로 사용할 수 있다. 인스톨 과정이 좀 복잡함, 커널 2.4부터 자동으로 포함되어 있다.

  (2) 화상(Video)

  •  리눅스에서 지원하는 화상캡쳐 장치들로는 TV 수신카드와 영상 캡쳐 장치들 그리고 USB 화상 CAM 으로 나눌 수 있다.
    • Video4Linux
      • Kernel에서 지원하는 기본 모듈로 TV 수신카드를 지원하기 위해 등장.
    • Video4Linux2
      • Video4Linux 1.0 버전이 TV 수신카드를 위해 등장했기 때문에 화상 Cam에는 맞지 않기 때문에 USB Web CAM을 위해서 등장했다.
      • 화면의 확대/축소 기능 지원

2. Linux Sound 프로그래밍

 (1) 사운드 프로그래밍

  • 리눅스에서의 사운드 프로그래밍은 커널에서 제공해주는 API를 이용해서 만든다.
  • 리눅스 사운드에서 Degital Audio("/dev/dsp"), mixer("/dev/mixer"), MIDI, raw Music 그리고 synthesizer와 같은 장치들을 사용한다.
  • 기본적으로 사용되는 Device 장치들
    • /dev/dsp(Digital voice device)
      • 마이크로 사운드를 녹음하고 스피커로 사운드를 출력하기 위해 사용됨
    • /dev/mixer(mixer)
      • 사운드 볼륨을 조절할 때 사용됨, 마이크의 입력 방향 설정 가능
    • /dev/sequencer(Synthesizer)
      • 사운드로 효과를 만드는데 사용된다. 미리 녹음된 소리(악기 소리나 기타소리)를 합성해서 새로운 소리를 만든다.
    • /dev/music
      • 기본적으로는 "/dev/dsp"와 같다. 차이는 알고리즘 적으로 /dev/dsp는 8bit unsigned 선형(Linear) Encoding을 사용하고, /dev/music은 mu-law Encoding을 사용한다.
    • /dev/midi
      • MIDI 인터페이스를 이용해서 MIDI 장치들(Keyboards, synthesizers, stage props)을 연결하는데 사용된다.
  • 우리는 여기서 /dev/dsp를 이용해서 사운드를 입력 받아서 출력하는 어플을 작성

 (2) OSS API Basic

  • OSS API들은 <soundcard.h>라는 헤더파일에 정의되어 있다.
  • 위의 헤더파일은 보통 "/usr/include/sys"에 위치하고 있다.
  • OSS에서 장치의 값을 설정하고 읽어오는 방법은 ioctl() 함수를 이용한다.

 (3) Audio Programming

  • 디지털 오디오(Digital Audio)는 컴퓨터 외부로 소리를 표현하는 일반적인 방법이다.
  • 오디오 프로그래밍의 일반적인 방법
    • 오디오 장치를 open() 한다.
    • 환경을 설정한다.
    • 입출력을 위한 메모리(버퍼)를 설정한다.
    • Read/Write 작어
    • 사용이 끝난 오디오 장치를 close() 한다.
  • 우선 "/dev/dsp"를 사용하기 위해서는 open()을 이용해서 장치를 열어야 한다.

### fedora11에서는 커널에 기본적으로 /dev/dsp와 /dev/mixer가 모듈로 설치가 되어서 부팅후 모듈을 올려줘야 한다. 아래처럼 시스템 시작시 모듈로 올라가도록 해준다.

# vi /etc/rc.d/rc.local
 ...
modprobe snd-pcm-oss

 

 

 (4) 사운드 장치 열기

  • open()의 flag 값
    • O_RDONLY : 사운드 장치(보통 마이크)로부터 입력을 받을 때 사용한다.
    • O_WRONLY : 사운드 장치(뽀통 스피커)로 사운드를 출력할 때 사용한다.
    • O_RDWR : 사운드 장치에서 사운드를 입력과 출력을 동시에 할 경우 사용된다.
    • if( fd = open("/dev/dsp", O_WRONLY, 0) ) == -1 ){
          perror("OSS : error opening device\n");
          return -1;
      }

  • 사운드 장치를 사용할 수 없을 경우 -1을 반환한다. 만약 다른 프로그램에서 사운드 장치를 사용하고 있을 경우 "EBUSY"라고 에러값을 설정한다.

 

 

 (5) 샘플링 환경 설정하기

  • 사운드 장치를 open한 후에는 사운드 입출력을 하기 전에 기본적인 설정이 필요하다. 사운드 음질에 영향을 미치는 다음의 기본적인 세가지 parameter가 존재한다.
    • Sample format(number of bits)
    • Channel의 수(mono or stereo)
    • Sample Rate(spee)
  • 위의 설정은 순서대로 해야한다. 아래의 설정을 위의 설정보다 먼저하면 설정이 되지 않는다.

 

 

 (6) 오디오 포맷 설저하기

  • Sample format은 음질에 영향을 미치는 중요한 변수이다.
  • Sample format은 여러가지가 있지만 여기서 AFMF_S16_LE를 사용하겠다. AFMF_S16_LE는 Signed 16Bit Little Endian을 뜻한다. 이 포맷은 일반적인 PC의 사운드 카드에서 사용되고 있다.
  • 사운드 카드를 설정하기 위해서는 앞에서 설명한 ioctl()에 매개변수로 SNDCTL_DSP_SETFMT를 사용한다.
    format = AFMF_S16_LE;
    if( ioctl(fd, SNDCTL_DSP_SETFMT, &format) == -1 ){
        perror("SOUND_PCM_SETFMT");
        return -1;
    }

 

 

 (7) 채널의 수 설정하기

  • 현재 사용되는 대부분의 오디오 장치들은 Stereo모드를 지원한다. 기본적으로 설정되는 모드는 Mono이다.
  • ioctl()에 SNDCTL_DSP_CHANNELS을 사용해서 채널의 수를 선택할 수 있다.
  • Mono의 경우는 1이고, Stereo는 2이다.
  • stereo = 2; // 1 : mono, 2 : stereo
    if( ioctl(fd, SNDCTL_DSP_CHANNELS, &stereo) == -1 ){
        perror("SOUND_PCM_CHANNELS");
        return -1;
    }

 

 

 (8) Sampling Rate 설정하기

  • Sampleing Rate는 소리의 질을 결정하는 파라미터이다.
  • OSS API는 1Hz에서 2GHz의 대역을 지원한다. 기본적으로 지원되는 Sampling rate는 8kHz이다.
  • 전화기(음성)에서 기본적으로 사용하는 것이 8kHz이다. CD의 경우 44.1kHz, DVD의 경우 96kHz의 값을 가지고 있다.
  • 우리는 음성을 이용해서 녹음/재생할 것이므로 8kHz를 이용할 것이다.
  • ioctl()에 SNDCTL_DSP_SPEED를 이용하면 Sampling Rate를 선택할 수 있다.
  • rate = 8000;
    if( ioctl(fd, SNDCTL_DSP_SPEED, &rate) == -1 ){
        perror("SOUND_PCM_SPEED");
        return -1;
    }

 

 

 (9) Full Duplex 설정하기

  • 많은 장치들이 half duplex이다. Half duplex의 경우 Recording이나 Playing이 동시에 되지 않는다. 오직 한 번에 한 가지의 일을 할 수 있다.
  • 물론 다중 채널이 지원되는 경우 Recording과 Playing을 각각 다른 채널을 이용해서 하면 된다.
  • 단일 채널에 Full Duplex를 지원하기 위해서는 사운드 장치를 설치하기에 앞서서 Full Duplex로 설정해아 한다. 설정은 다음과 같다.
  • if( ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0) == -1){
        perror("SOUND_PCM_SETDUPLEX");
        return -1;
    }

 

 

 (10) 사운드 입/출력

  • 일반적으로 리눅스에서는 장치를 파일의 개념으로 사용한다.
  • 사운드를 입력받기 위해서는 파일을 읽는 것과 마찬가지로 read()를 사용한다.
  • if( status = read(fd, buf, count) ) == -1 ){
        perror(SOUND_READ_ERROR");
        return -1;
    }

  • 마친가지로 사운드를 출력하기 위해서는 write()를 사용한다.
  • if( status = write(fd, buf, count) ) == -1 ){
        perror("SOUND_WRITE_ERROR");
        return -1;
    }

  • 더 자세한 사항을 알고 싶으면 OSS API 문서를 참조하라.

 

 

 (11) 동시에 여러가지 일하기

  • 여러가지 일을 동시에 실행시키기 위해서는 thread나 멀티  proecess를 사용해야 한다. 이것들은 설정이 복잡하다. 그래서 여기서는 기본적으로 Qt에서 제공하는 QTimer를 사용하도록 한다.(자세한 내용은 출처를 참고한다.)

 

3. Video4Linx 프로그래밍

  • Video4Linux는 리눅스에서 비디오 장치들을 제어하고 사용하기 위한 API들의 모임이다.
  • 비디오 장치들로는 튜너를 가지고 있는 비디오 카드나 PC Web CAM과 같은 장치들을 들 수 있다. 튜너를 가지고 있는 장치들을 제어해서 TV나 AM/FM 라디오, TeleText등의 방송을 시청할 수 있다.
  • Video4Linux는 커널에 기본적으로 포함되어 있으므로 따로 설치할 필요가 없다.
  • 이 Video4Linux를 이용해서 X윈도우 상에서 TV를 볼 수 있는 프로그램으로는 xawtv나 xwintv 등이 있다.
  • 이 곳에서는 Philips Web Cam을 이용해서 프로그램할 것이다. 튜너를 가지고 있는 디바이스(BT848)도 거의 같은 방식으로 동작하기 때문에 프로그램을 적용하는데 무리가 없을 것으로 생각이 든다.
  • 비디오 화면을 캡쳐하는 순서(드라이버에 따라서는 mmap 등 일부의 조작이 그 기능이 없는 경우 malloc으로 메모리 버퍼를 잡을 수도 있다.)
    • Video4Linux 장비의 정보(사양)을 얻기
      • capture 카드에 관한 정보를 얻는다. 프로그램 내에서 capture 카드를 하나로 고정하고 있다면, 하지 않아도 된다.
    • 사용 가능한 채널 얻기
      • capture 카드로 사용 가능한 채널(영상 소스)의 종류를 취득한다. 이것도 위와 마찬가지로 프로그램 내에서 capture 카드를 하나로 고정하고 있다면, 하지 않아도 된다.
    • Capture할 채널의 설정
      • 앞에서 가져온 정보를 이용해서 capture 하는 채널을 선택한다. 동시에, 영상 신호의 포맷 종류(NTSC, PAL, SECAM 등)도 선택한다.
    • 파라미터 설정
      • 밝음(Brightness), 대비(Contrast), 휴(Hue) 등의 파라미터 설정한다.
    • 메모리 공간 할당
      • malloc이나 mmap의 시스템 콜을 이용해서 캡쳐할 영상이 저장될 메모리 기억공간(buffer)을 확보한다.
    • Capture 시작하기
      • 앞에서 확보한 메모리 공간에 capture가 되도록 한다.
    • Capture 종료까지 기다리기
      • 그 밖에 하는 것이 없으면, capture 처리가 종료될 때까지 기다린다.
    • 화성처리
      • capture한 버퍼 내의 영상 데이터를 원하는 목적으로 처리한다. 이 과정에서 화면에 영상을 표시할 수 있다.
  • 더 자세한 내용은 출처를 참고한다.

 

 

출처 : 리눅스 멀티미디어 프로그래밍