Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Archives
Today
Total
관리 메뉴

Code Habit

fdk-aac decoder 본문

카테고리 없음

fdk-aac decoder

코드베어 2023. 3. 19. 11:23

압축(인코딩)된 aac데이터를 fdk-aac 라이브러리를 사용하여 decode 하는 예제이다. 결과물은 pcm 데이터로 저장되며 audacity uitl 등을 통해 decode된 음원을 재생해 볼 수 있다. 

 

- FDKAACDecoder.h

#include "aacdecoder_lib.h"

class CFDKAACDecoder 
{
public:
	CFDKAACDecoder();
	~CFDKAACDecoder();

	bool	Initialize();
	void	Destroy();
	int		Decode(BYTE* pBuffer, UINT nBufSize);

private:
	HANDLE_AACDECODER m_hDecoder;
	BOOL m_bInitialized;
	CStreamInfo m_stream_info;
};

 

- FDKAACDecoder.cpp 

#include "FDKAACDecoder.h"

#pragma comment(lib, "libfdk-aac.dll.a")

CFDKAACDecoder::CFDKAACDecoder()
	:m_hDecoder(NULL)
	,m_bInitialized(FALSE)
{
	memset(&m_stream_info, 0, sizeof(CStreamInfo));
}
CFDKAACDecoder::~CFDKAACDecoder()
{
}

bool CFDKAACDecoder::Initialize()
{
	// decoder를 오픈하고 핸들을 반환 받는다.
	m_hDecoder = aacDecoder_Open(TT_MP4_ADTS, 1);
	if (NULL == m_hDecoder) {
		OutputDebugString(L"Failed to aacDecoder_Open()");
		return false;
	}
	
	// 디코드 설정을 셋팅하는 함수로
	// 여기서는 따로 셋팅할 값이 없어 default 값 설정을 한다.
	AAC_DECODER_ERROR err = aacDecoder_SetParam(m_hDecoder, AAC_PCM_OUTPUT_INTERLEAVED, 1);
	if (AAC_DEC_OK != err) {
		OutputDebugString(L"Failed to aacDecoder_SetParam");
		return false;
	}

	return true;
}


void CFDKAACDecoder::Destroy()
{
	// 디코드 닫고 핸들 반환 
	if (NULL != m_hDecoder) {
		aacDecoder_Close(m_hDecoder);
		m_hDecoder = NULL;
	}
}

int CFDKAACDecoder::Decode(BYTE* pBuffer, UINT nBufSize)
{
	// In
	UINT nValid = nBufSize;

	// Out
	UINT nPcmPktSize = 0;
	INT_PCM vOutBuffer[8192] = { 0, };

	// (처음 한번) 디코드 하기전에 패킷 사이즈를 알 수 없어 처음에는 넉넉히 버퍼 크기를 정하고
	// 이 후는 아래와 같이 디코드 때 가져온 헤더 정보를 토대로 사이즈를 정해준다.
	// framesize * channel 수 * 2byte(16bit)
	if (TRUE == m_bInitialized) {
		nPcmPktSize = m_stream_info.frameSize * m_stream_info.numChannels * sizeof(SHORT);
	}
	else {
		nPcmPktSize = 8192;
	}

	// decode 할 버퍼를 채운다.
	// 채울 수 있는 만큼 채우고 남은 버퍼 사이즈를 nValid로 반환해준다.
	// ** 다음 버퍼를 채울때 nValid만큼 남은 버퍼를 앞에 붙여줘야 한다 !
	AAC_DECODER_ERROR err = AAC_DEC_OK;
	err = aacDecoder_Fill(m_hDecoder, &pBuffer, &nBufSize, &nValid);
	if (AAC_DEC_OK != err) {
		OutputDebugString(L"Failed to aacDecoder_Fill()");
		return -1;
	}

	int n = 100;
	while (1) {
		// aacDecoder_Fill에서 채워진 버퍼를 nPcmPktSize만큼 디코드 한다.
		// 채워진 버퍼를 여러번 돌며 디코드 하며 완료되면 AAC_DEC_NOT_ENOUGH_BITS를 리턴한다.
		err = aacDecoder_DecodeFrame(m_hDecoder, (INT_PCM*)vOutBuffer, nPcmPktSize, 0);
		if (AAC_DEC_NOT_ENOUGH_BITS == err) {
			return nValid;	// 채워진 버퍼 모두 처리. -> 정상 리턴
		}
		if (AAC_DEC_OK != err) {
			OutputDebugString(L"Failed to aacDecoder_DecodeFrame()");
			return -1;
		}

		// 스트림 정보 저장 ( 초기 한번만 )
		if (false == m_bInitialized) {
			CStreamInfo* pStream_info = aacDecoder_GetStreamInfo(m_hDecoder);
			memcpy_s(&m_stream_info, sizeof(CStreamInfo), pStream_info, sizeof(CStreamInfo));
			m_bInitialized = true;
		}

		// debug : 파일 쓰기
		FILE* pFile = NULL;
		errno_t err = _tfopen_s(&pFile, _T("TEST.pcm"), _T("ab+"));
		if (err) {
			return -1;
		}

		if (!pFile) {
			return -1;
		}

		fwrite(vOutBuffer, 1, m_stream_info.numChannels * 2 * m_stream_info.frameSize, pFile);

		if (fclose(pFile)) {
		}

		// 행 방지
		--n;
		if (0 > n) {
			break;
		}
	}

	return -1;
}

 

'libfdk-aac.dll.a', 'aacdecoder_lib.h' 는 fdk-aac 라이브러리를  빌드하거나 가져온 헤더파일로 아래 사이트를 참고하면 된다.

- https://github.com/mstorsjo/fdk-aac