简介
FLAC
是一种针对声音文件的无损压缩算法。压缩比略低于 AAC
,但是压缩和解压的速度很理想。使用 FLAC
压缩的无损音乐,体积将比没有经过压缩的无损音乐小很多(取决于音乐的平均音量。通常体积能减少到原文件的50%左右)。 相比较 MP3
有损压缩格式而言,FLAC
能保留100%的音质。对于广大音乐爱好者而言,相对于 MP3
,FLAC
是更好的选择。
flac源码下载地址:https://ftp.osuosl.org/pub/xiph/releases/flac/
flac源码编译
操作系统:Ubuntu 16 32位
下载好源码包后将其放在ubuntu相应目录中,输入以下命令解压;
tar -xvf flac-1.4.3.tar
cd flac-1.4.3/
源码目录结构如下:
创建安装目录
mkdir _install
生成MakeFile文件,指定安装路径
./configure --prefix=${PWD}/_install # PWD变量保存着当前路径
执行make,编译源码,安装程序
make && make install
执行完成后查看_install目录结构
至此,flac
已经编译完成,需要使用的时候将 _install 中的编译产物拷贝到相应的路径即可。
flac 移植
目标平台:I.MX6ULL
CPU架构:arm 32位
下载好源码包后将其放在ubuntu相应目录中,输入以下命令解压;
tar -xvf flac-1.4.3.tar
cd flac-1.4.3/
源码目录结构如下:
创建安装目录
mkdir _install
生成MakeFile文件,指定安装路径,禁用ogg,--host 一般为交叉编译器的前缀
./configure --prefix=/root/Workspace/package/flac-1.4.3/_install/ --host=arm-linux-gnueabihf --disable-ogg
设置环境变量,交叉编译器存放路径为:/opt/imx6ull/gcc-linaro-4.9.4-2017.01-i686_arm-linux-gnueabihf/bin
export PATH=/opt/imx6ull/gcc-linaro-4.9.4-2017.01-i686_arm-linux-gnueabihf/bin:${PATH}
执行make,编译源码,安装程序
make && make install
执行完成后查看_install目录结构
至此,flac
已经交叉编译完成,只需要将 _install 中的编译产物拷贝到I.MX6ULL 的相应的路径即可。
flac库的使用
encode编码
编码:将 WAV/PCM
格式的数据转换为 FLAC
格式
编码流程
-
创建编码器
-
设置编码器参数
-
初始化编码器
-
编码数据
-
完成编码
-
释放编码器
创建编码器
/* 创建一个新的流编码器实例。
* 实例是用默认设置创建的;
* 后续可以通过FLAC__stream_encoder_set_*()函数设置参数
* 如果分配内存错误,返回NULL,否则则返回新实例。
*/
FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new(void);
==============================================================
// 示例
FLAC__StreamEncoder *encoder = FLAC__stream_encoder_new();
if (!encoder) {
fprintf(stderr, "Cannot allocate FLAC__StreamEncoder\n");
return 1;
}
设置编码器参数
// 常用参数设置
// 设置通道数,0 < value < 8
FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encoder, uint32_t value);
// 设置位深度,4 8 16 24 32
FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder *encoder, uint32_t value);
// 设置采样率 value < 1048575u
FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *encoder, uint32_t value);
// 设置压缩级别 1-9
FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncoder *encoder, uint32_t value);
// 设置总采样率,如果不清楚可以设置为0
// 如果设置具体的值以后,编码出来的总样本数小于设置的总样本数,解码时会失败
// 计算方法:PCM数据总长度/(通道数 * 位深度 / 8)
FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__StreamEncoder *encoder, FLAC__uint64 value);
=========================================================================================
// 示例
// WAV文件头结构简化定义
typedef struct {
char riff[4]; // 'RIFF'
int chunkSize; // 文件总大小减8字节
char wave[4]; // 'WAVE'
char fmt[4]; // 'fmt '
int subchunk1Size; // 一般为16
short audioFormat; // 1 for PCM
short numChannels; // 通道数,1为单声道,2为立体声
int sampleRate; // 采样率
int byteRate; // sampleRate * numChannels * bitsPerSample/8
short blockAlign; // numChannels * bitsPerSample/8
short bitsPerSample; // 位深度,一般为16
char data[4]; // 'data'
int dataSize; // PCM数据大小
} WaveHeader;
// 初始化FLAC编码器参数
FLAC__bool ok = true;
ok &= FLAC__stream_encoder_set_channels(m_Encoder, header->wChannels);
ok &= FLAC__stream_encoder_set_bits_per_sample(m_Encoder, header->wBitsPerSample);
ok &= FLAC__stream_encoder_set_sample_rate(m_Encoder, header->nSamplesPerSec);
ok &= FLAC__stream_encoder_set_compression_level(m_Encoder, 5);
ok &= FLAC__stream_encoder_set_total_samples_estimate(m_Encoder, header->dataSize / (header->wChannels * header->wBitsPerSample / 8));
if (!ok)
{
fprintf(stderr, "Error setting Encoder param error\n");
ret = -1;
}
初始编码器
// 回调函数声明
/*
* encoder : flac编码器
* buffer : flac音频数据
* bytes : 传入的数据长度
* samples : 样本数据
* current_frame : 当前帧
* client_data : 设置回调函数时传入的参数
*/
// 写回调函数,当flac数据编码出来的时候,libFLAC接口会调用此函数建flac数据传递给用户
typedef FLAC__StreamEncoderWriteStatus (*FLAC__StreamEncoderWriteCallback)(const FLAC__StreamEncoder *encoder,
const FLAC__byte buffer[],
size_t bytes,
uint32_t samples,
uint32_t current_frame,
void *client_data);
/*
* encoder: 指向当前使用的FLAC编码器实例的指针
* absolute_byte_offset: 指定编码器应该定位到的绝对字节偏移量
* client_data: 用户提供的数据指针,通常用于传递回调函数所需的额外数据
*/
// 当FLAC编码器需要在输出流中定位到特定位置时,它会调用这个回调函数
typedef FLAC__StreamEncoderSeekStatus (*FLAC__StreamEncoderSeekCallback)(const FLAC__StreamEncoder *encoder,
FLAC__uint64 absolute_byte_offset,
void *client_data);
/*
* encoder: 指向当前使用的FLAC编码器实例的指针
* absolute_byte_offset: 指针,用于返回当前的绝对字节偏移量
* client_data: 用户提供的数据指针,通常用于传递回调函数所需的额外数据
*/
// 当FLAC编码器需要知道当前在输出流中的位置时,它会调用这个回调函数
typedef FLAC__StreamEncoderTellStatus (*FLAC__StreamEncoderTellCallback)(const FLAC__StreamEncoder *encoder,
FLAC__uint64 *absolute_byte_offset,
void *client_data);
/*
* encoder: 指向当前使用的FLAC编码器实例的指针
* metadata: 指向 FLAC__StreamMetadata 结构的指针,其中包含了当前元数据块的信息
* client_data: 用户提供的数据指针,通常用于传递回调函数所需的额外数据
*/
// 当FLAC编码器生成元数据块时,它会调用这个回调函数。
typedef void (*FLAC__StreamEncoderMetadataCallback)(const FLAC__StreamEncoder *encoder,
const FLAC__StreamMetadata *metadata,
void *client_data);
/*
* encoder: 指向当前使用的FLAC编码器实例的指针
* bytes_written: 自上次调用以来写入的字节数
* samples_written: 自上次调用以来写入的样本数(每个通道一个样本)
* frames_written: 自上次调用以来写入的帧数。注意,这里的一帧是指所有通道的一个样本集合
* total_frames_estimate: 对于整个流的帧数估计。如果编码器没有得到总样本数,则此值可能不准确
* client_data: 用户提供的数据指针,通常用于传递回调函数所需的额外数据
*/
// 当FLAC编码器进行编码时,它会周期性地调用这个回调函数来报告编码进度
typedef void (*FLAC__StreamEncoderProgressCallback)(const FLAC__StreamEncoder *encoder,
FLAC__uint64 bytes_written,
FLAC__uint64 samples_written,
uint32_t frames_written,
uint32_t total_frames_estimate,
void *client_data);
// 函数声明,初始化编码器
// 以数据流的方式初始化编码器,编码出来的flac数据会通过传入的写回调函数传递给用户
FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_stream(FLAC__StreamEncoder *encoder,
FLAC__StreamEncoderWriteCallback write_callback,
FLAC__StreamEncoderSeekCallback seek_callback,
FLAC__StreamEncoderTellCallback tell_callback,
FLAC__StreamEncoderMetadataCallback metadata_callback,
void *client_data);
// 编码出来的flac数据会写入传入的文件指针中
FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_FILE(FLAC__StreamEncoder *encoder, FILE *file,
FLAC__StreamEncoderProgressCallback progress_callback,
void *client_data);
// 编码出来的flac数据会写入传入的文件路径中
FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_file(FLAC__StreamEncoder *encoder,
const char *filename,
FLAC__StreamEncoderProgressCallback progress_callback,
void *client_data);
=========================================================================================
// 示例
// 写入回调函数
FLAC__StreamEncoderWriteStatus write_callback(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data)
{
CustomData *cd = (CustomData *)client_data;
size_t bytesWritten = 0;
printf("bytes %d, samples %u, current_frame %u, total_samples: %u\n", bytes, samples, current_frame, total_samples);
// 将编码后的数据写入文件
if( (bytesWritten = fwrite(buffer, bytes, 1, cd->outputFile)) < 0 )
{
printf("callback: write buffer fail, %s\n", strerror(errno));
return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
}
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
}
// 以数据流的方式初始化编码器
CustomData cd = { outputFile };
FLAC__StreamEncoderInitStatus init_status = FLAC__stream_encoder_init_stream(encoder, write_callback, NULL, NULL, NULL, &cd);
if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
fprintf(stderr, "Error encoder init stream, %s\n", FLAC__StreamEncoderInitStatusString[init_status]);
FLAC__stream_encoder_delete(encoder);
return -1;
}
编码数据
/*
* encoder: 指向当前使用的FLAC编码器实例的指针
* buffer: 包含要编码的交错音频数据的缓冲区,缓冲区中的数据应该按照通道顺序排列,即第一个样本的所有通道,然后是第二个样本的所有通道,以此类推
* samples: 缓冲区中包含的样本数量,注意,这指的是单声道的样本数,而不是帧数。如果音频是立体声的(2个通道),那么对于每帧来说,样本数将是帧数的两倍
*/
FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder,
const FLAC__int32 buffer[],
uint32_t samples);
=========================================================================================
// 示例
// 处理不同位深度的音频数据
FLAC__bool process_audio_data(FILE *inputFile, FLAC__StreamEncoder *encoder, const WaveHeader *header, FLAC__byte *buffer)
{
FLAC__bool ok = true;
size_t bytesRead = 0;
size_t left = header->dataSize / (header->numChannels * header->bitsPerSample / 8);
total_samples = left;
FLAC__int32 pcm[READSIZE/*samples*/ * header->numChannels/*channels*/];
while(ok && left)
{
size_t need = (left > READSIZE ? (size_t)READSIZE : left);
if(fread(buffer, header->numChannels*(header->bitsPerSample/8), need, inputFile) != need)
{
fprintf(stderr, "ERROR: reading from WAVE file\n");
ok = false;
}
else
{
/* convert the packed little-endian 16-bit PCM samples from WAVE into an interleaved FLAC__int32 buffer for libFLAC */
size_t i;
for(i = 0; i < need*header->numChannels; i++)
{
/* inefficient but simple and works on big- or little-endian machines */
pcm[i] = (FLAC__int32)(((FLAC__int16)(FLAC__int8)buffer[2*i+1] << 8) | (FLAC__int16)buffer[2*i]);
if (pcm[i] & 0x8000)
pcm[i] |= 0xFFFF0000;
}
/* feed samples to encoder */
ok = FLAC__stream_encoder_process_interleaved(encoder, pcm, need);
if( !ok )
{
fprintf(stderr, "FLAC__stream_encoder_process_interleaved fail\n");
}
else
{
fprintf(stdout, "FLAC__stream_encoder_process_interleaved ok\n");
}
}
left -= need;
}
return true;
}
完成编码
/*
* encoder: 指向当前使用的FLAC编码器实例的指针
*
* 完成编码过程,刷新编码缓冲区,释放资源,将编码器设置重置为默认值,
* 并将编码器状态返回FLAC_STREAM_ENCODER_UNINITIALIZED。
*/
FLAC_API FLAC__bool FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder);
===========================================================================================
// 示例
// 完成编码
FLAC__bool ok = false;
ok = FLAC__stream_encoder_finish(encoder);
if (!ok) {
fprintf(stderr, "Error finishing encoding\n");
return -1;
}
释放编码器
/*
* encoder: 指向需要释放的FLAC编码器实例的指针
*/
FLAC_API void FLAC__stream_encoder_delete(FLAC__StreamEncoder *encoder);
===========================================================================================
// 示例
FLAC__stream_encoder_delete(encoder);
完整示例代码
#include <FLAC/all.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#define READSIZE 1024
// WAV文件头结构简化定义
typedef struct {
char riff[4]; // 'RIFF'
int chunkSize; // 文件总大小减8字节
char wave[4]; // 'WAVE'
char fmt[4]; // 'fmt '
int subchunk1Size; // 一般为16
short audioFormat; // 1 for PCM
short numChannels; // 通道数,1为单声道,2为立体声
int sampleRate; // 采样率
int byteRate; // sampleRate * numChannels * bitsPerSample/8
short blockAlign; // numChannels * bitsPerSample/8
short bitsPerSample; // 位深度,一般为16
char data[4]; // 'data'
int dataSize; // PCM数据大小
} WaveHeader;
// 自定义回调数据结构
typedef struct {
FILE *outputFile;
} CustomData;
static unsigned total_samples;
// 写入回调函数
FLAC__StreamEncoderWriteStatus write_callback(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data)
{
CustomData *cd = (CustomData *)client_data;
size_t bytesWritten = 0;
printf("callback: bytes %d, samples %u, current_frame %u, total_samples: %u\n", bytes, samples, current_frame, total_samples);
// 将编码后的数据写入文件
if( (bytesWritten = fwrite(buffer, 1, bytes, cd->outputFile)) != bytes )
{
printf("callback: write buffer fail, %s\n", strerror(errno));
return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
}
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
}
// 读取 WAV 文件头
void readWaveHeader(FILE *file, WaveHeader *header) {
fread((char *)header, sizeof(WaveHeader), 1, file);
}
// 处理不同位深度的音频数据
FLAC__bool process_audio_data(FILE *inputFile, FLAC__StreamEncoder *encoder, const WaveHeader *header, FLAC__byte *buffer)
{
FLAC__bool ok = true;
size_t bytesRead = 0;
size_t left = header->dataSize / (header->numChannels * header->bitsPerSample / 8);
total_samples = left;
//size_t left = total_samples;
FLAC__int32 pcm[READSIZE/*samples*/ * header->numChannels/*channels*/];
// header.dataSize / (header.channels * (header.bitsPerSample / 8))
while(ok && left)
{
size_t need = (left > READSIZE ? (size_t)READSIZE : left);
if(fread(buffer, header->numChannels*(header->bitsPerSample/8), need, inputFile) != need)
{
fprintf(stderr, "ERROR: reading from WAVE file\n");
ok = false;
}
else
{
/* convert the packed little-endian 16-bit PCM samples from WAVE into an interleaved FLAC__int32 buffer for libFLAC */
size_t i;
for(i = 0; i < need*header->numChannels; i++)
{
/* inefficient but simple and works on big- or little-endian machines */
switch (header->bitsPerSample)
{
case 8:
{
pcm[i] = (FLAC__int32)buffer[i];
if (pcm[i] & 0x80)
pcm[i] |= 0xFFFFFF00;
break;
}
case 16:
{
pcm[i] = (FLAC__int32)(((FLAC__int16)(FLAC__int8)buffer[2*i+1] << 8) | (FLAC__int16)buffer[2*i]);
if (pcm[i] & 0x8000)
pcm[i] |= 0xFFFF0000;
break;
}
case 24:
{
pcm[i] = (FLAC__int32)(((FLAC__int32)buffer[3*i+2]) << 16 | (FLAC__int32)(buffer[3*i+1]) << 8 | (FLAC__int32)buffer[3*i]);
if (pcm[i] & 0x800000)
pcm[i] |= 0xFF000000;
break;
}
case 32:
pcm[i] = (FLAC__int32)(((FLAC__int32)buffer[4*i+3]) << 24 | (FLAC__int32)(buffer[4*i+2]) << 16 | (FLAC__int32)(buffer[4*i+1]) << 8 | (FLAC__int32)buffer[4*i]);
break;
default:
fprintf(stderr, "Unsupported bit depth: %u bits\n", header->bitsPerSample);
return false;
}
}
/* feed samples to encoder */
ok = FLAC__stream_encoder_process_interleaved(encoder, pcm, need);
if( !ok )
{
fprintf(stderr, "FLAC__stream_encoder_process_interleaved fail\n");
}
else
{
//fprintf(stdout, "FLAC__stream_encoder_process_interleaved ok\n");
}
}
left -= need;
}
return true;
}
int main(int argc, char *argv[])
{
if (argc != 3) {
fprintf(stderr, "Usage: %s <input.wav> <output.flac>\n", argv[0]);
return 1;
}
char *inputFilename = argv[1];
char *outputFilename = argv[2];
// 打开 WAV 文件
FILE *inputFile = fopen(inputFilename, "rb");
if (!inputFile) {
fprintf(stderr, "Failed to open input file '%s'.\n", inputFilename);
return 1;
}
WaveHeader header;
readWaveHeader(inputFile, &header);
// 显示wav头部信息
printf("================ wav header ================\n");
printf("riff: %c%c%c%c\n", header.riff[0], header.riff[1], header.riff[2], header.riff[3]);
printf("chunkSize: %d\n", header.chunkSize);
printf("wave: %c%c%c%c\n", header.wave[0], header.wave[1], header.wave[2], header.wave[3]);
printf("fmt: %c%c%c%c\n", header.fmt[0], header.fmt[1], header.fmt[2], header.fmt[3]);
printf("subchunk1Size: %d\n", header.subchunk1Size);
printf("audioFormat: %d\n", header.audioFormat);
printf("numChannels: %d\n", header.numChannels);
printf("sampleRate: %d\n", header.sampleRate);
printf("byteRate: %d\n", header.byteRate);
printf("blockAlign: %d\n", header.blockAlign);
printf("bitsPerSample: %d\n", header.bitsPerSample);
printf("data: %c%c%c%c\n", header.data[0], header.data[1], header.data[2], header.data[3]);
printf("dataSize: %d\n", header.dataSize);
printf("===========================================\n");
// 判断是否为标准的wav头
if (strncmp(header.riff, "RIFF", 4) ||
strncmp(header.wave, "WAVE", 4) ||
strncmp(header.fmt, "fmt ", 4) ||
strncmp(header.data, "data", 4) /*||
header.audioFormat != 1*/) {
fprintf(stderr, "Invalid WAV format.\n");
fclose(inputFile);
exit(-1);
}
// 跳过文件头
fseek(inputFile, 44, SEEK_SET);
// 创建 FLAC 编码器
FLAC__StreamEncoder *encoder = FLAC__stream_encoder_new();
if (!encoder) {
fprintf(stderr, "Cannot allocate FLAC__StreamEncoder\n");
fclose(inputFile);
return 1;
}
// 初始化 FLAC 编码器
FLAC__bool ok = false;
ok = FLAC__stream_encoder_set_channels(encoder, header.numChannels);
if (!ok) {
fprintf(stderr, "Error setting channels\n");
FLAC__stream_encoder_delete(encoder);
fclose(inputFile);
return 1;
}
// 设置位深度
ok = FLAC__stream_encoder_set_bits_per_sample(encoder, header.bitsPerSample);
if (!ok) {
fprintf(stderr, "Error setting bits per sample\n");
FLAC__stream_encoder_delete(encoder);
fclose(inputFile);
return 1;
}
// 设置采样率
ok = FLAC__stream_encoder_set_sample_rate(encoder, header.sampleRate);
if (!ok) {
fprintf(stderr, "Error setting sample rate\n");
FLAC__stream_encoder_delete(encoder);
fclose(inputFile);
return 1;
}
// 设置总样本数
ok = FLAC__stream_encoder_set_total_samples_estimate(encoder, header.dataSize / (header.numChannels * header.bitsPerSample / 8));
//ok = FLAC__stream_encoder_set_total_samples_estimate(encoder, 0);
if (!ok) {
fprintf(stderr, "Error setting total samples estimate\n");
FLAC__stream_encoder_delete(encoder);
fclose(inputFile);
return 1;
}
// 设置压缩级别
ok = FLAC__stream_encoder_set_compression_level(encoder, 5);
if (!ok) {
fprintf(stderr, "Error setting compression level\n");
FLAC__stream_encoder_delete(encoder);
fclose(inputFile);
return 1;
}
// 打开输出文件
FILE *outputFile = fopen(outputFilename, "wb");
if (!outputFile) {
fprintf(stderr, "Failed to open output file '%s'.\n", outputFilename);
FLAC__stream_encoder_delete(encoder);
fclose(inputFile);
return 1;
}
// 设置参数,初始化编码器
CustomData cd = { outputFile };
FLAC__StreamEncoderInitStatus init_status = FLAC__stream_encoder_init_stream(encoder, write_callback, NULL, NULL, NULL, (void *)&cd);
if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
fprintf(stderr, "Error encoder init stream, %s --> %u\n", FLAC__StreamEncoderInitStatusString[init_status],
FLAC__stream_encoder_get_bits_per_sample(encoder));
FLAC__stream_encoder_delete(encoder);
fclose(inputFile);
fclose(outputFile);
return 1;
}
// 根据位深度分配缓冲区
FLAC__byte *buffer = NULL;
buffer = (FLAC__byte *)malloc(READSIZE * header.numChannels * (header.bitsPerSample / 8));
if (!buffer) {
fprintf(stderr, "Failed to allocate buffer\n");
FLAC__stream_encoder_delete(encoder);
fclose(inputFile);
fclose(outputFile);
return 1;
}
// 处理音频数据
ok = process_audio_data(inputFile, encoder, &header, buffer);
if (!ok) {
fprintf(stderr, "Error processing audio data\n");
free(buffer);
FLAC__stream_encoder_delete(encoder);
fclose(inputFile);
fclose(outputFile);
return 1;
}
free(buffer);
// 完成编码
ok = FLAC__stream_encoder_finish(encoder);
if (!ok) {
fprintf(stderr, "Error finishing encoding\n");
FLAC__stream_encoder_delete(encoder);
fclose(inputFile);
fclose(outputFile);
return 1;
}
// 清理
FLAC__stream_encoder_delete(encoder);
fclose(inputFile);
fclose(outputFile);
return 0;
}
编译代码执行下面命令,-l
后接依赖的库名,-L
后指定依赖库所在的路径,-I
后指定文件路径
gcc MyWavToFlac.c -o MyWavToFlac -lFLAC -L ../flac_1.4.3/lib/ -I ../flac_1.4.3/include/
执行,自己随便找一首wav格式的歌曲即可:Usage: ./MyWavToFlac <input.wav> <output.flac>
./MyWavToFlac likeyou.wav likeyou.flac
decode解码
解码:将 FLAC
格式的数据转换为 WAV/PCM
格式的数据
目前无需使用,有时间再学习。。。
标签:__,ok,FLAC,stream,header,encoder,编译,应用 From: https://blog.csdn.net/m0_55275571/article/details/140927204