簡體   English   中英

如何在 c++ 中使用 lame (mp3->wav) 解碼

[英]How to decode using lame (mp3->wav) in c++

非常感謝您回答這個問題。

我使用跛腳,我想將 mp3 文件解碼為 wav。

通過多次搜索,我成功地將 mp3 文件解碼為 wav 文件。 但是,創建的 wav 文件的大小太大並出現錯誤消息。 媒體播放器錯誤消息:無法播放此文件。 文件格式可能不受支持,文件擴展名可能不正確,或者文件可能已損壞。

如果你知道我的問題,請給我一些建議。 謝謝

HEADER 文件

#pragma once
#ifndef _LAME_HELPER_H_
#define _LAME_HELPER_H_

#include <windows.h>
#include "lame.h"

#define LH_STARTED WM_USER+1
#define LH_COMPUTED WM_USER+2
#define LH_DONE WM_USER+3
#define LH_ERROR WM_USER+4

#define MAX_THREAD_COUNT 5

enum encode_mode_e
{
    EM_ABR,
    EM_CBR,
    EM_VBR
};

enum encode_channel_e
{
    EC_MONO,
    EC_STEREO
};

enum bitrate_e
{
    BR_8kbps = 8,
    BR_16kbps = 16,
    BR_24kbps = 24,
    BR_32kbps = 32,
    BR_40kbps = 40,
    BR_48kbps = 48,
    BR_56kbps = 56,
    BR_64kbps = 64,
    BR_80kbps = 80,
    BR_96kbps = 96,
    BR_112kbps = 112,
    BR_128kbps = 128,
    BR_144kbps = 144,
    BR_160kbps = 160,
    BR_192kbps = 192,
    BR_224kbps = 224,
    BR_256kbps = 256,
    BR_320kbps = 320
};

enum samplerate_e
{
    SR_8khz = 8000,
    SR_11khz = 11025,
    SR_12khz = 12000,
    SR_16khz = 16000,
    SR_22khz = 22050,
    SR_24khz = 24000,
    SR_32khz = 32000,
    SR_44khz = 44100,
    SR_48khz = 48000
};

struct settings_t
{
    char* title;
    char* artist;
    char* album;
    char* comment;
    char* year;
    char* track;
    char* genre;
    char* albumart;

    encode_channel_e channels;
    bitrate_e abr_bitrate;
    bitrate_e cbr_bitrate;
    int quality;
    encode_mode_e enc_mode;
    samplerate_e resample_frequency;
    samplerate_e in_samplerate;

    //The constructor; used to set default values
    settings_t();
};

class CLameHelper; //lameHelper prototype, needed because of struct StaticParam_t

//Use to hold parameters for the thread function
struct StaticParam_t
{
    char* pcm;
    char* mp3;
    settings_t settings;
    WNDPROC callback_proc;
    CLameHelper* lhObj;
};


class CLameHelper
{
public :
    static const int PCM_SIZE = 4096;
    static const int MP3_SIZE = 4096;

    HANDLE m_hThread[MAX_THREAD_COUNT];
    StaticParam_t* m_phSParam[MAX_THREAD_COUNT];

    static int Decode_s(void* pParam);
    
    void WriteWaveHeader(FILE* const, int, int, int, int);
    void Write32BitLowHigh(FILE*, int);
    void Write16BitLowHigh(FILE*, int);

    int SetID3AlbumArt(lame_t gfp, char const* szFileName);
    void errorHandler(char*);
    char errMsg[1000];

public:
    CLameHelper();
    ~CLameHelper();

    int Decode(char* szMp3_in, char* szPcm_out);
    int Decode(char* szMp3_in, char* szPcm_out, WNDPROC callback_proc); 
};

#endif

文件

#include "stdafx.h"
#include "LameHelper.h"

settings_t::settings_t()
{
    //Setting the default values
    title = "";
    artist = "";
    album = "";
    comment = "";
    year = "";
    track = "";
    genre = "";
    albumart = NULL;
    
    channels = EC_STEREO;
    abr_bitrate = BR_128kbps;
    cbr_bitrate = BR_128kbps;
    quality = 5;
    enc_mode = EM_CBR;
    resample_frequency = SR_44khz; 
    in_samplerate = SR_44khz;
}


CLameHelper::CLameHelper()
{
    //Initialize to NULL, aids deletion/closing later
    for(int i = 0; i < MAX_THREAD_COUNT; i++)
    {
        m_hThread[i] = NULL;
        m_phSParam[i] = NULL;
    }
    
}

CLameHelper::~CLameHelper()
{
    //Destroy all declared objects
    for(int i = 0; i < MAX_THREAD_COUNT; i++)
    {
        if(m_hThread[i] != NULL)
            CloseHandle(m_hThread[i]);

        if(m_phSParam[i] != NULL)
            delete m_phSParam[i];
    }
}


