Hachoir - 从组中获取数据

4 投票
2 回答
1593 浏览
提问于 2025-04-17 13:49

我在尝试用Hachoir从一个视频文件中提取元数据。整体上运行得还不错,但在用'get'或者类似的方法获取宽度和高度的时候遇到了一些问题。

我原本以为可以这样做:

metadata.get('width') 

但是这样会报错(对象没有'width'属性)。

当我运行以下代码时:

for data in sorted(metadata):
    if len(data.values ) > 0:
        print data.key, data.values[0].value

返回的只有“Common”组的信息。

而当我使用:

metadata.exportPlaintext 

...则返回了“Common”、“视频流”和“音频流”的信息。我可以简单地遍历返回的'text'项,提取出高度和宽度的值,但我更想用metadata.get('width')或者类似的方法来正确获取这些信息。

查看源代码后,我以为可以使用以下代码:

for key, metadata in metadata.__groups.iteritems():

来遍历元数据中的._groups,但这时却报了一个错误:“'AsfMetadata'对象没有属性'_groups'”,我觉得这不应该是这样,因为我以为'AsfMetadata'是MultipleMetadata()的一个子类,而后者确实有这个变量。

可能我漏掉了一些很明显的东西。

2 个回答

4

要从媒体文件中获取第一个顶层元数据组的 宽度 x 高度 信息,而不去访问私有属性,也不解析文本输出,你可以使用 file_metadata.iterGroups() 方法:

#!/usr/bin/env python
import sys
from itertools import chain

# $ pip install hachoir-{core,parser,metadata}
from hachoir_core.cmd_line import unicodeFilename
from hachoir_metadata import extractMetadata
from hachoir_parser import createParser

file_metadata = extractMetadata(createParser(unicodeFilename(sys.argv[1])))
it = chain([file_metadata], file_metadata.iterGroups())
print("%sx%s" % next((metadata.get('width'), metadata.get('height'))
                     for metadata in it
                     if metadata.has('width') and metadata.get('height')))

如果你想把 metadata 转换成字典(不递归,也就是说,如果需要的话手动遍历组):

def metadata_as_dict(metadata):
    return {item.key: (len(item.values) > 1 and 
                       [v.value for v in item.values] or
                       item.values[0].value)
            for item in metadata if item.values}
4

对于WMV文件,这个事情看起来就没那么简单了。我把这些视频的元数据变成了一个defaultdict,现在获取图片的宽度就简单多了:

from collections import defaultdict
from pprint import pprint

from hachoir_metadata import metadata
from hachoir_core.cmd_line import unicodeFilename
from hachoir_parser import createParser

# using this example http://archive.org/details/WorkToFishtestwmv
filename = './test_wmv.wmv' 
filename, realname = unicodeFilename(filename), filename
parser = createParser(filename)

# See what keys you can extract
for k,v in metadata.extractMetadata(parser)._Metadata__data.iteritems():
    if v.values:
        print v.key, v.values[0].value

# Turn the tags into a defaultdict
metalist = metadata.extractMetadata(parser).exportPlaintext()
meta = defaultdict(defaultdict)
for item in metalist:
    if item.endswith(':'):
        k = item[:-1]
    else:
        tag, value = item.split(': ')
        tag = tag[2:]
        meta[k][tag] = value

print meta['Video stream #1']['Image width'] # 320 pixels

撰写回答