// WAV文件頭(44字節(jié))
typedef struct {
// RIFF chunk的id
uint8_t riffChunkId[4] = {'R', 'I', 'F', 'F'};
// RIFF chunk的data大小,即文件總長度減去8字節(jié)
uint32_t riffChunkDataSize;
// "WAVE"
uint8_t format[4] = {'W', 'A', 'V', 'E'};
/* fmt chunk */
// fmt chunk的id
uint8_t fmtChunkId[4] = {'f', 'm', 't', ' '};
// fmt chunk的data大?。捍鎯CM數(shù)據(jù)時,是16
uint32_t fmtChunkDataSize = 16;
// 音頻編碼,1表示PCM,3表示Floating Point
uint16_t audioFormat = AUDIO_FORMAT_PCM;
// 聲道數(shù)
uint16_t numChannels;
// 采樣率
uint32_t sampleRate;
// 字節(jié)率 = sampleRate * blockAlign
uint32_t byteRate;
// 一個樣本的字節(jié)數(shù) = bitsPerSample * numChannels >> 3
uint16_t blockAlign;
// 位深度
uint16_t bitsPerSample;
/* data chunk */
// data chunk的id
uint8_t dataChunkId[4] = {'d', 'a', 't', 'a'};
// data chunk的data大?。阂纛l數(shù)據(jù)的總長度,即文件總長度減去文件頭的長度(一般是44)
uint32_t dataChunkDataSize;
} WAVHeader;
void FFmpegs::pcm2wav(WAVHeader &header,
const char *pcmFilename,
const char *wavFilename) {
header.blockAlign = header.bitsPerSample * header.numChannels >> 3;
header.byteRate = header.sampleRate * header.blockAlign;
// 打開pcm文件
QFile pcmFile(pcmFilename);
if (!pcmFile.open(QFile::ReadOnly)) {
qDebug() << "文件打開失敗" << pcmFilename;
return;
}
header.dataChunkDataSize = pcmFile.size();
header.riffChunkDataSize = header.dataChunkDataSize
+ sizeof (WAVHeader)
- sizeof (header.riffChunkId)
- sizeof (header.riffChunkDataSize);
// 打開wav文件
QFile wavFile(wavFilename);
if (!wavFile.open(QFile::WriteOnly)) {
qDebug() << "文件打開失敗" << wavFilename;
pcmFile.close();
return;
}
// 寫入頭部
wavFile.write((const char *) &header, sizeof (WAVHeader));
// 寫入pcm數(shù)據(jù)
char buf[1024];
int size;
while ((size = pcmFile.read(buf, sizeof (buf))) > 0) {
wavFile.write(buf, size);
}
// 關(guān)閉文件
pcmFile.close();
wavFile.close();
}
// 獲取輸入格式對象
AVInputFormat *fmt = av_find_input_format(FMT_NAME);
if (!fmt) {
qDebug() << "獲取輸入格式對象失敗" << FMT_NAME;
return;
}
// 格式上下文(將來可以利用上下文操作設備)
AVFormatContext *ctx = nullptr;
// 打開設備
int ret = avformat_open_input(&ctx, DEVICE_NAME, fmt, nullptr);
if (ret < 0) {
char errbuf[1024];
av_strerror(ret, errbuf, sizeof (errbuf));
qDebug() << "打開設備失敗" << errbuf;
return;
}
// 文件名
QString filename = FILEPATH;
filename += QDateTime::currentDateTime().toString("MM_dd_HH_mm_ss");
QString wavFilename = filename;
filename += ".pcm";
wavFilename += ".wav";
QFile file(filename);
// 打開文件
// WriteOnly:只寫模式。如果文件不存在,就創(chuàng)建文件;如果文件存在,就會清空文件內(nèi)容
if (!file.open(QFile::WriteOnly)) {
qDebug() << "文件打開失敗" << filename;
// 關(guān)閉設備
avformat_close_input(&ctx);
return;
}
// 數(shù)據(jù)包
AVPacket pkt;
while (!isInterruptionRequested()) {
// 不斷采集數(shù)據(jù)
ret = av_read_frame(ctx, &pkt);
if (ret == 0) { // 讀取成功
// 將數(shù)據(jù)寫入文件
file.write((const char *) pkt.data, pkt.size);
} else if (ret == AVERROR(EAGAIN)) { // 資源臨時不可用
continue;
} else { // 其他錯誤
char errbuf[1024];
av_strerror(ret, errbuf, sizeof (errbuf));
qDebug() << "av_read_frame error" << errbuf << ret;
break;
}
}
// 關(guān)閉文件
file.close();
// 獲取輸入流
AVStream *stream = ctx->streams[0];
// 獲取音頻參數(shù)
AVCodecParameters *params = stream->codecpar;
// pcm轉(zhuǎn)wav文件
WAVHeader header;
header.sampleRate = params->sample_rate;
header.bitsPerSample = av_get_bits_per_sample(params->codec_id);
header.numChannels = params->channels;
if (params->codec_id >= AV_CODEC_ID_PCM_F32BE) {
header.audioFormat = AUDIO_FORMAT_FLOAT;
}
FFmpegs::pcm2wav(header,
filename.toUtf8().data(),
wavFilename.toUtf8().data());
// 關(guān)閉設備
avformat_close_input(&ctx);
qDebug() << this << "正常結(jié)束----------";
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。