Есть ли какой-нибудь LAME C++ wraper\ проще (работающий на Linux Mac и Win из чистого кода)?
Итак, я хочу создать простой проект Pcm в mp3 C++. Я хочу использовать LAME. Я люблю LAME, но это действительно здорово. поэтому мне нужен какой-то OpenSource, работающий из чистого кода с простым упрощенным рабочим процессом. Скажем так, я даю ему файл с файлами PCM и DEST. Назовите что-то вроде
LameSimple.ToMP3(file with PCM, File with MP3 , 44100, 16, MP3, VBR);
или 4 - 5 строк (примеры конечно должны существовать), и у меня есть все, что мне нужно. Это должно быть легко, просто, powerfool, opensource, кроссплатформенный.
Есть ли такая вещь?!?
4 ответа
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;
}
Вдохновленный ответом Майка Сеймура, я создал чистую оболочку C++, которая позволяет кодировать / декодировать файлы WAV и MP3 всего за 2 строки кода.
convimp3::Codec::encode( "test.wav", "test.mp3" );
convimp3::Codec::decode( "test.mp3", "test_decoded.wav" );
не нужно беспокоиться о частоте дискретизации, байтовой скорости и количестве каналов - эта информация получается из файла WAV или MP3 во время кодирования / декодирования.
Библиотека не использует старые функции ввода / вывода C, а только потоки C++. Я нахожу это более элегантным.
Для удобства я создал очень тонкую оболочку C++ поверх LAME и назвал ее lameplus и небольшую библиотеку для извлечения выборочной информации из файлов WAV.
Все файлы можно найти здесь:
кодирование / декодирование: https://github.com/trodevel/convimp3
lameplus: https://github.com/trodevel/lameplus
обработка WAV: также на GitHub, хранилище является волна
Я успешно использовал 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.
Я получил это на работу, изменив 41000 примерно до 8000:
lame_set_in_samplerate(lame, 44100);
в
lame_set_in_samplerate(lame, 8000);
И скомпилировал прогу с:
gcc prog.c -lmp3lame -o prog
Файл.pcm звучит не так хорошо, как файл.mp3. Я получил идеальное преобразование, когда использовал команду bash:
lame -V 5 file.wav file.mp3