我发现在样本开始之前假设所有PCM wav音频文件都有44个字节的标题数据是危险的.虽然这很常见,但许多应用程序(例如ffmpeg)将生成带有46字节标头的wav,并忽略此事实,而处理将导致文件损坏且不可读.但是,如何判断标题实际存在多长时间?
显然有一种方法可以做到这一点,但我搜索并发现很少有关于此的讨论.根据作者自己的背景,很多音频项目假设44(或相反,46).
Rad*_*def 26
您应该检查所有标题数据以查看实际大小.广播波格式文件将包含更大的扩展子块.来自Pro Tools的WAV和AIFF文件具有更多未扩展的扩展块以及音频后的数据.如果您想确定样本数据的开始和结束位置,您需要实际查找数据块(WAV文件的"数据"和AIFF的"SSND").
作为回顾,所有WAV子块都符合以下格式:
Subchunk Descriptor (4 bytes)
Subchunk Size (4 byte integer, little endian)
Subchunk Data (size is Subchunk Size)
这很容易处理.您需要做的就是读取描述符,如果它不是您要查找的描述符,请读取数据大小并跳到下一个.一个简单的Java例程就是这样的:
//
// Quick note for people who don't know Java well:
// 'in.read(...)' returns -1 when the stream reaches
// the end of the file, so 'if (in.read(...) < 0)'
// is checking for the end of file.
//
public static void printWaveDescriptors(File file)
throws IOException {
try (FileInputStream in = new FileInputStream(file)) {
byte[] bytes = new byte[4];
// Read first 4 bytes.
// (Should be RIFF descriptor.)
if (in.read(bytes) < 0) {
return;
}
printDescriptor(bytes);
// First subchunk will always be at byte 12.
// (There is no other dependable constant.)
in.skip(8);
for (;;) {
// Read each chunk descriptor.
if (in.read(bytes) < 0) {
break;
}
printDescriptor(bytes);
// Read chunk length.
if (in.read(bytes) < 0) {
break;
}
// Skip the length of this chunk.
// Next bytes should be another descriptor or EOF.
int length = (
Byte.toUnsignedInt(bytes[0])
| Byte.toUnsignedInt(bytes[1]) << 8
| Byte.toUnsignedInt(bytes[2]) << 16
| Byte.toUnsignedInt(bytes[3]) << 24
);
in.skip(Integer.toUnsignedLong(length));
}
System.out.println("End of file.");
}
}
private static void printDescriptor(byte[] bytes)
throws IOException {
String desc = new String(bytes, "US-ASCII");
System.out.println("Found '" + desc + "' descriptor.");
}
Run Code Online (Sandbox Code Playgroud)
例如,这是我有一个随机的WAV文件:
Found 'RIFF' descriptor. Found 'bext' descriptor. Found 'fmt ' descriptor. Found 'minf' descriptor. Found 'elm1' descriptor. Found 'data' descriptor. Found 'regn' descriptor. Found 'ovwf' descriptor. Found 'umid' descriptor. End of file.
值得注意的是,这里'fmt'和'data'合法地出现在其他块之间,因为Microsoft的RIFF规范说子块可以按任何顺序出现.甚至我所知道的一些主要音频系统也会出错,并没有考虑到这一点.
因此,如果要查找某个块,请遍历文件检查每个描述符,直到找到您要查找的那个.
Mat*_* J. 10
诀窍是查看"Subchunk1Size",它是从头的字节16开始的4字节整数.在正常的44字节wav中,此整数将为16 [10,0,0,0].如果它是一个46字节的标题,如果有额外的可扩展元数据(罕见?),这个整数将是18 [12,0,0,0]或甚至更高.
额外数据本身(如果存在)从字节36开始.
因此,检测标头长度的简单C#程序如下所示:
static void Main(string[] args)
{
byte[] bytes = new byte[4];
FileStream fileStream = new FileStream(args[0], FileMode.Open, FileAccess.Read);
fileStream.Seek(16, 0);
fileStream.Read(bytes, 0, 4);
fileStream.Close();
int Subchunk1Size = BitConverter.ToInt32(bytes, 0);
if (Subchunk1Size < 16)
Console.WriteLine("This is not a valid wav file");
else
switch (Subchunk1Size)
{
case 16:
Console.WriteLine("44-byte header");
break;
case 18:
Console.WriteLine("46-byte header");
break;
default:
Console.WriteLine("Header contains extra data and is larger than 46 bytes");
break;
}
}
Run Code Online (Sandbox Code Playgroud)