2009/12/24

[Qt/X11] 데스크탑 비디오 캡쳐 3


먼저, 동영상이란 무엇인가? 각 그림이 하나의 프레임을 이루어, 프레임이 모여 동영상을 만드는 것이다.(라고 알고 있다) 그림을 여러장을 빨리, 똑같은 간격으로 보여주는 것만으로도 동영상처럼 보여줄 수 있다는 소리. 그러니까 Phonon을 쓰지 않아도 캡쳐한 그림을 QLabel::setPixmap으로 라벨에 보여주기만 해도 동영상처럼 사용할 수 있다는 뜻. 만약 클라이언트가 있어서 이 그림을 클라이언트에게 전송한다면 마찬가지로 똑같이 동영상처럼 보이게 할 수 있겠지만, 전송 속도나 그런 것에 영향을 심하게 받지 않을까 생각한다. 아무튼, 메인윈도우에 나오는 그림이 위에 쓴 그 상태고, 지금은 캡쳐 영역의 일부분만 나오는데 그건 scaled를 안해줘서 그렇다.
지금 만들고 있는 이거는 계획이 서버-클라이언트라 서버에서 찍은 동영상을 클라이언트들이 볼 수 있어야 하는데, 서버에서 굳이 동영상 인코딩한걸 재생까지 할 필요는 없을것 같다. 어차피 서버에서는 사운드 캡쳐를 안해도 딜레이 없이 똑같이 보이니까 저런 식으로 처리해도 무리는 없을 것 같음.

모든 캡쳐된 그림은 QQueue로 넣어서 사용하기로 하였다. 좀 쌓아놨다가 한번에 인코딩할 수도 있겠고, 생각해 보면 그때그때 생긴 그림을 바로 인코딩하는 것보다 CD플레이어의 안티쇼크 기능처럼 많이 가지고 있으면 뭔가 더 안정적일 것이라 생각하고 있다. 예를 들어 그림 한 장 인코딩을 놓치면 소실이지만 그 프레임은 그냥 소실이지만, 일단 큐에 쥐고만 있으면 어떻게든 할 수 있겠지; 그런데 이렇게 생각하고서는 별 생각없이 Queue의 최대값을 1000으로 잡았더니 나중에 컴퓨터가 거의 멈추어버렸다. 아마도 용량이 커서 그런 것이 아닐까. QPixmap이란게 픽셀 데이터를 담고 있다고 하니 단순하게 생각해서 좌표 x,y 각각 2바이트, RGB값 각각 3바이트 이상... 으로만 계산해서 10바이트가 넘는데 저 영역이 284*184의 영역을 캡쳐하니까 52556 * 10바이트, 그러니까 QPixmap 하나가 500KB정도의 용량을 차지한다고 생각해 볼 수 있겠다. QPixmap이 어떤 식으로 저장하는지는 잘 모르니까... 녹화 영역이 더 커진다면 더 위험하고.

근데 지금은 enqueue만 해놓고 dequeue를 안해놨으니까 쌓이기만 하다 문제가 생기는게 당연한 것 같긴 하다. 빨리 쌓인 이미지를 인코딩할 수 있게 해야 하는데; 그렇게 하면 큐에 그림이 차면서 빠지고 차면서 빠지고 해서 적당량을 유지할 것 같다. 그리고 어쨌든 큐의 최대값을 줄여야 하겠고.

 

어쨌든 지금까지는 별 문제 없이 모든걸 해결했다. 진정한 문제는 이제부터.

 

- 사운드 캡쳐 문제

RtAudio 이야기를 했었는데 이게... pulseaudio를 지원 안하는 것 같아 쓰려다 말았다. 우분투에서 pulseaudio를 쓰는데 만약에 이 프로그램을 쓸 사람이 봤더니, 사운드 지원을 위해 alsa나 oss를 설치해야 한다는 소리를 들으면 차라리 안쓰고 말지 않을까. 귀찮기도 하고. 그래서 cross platfom sound library 이런거 검색어로 넣고 마구 검색해봤는데 쓸만한 것이 없는것 같다. 어떻게 해야할지... recordmydesktop 소스코드를 보고 분석해서 집어넣는다고 해도 윈도우는 어떻게 해야 할지; 윈도우 고수들는 주위에도 몇명 있으니 하려면 어떻게든 하겠지만, 사운드가 우선적인 순위는 아니라 이건 급하진 않고.

 

 - 인코딩 문제

