两个时间码相减

两个时间码相减

我需要将两个时间代码相减,数组中有多个时间代码,输出如下所示:

**Input:**
echo ${arr3[0]}
echo ${arr3[1]}

**Output:**    
00:00:22.180 --> 00:00:25.600
00:00:24.070 --> 00:00:27.790

在此示例中,需要使用以下等式00:00:25.600 - 00:00:22.180 = output into array,并且00:00:27.790 - 00:00:24.070 = output into the same array它需要采用相同的格式,以便可以在 FFMPEG 中使用它。

我还需要每个数组条目的第一个时间码,因此:

00:00:22.180 
00:00:24.070

在另一个数组中,这样我也可以在 ffmpeg 中使用这些输入。

编辑:

我将按如下方式使用数据

time=$(The first timecode of the array)
duration=$(Timecodes subtracted)

ffmpeg -i movie.mp4 -ss $time -t $duration -async 1 cut.mp4 

答案1

给定一个包含样本数据的数组 arr3:

declare -a arr3=([0]="00:00:22.180 --> 00:00:25.600"
                 [1]="00:00:24.070 --> 00:00:27.790")

您可以循环遍历数组中的每个元素,去掉开始时间和结束时间,将它们转换为小数秒,计算持续时间,然后将该持续时间转换回 ffmpeg 命令的 hh:mm:ss.sss 格式。

# converts HH:MM:SS.sss to fractional seconds
codes2seconds() (
  local hh=${1%%:*}
  local rest=${1#*:}
  local mm=${rest%%:*}
  local ss=${rest#*:}
  printf "%s" $(bc <<< "$hh * 60 * 60 + $mm * 60 + $ss")
)

# converts fractional seconds to HH:MM:SS.sss
seconds2codes() (
  local seconds=$1
  local hh=$(bc <<< "scale=0; $seconds / 3600")
  local remainder=$(bc <<< "$seconds % 3600")
  local mm=$(bc <<< "scale=0; $remainder / 60")
  local ss=$(bc <<< "$remainder % 60")
  printf "%02d:%02d:%06.3f" "$hh" "$mm" "$ss"
)

subtracttimes() (
  local t1sec=$(codes2seconds "$1")
  local t2sec=$(codes2seconds "$2")
  printf "%s" $(bc <<< "$t2sec - $t1sec")
)

declare -a arr3=([0]="00:00:22.180 --> 00:00:25.600"
                 [1]="00:00:24.070 --> 00:00:27.790")

for range in "${arr3[@]}"
do
  duration=$(subtracttimes "${range%% -->*}" "${range##*--> }")
  printf "%s\n" "ffmpeg -i movie.mp4 -ss ${range%% -->*} -t $duration -async 1 cut.mp4"
done

codes2seconds函数需要 HH:MM:SS.sss 格式的输入;它使用参数扩展去除各种元素,然后将它们传递给bc转换为总秒数。

seconds2codes函数需要秒的小数部分并反转转换,从而产生 HH:MM:SS.sss 字符串。

subtracttimes函数将两个参数转换为秒的小数部分,然后询问bc它们的差异。

最后的循环遍历arr3的每个元素;它使用上述函数来计算持续时间(再次使用参数扩展来检索两次),然后打印出一个示例ffmpeg调用以匹配您的示例输出。

结果:

ffmpeg -i movie.mp4 -ss 00:00:22.180 -t 3.420 -async 1 cut.mp4
ffmpeg -i movie.mp4 -ss 00:00:24.070 -t 3.720 -async 1 cut.mp4

答案2

嗯,因为时间代码date通常会出现在我的脑海中。不是最优雅的脚本,但它完成了工作......

我从你的问题中假设,你已经将开始时间和结束时间读入各自的数组中,并将在此处使用startend作为这些值并逐步执行:

#!/bin/bash

start=00:00:22.180
end=00:00:24.070

#convert timestamps to epoch time in nano seconds
start_ns="$(date -u -d"$start" +%s%N)"
end_ns="$(date -u -d"$end" +%s%N)"

difference="$(($end_ns-$start_ns))"

#date does not read epoch time in nanoseconds, 
#so it must be converted by division vith 10^9 before display
#date_diff is accurate up to full seconds
#use UTC time (-u) to avoid problems with time zones

date_diff="$( date -u -d@$((difference/1000000000)) +%H:%M:%S )"

#take care of milliseconds as remainder of division by 10^9 and correction by 10^6
ms_diff="$(( $difference%1000000000/1000000 ))"

#combine output to create desired format

echo "$date_diff"."$ms_diff"

结果

bash script.sh
00:00:01.890

全部排成一行

echo "$(date -u -d@"$(( ($(date -u -d"$end" +%s%N) - $(date -u -d"$start" +%s%N))/1000000000 ))" +%H:%M:%S)"."$(( ($(date -u -d"$end" +%s%N) - $(date -u -d"$start" +%s%N))%1000000000/1000000 ))"

请注意,我不知道纳秒时间是否date是 POSIX 标准功能。

相关内容