int CLameHelper::SetID3AlbumArt(lame_t gfp, char const* szFileName)
{
    int iResult = -1;
    FILE *pFileName = 0;
    char *szAlbumart = 0;

    if(szFileName == NULL) 
    {
        return 0;
    }

    pFileName = fopen(szFileName, "rb");

    if(!pFileName) 
    {
        iResult = 1;
    }
    else
    {
        size_t size;

        fseek(pFileName, 0, SEEK_END);
        size = ftell(pFileName);
        fseek(pFileName, 0, SEEK_SET);
        szAlbumart = (char*)malloc(size);
        if(!szAlbumart)
        {
            iResult = 2;            
        }
        else 
        {
            if(fread(szAlbumart, 1, size, pFileName) != size)
            {
                iResult = 3;
            }
            else 
            {
                iResult = (gfp, szAlbumart, size) ? 4 : 0;
            }
            free(szAlbumart);
        }
        fclose(pFileName);
    }
    switch(iResult)
    {
    case 1:
        sprintf(errMsg, "WARNING: could not find file '%s' for szAlbumart.\n", szFileName);
        errorHandler(errMsg); 
        break;
    case 2:
        errorHandler("WARNING: insufficient memory for reading the szAlbumart.\n");
        break;
    case 3:
        sprintf(errMsg, "WARNING: read error in '%s' for szAlbumart.\n", szFileName);
        errorHandler(errMsg);
        break;
    case 4: 
        sprintf(errMsg, "WARNING: unsupported image: '%s' for szAlbumart. Specify JPEG/PNG/GIF image\n", szFileName);
        errorHandler(errMsg);
        break;
    default: 
        break;
    }
    return iResult;
}


void CLameHelper::Write16BitLowHigh(FILE * fp, int val)
{
    unsigned char bytes[2];
    bytes[0] = (val & 0xff);
    bytes[1] = ((val >> 8) & 0xff);
    fwrite(bytes, 1, 2, fp);
}

void CLameHelper::Write32BitLowHigh(FILE * fp, int val)
{
    unsigned char bytes[4];
    bytes[0] = (val & 0xff);
    bytes[1] = ((val >> 8) & 0xff);
    bytes[2] = ((val >> 16) & 0xff);
    bytes[3] = ((val >> 24) & 0xff);
    fwrite(bytes, 1, 4, fp);
}

void CLameHelper::WriteWaveHeader(FILE * const fp, int pcmbytes, int freq, int channels, int bits)
{
    int     bytes = (bits + 7) / 8;
    /* quick and dirty, but documented */
    fwrite("RIFF", 1, 4, fp); /* label */
    Write32BitLowHigh(fp, pcmbytes + 44 - 8); /* length in bytes without header */
    fwrite("WAVEfmt ", 2, 4, fp); /* 2 labels */
    Write32BitLowHigh(fp, 2 + 2 + 4 + 4 + 2 + 2); /* length of PCM format declaration area */
    Write16BitLowHigh(fp, 1); /* is PCM? */
    Write16BitLowHigh(fp, channels); /* number of channels */
    Write32BitLowHigh(fp, freq); /* sample frequency in [Hz] */
    Write32BitLowHigh(fp, freq * channels * bytes); /* bytes per second */
    Write16BitLowHigh(fp, channels * bytes); /* bytes per sample time */
    Write16BitLowHigh(fp, bits); /* bits per sample */
    fwrite("data", 1, 4, fp); /* label */
    Write32BitLowHigh(fp, pcmbytes); /* length in bytes of raw PCM data */
}

int CLameHelper::Decode(char* szMp3_in, char* szPcm_out)
{
    return Decode(szMp3_in, szPcm_out, NULL);
}

//the static function used for the thread
int CLameHelper::Decode_s(void* param)
{
    StaticParam_t* sp = (StaticParam_t*)param;
    char* szPcm_out = sp->pcm;
    char* szMp3_in = sp->mp3;
    WNDPROC callback_proc = sp->callback_proc;

    CLameHelper* lh = (CLameHelper*)sp->lhObj;
    return lh->Decode(szMp3_in, szPcm_out, callback_proc);
}


