Handbrake 是一款很棒的视频压缩工具,但它似乎在视频压缩后无法保留原始捕获时间。有没有什么办法可以解决这个问题?
答案1
您可以将现有元数据从一个文件复制到另一个文件,而无需使用以下方法重新编码视频FFmpeg。基本上只需要一秒钟。为此,我们假设有三个文件:
in.mp4
– 转换前的原始文件out.mp4
– Handbrake 转换后的文件fixed.mp4
– 具有“更正”元数据的文件
将完整的元数据记录复制到新文件的 FFmpeg 命令将是:
ffmpeg -i in.mp4 -i out.mp4 -map 1 -map_metadata 0 -c copy fixed.mp4
语法解释:
具体来说,这将执行以下操作:
- 取两个输入文件(
in.mp4
和out.mp4
),分别分配有 ID 0 和 1。 - 仅将文件 1 中的视频/音频/字幕流映射到输出(
-map 1
),因此我们采用已转换的比特流 - 仅将文件 0 中的元数据映射到输出 (
-map_metadata 0
) - 使用复制编解码器(
-c copy
)复制所有比特流,而不是重新编码视频。
此后,您显然可以重命名fixed.mp4
为out.mp4
。
证明:
举个例子,这是我的原始文件的元数据记录的一部分:
$ mediainfo in.mp4 | grep "Encoded date" | head -n 1
Encoded date : UTC 2012-01-08 11:16:19
这是 Handbrake 转换后的文件:
$ mediainfo out.mp4 | grep "Encoded date" | head -n 1
Encoded date : UTC 2012-12-24 11:39:35
这是映射元数据后的最终文件:
$ ffmpeg -i in.mp4 -i out.mp4 -map 1 -map_metadata 0 -c copy fixed.mp4
[…]
$ mediainfo fixed.mp4 | grep "Encoded date" | head -n 1
Encoded date : UTC 2012-01-08 11:16:19
如果您想使用 FFmpeg 完成所有操作:
实际上,如果您可以使用 FFmpeg,您实际上并不需要使用 Handbrake,因为 Handbrake 无论如何都依赖它。在最简单的情况下,您可以像这样进行转换:
ffmpeg -i in.mp4 -c:v libx264 -crf 23 -c:a aac -map_metadata 0 out.mp4
这会将带有 x264 编码器和 AAC 音频的输入转换为输出文件,并复制原始元数据。为了更改输出的质量,您可以:
- 更改视频的 CRF 值。值越低表示质量越好。23 是默认值,低于 18 的任何值可能在视觉上无损。
- 更改音频的比特率。请参阅AAC 编码指南了解更多信息。
阅读x264 编码指南更多详情请参阅 FFmpeg wiki。
答案2
不幸的是,handbrake 似乎无法自行完成此操作,但与 ffmpeg 示例类似,可以使用touch
unix 命令在压缩后从原始文件复制时间戳:
touch -r MVI_1234.MOV compressed_MVI_1234.m4v
这会将压缩文件上的时间戳设置为与给定的参考文件相同。
答案3
答案4
我制作了一个可以批量传输元数据的 bash 脚本,使用方法touch
如上所述。要使其工作,您必须将原始文件和转换后的文件放在不同的目录中,每个目录的文件数量相同(目录必须只有视频文件,因为其他文件/目录会干扰)且顺序相同。然后它只需复制元数据,您就大功告成了。脚本列出了所有文件对,因此您可以在最后检查错误(如果您愿意)。
由于这是我的第一个正确的 bash 脚本,因此该代码可能不是最简洁的,但对我来说它非常快且稳定,因此如下所示:
#!/bin/bash
#Sets IFS to \n to allow for filenames with spaces
IFS=$'\n'
#Source directory and converted direcotry
dir1=$1
dir2=$2
#Array with source filepaths
srcf=()
#Array with converted filepaths
cnvf=()
#Adds filepaths from the source directory to srcf array
for file in $(ls -1 $dir1); do
srcf+=("$dir1/$file")
done
#Adds filepaths from the converted directory to cnvf array
for file in $(ls -1 $dir2); do
cnvf+=("$dir2/$file")
done
#Checks if source and convert folders have the same number of files
if [ ${#srcf[*]} -eq ${#cnvf[*]} ]
then
#Counter variable
fnum=0
#Loops through the arrays and runs touch command on pairs of files to transfer the metadata
while [ $fnum -lt ${#srcf[*]} ]; do
echo $fnum
echo ${srcf[$fnum]} ${cnvf[$fnum]}
touch -r ${srcf[$fnum]} ${cnvf[$fnum]}
((fnum++))
done
else
echo "The provided paths do not have the same number of files. Both paths must have the same number of files in the same order."
fi
运行如下:sudo bash script.sh /sourcedir /converteddir