使用 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));
不幸的是 .parse
是 Tag
的受保护方法。我尝试继承并创建一个内部调用 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());
我有一组音频文件(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));
不幸的是 .parse
是 Tag
的受保护方法。我尝试继承并创建一个内部调用 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());