2

我在编写脚本以使用诱变剂标记我的音乐库时遇到问题。以下代码在处理 mp3 文件时工作正常,但会损坏 m4a 文件。

def set_video_tags(video, filepath):
    try:
        tags = ID3(filepath, v2_version=3)
    except ID3NoHeaderError:
        tags = ID3()

    tags.add(TXXX(3, desc='desc:custom_tag',text= video.custom_text))
    tags.save(filepath, v2_version=3)

处理完 m4a 文件后,可以使用 mutagen 回读标签,但其他播放器不会检测到标签,并且不会播放音频。

在调用此函数之前,我尝试从文件中删除 MP4 标签,但没有帮助。

我究竟做错了什么?

4

1 回答 1

9

正如我在评论中所说,MP4 和 MP3 是不同的容器,它们使用完全不同的结构来存储元数据。虽然从技术上讲,您可以在 MP4 元数据中对 ID3 字段进行编码,但这些字段的使用在很大程度上取决于您的标注器/播放器,因为有很多方法可以做到这一点,而且每个人都认为他们有最好的方法,从而推动他们自己的结构。

MP3 容器的 ID3 是什么,XMP用于 MP4/M4A 容器(如果您愿意,还可以用于许多其他容器,如 JPEG、PDF 甚至 MP3)——除了 XMP 是一个实际标准,而 ID3 是事后才想到的(字面意思是只是在 MP3 文件末尾添加的尾随结构),每个人都同意,它的功能主要由当时流行的播放器如 WinAmp、foobar2000 等决定。相比之下,XMP 本质上是一个类似 atom-feed 的结构(这就是为什么你会听到 mp4 标签被称为“原子”,即使它们不是指同一个东西),它连同它的元数据还携带着什么信息元数据呈现的如此之多,即使是第一次遇到它的玩家,理论上也可以从不相关的元数据中辨别出相关的。

当然,在实践中,这也变成了玩家/标签者之战,因此他们中的许多人使用自己的自定义“扩展”进行标签 - 目前 iTunes 对应该使用哪些字段以及如何使用以及其他玩家有很大的影响力 -打球-也是如此mutagen。iTunes 将标签作为非视频/音频帧(实际的“原子”)传播到 MP4 结构本身中,而不是单个 XMP 结构,并且某些“标签”必须以奇怪的名称命名(二进制名称等),因此它们不会t 干扰格式本身。虽然这种方法有一些优势(使用流媒体更改元数据,这对实时事件非常有用),但它使标记变得不必要地复杂,并且再次成为非标准的。

无论如何,您的问题发生是因为您试图将 ID3 结构写入 MP4 容器 - 当写入 ID3 标签时mutagen不会解析整个文件以辨别底层文件是否支持 ID3 以及在哪里/如何写入它,而是假设它被输入了一个普通的 MP3 文件,并在错误的地方以错误的格式写下了,充其量只是在文件末尾添加一些垃圾(早期的、不可流式传输的 ID3 版本),或者最坏的情况是破坏你的 M4A结果是容器。当您读回文件时也是如此 - 它可以在可预测的位置读取它之前写入的 ID3 结构,它不关心其余数据是什么。

因此,正如我所说的,正如文档中所示,在处理 MP4/M4A 容器时使用mutagen.mp4.MP4(或更确切地说是底层),因为这些容器是为使用 MP4 容器而创建的。mutagen.mp4.MP4Tags例如,要在desc您尝试时更改标签:

from mutagen.mp4 import MP4

def get_description(filename):
    return MP4(filename).tags.get("desc", [None])[-1]

def set_description(filename, description):
    tags = MP4(filename).tags
    tags["desc"] = description
    tags.save(filename)

注意:我只使用函数中的最后一个desc条目,get_description()因为每个“标签”支持多个条目,因此现有标签作为列表返回。您显然不会在生产环境中使用上述内容。

您可以使用以下方法对其进行测试:

print("Current description: {}".format(get_description("test.m4a")))
# Current description: None

set_description("test.m4a", "Test description")  # let's add some description
print("Current description: {}".format(get_description("test.m4a")))
# Current description: Test description

# You can also modify the description once set:
set_description("test.m4a", get_description("test.m4a") + " update")
print("Current description: {}".format(get_description("test.m4a")))
# Current description: Test description update

# etc.

对于完整的“支持”(或者更确切地说是 iTunes,嗯,鼓励)键,您可以查看mutagen.mp4.MP4Tag文档。当然,您可以使用自由形式的结构(即----:foo:bar)发明自己的密钥,但不要指望任何其他玩家能够识别它们。

于 2017-07-04T12:49:48.803 回答