0

我正在尝试读取 .wav 文件的标头信息。

如果我有一个低采样率(22050)的 .wav 文件,它将完美地读取所有信息,但是,如果我有更高的采样率(8000),则它无法读取一些信息:

“dataSize”在使用 22050 .wav 文件时设置,但是,当使用 8000 .wav 文件时,它不会被设置,只是显示一些随机数。例如,当实际大小约为 4k-4.5k 时,“1672494080”。

对我哪里出错有什么建议吗?

编辑:

#include <iostream>
#include <fstream>
#include <vector>
#include <inttypes.h>
#include <stdint.h>
#include <math.h>

using namespace std;
struct riff_hdr
{
   char id[4];
   uint32_t size;
   char type[4];
};

struct chunk_hdr
{
   char id[4];
   uint32_t size;
};

struct wavefmt
{
   uint16_t format_tag;
   uint16_t channels;
   uint32_t sample_rate;
   uint32_t avg_bytes_sec;
   uint16_t block_align;
   uint16_t bits_per_sample;
   uint16_t extra_size;
};


riff_hdr riff;
chunk_hdr chunk;
wavefmt fmt = {0};
uint32_t padded_size;
vector<uint8_t> chunk_data;

bool readHeader(ifstream &file) {

file.read(reinterpret_cast<char*>(&riff), sizeof(riff));
if (memcmp(riff.id, "RIFF", 4) == 0)
{
    cout << "size=" << riff.size << endl;
    cout << "id=" << string(riff.type, 4) << endl;

    if (memcmp(riff.type, "WAVE", 4) == 0)
    {
        // chunks can be in any order!
        // there is no guarantee that "fmt" is the first chunk.
        // there is no guarantee that "fmt" is immediately followed by "data".
        // There can be other chunks present!

        do {

            file.read(reinterpret_cast<char*>(&chunk), sizeof(chunk));
            padded_size = ((chunk.size + 2 - 1) & ~1);

             cout << "id=" << string(chunk.id, 4) << endl;
             cout << "size=" << chunk.size << endl;
             cout << "padded size=" << padded_size << endl;

             if (memcmp(chunk.id, "fmt\0", 4) == 0) 
             {
                 if (chunk.size < sizeof(wavefmt))
                 {
                     // error!
                     file.ignore(padded_size);
                 }else{

                    // THIS block doesn't seem to be executing
                    chunk_data.resize(padded_size);
                    file.read(reinterpret_cast<char*>(&chunk_data[0]), padded_size);

                    fmt = *(reinterpret_cast<wavefmt*>(&chunk_data[0]));

                    cout << "format_tag=" << fmt.format_tag << endl;
                    cout << "channels=" << fmt.channels << endl;
                    cout << "sample_rate=" << fmt.sample_rate << endl;
                    cout << "avg_bytes_sec=" << fmt.avg_bytes_sec << endl;
                    cout << "block_align=" << fmt.block_align << endl;
                    cout << "bits_per_sample=" << fmt.bits_per_sample << endl;
                    cout << "extra_size=" << fmt.extra_size << endl;
                }

                if(fmt.format_tag != 1)
                {
                    uint8_t *extra_data = &chunk_data[sizeof(wavefmt)];
                }
             }else if(memcmp(chunk.id, "data", 4) == 0) {
                file.ignore(padded_size);
            }else{
                file.ignore(padded_size);
            }
        }while ((!file) && (!file.eof()));
    }
}

    return true;
}

int main()
{
ifstream file("example2.wav");


readHeader(file);
return 0;
}

输出:

大小=41398

id=WAVE

id=fmt

尺寸=18

填充尺寸=18

块数据大小=0

我哪里错了?

4

1 回答 1

2

您的代码有两个问题:

  1. bitsPerSample在您未读取的值之后有一个 2 字节整数。它指定该块中任何额外数据的大小。如果 的值format2仅表示 PCM 格式,您可以忽略整数的值(无论如何它通常为 0,但也可能是垃圾),但您仍然需要考虑它的存在。对于非 PCM 格式,整数不能忽略,您必须读取该值,然后读取它表示的字节数。您需要确保在进入while循环之前读取整个块,否则您将无法在文件中的正确起始位置读取更多块。

  2. 您没有考虑到块被填充到最近的 WORD 边界,但块大小不包括任何填充。调用seekg()时,需要将值向上舍入到下一个 WORD 边界。

更新:根据您发布的新代码,它应该看起来更像这样:

#include <iostream>
#include <fstream>
#include <vector>
#include <inttypes.h>
#include <stdint.h>
#include <math.h>

using namespace std;

// if your compiler does not have pshpack1.h and poppack.h, then
// use #pragma pack instead. It is important that these structures
// be byte-alignd!

#include <pshpack1.h>

struct s_riff_hdr
{
   char id[4];
   uint32_t size;
   char type[4];
};

struct s_chunk_hdr
{
   char id[4];
   uint32_t size;
};

struct s_wavefmt
{
   uint16_t format_tag;
   uint16_t channels;
   uint32_t sample_rate;
   uint32_t avg_bytes_sec;
   uint16_t block_align;
};

struct s_wavefmtex
{
   s_wavefmt fmt;
   uint16_t bits_per_sample;
   uint16_t extra_size;
};

struct s_pcmwavefmt
{
   s_wavefmt fmt;
   uint16_t bits_per_sample;
};

#include <poppack.h>

bool readWave(ifstream &file)
{
    s_riff_hdr riff_hdr;
    s_chunk_hdr chunk_hdr;
    uint32_t padded_size;
    vector<uint8_t> fmt_data;
    s_wavefmt *fmt = NULL;

    file.read(reinterpret_cast<char*>(&riff_hdr), sizeof(riff_hdr));
    if (!file) return false;

    if (memcmp(riff_hdr.id, "RIFF", 4) != 0) return false;

    cout << "size=" << riff_hdr.size << endl;
    cout << "type=" << string(riff_hdr.type, 4) << endl;

    if (memcmp(riff_hdr.type, "WAVE", 4) != 0) return false;

    // chunks can be in any order!
    // there is no guarantee that "fmt" is the first chunk.
    // there is no guarantee that "fmt" is immediately followed by "data".
    // There can be other chunks present!

    do
    {
        file.read(reinterpret_cast<char*>(&chunk_hdr), sizeof(chunk_hdr));
        if (!file) return false;

        padded_size = ((chunk_hdr.size + 1) & ~1);

        cout << "id=" << string(chunk_hdr.id, 4) << endl;
        cout << "size=" << chunk_hdr.size << endl;
        cout << "padded size=" << padded_size << endl;

        if (memcmp(chunk_hdr.id, "fmt ", 4) == 0) 
        {
            if (chunk_hdr.size < sizeof(s_wavefmt)) return false;

            fmt_data.resize(padded_size);

            file.read(reinterpret_cast<char*>(&fmt_data[0]), padded_size);
            if (!file) return false;

            fmt = reinterpret_cast<s_wavefmt*>(&fmt_data[0]);

            cout << "format_tag=" << fmt->format_tag << endl;
            cout << "channels=" << fmt->channels << endl;
            cout << "sample_rate=" << fmt->sample_rate << endl;
            cout << "avg_bytes_sec=" << fmt->avg_bytes_sec << endl;
            cout << "block_align=" << fmt->block_align << endl;

            if (fmt->format_tag == 1) // PCM
            {
                if (chunk_hdr.size < sizeof(s_pcmwavefmt)) return false;

                s_pcmwavefmt *pcm_fmt = reinterpret_cast<s_pcmwavefmt*>(fmt);

                cout << "bits_per_sample=" << pcm_fmt->bits_per_sample << endl;
            }
            else
            {
                if (chunk_hdr.size < sizeof(s_wavefmtex)) return false;

                s_wavefmtex *fmt_ex = reinterpret_cast<s_wavefmtex*>(fmt);

                cout << "bits_per_sample=" << fmt_ex->bits_per_sample << endl;
                cout << "extra_size=" << fmt_ex->extra_size << endl;

                if (fmt_ex->extra_size != 0)
                {
                    if (chunk_hdr.size < (sizeof(s_wavefmtex) + fmt_ex->extra_size)) return false;

                    uint8_t *extra_data = reinterpret_cast<uint8_t*>(fmt_ex + 1);
                    // use extra_data, up to extra_size bytes, as needed...
                }
            }
        }
        else if (memcmp(chunk_hdr.id, "data", 4) == 0)
        {
            // process chunk data, according to fmt, as needed...

            file.ignore(padded_size);
            if (!file) return false;
        }
        else
        {
            // process other chunks as needed...

            file.ignore(padded_size);
            if (!file) return false;
        }
    }
    while (!file.eof());

    return true;
}

int main()
{
    ifstream file("example2.wav");
    readWave(file);
    return 0;
}
于 2012-12-19T00:19:42.370 回答