2010-03-22 26 views
10

Tak więc chcę utworzyć prosty projekt pcm do mp3 C++. Chcę, żeby używał LAME. Uwielbiam LAME, ale to naprawdę biiig. więc potrzebuję jakiegoś OpenSource działającego z czystego kodu z uproszczonym uproszczeniem workflow. Można więc powiedzieć, że daję mu plik z plikami PCM i DEST. coś takiegoCzy istnieje LAME C++ wraper simplifite (działa na Linux Mac i Win z czystego kodu)?

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

rudy czegoś takiego w 4 nazwać - 5 linii (oczywiście powinny istnieć przykłady) i mam vhat Potrzebowałem Powinien być lekki, prosty, powerfool, opensource, crossplatform.

Czy jest coś takiego?!?

+1

Pomimo lame źródeł dość duże , nie ma potrzeby uczyć się pełnych źródeł. Wystarczy tylko analizować parametry limitu poleceń i ich mapowanie na wewnętrzne struktury. – VitalyVal

Odpowiedz

41

Lame naprawdę nie jest trudne w użyciu, chociaż istnieje wiele opcjonalnych funkcji konfiguracyjnych, jeśli ich potrzebujesz. Do kodowania pliku potrzeba nieco więcej niż 4-5 linii, ale niewiele więcej. Oto przykład roboczych Zapukałem razem (tylko podstawowa funkcjonalność, sprawdzanie bez błędu):

#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; 
} 
+0

proszę, czy mógłbyś udostępnić plik projektu, naprawdę nie owijaj czegoś - jak podłączyć LAME do twojego projektu CPP, pomóż – Rella

+1

Zbudowałem go na Linuxie Ubuntu 'gcc lametest.c -lmp3lame' (po zainstalowaniu biblioteki i pliki nagłówkowe z opcją 'sudo apt-get install libmp3lame-dev'). Obawiam się, że nie mam pojęcia, jak zainstalować i połączyć się z bibliotekami na Mac i Windows. –

+0

Ser Czy chciałbyś podzielić się kilkoma linkami (lub lepszymi bezpośrednimi instrukcjami) do instalowania Lame dla programistów na Linuksie. – Rella

1

Dostałem to do pracy poprzez zmianę 41000 do około 8000:

lame_set_in_samplerate(lame, 44100); 

do

lame_set_in_samplerate(lame, 8000); 

i skompilowane prog.c z:

gcc prog.c -lmp3lame -o prog 

Plik.pcm nie brzmi dobrze jako plik.mp3. Mam doskonałą konwersję, gdy użyłem tego polecenia bash:

lame -V 5 file.wav file.mp3 
1

Z powodzeniem wykorzystałem libmp3lame w sposób zaproponowany przez mike sexy. Teraz próbuję użyć tego samego podejścia, używając wątków posix, aby przyspieszyć kodowanie. Po uruchomieniu jednego wskaźnika lame_t mam kilka wątków wykonujących bity konwersji, , zwracając uwagę, że każdy wątek ma unikatowy fragment utworu pcm, który transkoduje.

Używam jednej globalnej struktury lame_t, która jest używana do kodowania w każdym wątku. Mój kod działa dla 1 wątku (bez wykonywania równoległego), działa również, gdy opóźniam tworzenie wątku w trybie równoległym (tak, że nie ma równoległego wykonania, ale struktury danych są tablicami).

Kiedy uruchamiam mojego kodu w trybie równoległym, dostaję mnóstwo błędów takich jak

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 

Dla referernce, załączam kod, który używam, który kompiluje dobrze.

#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); 

} 

Może ktoś wie, że kulawego nie można używać w ten sposób w równoległym kodzie. Nie znalazłem żadnych wskazówek, jeśli to możliwe, czy nie.

Problem polega na tym, że globalna struktura lame_t jest dostępna dla wielu wątków w tym samym czasie. Myślałem, że to będzie tylko czytanie, więc nie ma problemu, ale wydaje mi się, że się mylę.

Sądziłem również, że rozwiązaniem może być utworzenie obiektu lame_t dla każdego wątku. Próbowałem tego, używając wątków do kodowania wzajemnie wykluczających się bitów oryginalnego pliku WAV.

Kod kompiluje się i działa bezproblemowo, ale wynikowy plik nie zawiera dźwięku.

Jeśli ktoś jest zainteresowany, mogę dodać kod. Jest to tylko niewielka modyfikacja powyższego kodu, przy czym lame_t jest tablicą rozmiarów NTHREADS.

3

zainspirowany odpowiedź Mike'a Seymoura stworzyłem czystym C otoki ++, który pozwala na kodowanie/dekodowanie WAV i MP3 w ciągu zaledwie 2 linii kodu

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

nie trzeba się martwić o szybkości próbkowania, bajtów i liczby kanałów - informacje te są uzyskiwane z plików WAV lub MP3 podczas kodowania/dekodowania.

Biblioteka nie używa starych funkcji C/Oo, ale tylko strumienie C++. Uważam, że jest bardziej elegancki.

Dla wygody stworzyłem bardzo cienki wrapper C++ nad LAME i nazwał go lameplus oraz małą bibliotekę do ekstrakcji informacji próbkowania z plików WAV.

Wszystkie pliki można znaleźć tutaj:

kodowania/dekodowania: https://github.com/trodevel/convimp3

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

obsługa

wav: również na github, repozytorium jest wave