당면한 가장 큰 문제가 이건데, 나는 그때 별 무리없이 ffmpeg가 컴파일되는 것을 보고 별 어려움이 없겠지 생각했는데 일단 컴파일이 안된다; 이것저것 헤더 경로 수정하고 해도 안되길래, 아예 apt-get으로 libavcodec-dev 이런거 다 설치해버렸는데 그래도 안된다. 뭐가 문제지; 그래 어쨌든 이건 15분도 투자 안했으니 조금 더 투자하면 문제의 원인을 안다고 쳐도, 인코딩을 어떻게 할 것인가. 그렇게 내가 실력이 뛰어나지 않아서 그런걸까, 조금 확실한 예제와 설명을 볼 수 있으면 좋겠는데 찾아보기도 쉽지가 않다.

 

- fps문제

전에도 쓴 이야기지만, 내가 캡쳐 간격을 100밀리세컨드로 잡아놨다고 해서 그림이 100밀리세컨드에 정확히 한장씩 찍힌다는 보장이 있을까? 지금 한쪽 쓰레드에서 알람시계처럼 시그널을 계속 던지고, 이걸 메인 쓰레드에서 처리하는데 만약 뭔가 일이 복잡해져서 110밀리세컨드에 그림을 저장했다면? 그리고 이런게 연속된다면 동영상의 길이가 실제 캡쳐시간과 틀려질테니 말이다. 아직 인코딩도 하기 전에 이런 생각을 하는 것이 조금은 이상하기는 하지만... 일단 만들어놓고 테스트를 해봐야 하나?

2009/12/22

[Qt/X11] 데스크탑 비디오 캡쳐 2

어제에 이어...

 

 - Thread

 

먼저 쓰레드를 수정했다. 먼저 쓰레드 전에 다른 슬롯함수를 바꿨는데

 

[code]void ScreenCapture::SetThreadState(bool Flag)
{
        if ( Flag == true )
        {
            fileNumber = 0;
            this->start();
        }

        else
        {
            this->terminate();
        }
}[/code]
 

전에는 쓰레드 객체를 만든 곳에서 start()를 호출해서 쓰레드를 바로 실행시켰는데 생각해 보니 이럴 필요가 없었다. 그냥 시작버튼을 눌렀을 때 시그널을 날리게 되면 그때 쓰레드를 start()하거나 terminate() 하면 되는 거였는데... 역시 경험이 많아야 하는 것이다. 어쨌든 위의 슬롯 함수 덕택에 쓰레드 함수는 상당히 간결하고 효율적으로 변했다.

[code] void ScreenCapture::run()
{
        while(true)
        {
                fileNumber++;
                emit SaveScreen();
                msleep(100);
        }
}
[/code]

 

 - FFMPEG

 

ffmpeg의 libavcodec을 따로 컴파일하고 가져다 쓰면 편하지 않나 싶어서 이것저것 알아봤는데... 내가 잘못 알았던 것이 있었다. ffmpeg에 libavcodec과 libavdevice등등의 라이브러리가 있고 ffmpeg는 단지 이걸 가져다 사용하는 프로그램이었던 것인데 라이브러리만 따로 빼서 컴파일 한다고 그랬으니... 그냥 ffmpeg를 컴파일하면 자동으로 다 같이 컴파일이 되고 그러면 그걸 사용하면 되는 것이었다. 바보같으니;

우분투에서는 sudo apt-get install ffmpeg로 간단히 설치할 수 있는데, 이러면 다른 곳에서도 ffmpeg를 설치해야 하기 때문에 따로 받아서 컴파일하고 프로젝트 폴더에 옮기기로 하였다.

 

먼저 ffmpeg의 소스코드를 받아야 하는데 흔히 보는 것처럼 tar.gz 이런 식으로 다운로드 가능한 것은 아니고(찾아보면 있다. 윈도우용 바이너리도 찾아보면 다 있다) svn으로 받아야 하는데 리눅스 터미널이라면

 

svn checkout svn://svn.ffmpeg.org/ffmpeg/trunk ffmpeg