int CLameHelper::Decode(char* szMp3_in, char* szPcm_out, WNDPROC callback_proc)
{
    int read, i, samples;
    long wavsize = 0; // use to count the number of mp3 byte read, this is used to write the length of the wave file
    long cumulative_read = 0;

    short int pcm_l[PCM_SIZE], pcm_r[PCM_SIZE];
    unsigned char mp3_buffer[MP3_SIZE];

    FILE* mp3 = fopen(szMp3_in, "rb");
    if(mp3 == NULL)
    {
        if(callback_proc != NULL)
        {
            callback_proc((HWND)GetModuleHandle(NULL), LH_ERROR, -1, NULL);
        }
        sprintf(errMsg, "FATAL ERROR: file '%s' can't be open for read. Aborting!\n", szMp3_in);
        errorHandler(errMsg);
        return -1;
    }
    fseek(mp3, 0, SEEK_END);
    long MP3_total_size = ftell(mp3);
    fseek(mp3, 0, SEEK_SET);

    
    FILE* pcm = fopen(szPcm_out, "wb");
    if(pcm == NULL)
    {
        if(callback_proc != NULL)
        {
            callback_proc((HWND)GetModuleHandle(NULL), LH_ERROR, -1, NULL);
        }
        sprintf(errMsg, "FATAL ERROR: file '%s' can't be open for write. Aborting!\n", szPcm_out);
        errorHandler(errMsg);
        return -1;
    }

    
    lame_t lame = lame_init();
    lame_set_decode_only(lame, 1);
    if(lame_init_params(lame) == -1)
    {
        if(callback_proc != NULL)
        {
            callback_proc((HWND)GetModuleHandle(NULL), LH_ERROR, -2, NULL);
        }
        sprintf(errMsg, "FATAL ERROR: parameters failed to initialize properly in lame. Aborting!\n", szPcm_out);
        errorHandler(errMsg);
        return -2;
    }

    hip_t hip = hip_decode_init();
    
    mp3data_struct mp3data;
    memset(&mp3data, 0, sizeof(mp3data));
    
    int nChannels = -1;
    int nSampleRate = -1;
    int mp3_len;

    if(callback_proc != NULL)
    {
        callback_proc((HWND)GetModuleHandle(NULL), LH_STARTED, NULL, NULL);
    }

    while((read = fread(mp3_buffer, sizeof(char), MP3_SIZE, mp3)) > 0)
    {
        mp3_len = read;
        cumulative_read += read * sizeof(char);
        do
        {
            samples = hip_decode1_headers(hip, mp3_buffer, mp3_len, pcm_l, pcm_r, &mp3data);
            wavsize += samples;

            if(mp3data.header_parsed == 1)//header is gotten
            {
                if(nChannels < 0)//reading for the first time
                {
                    //Write the header
                    WriteWaveHeader(pcm, 0x7FFFFFFF, mp3data.samplerate, mp3data.stereo, 16); //unknown size, so write maximum 32 bit signed value
                }
                nChannels = mp3data.stereo;
                nSampleRate = mp3data.samplerate;
            }

            if(samples > 0 && mp3data.header_parsed != 1)
            {
                errorHandler("WARNING: lame decode error occured!");
                break;
            }

            if(samples > 0)
            {
                for(i = 0 ; i < samples; i++)
                {
                    fwrite((char*)&pcm_l[i], sizeof(char), sizeof(pcm_l[i]), pcm);
                    if(nChannels == 2)
                    {
                        fwrite((char*)&pcm_r[i], sizeof(char), sizeof(pcm_r[i]), pcm);
                    }
                }
            }
            mp3_len = 0;

            if(callback_proc != NULL)
            {
                int percentage = ((float)cumulative_read/MP3_total_size)*100;
                callback_proc((HWND)GetModuleHandle(NULL), LH_COMPUTED, percentage, NULL);
            }
        }while(samples>0);
    }

    i = (16 / 8) * mp3data.stereo;
    if (wavsize <= 0) 
    {
       wavsize = 0;
    }
    else if (wavsize > 0xFFFFFFD0 / i) 
    {
        wavsize = 0xFFFFFFD0;
    }
    else 
    {
        wavsize *= i;
    }
    
    if(!fseek(pcm, 0l, SEEK_SET))//seek back and adjust length
        WriteWaveHeader(pcm, (int) wavsize, mp3data.samplerate, mp3data.stereo, 16);
    else
        errorHandler("WARNING: can't seek back to adjust length in wave header!");

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

    if(callback_proc != NULL)
    {
        callback_proc((HWND)GetModuleHandle(NULL), LH_DONE, NULL, NULL);
    }
    return 0;
}

void CLameHelper::errorHandler(char* msg)
{
    printf("%s\n", msg);
}

我想使用 lame 將mp3解碼為PCM 我遇到的問題是

samples = hip_decode1_headers (hip, mp3_buffer, mp3_len, pcm_l, pcm_r, & mp3data);

總是返回 0。

我傳遞的mp3_buffer去掉了ID3標簽,它包含大約 8 個 mp3 幀。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM