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

发布于 2024-12-22 08:31:56 字数 3482 浏览 7 评论 0原文

我正在学习 Visual Basic .net,并尝试将一些 Java 源代码转换为 vb.net 项目。该项目读取 mp3 详细信息,然后根据帧头详细信息等准确分割文件。

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

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

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

我看过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 位。 读取 mpegID 值的位 13。 读取第 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;
    }
}

I am learning visual basic .net and I am attempting to translate some java source code to a vb.net project. The project reads mp3 details and then splits the file accurately according to the frameheader details etc.

My question relates to reading the frame header of mp3 files. I understand that the frame details are contained in the first 4 (32-bits) bytes of a frame and certain bits represent certain values as detailed here: http://www.mp3-tech.org/programmer/frame_header.html

Using FileStream I have been able to read this data and display it in binary within a text box.

I am looking for help on reading the bits and assigning them to variables within my class. I am not sure what would be the correct procedure to do this as some values as 1, 2 or 4 bits in length e.g. bits 19-20 = MpegType, bits 12-15 = BitrateIndex, bit 9 = Padding etc.

I have looked at similar projects available on codeproject.com but I do not understand how they have achieved the above.

Any help is much appreciated.

EDIT:

Here is the main sub so far, I have not included the code declaring variables and properties etc.

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

When this is run the output in the rich text box is as follows:

11111111
11111010
10110011
01001100

I want to read through these bits and assign the appropriate values to the variables e.g.

Read the first 12 bits for sync value.
Read bit 13 for mpegID value.
Read bit 14 and 15 for layerID value etc.

Hope that is clearer.

The java code is as follows:

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;
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

沉睡月亮 2024-12-29 08:31:56

这里详细解释了帧以及如何在标头(前 4 个字节)中保存数据的公式的一个框架。
我不确定你想要完成什么,但为了以防万一,给你。重新发明轮子是没有意义的。

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

Here is a detailed explanation of frames and a formula on how data is held in the header, the first 4 bytes of a frame.
I am not sure what you are trying to accomplish but, just in case, here you go. There is no point in reinventing the wheel.

.Net has class called BitArray that you would use to store your bits.

红ご颜醉 2024-12-29 08:31:56

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

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

I have come across a similar project that uses a function to converts bits to string. I've combined this code with another example I found that changed a binary string to integer. Interested to hear of alternative methods?

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文