요렇게 하면 된다. 현재 폴더의 하위에 ffmpeg폴더를 만들고 거기에 다운로드가 된다. 그리고는 컴파일을 하면 되는데, 보통 configure를 실행하면 뭔가 에러가 수없이 뜨고 그러는데 이번엔 하나도 안떠서 오히려 깜짝 놀랐다. 일이 되려면 잘 풀리는것인지; 아마도 나도 모르는 사이에 컴파일에 필요한 라이브러리들이 다 설치된듯.

 

내가 준 옵션은 그냥 prefix로 설치될 폴더만 바꿔준 것 뿐인데(--prefix=경로) 그 다음 make, make install로 무사히 처리. 아직 이걸로 뭔가를 테스트해 본것은 아니라서 정확히 된다고 말은 못하겠지만 하여간 이런 식으로 하면 된다.

 

 - 사운드 캡쳐

Qt에서는 사운드 캡쳐를 어떻게 지원하는지 모르겠다. QSound라는 클래스가 있는데 녹음을 지원하는 것이 아니고 재생만 지원하는듯 해서... 윈도우, 리눅스 플랫폼에서 똑같이 쓸 수 있는 걸 찾다 보니 하나 건졌는데 RtAudio라고 하는데, 위키에 검색해보니 뭐 다른게 나오는 것 같고 네이버에 검색해도 딱히 사용기나 뭐 그런게 나오질 않아서 상당히 당황스럽게 생각하고 있다. 이걸 사용해서 사운드를 캡쳐할 수 있다면 libavcodec을 이용해서 동영상을 인코딩할 때 같이 넣어주면 되는데 이때 생기는 또 하나의 고민이, 10프레임 간격으로 이미지를 집어넣어 동영상으로 변환을 한다면 사운드와의 싱크는 어떻게 맞출 수 있을 것인가가 그것이다. 혹시 사운드도 프레임 단위로 이루어져 있나? 그러면 한결 편할텐데...

 

 - 이미지 캡쳐 문제

전에 이미지 캡쳐를 할때 느꼈던 문제점 중 하나가 뭐였냐 하면 QPixmap에서 이미지를 캡쳐후 저장할 때 로우 데이터를 뭔가로 변환하고, 그 다음 다시 동영상으로 변환하니까 조금은 비효율적이지 않을까 했던 것이었는데, 먼저 Qt Assistant의 QPixmap::grabWindow를 살펴보면 각 픽셀 정보를 가져오는 것 같다. 그런데 보통 그림이 다들 그렇지 않나; bmp도 그렇던데 그러면 이게 QPixmap이니까 픽스맵이라고 하면 도대체 비트맵하고는 뭐가 틀린건지; 비트맵으로 하면 속도의 이득을 볼 수 있는 것인지 그걸 모르겠다. 아무튼 메모리에 올리게 되면 jpg 이런 파일로 디스크에 저장하는 것보다 속도가 뛸게 분명하고 그럼 지금보다 높은 fps로도 캡쳐가 가능할 듯 싶다.

 

 

 

 

 

 

2009/12/21

[Qt/X11] 데스크탑 비디오 캡쳐

cyan색의 틀 안쪽이 캡쳐 영역이다.


우분투 9.10 새 버전을 깔았는데 윈도우 부트로더가 복구가 안된다. 몇번 시도를 해 봤는데 복구가 잘 안되서 일단 윈도우에서는 테스트 해 보지는 않았지만 그 쪽에서도 별 문제는 없을 것이라고 개인적으로는 판단하고 있다. 그래도 테스트는 해봐야겠지만;


텍스트큐브에서는 자체적인 동영상 첨부가 안되나? 티스토리에 올리고 여기다 링크해야 하는군; 아무튼,

기본적인 방식은 캡쳐창 안쪽의 영역을 일정한 시간마다 캡쳐하여 그림을 만들고 그 그림을 동영상으로 인코딩하는 방식으로 만들었다. 간단한 캡쳐창을 만들고 나서 그 캡쳐창 안쪽을 캡쳐할 영역으로 지정하였다. 그리고 QPixmap의 grabWindow메소드를 사용하여 캡쳐. 원래는 다른 쓰레드를 하나 세우고 그 쓰레드에서 캡쳐를 처리하려고 했는데 Gui Thread가 아닌 곳에서는 QPixmap을 사용하지 말라는 경고 메시지도 뜨는데다가, QApplication::desktop()->winId(); 부분이 에러를 발생시켜서; 이쪽 쓰레드에서는 시간이 될 때마다 시그널만 만들고 이 시그널을 Gui Thread에서 받아서 처리하는 식으로 하였다. 현재는 10fps, 즉 1초에 10장을 찍는데 이게 최적화를 어떻게 시켜야 할지 참 난감하다. 자세하게 써 보면...

