【问题标题】:Is there any LAME C++ wrapper\simplifier (working on Linux Mac and Win from pure code)?是否有任何 LAME C++ 包装器\简化器(在 Linux Mac 和纯代码 Win 上工作)?
【发布时间】:2010-03-22 20:19:38
【问题描述】:

我想创建简单的 pcm 到 mp3 C++ 项目。我希望它使用 LAME。我喜欢 LAME,但它真的很大。所以我需要某种开源代码,使用纯代码工作流简化器。可以这么说,我给它一个带有 PCM 和 DEST 文件的文件。调用类似:

LameSimple.ToMP3(file with PCM, File with MP3 , 44100, 16, MP3, VBR);

在 4 到 5 行中找到这样的东西(当然应该有例子),我有我需要的东西它应该是轻量级的、简单的、强大的、开源的、跨平台的。

有这样的吗?

【问题讨论】:

  • 尽管蹩脚的资源相当大,但没有必要学习完整的资源。您只需要通过解析命令石灰参数及其到内部跛脚结构的映射来查看。

标签: c++ c cross-platform wrapper lame


【解决方案1】:

Lame 确实不难使用,虽然有很多可选的配置功能,如果你需要的话。编码一个文件需要略多于 4 到 5 行,但也不会更多。这是我拼凑的一个工作示例(只是基本功能,没有错误检查):

#include <stdio.h>
#include <lame/lame.h>

int main(void)
{
    int read, write;

    FILE *pcm = fopen("file.pcm", "rb");
    FILE *mp3 = fopen("file.mp3", "wb");

    const int PCM_SIZE = 8192;
    const int MP3_SIZE = 8192;

    short int pcm_buffer[PCM_SIZE*2];
    unsigned char mp3_buffer[MP3_SIZE];

    lame_t lame = lame_init();
    lame_set_in_samplerate(lame, 44100);
    lame_set_VBR(lame, vbr_default);
    lame_init_params(lame);

    do {
        read = fread(pcm_buffer, 2*sizeof(short int), PCM_SIZE, pcm);
        if (read == 0)
            write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
        else
            write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);
        fwrite(mp3_buffer, write, 1, mp3);
    } while (read != 0);

    lame_close(lame);
    fclose(mp3);
    fclose(pcm);

    return 0;
}

【讨论】:

  • 拜托,你能分享一个项目文件吗,我真的不明白 - 如何将 LAME 连接到你的 CPP 项目,请帮助
  • 我在 Ubuntu linux 上使用 gcc lametest.c -lmp3lame 构建了它(在使用 sudo apt-get install libmp3lame-dev 安装库和头文件之后)。恐怕我不知道如何在 Mac 和 Windows 上安装和链接库。
  • Ser 请您介意分享一些链接(或者,更好的直接说明),以便在 linux 上为开发人员安装 Lame。
  • btw 在此处发布您的答案stackoverflow.com/questions/2419928/… win 100 bounty=) 感谢 WWmuch 提供此代码示例。
  • 在 Ubuntu、Debian 或其他基于 apt 的发行版上,打开 shell 并输入 sudo apt-get install libmp3lame-dev。否则,请使用您的发行版的包管理器搜索类似的内容,或从sourceforge.net/projects/lame/files 下载源代码并按照您在此处找到的任何说明进行构建和安装。
【解决方案2】:

受 Mike Seymour 的回答启发,我创建了一个纯 C++ 包装器,只需 2 行代码即可对 WAV 和 MP3 文件进行编码/解码

convimp3::Codec::encode( "test.wav", "test.mp3" );
convimp3::Codec::decode( "test.mp3", "test_decoded.wav" );

无需担心采样率、字节率和通道数——这些信息是在编码/解码期间从 WAV 或 MP3 文件中获取的。

该库不使用旧的 C i/o 函数,而仅使用 C++ 流。我觉得它更优雅。

为了方便起见,我在 LAME 上创建了一个非常薄的 C++ 包装器,并将其命名为 lameplus 和一个用于从 WAV 文件中提取采样信息的小型库。

所有文件都可以在这里找到:

编码/解码:https://github.com/trodevel/convimp3

