16

単純なpcmからmp3C++プロジェクトを作成したいと思います。LAMEを使って欲しいです。LAMEは大好きですが、本当に大きいです。したがって、純粋なラメコードワークフローシンプリファイアを使用して純粋なコードから動作するある種のOpenSourceが必要です。つまり、PCMとDESTファイルを含むファイルを指定します。次のように呼び出します。

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

そのようなものを4〜5行で(もちろん例が存在するはずです)、私は必要なものを持っていますそれは軽く、シンプルで、パワーフール、オープンソース、クロスプラットフォームでなければなりません。

このようなものはありますか?

4

4 に答える 4

53

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;
}
于 2010-03-23T00:52:47.183 に答える
6

Mike Seymourの回答に触発されて、わずか2行のコードでWAVファイルとMP3ファイルをエンコード/デコードできる純粋なC++ラッパーを作成しました。

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

サンプルレート、バイトレート、チャネル数を気にする必要はありません。この情報は、エンコード/デコード中にWAVまたはMP3ファイルから取得されます。

ライブラリは古いCi/ o関数を使用しませんが、C++ストリームのみを使用します。もっとエレガントだと思います。

便宜上、LAME上に非常に薄いC ++ラッパーを作成し、それをlameplusと呼び、WAVファイルからサンプリング情報を抽出するための小さなライブラリーと呼びました。

すべてのファイルはここにあります:

エンコード/デコード:https ://github.com/trodevel/convimp3

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

wav処理:githubでも、リポジトリはwaveです

于 2015-04-26T01:52:05.407 に答える
1

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-01T01:14:11.380 に答える
1

私はmikeseymourが提案した方法でlibmp3lameをうまく使用しました。私は現在、POSIXスレッドを使用して同じアプローチを使用してエンコードを高速化しようとしています。私は1つのlame_tポインターをすばらしいものにしており、各スレッドがトランスコードするpcmトラックの一意のビットを持っていることに注意しながら、変換のビットを実行する複数のスレッドがあります。

各スレッドのエンコーディングに使用される1つのグローバル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_t構造が同時に複数のスレッドによってアクセスされることであるように思われます。読んでいるだけだと思っていたので問題ありませんが、間違えたようです。

また、回避策はスレッドごとにlame_tオブジェクトを作成することかもしれないと思いました。スレッドを使用して、元のwavファイルの相互に排他的なビットをエンコードしてみました。

コードは問題なくコンパイルおよび実行されますが、結果のファイルにはサウンドが含まれていません。

興味があれば、コードを追加できます。これは、lame_tがサイズNTHREADSの配列である、上記のコードのマイナーな変更にすぎません。

于 2014-08-03T23:36:45.113 に答える