[code]QString format = "jpg";
QString fileName;
QRect RecordPos = Rec_Widget->RecordPosRect();

ScreenImage = QPixmap::grabWindow(winid,
                                RecordPos.x(),
                                RecordPos.y(),
                                RecordPos.width(),
                                RecordPos.height()
                                );
ScreenImage.save(fileName.setNum(filesequence) + tr(".") + format, format.toAscii());

filesequence++;
[/code]

현재는 대충 이런 식으로 파일을 저장하는데 이걸 보면서 생각해 보면...

X윈도우에서 grabWindow로 그림을 캡쳐한 다음엔 QPixmap의 save를 이용해서 jpg로 파일을 저장하는데, 만약 캡쳐한 데이터가 로우 데이터인데 jpg로 변환해서 저장하는 것이라면 여기서 필요없는 부분이 생기는 것 같다. jpg로 변환할 필요 없이 바로 동영상으로 인코딩하는 것이 더 나을거 같기도 하고. 자세히 파고든건 아니지만 XBM과 XPM이라는, X11 형식의 그림 파일이 엄연히 존재하는데 이걸 다시 jpg로 변환하는 것은 아닌가 하는 생각 말이다. 이건 조금 더 알아봐야 할 것 같다.

다른 문제는 뭐냐하면 동영상에도 나오지만 캡쳐창을 드래그하면 찍히지 말아야 할 캡쳐창도 같이 찍히는 것이다. 바뀐 영역을 저장 후에 이 영역으로 캡쳐를 떠야 하는데, 저장하고 난 다음에 바뀐 영역이 저장이 되는건지; 그런데 사실 실제로 캡쳐하는 데에서 캡쳐창을 잡고 이리저리 휘두를 사람은 없을것 같아서, 이건 제일 낮은 순위의 버그다.

그리고 현재 쓰레드 부분을 보면...

 

[code]void ScreenCapture::run()
{
    while(true)
    {
        if (ThreadState == false)
        {
            fileNumber = 0;
        }

        else
        {
            fileNumber++;
            emit SaveScreen();
            msleep(100);
        }
    }
}
[/code]


쓰레드의 루프는 계속 돌아가고, ThreadState라는 플래그의 값을 바꾸는 것으로 원하는 동작을 수행하게 하였다. 그런데 문제인 것이, 위의 소스코드에서 시그널 SaveScreen()을 호출하고 처리가 끝난 후 다시 돌아온 후에 100밀리세컨드를 대기하면 다음 SaveScreen()을 호출하는 것은 적어도 (100+x)밀리세컨드의 시간을 소비하는 것이 아닐까? 정확히 100밀리세컨드를 대기해야만 나중에 10프레임으로 인코딩 될 동영상의 길이가 내 데스크탑에서의 시간과 일치한다는 보장이 생기는 것일텐데 말이다. 시그널을 호출하고 다시 돌아오지 않는다면 100% 문제가 있는거고, 호출만 하고 이쪽 쓰레드가 계속 돈다 해도 100+x의 상황인 것 같다. 만약 시간이 틀리다면, 10프레임으로 인코딩한 동영상이 실제 데스크탑 시간보다 더 길어지는 문제가 생기겠지;

그리고 다른 문제도 있는데 쓰레드의 문제. 뮤텍스를 세워서 해야 하는건지 아닌지는 모르겠지만, 지금 보면 ThreadState의 값이 false일 때 전혀 다른 동작을 수행하게 해서 원래의 동작을 막았다. 즉, 쓰레드가 멈춘 것이 아니라 동작하고 있는 것이다. 이것도 쓸데없는 부분 같은데 이걸 어떻게 해결해야 할지; 예전 운영체제 수업을 들을때 쓰레드와 뮤텍스 부분에 대해서 상세한 수업을 들었었는데 벌써 잊어먹었다니, 다시 한 번 찾아보아야 할 듯 싶다. 사실 그리고 QWaitCondition부분에서 해결을 볼 수 있을거같은데 참 찾아보기가 귀찮기도 하다.

동영상은 ffmpeg를 사용해서 변환을 하였다. 명령줄은...

