使用最小重新编码的方式,使用FFMPEG添加覆盖层

11

FFMPEG非常适用于剪辑视频,而无需重新编码整个视频。

我知道也可以使用FFMPEG将覆盖图像添加到视频中,在视频的某个部分(例如从10秒到20秒)。

我的问题是:如果我执行这种图像叠加操作,是否会因此重新编码整个视频?还是只编码相关时长部分的视频?

此外,是否有任何选项可以尽可能减少重新编码的数量?
当然目的是保持视频的质量,就像原始视频一样..
(我希望完全不需要重新编码,但我不知道是否可能...)

谢谢


3
过滤时整个视频将会被重新编码。 - aergistal
2
可能能够在不重新编码的情况下进行分割,仅将覆盖层添加到相关片段,然后将所有内容连接起来。根据关键帧的位置,您可能无法在10秒和20秒标记之间精确切割。请尝试访问http://video.stackexchange.com/。 - aergistal
1
那是一个有趣的(肯定会奏效)想法。关于“取决于您的关键帧位置,您可能无法在10秒和20秒标记之间精确切割。” - 有没有办法让我给FFMPEG一个视频文件,并让它为我列出所有作为新“数据包”(或称为几秒钟段)的时间点?这样我就可以尝试计划在一个结束和另一个开始时进行精确切割... - spaceman
是的,您可以使用相同软件包中的 ffprobe 来显示数据包并搜索关键帧时间戳 ffprobe -show_packets -select_streams v <input>。另请参阅 ffmpeg 寻求 维基,它会有所帮助。 - aergistal
1
不是的。我的问题是关于将覆盖图像添加到视频中,而你链接的问题是将视频覆盖层添加到视频中。此外,我的问题是来自2015年,那里的不同问题是来自2016年。即使它是一个重复的问题,方向也是相反的,对吧? - spaceman
显示剩余3条评论
2个回答

3
整个视频将重新编码,如果您在其中一部分上叠加图像。避免重新编码整个视频的一种方法是剪辑出您希望叠加的部分,并仅重新编码该部分(请参见documentation中的-t duration开关和-ss position开关)。
在整个过程中,您将希望保持当前的编码参数不变。当拆分时,这很容易做到,因为您可以使用复制参数来进行编解码器切换,例如-c:a copy -c:v copy
为了概念化(请注意,这些不是完整的命令):

第一部分:电影的开头(前10秒,您不希望覆盖)(使用 ffmpeg -i SourceFileName -t 10 -c:a copy -c:v copy SourceFileNameP1.mkv 获取,其中SourceFileName是要处理的视频。 第二部分:电影的10至20秒之间您想要叠加的部分(使用 ffmpeg -i SourceFileName -ss 10 -t 10 -c:a copy -c:v copy SourceFileNameP2 获取) 第三部分:电影的结尾(使用`ffmpeg -ss 20 -c:a copy -c:v copy)

获取

额外提示:您可以通过将“-ss”参数移到输出文件之前来获得更慢但更准确的剪辑。这将从输出中删除帧,而不是在创建输出之前尝试寻找正确位置。

如果您不知道源文件的编码细节,您可以使用ffprobe SourceFileName或我的最爱mediainfo SourceFileName来获取它们。

由于其灵活性和低开销,我建议至少使用Matroska容器作为中间输出。

这里是一个脚本(适用于基于Debian的系统),您可以使用它来获取匹配所需参数的方式。

#!/bin/bash
#mknfo.sh
#Written by Elder Geek for the Stack Exchange network
# 1/1/2018 
####################################################################################################
#bash script to create an nfo file which includes information to help joining video clips          #
####################################################################################################
# This function will create an nfo file including the tech specs for a specified media file        #
####################################################################################################
function shortinfo {
   echo $@
      mediainfo --Inform="General;Duration=%Duration/String2%\nFile size=%FileSize/String1%\nBit Rate=%OverallBitRate/String% " "$@"
   echo -n "Video: "
   mediainfo --Inform="Video;FrameRate=%FrameRate/String% BitRate=%BitRate/String% Resolution=%Width%x%Height% Codec=%CodecID%" "$@";
    echo -n "Audio: "
   mediainfo --Inform="Audio;Mode=%BitRate_Mode/String% BitRate=%BitRate/String% Format=%Format%" "$@";
   echo "-----------------------------------------------------------------------------"
}
####################################################################################################
# This function will check for the existence of mediainfo and attempt installation if not found     #
####################################################################################################
function getmi {
   echo "mediainfo is required and not found. Attempt install Y/N"
   read -n 1 solve
    if [ $solve=={Yy} ]
    then sudo apt-get -y install mediainfo
    else echo "Cannot continue"
    exit 1
    fi
}
####################################################################################################
# Main program                                             #
####################################################################################################
if [ $# -ne 1 ] 
    then    
    echo Error 
    echo "$0" requires a single filename argument. Example: "$0" Videofile
    exit 2
fi
exist=$(which mediainfo)
    if [ "$exist" == "" ];
    then getmi
    fi
target=$(pwd)"/"$1".nfo"
    if [ -e $target ] 
    then 
    echo Error: "$1.nfo" already exists
    exit 3
    fi
echo "Creating $target"
        shortinfo "$1" > "$target"
    exit 0


Now you'll want to re-encode the overlay section (Part2) of the video to exactly match the parameters (same audio and video codecs and same bitrate and sample rate as the original of Part1 and Part3 to allow for joining.

完成后,您可以将所有部分组合在一起。 mkvmerge -o joined.mkv Part1 + Part2Reencoded + Part3 请注意,重新编码总会导致一些质量损失,因此部分之间的连接可能会显示可见缺陷。这可能会因覆盖同时出现和消失的代码所引起的干扰而有或没有被注意到。
这可能会显著减少重新编码时间,具体取决于素材的长度,并且具有仅重新编码必须重新编码的内容的附加好处。
如何叠加您重新编码的片段,请参阅此处,您可以调整接受的答案以匹配您的素材。

1
另一种方法是使用播放器:

ffplay -f lavfi "movie=main.mkv[bg];movie=logo.png[fg];[bg][fg]overlay=W-w-10:H-h-10:enable=between'(t,10,20)'[out0];amovie=main.mkv[out1]"

不需要编码。没有质量损失。即时满足。

如果我理解正确的话,由于您正在执行ffplay,这意味着叠加层仅显示在屏幕上,而不是以某种方式嵌入到文件中。我也希望文件中也能有所变化(只希望可以最小限度地重新编码)。 - spaceman
@spaceman 正确。问题中并没有明确需要将其永久成为视频的一部分,但也许这种方法对其他有一些奇怪用例的用户也有用。 - llogan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接