先安裝開發程式庫
sudo apt install libfdk-acc-dev libasound-dev
下載一些測試 aac 檔案: https://espressif-docs.readthedocs-hosted.com/projects/esp-adf/en/latest/design-guide/audio-samples.html
// 主程式: aacplay.cpp
#include <sys/mman.h>
#include <fdk-aac/aacdecoder_lib.h>
#include <alsa/asoundlib.h>
struct PCM16 {
int16_t *data;
int length;
int channel;
int fs;
};
const PCM16 zeroPCM16 = {.data = (int16_t *)0, .length = 0, .channel = 0, .fs = 0};
const char *path_to_close = "./close!";
auto stepDecoder = [](const void *path = nullptr, int repeate = 0) {
static void *mmapFile = MAP_FAILED; // to management mmap file
static HANDLE_AACDECODER decoder = nullptr;
static int32_t length = 0;// mmap file length
static int32_t position = 0; // trace file position
static int32_t remainRepeate = 0;
if (path == path_to_close) { // to close decoder
if (decoder) {
aacDecoder_Close(decoder);
decoder = nullptr;
length = 0;
position = 0;
remainRepeate = 0;
}
} else {
if (path) {// use non-null path to initialize mmap
const char *filename = (const char *)path;
int fd = open(filename, O_RDONLY);
if (mmapFile != MAP_FAILED) munmap(mmapFile, length);
if (fd < 0) {
printf("%s => not found.\n", filename);
} else {
int fileLength = lseek(fd, 0l, SEEK_END);
if (fileLength >= 512) {
mmapFile = mmap(0, fileLength, PROT_READ, MAP_PRIVATE, fd, 0);
if (mmapFile == MAP_FAILED) {
printf("%s mmap fail.\n", filename);
} else {
if (decoder) aacDecoder_Close(decoder);
decoder = aacDecoder_Open(TT_MP4_ADTS, 1);
printf("%s file length = %d\n", filename, fileLength);
length = fileLength;// mmap sucess
position = 0;
remainRepeate = repeate;
}
}
close(fd);// After the mmap() call, fd can be closed immediately.
}
}
if (remainRepeate > 0 && (position >= length)) { // when repeate enable
printf("End of file, position = %d, wrap arond to repeate again. remainRepeate = %d\n", position, remainRepeate);
remainRepeate --;
position = 0;
}
if (position < length) {
unsigned char *src[] = { (unsigned char *)mmapFile + position };
static int16_t pcmdist[1152 * 5];// distinct PCM16 buffer for 5 channels
const uint32_t maxSteps = length - position;
uint32_t tempSteps = maxSteps;// tempSteps will be updated by decoder
aacDecoder_Fill(decoder, src, &maxSteps, &tempSteps);
int result = (int)aacDecoder_DecodeFrame(decoder, pcmdist, sizeof(pcmdist), 0);
position += maxSteps - tempSteps; // go ahead, and back off by tempSteps
printf("maxSteps = %8d, tempSteps = %8d, position = %8d, steps = %8d, err = %4x:\t\t\n",
maxSteps,
tempSteps,
position,
maxSteps - tempSteps,
(unsigned)result
);
if (result == AAC_DEC_OK) {
CStreamInfo *info = aacDecoder_GetStreamInfo(decoder);
return PCM16 {
.data = pcmdist,
.length = info->frameSize,
.channel = info->numChannels,
.fs = info->sampleRate
};
}
}
}
return zeroPCM16;
};
int main(int argc, char const *argv[]) {
PCM16 frame = stepDecoder((argc > 1) ? argv[1] : "test.aac");
if (frame.length==0) return 0;
snd_pcm_t *handle;
if (snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0) == 0) {
if (snd_pcm_set_params(handle, SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED, frame.channel, frame.fs, 1, frame.fs / 4) == 0) {
do {
int err = snd_pcm_writei(handle, frame.data, frame.length);
if (err < 0) {// try to recover
if (snd_pcm_recover(handle, err, 0) < 0) {
printf("alsa can't recover\n");
break;
}
}
frame = stepDecoder();
} while (frame.length);
}
snd_pcm_close(handle);
}
stepDecoder(path_to_close);
return 0;
}
編譯並執行:
g++ aacplay.cpp -lfdk-aac -lasound && ./a.out
沒有留言:
張貼留言