Subtrair dois códigos de tempo

0

Eu preciso subtrair dois códigos de tempo um do outro, tenho vários em uma matriz e a saída é assim:

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

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

Neste exemplo, a seguinte equação precisa ocorrer 00:00:25.600 - 00:00:22.180 = output into array e 00:00:27.790 - 00:00:24.070 = output into the same array Ela precisa estar no mesmo formato para poder usá-la no FFMPEG.

Eu também preciso do primeiro timecode de cada entrada de array, então:

00:00:22.180 
00:00:24.070

em outra matriz, para que eu possa usar essas entradas no ffmpeg também.

EDITAR:

Vou usar os dados da seguinte forma

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

ffmpeg -i movie.mp4 -ss $time -t $duration -async 1 cut.mp4 
    
por tjallo 26.02.2018 / 17:14

2 respostas

1

Dado um array arr3 que contém dados de amostra:

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

Você pode percorrer cada elemento na matriz, remover a hora de início e a hora de término, convertê-los em segundos fracionários, calcular a duração e, em seguida, converter a duração de volta no formato hh: mm: ss.sss para o comando ffmpeg .

# 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

A função codes2seconds espera entrada no formato HH: MM: SS.sss; elimina os vários elementos usando a expansão de parâmetro e passa-os para bc para a conversão em número total de segundos.

A função seconds2codes espera um número fracionário de segundos e inverte a conversão, resultando em uma string HH: MM: SS.sss.

A função subtracttimes converte os dois parâmetros em segundos fracionários e depois pergunta bc pela diferença.

O loop no final passa por cada elemento de arr3; ele usa as funções acima para calcular a duração (novamente usando a expansão de parâmetro para recuperar as duas vezes) e depois imprime uma amostra de ffmpeg para corresponder à sua saída de amostra.

Resultados:

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
    
por 27.02.2018 / 03:00
1

Bem, para os códigos de tempo date costumam aparecer em minha mente. Não é o roteiro mais elegante, mas faz o trabalho ...

Parto da sua pergunta que você já tem horários de início e de término lidos nos respectivos arrays e usará start e end como esses valores aqui e faça isso passo a passo:

#!/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"

Resultado

bash script.sh
00:00:01.890

Tudo em uma linha

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 ))"

Por favor, note que eu não sei se o tempo de nanossecond em date é um recurso padrão POSIX.

    
por 26.02.2018 / 18:40