1. 새 프로젝트
File -> New -> Project…
Win32 / Win32 Project 선택 , 폴더를 선택하고 Name 을 입력합니다. 여기서는 “audio_volume” 프로젝트로
프로젝트 명을 정하겠습니다.
다음 페이지에서 Application type을 DLL 로 Application option 은 Empty project 로
선택합니다.
2. Filter 만들기
CLSID, interface IID, interface 정의 등을 가지는 헤더파일을 하나 만듭니다.
프로젝트의 헤더파일에서 추가> 새항목으로 새로운 헤더파일을 하나 추가합니다.
헤더파일의 이름은 “audio_types.h” 로 합니다.
새로운 필터를 위한 class ID를 생성하기 위해서는 도구 -> GUID 만들기 를 사용합니다.
필자는 “static const struct GUID ….” 항목을 주로 사용합니다.
새롭게 생성된 GUID를 위해 “CLSID_AudioVolume” 라는 이름을 사용하도록 하겠습니다.
아래는 audio_types.h 의 내용입니다.
// {212A25F7-7000-4f74-9E4C-6FFB3F595EE4} |
filter 를 위한 기본 헤더파일을 만듭니다. 파일명은 “audio_filter.h” 로 하고 아래의 코드를 추가시킵니다.
#pragma once class AudioVolume : public CTransformFilter // CTransformFilter overriden |
다음은 filter 구현을 위해 cpp 파일을 추가합니다. 파일명은 “audio_filter.cpp” 로 하고 다음 코드를
써줍니다.
아래는 생성자와 소멸자 그리고 audio filter 의 인스턴스를 넘겨주는 정적 메소드 입니다.
AudioVolume::AudioVolume(LPUNKNOWN pUnk, HRESULT *phr) : AudioVolume::~AudioVolume() CUnknown *WINAPI AudioVolume::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr) |
이제 우리는 CTransformFilter 의 함수들을 오버라이딩 해야되는데요..
upstream 필터가 현재 필터에 연결되기 위해서는 첫번째로 적당한 media type을 협상하게 됩니다.
여기서는 16-bit raw PCM audio data만 허용할 것입니다.
그래서 AudioVolume::CheckMediaType 함수를 아래와 같이 override 합니다.
HRESULT AudioVolume::CheckInputType(const // and we only want 16-bit return NOERROR; |
우리 필터는 encode/decode 또는 데이터를 스크렘블 하지 않고 그냥 PCM audio 를 내보낼 것입니다.
HRESULT AudioVolume::CheckTransform(const // must also be PCM audio return NOERROR; |
입력 media type과 출력 media type을 동일하게 하기 위해 입력 type을 복사해 둡니다.
HRESULT AudioVolume::SetMediaType(PIN_DIRECTION direction, const CMediaType *pmt) // keep a local copy of the type if (direction == PINDIR_INPUT) { return NOERROR; HRESULT AudioVolume::GetMediaType(int iPosition, // the input pin must be connected first // we offer only one type – the same as input |
얼마나 큰 버퍼를 사용할 지 명시적으로 만들어 줍니다.
HRESULT AudioVolume::DecideBufferSize(IMemAllocator *pAlloc, // this might be put too simly but // when working with audio always try to have ALLOCATOR_PROPERTIES act; if (act.cbBuffer < pProp->cbBuffer) |
마지막 단계 – audio 처리를 합니다. 우리는 각 PCM sample 에 0.5 를 곱하도록 하고 있습니다. 이것은 -6.0205 dB
만큼 신호를 증폭시키는 것입니다.
(0.5를 곱하면 크게 차이가 나지 않는다. 실제 필터를
만들때 0을 곱해서 음소거를 알아볼수도 있고 2 정도를 곱해서 소리가 엄청 크게 됨을 알수도 있다.)
HRESULT AudioVolume::Transform(IMediaSample *pIn, IMediaSample *pOut) // get the input and output buffers // and get the data size // since we’re dealing with 16-bit PCM // now deal with the samples and lower the volume // and set the data size |
기능적인 구현은 끝났습니다.
다음은 GraphBuilder 가 필터를 인식할수 있도록 여러가지를 추가시켜야 됩니다.
3. 레지스트리 정보
레지스트리 정보와 DLL entry points 를 위해 따로 파일을 만드는 것은 좋은 습관입니다.
필자는 “*_reg.cpp” 형태를 사용하곤 합니다. 그래서 여기서는 “audio_reg.cpp” 파일을 만들었습니다. 그리고 아래 코드를
추가합니다.
필자는 표준 merit 값을 사용하기를 강력하게 추천합니다. 특별한 일이 없으면 MERIT_UNLIKELY or
MERIT_NORMAL 을 사용하세요.
// Media Types // Pins // Filters // Templates int g_cTemplates = sizeof(g_Templates)/sizeof(g_Templates[0]); |
DirectShow filter는 COM 객체입니다. 따라서 라이브러리를 등록하고 등록 해제 하기 위해서는 아래 코드를 추가하세요
STDAPI DllRegisterServer() STDAPI DllUnregisterServer() extern “C” BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID); BOOL APIENTRY DllMain(HANDLE hModule, #pragma warning( disable:4514) |
4. Headers
다음은 “headers.h” 파일을 만들고 아래 코드를 입력합니다.
#include <streams.h>
#include <initguid.h> #include “audio_types.h” #include “audio_filter.h” |
그리고 모든 *.cpp 파일에 header.h 파일을 include 시킵니다.
5. 외부기호
프로그래밍 하는 것은 다 했습니다. 이제 DLL 라이브러리는 외부로 함수를 함수를 노출시켜 주어야 되는데 COM 라이브러리는 아래와 같이
최소 4개의 함수를 노출시켜야 됩니다.
- DllRegisterServer
- DllUnregisterServer
- DllGetClassObject
- DllCanUnloadNow
처음 두개는 앞에서 이미 선언했고 뒤의 두개는 bassclasses 라이브러리에 구현되어 있습니다.
그러나 우리는 링커에게 우리가 진짜로 이 함수들을 노출시키고 싶다는 걸 알려야 됩니다.
그래서 새항목 추가를 통해 프로젝트에 “모듈 정의 파일(.def) 파일을 추가하고 “audio_volume.def” 파일이름을
정합니다.
그리고 아래와 같이 편집해 줍니다.
LIBRARY audiovolume.ax |
6. 프로젝트 옵션
빌드 환경 설정 : 프로젝트 속성에서
1) C/C++ > 고급 > 호출규칙: __stdcall 으로 변경
2) 일반 > 문자집합: 멀티바이트 문자집합 사용 으로 변경
3) C/C++ 추가포함 디렉토리 에서 디렉토리 추가
– C:\SKD\WSDK\Samples\Multimedia\DirectShow\BaseClasses
– C:\SKD\WSDK\Include
– C:\SKD\WSDK\lib
: BaseClasses를 맨 상위로 오도록 해야된다 그렇지 않으면
C:\Program Files\Microsof
SDKs\Windows\v6.0\Samples\Multimedia
\DirectShow\BaseClasses\refclock.h(80) : error C2061: syntax error : identifier
‘CAMSchedule’
에러가 발생할 수도 있습니다.
4) C/C++ > 코드생성 > 런타임 라이브러리 : 다중 쓰레드 디버그 DLL (/MDd) 으로 변경
5) 링커 > 입력 > 추가 종속성
* Debug Build: Strmbasd.lib strmiids.lib Msvcrtd.lib Winmm.lib
* Debug Build: Strmbase.lib strmiids.lib Msvcrt.lib Winmm.lib
6) 링커 > 출력파일의 확장자를 dll 에서 ax로 변경 ( dll 로 해도 상관은 없습니다만 .def 파일의 내용도 바꿔 주어야
됩니다.)
7) C/C++ > 미리 컴파일된 헤더: 미리 컴파일된 헤더 사용 안함 으로 설정
예(/NODEFAULTLIB)
7. 테스트
GraphEdit 툴로 “Audio Volume” 필터를 추가하기 전에 음원 파일을 동작시키고 추가한 다음에 동작시키면 audio 볼륨에
대한 효과를 알수 있을 것입니다.