从多个视频中提取元数据

问题描述:

我面临的挑战需要bash的多个方面。我在Linux上工作(正是Debian Stretch)。这里的情况(所有点/问题,我沿着我认为对于现在的解决办法写,但我接受其他的想法):从多个视频中提取元数据

  • 我有多种类型(以及各种上下案例视频),如.mp4,.mov,.MOV,.MP4,.avi,...位于一个目录中(并遍布在一个几乎没有结构的目录树中)。为了找到所有我试图使用find命令

  • 对于每个视频,我需要提取一些元数据(即文件的名称,视频的持续时间,文件大小和创建日期/上次修改)。包mediainfo产生(在很多其他事情中)所需的字段。 mediainfo的输出格式为:<Tag>\t : <value>。我需要提取字段的值完整名称,持续时间,文件大小编码日期

  • 因此,所有这些信息,我必须过滤所需的字段值,并把它们放入一个CSV文件。我考虑使用sed

我的目标是通过脚本或少量单独的命令实现所有这些任务。

的想法代码(这个代码是令人发指的错,但你可以得到一个想法):

find . -type f -name "*.[mp4|MP4|mov|MOV|avi|AVI]" -exec mediainfo {} | sed '/Complete name|Duration|File size|Encoded date/p' > myfile.csv \;

请问您有什么想法如何执行这项任务?我觉得结合发现,执行和sed和输出到csv感到非常失落...

在此先感谢您的帮助!

+0

你知道吗,那个'mediainfo' [有](http://manpages.ubuntu.com/manpages/precise/man1/mediainfo.1.html)'--output = XML'参数?也许这会更容易解析XML甚至使用它而不是CSV?为了使用xml,你可以使用[xmllint](http://xmlsoft.org/xmllint.html)。 – grundic

+0

不知道,它可能确实更容易解析。谢谢。 – Battleman

所以我终于设法编写了一个脚本。可能不是最好的办法,但在这里它是:

resFile="myresult.csv" 
dstDir="./destination/" 
srcDir="./source/" 

#first copy all files at same level in dstDir (with preserve and update) 
#this is somehow necessary, relative name for MOV files and mediainfo 
#do not seem to work together. 
find $srcDir -type f \(-name "*.mp4" -o -name "*.mov" -o -name "*.MOV" -o -name "*.avi" \) -exec cp -up {} $dstDir \; 

#then for each file, output mediainfo of file and keep only interesting tags. add ### between each file. 
find $dstDir -type f \(-name "*.mp4" -o -name "*.mov" -o -name "*.MOV" -o -name "*.avi"\ 
    -exec sh -c " mediainfo --Output=XML {} | sed '1,15!d;/Duration\|Complete\|File_size\|Encoded_date/!d' >> $resFile && echo '########' >> $resFile" \; 

#removes tags : <Duration>42s 15ms</Duration> -> 42s 15ms 
sed -i 's/^<.*>\(.*\)<.*>/\1/I' $resFile 

#Extract exact filename (and not relative) 
sed -i 's/^\.\/.*\/\(.*\)\.[mp4|MOV|mov|avi|MP4]/\1/' $resFile 

#Puts fields for a file on a unique line separated with commas 
sed -i 'N;s/\n/,/;N;s/\n/,/;N;s/\n/,/;N;s/\n/,/' $resFile 

#remove all trailing ### 
sed -i 's/,#*$//' $resFile 

我仍然有兴趣,如果任何人有想法,以改善代码。 我“最小化”了一点,我的实际代码是一个更模块化,并执行一些检查

试试这个。由于时间较少,我无法完成。您只需将输出发送到CSV。

for c in $(locate --basename .mp4 .mkv .wmv .flv .webm .mov .avi) 

do 

Complete_name=$(mediainfo --Output=XML $c | xml_grep 'Complete_name' --text_only| awk 'BEGIN{FS="/"}{print $NF}') 

    echo $Complete_name 

Duration=$(mediainfo --Output=XML $c | xml_grep 'Duration' --text_only --nb_result 1) 

    echo $Duration 

File_size=$(mediainfo --Output=XML $c | xml_grep 'File_size' --text_only) 

echo $File_size 

Encoded_date=$(mediainfo --Output=XML $c | xml_grep 'Encoded_date' --text_only -nb_result 1 | awk '{print $2}') 

echo $Encoded_date 

done 
+0

看起来不错。我需要一些时间来深入了解并修正一些细节,但看起来效率很高。谢谢。 – Battleman