读取MP3帧头 - 将位值分配给变量

时间:2011-12-20 22:02:58

标签: vb.net mp3 filestream bitarray bitconverter

我正在学习visual basic .net,我正在尝试将一些java源代码翻译成vb.net项目。该项目读取mp3详细信息,然后根据frameheader详细信息等准确地拆分文件。

我的问题涉及阅读mp3文件的帧头。我知道帧的详细信息包含在帧的前4(32位)字节中,某些位表示某些值,如下所示:http://www.mp3-tech.org/programmer/frame_header.html

使用FileStream我已经能够读取这些数据并在文本框中以二进制形式显示它。

我正在寻找帮助读取这些位并将它们分配给我班级中的变量。我不确定执行此操作的正确程序是什么,因为某些值的长度为1,2或4位,例如位19-20 = MpegType,位12-15 = BitrateIndex,位9 =填充等。

我已经查看了codeproject.com上提供的类似项目,但我不明白他们是如何实现上述目标的。

非常感谢任何帮助。

编辑:

这是主要的子目录,我还没有包含声明变量和属性等的代码。

Public Sub decode()
    Dim fs As FileStream
    Dim bytes(3) As Byte
    fs = New FileStream(mFilename, FileMode.Open, FileAccess.Read)

    If fs.CanRead Then
        fs.Read(bytes, 0, bytes.Length)
        For i As Integer = 0 To bytes.Length - 1
            Form1.RichTextBox.Text += Convert.ToString(bytes(i), 2).PadLeft(8, "0"c) & vbCrLf
        Next
        fs.Close()
        fs.Dispose()
    Else
        MsgBox("File CANNOT be read!!!")
    End If
End Sub

运行此操作时,富文本框中的输出如下:

11111111
11111010
10110011
01001100

我想通读这些位并为变量分配适当的值,例如

读取同步值的前12位。 读取位13以获取mpegID值。 读取第14位和第15位的layerID值等。

希望更清楚。

java代码如下:

public FrameHeader() {
    this.header32 = 0;
    valid = false;
}

public FrameHeader(int header32) {
    this.header32 = header32;
    decode();
}

public void setHeader32(int header32) {
    this.header32 = header32;
    decode();
}

private void decode() {
    mpegID = (header32 >> 19) & 3;
    layerID = (header32 >> 17) & 3;
    crc16used = (header32 & 0x00010000) == 0;
    bitrateIndex = (header32 >> 12) & 0xF;
    samplingrateIndex = (header32 >> 10) & 3;
    padding = (header32 & 0x00000200) != 0;
    privateBitSet = (header32 & 0x00000100) != 0;
    mode = (header32 >> 6) & 3;
    modeExtension = (header32 >> 4) & 3;
    copyrighted = (header32 & 0x00000008) != 0;
    original = (header32 & 0x00000004) == 0; // bit set -> copy
    emphasis = header32 & 3;
    valid = (mpegID != ILLEGAL_MPEG_ID) && (layerID != ILLEGAL_LAYER_ID) && (bitrateIndex != 0)
            && (bitrateIndex != 15) && (samplingrateIndex != ILLEGAL_SR);
    if (valid) {
        samplingrateHz = SAMPLING_RATES[samplingrateIndex];
        if (mpegID == MPEG2_ID)
            samplingrateHz >>= 1; // 16,22,48 kHz
        if (mpegID == MPEG25_ID)
            samplingrateHz >>= 2; // 8,11,24 kHz
        channels = (mode == MODE_MONO) ? 1 : 2;
        bitrateKBPS = BITRATE_MAP[mpegID][layerID][bitrateIndex];
        if (layerID == LAYER1_ID) {
            // layer 1: always 384 samples/frame and 4byte-slots
            samplesPerFrame = 384;
            bytesPerSlot = 4;
        }
        else {
            // layer 2: always 1152 samples/frame
            // layer 3: MPEG1: 1152 samples/frame, MPEG2/2.5: 576
            // samples/frame
            samplesPerFrame = ((mpegID == MPEG1_ID) || (layerID == LAYER2_ID)) ? 1152 : 576;
            bytesPerSlot = 1;
        }
        frameSize = ((bitrateKBPS * 125) * samplesPerFrame) / samplingrateHz;
        if (bytesPerSlot > 1)
            frameSize -= frameSize % bytesPerSlot;
        if (padding)
            frameSize += bytesPerSlot;
    }
}

2 个答案:

答案 0 :(得分:0)

Here is详细解释了帧和数据如何保存在标题中,即帧的前4个字节。 我不确定你要完成什么,但为了以防万一,here you go。重新发明轮子毫无意义。

.Net有一个名为BitArray的类,您可以使用它来存储您的位。

答案 1 :(得分:0)

我遇到过一个类似的项目,它使用一个函数将位转换为字符串。我已将此代码与另一个示例相结合,我发现将二进制字符串更改为整数。有兴趣听说其他方法吗?

Public Function BinaryToInteger(ByVal objBitArray As BitArray, ByVal intStart As Integer, ByVal intEnd As Integer) As Integer

    Dim BinaryString As String
    Dim BinaryNum As Integer
    Dim BitCount As Short

    BinaryString = ""

    For i As Integer = intStart To intEnd
        BinaryString &= IIf(objBitArray.Item(i), "1", "0")
    Next

    For BitCount = 1 To Len(BinaryString)
        BinaryNum = BinaryNum + (CDbl(Mid(BinaryString, Len(BinaryString) - BitCount + 1, 1)) * (2 ^ (BitCount - 1)))
    Next BitCount

    BinaryToInteger = BinaryNum

End Function