2016-10-25 31 views
0

我正在写一个WAV录像机,使用QFile作为主干。但是,当我填充我的Wav结构,并尝试将其写入我的QFile时,它只写入“RIFF”,我用unix的od -cb 1.wav查看它。这里是samle代码:QFile写入一个WAV头只写4个字节的数据

wavwriter.cpp

Wav::Wav(const char *fname, QFile* parent) 
    : QFile(fname, parent), 
     m_fname(fname) 
{ 
    setFileName(fname); 
    bool res = this->open(QIODevice::ReadWrite); 
    if (res) { 
     std::cout << "File opened for RW\n"; 
    } 
} 

Wav::~Wav() 
{ 
} 

void Wav::writeHeader(const WavHdr* hdr) 
{ 
    write((char*)hdr); 
    flush(); 
} 

void Wav::appendData(const QByteArray &data) 
{ 
    m_data.append(data); 
} 

QByteArray Wav::getWavData() 
{ 
    return m_data; 
} 

而且用法如下:

WavHdr hdr; 
    hdr.bits_per_sample = 8; 
    hdr.riff[0] = 'R'; 
    hdr.riff[1] = 'I'; 
    hdr.riff[2] = 'F'; 
    hdr.riff[3] = 'F'; 
    hdr.sample_rate = 8; 
    hdr.fmt[0] = 'f'; 
    hdr.fmt[1] = 'm'; 
    hdr.fmt[2] = 't'; 
    m_wavs[i]->writeHeader(&hdr); 

的WavHdr具有以下设置:

struct WavHdr 
{ 
    char riff[4]; 
    qint32 file_size; 
    char wave[4]; 
    char fmt[4]; 
    char len[3]; 
    qint16 type; 
    quint16 format; 
    qint32 sample_rate; 
    qint32 sr_bs_channs; 
    quint8 bits_per_sample; 
    char data[4]; 
    qint32 fsize; 
}; 

回答

-1

似乎像这样的代码写入所有44个字节:

char wav[44]={0}; 
memcpy(wav, hdr, 44); 
write(QByteArray(wav), 44); 
flush(); 

但是我必须检查一切是否正确填充。

+0

这是不对的。如果碰巧有效,那只是因为你很幸运,并不是因为你的代码是正确的。这是一种反模式。不要这样做。而且,'flush()'是不必要的。 –

1
  1. 您不能直接将WavHdr转储到磁盘。

    您使用write方法的方式仅适用于以零结尾的字符串。它将停止写入第一个零值字节。 A WavHdr而不是以空终止的字符串。

    你不能假设结构在内存中有任何特定的表示。编译器可以自由地按照它认为合适的方式安排这个结构。它不仅可以任意填补和对齐成员,还可以重新排列成员。所以这是一种不可移植的反模式:它可能发生在某些编译器上,在其他一些编译器上它会被彻底破坏。

  2. 您的WavHdr是错误的。

    请参阅here以供参考。我在下面包含了一个正确的标题结构。您可能希望使用QSaveFile

    保存文件时,通常希望文件写入是原子的:要么成功,要么获得完整,有效的WAV文件,要么失败并且磁盘上没有任何更改(例如,现有文件未被覆盖并损坏) 。这就是QSaveFile的设计目的。

  3. 您可能希望您的wave类使用I/O设备,但不是一个。

    只需要一个QIODevice*的实例即可完成I/O操作:然后,您可以轻松地将数据写入内存缓冲区,文件,网络套接字等。类的用户应该是免费的选择要使用的特定设备。

相反,使用QDataStream写头的便携式方式:

struct WavHdr 
{ 
    constexpr static quint32 k_riff_id = 0x46464952; 
    constexpr static quint32 k_wave_format = 0x45564157; 
    constexpr static quint32 k_fmt_id = 0x20746d66; 
    constexpr static quint32 k_data_id = 0x61746164; 
    // RIFF 
    quint32 chunk_id = k_riff_id; 
    quint32 chunk_size; 
    quint32 chunk_format = k_wave_format; 
    // fmt 
    quint32 fmt_id = k_fmt_id; 
    quint32 fmt_size; 
    quint16 audio_format; 
    quint16 num_channels; 
    quint32 sample_rate; 
    quint32 byte_rate; 
    quint16 block_align; 
    quint16 bits_per_sample; 
    // data 
    quint32 data_id = k_data_id; 
    quint32 data_size; 
}; 

bool write(QIODevice * dev, const WavHdr & h) { 
    QDataStream s{dev}; 
    s.setByteOrder(QDataStream::LittleEndian); // for RIFF 
    s << h.chunk_id << h.chunk_size 
    << h.chunk_format; 
    s << h.fmt_id << h.fmt_size 
    << h.audio_format 
    << h.num_channels 
    << h.sample_rate 
    << h.byte_rate 
    << h.block_align 
    << h.bits_per_sample; 
    s << h.data_id << h.data_size; 
    return s.status() == QDataStream::Ok; 
} 
+0

1st错了。你可以做'write(reinterpret_cast (hdr),sizeof(* hdr));'当文件以二进制打开时。但是必须打包结构才能正确完成,并且必须提供小端。 – ilotXXI

+0

@ilotXXI正确地“包装”结构并使其变得小端不便携。 C/C++'struct'不是为了给你任何可以依赖的二进制布局。你可以做很多黑客,但这并不意味着他们是正确的或合理的。 –

相关问题