lameplus:https://github.com/trodevel/lameplus

wav 处理:也在 github 上,存储库是 wave

【讨论】:

    【解决方案3】:

    我已经按照 mike seymour 建议的方式成功使用了 libmp3lame。 我现在正在尝试使用相同的方法使用 posix 线程来加速编码。 我正在使用一个 lame_t 指针,并且有几个线程在做一些转换, 注意每个线程都有它转码的 pcm 轨道的唯一位。

    我使用一个全局 lame_t 结构,用于每个线程中的编码。 我的代码适用于 1 个线程(没有并行执行),如果我在并行模式下延迟创建线程(这样没有并行执行,但数据结构是数组),它也可以工作。

    当我以并行模式运行我的代码时,我会遇到很多错误,例如

    Internal buffer inconsistency. flushbits <> ResvSizebit reservoir error: 
    l3_side->main_data_begin: 5440 
    Resvoir size:             4088 
    resv drain (post)         1 
    resv drain (pre)          184 
    header and sideinfo:      288 
    data bits:                1085 
    total bits:               1374 (remainder: 6) 
    bitsperframe:             3336 
    This is a fatal error.  It has several possible causes:90%  LAME compiled with buggy version of gcc using advanced optimizations 9%  Your system is overclocked 1%  bug in LAME encoding libraryfinished encoding 
    Internal buffer inconsistency. flushbits <> ResvSizefinished encoding 
    

    作为参考,我附上了我正在使用的代码,它编译得很好。

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <math.h>
    #include <iostream>
    #include <string>
    #include <lame/lame.h>
    #include <pthread.h>
    #include <thread>
    #include <chrono>
    
    using namespace std;
    
    typedef struct Data{
        lame_t lame;
        FILE * wav_file;
        short int * pcm_buffer;
        unsigned char * mp3_buffer;
        unsigned long mp3_buffer_size;
        unsigned long first_sample;
        unsigned long n_samples;
        unsigned long items_read;
        unsigned long mp3_bytes_to_write;
        pthread_mutex_t *mutexForReading;
    } Data;
    
    void *encode_chunk(void *arg)
    {
        Data * data = (Data *) arg;
    
        unsigned long offset = 40 + 2 * 2 * data->first_sample;
        pthread_mutex_lock(data->mutexForReading);
        fseek(data->wav_file, offset, SEEK_SET);
    
        data->items_read = fread(data->pcm_buffer, 2*sizeof(short int) , data->n_samples, data->wav_file);
    
        cout << "first sample " << data->first_sample << " n_samples "<<  data->n_samples << " items read " << data->items_read << " data address " << data << " mp3 a " << static_cast<void *> (data->mp3_buffer) << endl;
        pthread_mutex_unlock(data->mutexForReading);
    
        if (data->items_read != 0) 
        {
            data->mp3_bytes_to_write = lame_encode_buffer_interleaved(data->lame, 
                                                                      data->pcm_buffer, 
                                                                      data->items_read,
                                                                      data->mp3_buffer, 
                                                                      data->mp3_buffer_size);
        }
        cout << "finished encoding " << endl;
        return NULL;
    }
    
    int main(int argc, char * argv[])
    {
        int read,write;
    
        FILE *wav = fopen("test.wav", "rb");
        FILE *mp3 = fopen("file.mp3", "wb");
    
        fseek(wav,0,SEEK_END);
    
        unsigned long file_size_wav = ftell(wav);
        unsigned long bytes_PCM = file_size_wav - 40;
        unsigned long n_total_samples = bytes_PCM / 4;
    
        const unsigned long MAX_SAMPLE_NUMBER = pow(2,10);
        const unsigned short NTHREADS = 2;
        const unsigned long MAX_MP3_SIZE = int(MAX_SAMPLE_NUMBER * 1.25 + 7200) + 1;
    
        short int pcm_buffer[NTHREADS][MAX_SAMPLE_NUMBER * 2]; // 2 channels
        unsigned char mp3_buffer[NTHREADS][MAX_MP3_SIZE]; // according to libmp3lame api
    
        lame_t lame = lame_init();
        lame_set_in_samplerate(lame, 44100);
        lame_set_VBR(lame, vbr_default);
    
        // lame_set_brate(lame, 128); // only for CBR mode
        // lame_set_quality(lame, 2); 
        // lame_set_mode(lame, JOINT_STEREO); // 1 joint stereo , 3 mono
    
        lame_init_params(lame);
    
        Data data_ptr[NTHREADS];
    
        unsigned short n_main_loops = n_total_samples / MAX_SAMPLE_NUMBER / NTHREADS + 1;
    
        cout << "total samples " << n_total_samples << endl;
        cout << "Number of iterations in main loop : " << n_main_loops << endl;
    
        unsigned long samples_remaining = n_total_samples;
        unsigned long current_sample = 0;
    
        pthread_t threadID[NTHREADS];
        pthread_mutex_t mutexForReading = PTHREAD_MUTEX_INITIALIZER;
    
        for (unsigned long i = 0 ; i < n_main_loops; i ++)
        {
            for (unsigned short j = 0; j < NTHREADS; j++ )
            {
                Data data;
                data.lame = lame;
                data.wav_file = wav;
                data.pcm_buffer = pcm_buffer[j];
                data.mp3_buffer = mp3_buffer[j];
                data.first_sample = current_sample;
                data.n_samples = min(MAX_SAMPLE_NUMBER, n_total_samples - current_sample);
                data.mutexForReading = &mutexForReading;
    
                current_sample += data.n_samples;
                samples_remaining -= data.n_samples;
    
                data_ptr[j] = data;
    
                if (data_ptr[j].n_samples > 0)
    
                {   
                    cout << "creating " << i << " " << j << " " << data_ptr[j].first_sample << " " << data_ptr[j].n_samples << endl;
                    pthread_create( &threadID[j], 
                               NULL, 
                               encode_chunk, 
                               (void *) (&data_ptr[j]));
                }
    
            }
            for (unsigned short j = 0; j < NTHREADS; j++)
            {
                if (data_ptr[j].n_samples > 0)
                {   
                    pthread_join( threadID[j], NULL); 
                } 
            }
    
            for (unsigned short j = 0; j< NTHREADS; j++)
                if (data_ptr[j].n_samples > 0)
                {
    
                    fwrite(data_ptr[j].mp3_buffer, data_ptr[j].mp3_bytes_to_write, 1, mp3);
                }
                else
                {
                    data_ptr[j].mp3_bytes_to_write = lame_encode_flush(lame, data_ptr[j].mp3_buffer, data_ptr[j].mp3_buffer_size);
    
                }
    
        }
    
    
    
    
        lame_close(lame);
        fclose(mp3);
        fclose(wav);
    
    }
    

    也许有人知道在并行代码中是否不能以这种方式使用 lame。如果这可能与否,我没有找到任何提示。

    问题似乎是多个线程同时访问全局lame_t结构。我以为这只是阅读,所以没问题,但我似乎弄错了。

    我还认为一种解决方法可能是为每个线程创建一个 lame_t 对象。 我试过了,使用线程对原始 wav 文件的互斥位进行编码。

    代码编译并运行没有问题,但生成的文件没有声音。

    如果有人有兴趣,我可以添加代码。这只是上面代码的一个小修改,lame_t 是一个大小为 NTHREADS 的数组。

    【讨论】:

      【解决方案4】:

      我通过将 41000 更改为 8000 左右来实现这一点:

      lame_set_in_samplerate(lame, 44100);
      

      lame_set_in_samplerate(lame, 8000);
      

      并将 prog.c 编译为:

      gcc prog.c -lmp3lame -o prog
      

      file.pcm 听起来不如 file.mp3。当我使用这个 bash 命令时,我得到了完美的转换:

      lame -V 5 file.wav file.mp3
      

      【讨论】:

        猜你喜欢
        • 2013-02-24
        • 2013-05-22
        • 1970-01-01
        • 2012-04-29
        • 1970-01-01
        • 2012-02-17
        • 2021-03-20
        • 2011-08-30
        • 1970-01-01
        相关资源
        最近更新 更多