首页 > 其他分享 >FLAC库的编译及应用

FLAC库的编译及应用

时间:2024-08-05 15:26:28浏览次数:17  
标签:__ ok FLAC stream header encoder 编译 应用

简介

FLAC 是一种针对声音文件的无损压缩算法。压缩比略低于 AAC,但是压缩和解压的速度很理想。使用 FLAC 压缩的无损音乐,体积将比没有经过压缩的无损音乐小很多(取决于音乐的平均音量。通常体积能减少到原文件的50%左右)。 相比较 MP3 有损压缩格式而言,FLAC 能保留100%的音质。对于广大音乐爱好者而言,相对于 MP3FLAC 是更好的选择。


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 格式

编码流程

  1. 创建编码器

  2. 设置编码器参数

  3. 初始化编码器

  4. 编码数据

  5. 完成编码

  6. 释放编码器

创建编码器

/* 创建一个新的流编码器实例。
 * 实例是用默认设置创建的;
 * 后续可以通过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

相关文章

  • Kotlin 布尔值教程:深入理解与应用示例
    Kotlin布尔值在编程中,您经常需要一种只能有两个值的数据类型,例如:是/否开/关真/假为此,Kotlin有一种布尔数据类型,可以取true或false值。布尔值布尔类型可以用Boolean关键字声明,并且只能取true或false值:示例valisKotlinFun:Boolean=truevalisFi......
  • 我可以将 Python 与 javascript 结合起来用于网站或应用程序吗
    我不知道如果j添加Python和javascript可以吗我尝试过。但决定在继续之前询问一下是否可以继续但是如果我只使用javascript还是只使用python会更好吗?我只需要建议或答案将Python与Javascript结合用于网站或应用程序不仅完全可行,而且也是一种非常常见的做法!二者......
  • 反射内存卡应用案例
    飞机动力系统半实物仿真:在美国空军的相关应用中,涡轮发动机模型运行在RedhawkLinux软实时环境中,而转子模型则运行在Speedgoat硬实时环境里,两者之间通过反射内存卡来同步数据。通过转子动力学模型,用户能够灵活地调整发动机和发电机之间的功率与转速。特别是当有代表性的动力系......
  • python实现局域网及广域网私人聊天(Socket库局域网应用)
    引言在当今这个数字化时代,即时通讯已成为我们日常生活的一部分。无论是通过手机还是电脑,人们都在寻找更高效、更私密的沟通方式。想象一下,在你自己的局域网内,与朋友或同事建立一个专属的聊天室,无需担心数据泄露或者被第三方监听。本文将引导你从零开始,利用Python和Socket库......
  • 《数据资产管理核心技术与应用》读书笔记-第一章:认识数据资产
    《数据资产管理核心技术与应用》是清华大学出版社出版的一本图书,全书共分10章,第1章主要让读者认识数据资产,了解数据资产相关的基础概念,以及数据资产的发展情况。第2~8章主要介绍大数据时代数据资产管理所涉及的核心技术,内容包括元数据的采集与存储、数据血缘、数据质量、数据监控与......
  • VisionPro二次开发学习笔记1-创建基于QuickBuild的C#应用程序
    创建基于QuickBuild的C#应用程序使用的QuickBuild应用程序位于%VPRO_ROOT%/Samples/Programming/QuickBuild/advancedAppOne.vpp中。在继续之前,可以在QuickBuild中运行该应用程序。QuickBuild应用程序使用PatMax查找支架的“耳朵”之一,使用CogFixture工具设置图像的......
  • PlayCover Mac电脑全屏运行ios应用软件 for Mac免费下载
    PlayCover是一款功能强大的软件,主要用于在Mac平台上运行iOS应用程序和Android应用程序(取决于具体版本)。对于iOS应用,PlayCover通过模拟iOS环境,让用户能够在Mac上直接运行iPhone和iPad应用,无需虚拟机或双重启动,支持多点触控、传感器模拟等特性,提供舒适的使用体验。对于Android应用,P......
  • Python实现简单的情感分析应用
    Python实现简单的情感分析应用情感的力量:走进情感分析的世界什么是情感分析:从日常对话到大数据分析情感分析的应用场景:从社交媒体到客户服务为何Python成为情感分析的最佳拍档准备工作:Python环境与必备库Python安装指南:快速搭建开发环境必不可少的库:nltk与TextBlob的简......
  • 软件工程专业导论大作业-关于华为自主研发的新编程语言基本原理其应用场景分析
    摘 要在2024年6月21日的华为开发者大会上,华为宣布了其自主研发的全新编程语言——“仓颉”。这一语言的推出旨在为其“升腾”AI芯片和云原生应用开发提供强大支持,并且有助于构建全球技术生态系统。“仓颉”编程语言特别设计以应对华为“升腾”AI芯片的需求,并且专注于硬件和......
  • 深入解析通信协议在网络中的神奇应用
    好久不见!又到了分享时间~通信协议是网络通信的基石,它们决定了数据在网络中的传输方式和处理规则。接下来,让我们一起看看通信协议在网络通信中的具体应用吧!1.互联网通信互联网通信是最广泛使用的应用场景之一。以下是一些常见的互联网通信协议及其应用。HTTP/HTTPS:用于浏览......