ffmpeg -r 10 -b 1000 -i %d.jpg output.avi

그림을 100밀리세컨드마다 찍었기 때문에 프레임은 10으로(-r) 지정하였다. 다만 QProcess나 이런 식으로 실행한 것은 아니고 캡쳐된 결과물(이미지 110장 -_-)을 터미널에서 변환했는데, libavcodec을 따로 라이브러리 컴파일해서 사용할 수 있으면 프로그램에서 직접 호출로 사용할 수 있을 것 같다. 동영상은 Phonon모듈로 재생하면 되고.

2009/12/11

[Qt] Undefined reference to 'vtable for...'

컴파일 하다 이 에러가 뜬다면...?

사실 Qt에서 C++ 문법적으로 크게 틀린게 없는거 같은데도 이 에러가 뜨는 경우가 자주 있다. 그동안은 어떻게어떻게 하니 이게 해결이 되어버려서 -_- 별 신경을 안썼더니 아예 이런 일이 있었다는 것 자체를 잊고 있었는데, 오늘은 아무리 컴파일을 하고 소스코드를 수정하고 별 짓을 다해도 이게 해결이 되지 않았다.

일단 인터넷(네이버)에서 찾아서 나온 대부분의 답은 뭐였냐 하면 'Q_OBJECT라인을 삭제해 주면 된다. 시그널과 슬롯을 쓰지 않는데 추가한다면 에러가 나기 때문이다. 지우면 에러가 뜨지 않는다...' 였는데, 그래서 지웠다. 물론 이렇게 하면 시그널과 슬롯을 사용하지 못하기 때문에 이것도 같이 주석처리하고 컴파일했더니 잘 된다. 잘되는군... 그런데 사실 시그널과 슬롯이 필요해서 지금 이 에러를 계속 수정하는건데 이걸 지워야 해결이 되다니 이게 말이 되나; 다시 추가하고서 문법적으로 뭔가 잘못된게 있었나 다시 찾아보았다. 그래도 답이 안나와 도저히 모르겠다 싶어 구글신님께 물어보니...

- "undefined reference to ‘vtable for …"
after adding classes that inherit QObject and have Q_OBJECT functionalities (like signals and slots) you have to manually launch "qmake" (without any parameter), because it has to regenerate the makefile adding the calls to MOC files for the new classes.


클래스에 Q_OBJECT 키워드를 추가하거나 하면 다시 MOC를 만들어야 하기 때문에, 결론은 qmake를 한번 실행해 주면 된다.

그러고 보니 예전에는 QtCreator 쓰기 전에 QDevelop을 썼었다. 여기서는 qmake부터 쭈욱 컴파일해줬던 옵션이 있었던 것 같았는데 QtCreator는 없는것 같다. 그래서 QDevelop쓰던 때에는 이 에러를 잘 못본건가 싶다. 아니면 답답한 마음에 이것저것 누르다 qmake를 눌렀다거나;

2009/12/08

Qt 4.6 릴리즈

Qt의 새 버전, 4.6이 12월 2일 공개되었다. 신나게 버전업 하는구나...

아무튼 중요한 변경점으로는,

 

  • Animation Framework
  • State Machine Framework
  • Multi-Touch and Gestures
  • DOM access API
  • Performance Optimizations
  • Graphics Effects
  • XML Schema Validation
  • Qt3D enablers
  • Multimedia Services
  • New Classes, Functions, Macros, etc.

 

어느샌가 trolltech.com이라는 주소가 qtdownload.com으로 바뀐 다음 또 qt.nokia.com으로 바뀌었길래 qt가 노키아 휴대폰에라도 올라가려나 했는데 이번 4.6버전부터 심비안os를 정식으로 지원한다고 한다. 대충 검색해보니 노키아의 S60이라고 하는게 참으로 골때렸다고 하던데 그것 때문인지는 몰라도 인수 후 Qt로 바꿔나가는듯 하다. Maemo도 가능하다고 하니, 그럼 내가 노키아 휴대폰을 사면 간단한 어플 같은건 직접 만들수 있는건가...? 어떤 글에서 Qt가 가능하면 노키아 휴대폰이 장난감이라고 썼던데 그게 맞는 말인듯. 이거 일단 에뮬레이터 같은걸로다가 간단한거 하나 만들어보고 싶다.

 

