Преобразование pcm в mp3 (с помощью LAME) вызывает щелчки в файле mp3

Мое приложение использует LAME для кодирования необработанных данных PCM в mp3. Но у меня есть проблема - выходной mp3 содержит "клики" в постоянном промежутке времени. Что-то такое:

звук... "щелчок" звук.. "щелчок" звук.. "щелчок" и т.д...

Я пробовал разные версии LAME и пытался изменить многие настройки LAME, но безуспешно. Мое приложение также может конвертировать pcm в wav и ogg, но эти конвертеры не приводят к "щелчкам".

Существует код кодирования (вход PCM содержит данные одного канала, PCM уже передискретизирован до частоты 44100):

Инициализация:

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

//Samples count (do not have any effect on output)
dwSamples=1024;

//mp3 buffer size, if it do not equals dwSamples*2 than output sound getting scaled
dwMP3Buffer=dwSamples*2;

pMP3Buffer = new BYTE[dwMP3Buffer];

Запись данных PCM

int Mp3Stream :: Write(short * _data, int _size)
{
    if (_size > 0)
    {
        for(int curPos = 0; curPos < _size; curPos += dwMP3Buffer)
        {
            //int size = dwMP3Buffer;

            //if (_size - curPos < dwMP3Buffer)
            //  size = _size - curPos;

            int bytes = lame_encode_buffer(lame, (short *)((char *)_data + curPos), (short *)((char *)_data + curPos), dwSamples, pMP3Buffer, 0);

            IPF_TRACE(1, "MP3 encoder wrote "<<bytes<<" bytes");

            if (bytes<0)
            {
                IPF_TRACE(1, "MP3 encoding failed with code "<<bytes);
                return bytes;
            }

            BOOL bResult = WriteFile(hFile, pMP3Buffer, bytes, &bw, NULL);

            if (!bResult || bytes != bw)
            {
                IPF_TRACE(1, "MP3 write to file failed with code "<<bytes);
            }
        };
    }
}

Завершение

int bytes = lame_encode_flush(lame, pMP3Buffer, 0);
    if (bytes<0)
{
    IPF_TRACE(1, "MP3 flush failed with code "<<bytes);
}
BOOL bResult = WriteFile(hFile, pMP3Buffer, bytes, &bw, NULL);
if (!bResult || bytes != bw)
{
    IPF_TRACE(1, "MP3 write to file failed with code "<<bytes);
}
int ret = lame_close(lame);
if (ret < 0) 
{
    IPF_TRACE(1, "MP3 lame close failed with code "<<ret);
}
delete []pMP3Buffer;

person Sergei Gorbunov    schedule 27.04.2012    source источник
comment
У меня была та же проблема, и решение было здесь: stackoverflow.com/questions/13277042/   -  person Jeff    schedule 28.01.2016


Ответы (3)


Шаблон Sound -> Click -> Sound -> Click, скорее всего, означает, что вы записываете только половину своего буфера за раз, а другая половина остается обнуленной для каждого цикла внутри вызова Write.

Причина этого в том, что ваш инкрементатор цикла основан на значении dwMP3Buffer dwSamples*2.

 for(int curPos = 0; curPos < _size; curPos += dwMP3Buffer){

Это означает, что вы на самом деле не кодируете все свои входные значения, поскольку dwMP3Buffer в два раза превышает количество сэмплов, которые вы фактически передаете вызову lame_encode_buffer (dwSamples).

lame_encode_buffer(lame, (short *)((char *)_data + curPos), 
                   (short *)((char *)_data + curPos), dwSamples, pMP3Buffer, 0);

Попробуйте изменить инкремент цикла на следующее:

 for(int curPos = 0; curPos < _size; curPos += dwSamples){
person nvuono    schedule 27.04.2012
comment
Когда-то у нас была похожая проблема при использовании Windows ACM для кодирования WAV в MP3 — он не обрабатывал весь входной буфер, и мы отбрасывали оставшиеся байты между вызовами. - person Roger Lipscombe; 27.04.2012

Попробуй это,

void AQRecorder::MyInputBufferHandler(  void *                              inUserData,
                                AudioQueueRef                       inAQ,
                                AudioQueueBufferRef                 inBuffer,
                                const AudioTimeStamp *              inStartTime,
                                UInt32                              inNumPackets,
                                const AudioStreamPacketDescription* inPacketDesc)
{
AQRecorder *aqr = (AQRecorder *)inUserData;
//    NSLog(@"%f",inStartTime->mSampleTime);
try
{
    if (inNumPackets > 0)
    {
        AudioFileWritePackets(aqr->mRecordFile, FALSE, inBuffer->mAudioDataByteSize, inPacketDesc, aqr->mRecordPacket, &inNumPackets, inBuffer->mAudioData);

        aqr->mRecordPacket += inNumPackets;

        int MP3_SIZE =inBuffer->mAudioDataByteSize * 4;
        unsigned char mp3_buffer[MP3_SIZE];
        AppDelegate *delegate =[[UIApplication sharedApplication]delegate];
        lame_t lame = lame_init();
        lame_set_in_samplerate(lame, 44100);
        lame_set_VBR(lame, vbr_default);
        lame_init_params(lame);

  //                int encodedBytes=lame_encode_buffer_interleaved(lame, (short int *)inBuffer->mAudioData , inNumPackets, mp3_buffer, MP3_SIZE);


        int encodedBytes = lame_encode_buffer(lame, (short*)inBuffer->mAudioData,  (short*)inBuffer->mAudioData, inNumPackets, mp3_buffer, MP3_SIZE);

        [delegate.mp3AudioData appendBytes:mp3_buffer length:encodedBytes];

        if (inBuffer->mAudioDataByteSize != 0) {
        }
        else
        {
            int encode=lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
            [delegate.mp3AudioData appendBytes:mp3_buffer length:encode];
        }
        lame_close(lame);
    }

    if (aqr->IsRunning())
    {
        AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL);
    }
 } catch (CAXException e)
 {
 char buf[256];
 fprintf(stderr, "Error: %s (%s)\n", e.mOperation, e.FormatError(buf));
}
}
person Ravindhiran    schedule 22.08.2013

я бы попробовал поставить

dwSamples = 1152

1152 - размер аудиокадра (в сэмплах) для кодировщика MPEG1Audio. Похоже, что LAME обрабатывает данные фрагментами, состоящими из нескольких кадров.

person rusxg    schedule 28.04.2012