使用 TagLib 从 char* 缓冲区解析 ID3v2

Parsing ID3v2 from char* buffer using TagLib

我有一组音频文件(DSDIFF,specification),有人在其中附加了一个 ID3v2 标签。这不符合文件的标准,因此标准 ID3v2 解析器(如 TagLib)无法识别音频文件并拒绝解析它。 (为什么做这样的非标准的东西看起来是个好主意我不明白。)

我可以手动解析文件并提取原始 ID3 标签(作为 char* + size);但是,我不确定如何从这里开始获取原始标签内各个帧的值。

我想用TagLib来解析char*,但是我从来没有用过这个库。我也可以使用其他库。我不想从头开始编写自己的解析器。

这是我目前尝试过的方法:

尝试 1

auto file_name = std::filesystem::path("location/of/audio.dff");
auto file_stream = std::fstream(file_name);

// ... parsing the DSDIFF section of the file
// until I encounter the "ID3 " chunk.

auto id3_start = file_stream.tellg();
TagLib::FileRef taglib_file(file_name.string().cstr());

// when executing, taglib_file.isNull() evaluates to true
if (taglib_file.isNull()) 
    std::cerr << "TagLib can't read the file." << std::endl;

auto tag = TagLib::ID3v2::Tag(taglib_file.file(), id3_start);
// ... handle the tag

这种方法行不通,因为TagLib 不知道如何解析DSDIFF 格式。结果,taglib_file 是一个 NULL 指针,没有读取标签。

尝试 2

auto file_name = std::filesystem::path("location/of/audio.dff");
auto file_stream = std::fstream(file_name);

// ... parsing the DSDIFF section of the file
// until I encounter "ID3 ".
// read the size of the tag and store it in `size`

char* id3tag = new char[size];
file_stream.read(buff, size);

// How to parse the id3tag here?

paddy 建议使用

auto tag = TagLib::ID3v2::Tag().parse(TagLib::ByteVector(buff, size));

不幸的是 .parseTag 的受保护方法。我尝试继承并创建一个内部调用 parse 的瘦包装器 from_buffer,但这也不起作用。

非常感谢您的建议:)


我知道是否有类似问题:

但是,那里的答案是“只需为您的文件类型使用特定的解析器”。在我的例子中,这个解析器不存在,因为文件类型实际上不支持 ID3 标签;反正有人只是附加了它们。

如果您已经能够提取 ID3 数据,则将其放入 a/make 和 IOStream,然后您可以将其交给 TagLib 的 File 构造函数。或者将它存储在一个单独的(临时)文件中,让 TagLib 访问它。我自己从未使用过它,但如果它需要 MPEG 数据来识别任何 ID3 标签,我会感到惊讶(毕竟这些标签总是位于文件的开头或结尾,而无需解析任何音频数据)。

您要提供的示例文件应该很小 - 我们 none 需要音频数据,只需要 ID3 数据(前后可能有 50 个字节)。即便如此,ID3v2 内容仍然无关紧要 - 它的前 30 个字节应该足以进行演示 - 并且可以像这样轻松打印:\x49\x44\x33\x03...

AmigoJack 让我走上了正确的道路,找到了解决方案。虽然 TagLib::File 是一个抽象 class 并且不能直接实例化,但是可以使用现有的文件格式特定解析器之一。可以创建一个只包含 ID3 标签的文件并使用 MPEG 解析器读取它。

这里是相关的代码片段:

// ... parse the DSDIFF file and convert the data into FLAC format
// until ID3 tag

const struct {
    int length; // number of bytes in ID3 tag
    char* data; // filled while parsing the DSDIFF file
} *id3_data;

const auto data = TagLib::ByteVector(id3_data->data, id3_data->length);
auto stream = TagLib::ByteVectorStream(data);
auto file = TagLib::MPEG::File(&stream, TagLib::ID3v2::FrameFactory::instance());

/* copy all supported tags to the FLAC file*/
flac_tags.tag()->setProperties(file.tag()->properties());