거기다 위에 써 있듯이 여러 프레임워크가 추가된 것도 있고 최적화도 되었다 하니 역시 새로운 버전이 나오면 바로바로 버전업을 하는 것이 나을듯 하다.(그리고 Win9X 지원은 이제 안되는듯.) 멀티 터치도 지원된다고 하니 윈도우 7에서도 좋을 것 같고.

멀티터치의 위엄

 

그리고 Qt SDK도 2009.05로 버전이 올라감. 이게 뒤의 숫자가 몇 월에 나왔는지 쓰는건줄 알았는데 그냥 버전 숫자인듯 하다. 며칠전에 윈도우 포맷했을 때 다시 깔았을때도 2009.04였는데 잠깐 틈을 보인 사이에 업데이트를...

 

사실 내가 이런 쪽에 대해서 조금 잘 알면 자세한 설명을 포함해서 정보글을 작성할텐데 그게 안되니 조금 안타깝다. 새롭게 추가된 프레임워크라던가(애니메이션) 기타 변경사항 등을 한번 테스트 해봐야 할 것같다.

 

 

2009/12/07

간단한 쉘 프로그래밍

[code]#!/bin/bash

filename="length"
fileext=.txt

destfile="wordfile.txt"

for ((i=2;i<33;i++)); do
    let    j=i/10
    let k=i%10
    cat $filename$j$k$fileext >> $destfile
done
[/code]
잠깐 쓸 일이 있어서 모든 영어단어가 담긴 8.4메가짜리 파일을 받았다. 그런데 열어보니 황당했던 것이, 이게 하나의 파일에 통합되어 들어있었던 것이 아니고 2자부터 32자까지 단어의 숫자별로 파일이 나눠져 있었던 것이다. 내가 필요했던 것은 통짜 파일이었기 때문에 귀찮게 되었군, 이 파일을 모두 합쳐야겠다 생각했는데, 리다이렉션 생각을 전혀 못했을 때는 합치는 것이 정말 일이었다. 메모장으로 일일히 옮길 수도 없고 말이다. 리다이렉션 생각이 나서 다행이라고 생각했는데 또 문제가, 파일이 2~32번의 30여개 정도 되는 갯수였기 때문에 리다이렉션도 30여번을 해야 하나 싶어서 다시 한숨이 나왔다. 그러다 한줄기 구원같은 쉘 프로그래밍이 생각났다. 지금 나에게 필요한 것은 반복문이었다. 아... 반복문... 그래, 그걸 한번 해보자!

 

파일명은 lengthNN.txt였고(NN는 두 자리 숫자) 최종으로 합쳐지게 될 파일은 wordfile.txt로 정했다. 어차피 소스코드야 다 비슷비슷하기 때문에 별로 짜는데 문제될 것은 없었는데 헷갈렸던게 뭐냐 하면 계산식을 쓰는 부분과 쉘 명령어를 쓰는 부분이었다. 처음에는 다른 프로그램처럼 그냥 계산식만 쓰면 되는줄 알았는데 그렇게 해도 에러만 나길래 뭔가 했더니, 계산식을 쓰기 전에는 항상 let을 써 줘야 하는 것이었다. 음... 불편하군... 그 다음에 겪었던 문제는 echo 명령어로 출력을 해도 아무런 효과가 나타나지 않는 것이었다. 출력은 되는데 명령어의 효력이 없었다고나 할까. php에서 echo로 출력을 하는 것과 같다고 생각했는데 그것과 달랐던 것. 명령어를 사용하려면 그냥 명령어만 써 주면 된다.


음, 그리고 리다이렉션. >과 >>의 차이를 잘 몰랐었다. 왜냐하면 별로 리다이렉션을 사용할 일이 없었기 때문이었는데 저 두 명령어에는 중요한 차이가 있었으니... >는 파일을 덮어쓰는 것이고 >>는 이어쓰는 차이다. 또한 쉘에서 변수를 선언하고 값을 대입하는 부분에 있어서 특이한 것이, =이퀄 사이에는 절대 공백이 없어야 한다는 것.

 

어쨌든 파일을 모두 합치니 8.4메가의 위엄 쩌는 텍스트파일이 나왔고 이제 이것을 사용하기만 하면 된다. 영단어 모음 파일도 같이 첨부함. 역시 간단한 거라도 머리를 써야 능률이 오르는 법. 괜한 고생 할 뻔했다.