1

我正在编写一些快速代码来尝试从 mp3 文件头中提取数据。

目标是从标头中提取信息,例如比特率和其他重要信息,以便我可以适当地将文件流式传输到带有必要参数的 mp3decoder。

这是显示 mp3header 信息的维基百科图像:http: //upload.wikimedia.org/wikipedia/commons/0/01/Mp3filestructure.svg

我的问题是,我是否正确地攻击了这个?打印收到的数据毫无价值——我只是得到一堆随机字符。我需要获取二进制文件,以便对其进行解码并确定重要信息。

这是我的基线代码:

// mp3 Header File IO.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"

// Main function
int main (void)
{
    // Declare variables
    FILE *mp3file;
    char *mp3syncword; // we will need to allocate memory to this!!
    char requestedFile[255] = "";
    unsigned long fileLength;

    // Counters
    int i;

    // Memory allocation with malloc
    mp3syncword=(char *)malloc(2000);

    // Let's get the name of the requested file (hard-coded for now)
    strcpy(requestedFile,"testmp3.mp3");

    // Open the file with mode read, binary
    mp3file = fopen(requestedFile, "rb"); 
    if (!mp3file){
         // If we can't find the file, notify the user of the problem
         printf("Not found!");
    }

    // Let's get some header data from the file
    fseek(mp3file,1,SEEK_SET);
    fread(mp3syncword,32,1,mp3file);

    // For debug purposes, lets print the received data
     for(i = 0; i < 32; ++i)
        printf("%c", ((char *)mp3syncword)[i]);
    enter code here
    return 0;
}

帮助表示赞赏。

4

3 回答 3

1

您正在使用%c格式说明符打印字节。您需要使用无符号数字格式说明符(例如%u十进制数或%x十六%X进制)来打印字节值。

您还应该声明您的字节数组,unsigned char因为它们在 Windows 上是默认签名的。

您可能还想在每个字节值之后打印一个空格(或其他分隔符)以使输出更清晰。

该标准printf不提供二进制表示类型说明符。一些实现确实有这个,但 Visual Studio 提供的版本没有。为了输出这个,您需要对数字执行位操作以提取各个位并为每个字节依次打印每个位。例如:

unsigned char byte = // Read from file
unsigned char mask = 1; // Bit mask
unsigned char bits[8];

// Extract the bits
for (int i = 0; i < 8; i++) {
    // Mask each bit in the byte and store it
    bits[i] = (byte & (mask << i)) >> i;
}

// The bits array now contains eight 1 or 0 values
// bits[0] contains the least significant bit
// bits[7] contains the most significant bit
于 2009-11-05T10:03:24.180 回答
1

C 没有printf()以二进制形式打印的说明符。大多数人用十六进制打印,这将给你(通常)一次八位:

printf("the first eight bits are %02x\n", (unsigned char) mp3syncword[0]);

您将需要手动解释这一点以找出各个位的值。对论点的强制转换unsigned char是为了避免在它是否定的情况下出现意外。

要测试位,您可以将&运算符与按位左移运算符一起使用<<

if(mp3syncword[2] & (1 << 2))
{
  /* The third bit from the right of the third byte was set. */
}

如果您希望能够对位使用“大”(大于 7)索引,即将数据视为 32 位字,则最好将其读入例如 anunsigned int中,然后对其进行检查。但是,当你阅读时要小心字节序。

于 2009-11-05T10:40:15.420 回答
1

警告:这种方法可能存在内存布局和/或字节序错误。不保证结构成员在计算机之间匹配相同的位。
简而言之:不要依赖这个(我会留下答案,它可能对其他东西有用)

您可以使用位字段定义结构:

struct MP3Header {
    unsigned SyncWord : 12;
    unsigned Version : 1;
    unsigned Layer : 2;
    unsigned ErrorProtection : 1;
    unsigned BitRate : 4;
    unsigned Frequency : 2;
    unsigned PadBit : 1;
    unsigned PrivBit : 1;
    unsigned Mode : 2;
    unsigned ModeExtension : 2;
    unsigned Copy : 1;
    unsigned Original : 1;
    unsigned Emphasis : 2;
};

然后将每个成员用作隔离值:

struct MP3Header h;
/* ... */
fread(&h, sizeof h, 1, mp3file); /* error check!! */
printf("Frequency: %u\n", h.Frequency);
于 2009-11-05T10:47:12.120 回答