从 libav 收集解码后的音频作为双打
Collect decoded audio from libav as doubles
我目前正在尝试收集解码后的音频数据(来自多种格式)以执行某些音频操作(使用 *.wav 文件进行测试)。
我有一个 class 通过 FFmpeg libav 处理所有解码。如果我将数据提取为 unit8_t 到一个向量中,并且
for (int i = 0; i < bytevector.size(); i++) {
fwrite(&bytevector[i], sizeof (uint8_t), 1, outfile2);
}
到原始文件并通过
play -t raw -r 44100 -b16 -c 1 -e signed sound.raw
听起来不错。
但是,当文件例如每个样本 2 个字节并且 frame->data
信息给出为uint8_t?我测试过的 wav 文件是 44100/16bits/1 通道。 (我已经有了将 uint8_t* 变成双精度的代码)
使用 Scilab 打开相同的文件将显示字节向量大小的一半作为双精度值。
wav file in Scilab as an array of doubles shows:
-0.1, -0.099, -0.098, ..., 0.099, +0.1
versus byte vector:
51, 243, 84, 243, 117, 243, ...
51和243真的能成双吗?关于如何解决这个问题有什么建议吗?
以下代码供参考:
while ((av_read_frame(formatContext, &readingPacket)) == 0) {
if (readingPacket.stream_index == audioStreamIdx) {
AVPacket decodingPacket = readingPacket;
while (decodingPacket.size > 0) {
int gotFrame = 0;
int result = avcodec_decode_audio4(context, frame, &gotFrame, &decodingPacket);
if (result < 0) {
break;
}
decoded = FFMIN(result, decodingPacket.size);
if (gotFrame) {
data_size = (av_get_bytes_per_sample(context->sample_fmt));
if (data_size < 0) {
}
// Only for 1 channel temporarily
for (int i = 0; i < frame->nb_samples; i++) {
for (int ch = 0; ch < context->channels; ch++) {
for (int j = 0; j < data_size; j++) {
bytevector.push_back(*(frame->data[ch] + data_size * i + j));
}
}
}
} else {
decodingPacket.size = 0;
decodingPacket.data = NULL;
}
decodingPacket.size -= result;
decodingPacket.data += result;
}
}
av_free_packet(&readingPacket);
}
将两个字节转换为float的快速方法:
byte bits[] = {195,255}; //first sample in the test s16 wav file
int16_t sample;
memcpy(&sample,&bits,sizeof(bits));
std::cout<<sample*(1.0f/32768.0f)<<std::endl;
此代码在打印时产生 -0.001861572265625
(更精确的 setprecision(xx);),这是 Scilab 在同一文件中给出的第一个数字。
我希望这对遇到类似问题的任何人有所帮助。
音频数据以多种不同的格式存储。你得到一个 uint8_t[]
数组意义不大。每个数组不是一个字节。相反,您需要知道格式。这里 -b16
告诉我 uint8_t[]
数据实际上是 16 位 PCM 编码数据,即从 -32768 到 +32767 的范围。 Scilab 似乎更喜欢浮点数,因此除以 32768.0。那只是一种表示形式的变化;它只是将比例缩小到 -1.0, +1.0.
将它与角度进行比较:直角是 pi/2 弧度上的 90 度;确切的数字并不重要,但两者都是完整圆的 1/4。
我目前正在尝试收集解码后的音频数据(来自多种格式)以执行某些音频操作(使用 *.wav 文件进行测试)。
我有一个 class 通过 FFmpeg libav 处理所有解码。如果我将数据提取为 unit8_t 到一个向量中,并且
for (int i = 0; i < bytevector.size(); i++) {
fwrite(&bytevector[i], sizeof (uint8_t), 1, outfile2);
}
到原始文件并通过
play -t raw -r 44100 -b16 -c 1 -e signed sound.raw
听起来不错。
但是,当文件例如每个样本 2 个字节并且 frame->data
信息给出为uint8_t?我测试过的 wav 文件是 44100/16bits/1 通道。 (我已经有了将 uint8_t* 变成双精度的代码)
使用 Scilab 打开相同的文件将显示字节向量大小的一半作为双精度值。
wav file in Scilab as an array of doubles shows:
-0.1, -0.099, -0.098, ..., 0.099, +0.1versus byte vector:
51, 243, 84, 243, 117, 243, ...
51和243真的能成双吗?关于如何解决这个问题有什么建议吗?
以下代码供参考:
while ((av_read_frame(formatContext, &readingPacket)) == 0) {
if (readingPacket.stream_index == audioStreamIdx) {
AVPacket decodingPacket = readingPacket;
while (decodingPacket.size > 0) {
int gotFrame = 0;
int result = avcodec_decode_audio4(context, frame, &gotFrame, &decodingPacket);
if (result < 0) {
break;
}
decoded = FFMIN(result, decodingPacket.size);
if (gotFrame) {
data_size = (av_get_bytes_per_sample(context->sample_fmt));
if (data_size < 0) {
}
// Only for 1 channel temporarily
for (int i = 0; i < frame->nb_samples; i++) {
for (int ch = 0; ch < context->channels; ch++) {
for (int j = 0; j < data_size; j++) {
bytevector.push_back(*(frame->data[ch] + data_size * i + j));
}
}
}
} else {
decodingPacket.size = 0;
decodingPacket.data = NULL;
}
decodingPacket.size -= result;
decodingPacket.data += result;
}
}
av_free_packet(&readingPacket);
}
将两个字节转换为float的快速方法:
byte bits[] = {195,255}; //first sample in the test s16 wav file
int16_t sample;
memcpy(&sample,&bits,sizeof(bits));
std::cout<<sample*(1.0f/32768.0f)<<std::endl;
此代码在打印时产生 -0.001861572265625
(更精确的 setprecision(xx);),这是 Scilab 在同一文件中给出的第一个数字。
我希望这对遇到类似问题的任何人有所帮助。
音频数据以多种不同的格式存储。你得到一个 uint8_t[]
数组意义不大。每个数组不是一个字节。相反,您需要知道格式。这里 -b16
告诉我 uint8_t[]
数据实际上是 16 位 PCM 编码数据,即从 -32768 到 +32767 的范围。 Scilab 似乎更喜欢浮点数,因此除以 32768.0。那只是一种表示形式的变化;它只是将比例缩小到 -1.0, +1.0.
将它与角度进行比较:直角是 pi/2 弧度上的 90 度;确切的数字并不重要,但两者都是完整圆的 1/4。