用于跟踪 ffplay 位置的 Bash 脚本

用于跟踪 ffplay 位置的 Bash 脚本

我希望能通过某种方式将 ffplay 的控制台输出传输到 bash 脚本,该脚本会解析它并隔离当前寻道时间并将该数字保存到文本文件(我可以将其放在 RAM 磁盘中)。这样我就可以获取该数字并将其用于我正在制作的临时快速编辑器,以便将立体 gopro 文件的粗略剪辑拼接在一起,而无需将所有内容导入到臃肿的编辑器中。到目前为止,我的脚本可以正常工作,它会读取包含文件名和时间戳列表的文件,但剪切和粘贴工作量很大

我可以轻松编写一个 bash 脚本来构建此列表,但我需要一种方法来在我按下其他脚本中的某个键时实时获取该数字

有人见过这样的事情吗?

即通过管道将 ffplay 传输到脚本,该脚本将 grep / awk / sed / perl 无论文件的帧时间是多少?

答案1

好的,我已经找到解决办法了。

这很粗糙,但足以向你展示我是怎么做的。

另外还有 ffprobe_parse 函数,您还可以使用它来解析 ffprobe 的输出,以获取持续时间和帧速率,它恰好与 ffplay 打印的相同信息格式相同,所以我将它包装在一个函数中以使该部分可重复使用。

#!/bin/bash

if [ ".$1" = "." ] ; then
    echo "usage 

$0 moviefilename "

    exit 0
fi

QUIET=0
MOVIE="$1"
NOW_STAMP="$MOVIE.stamp.txt"

function ffprobe_parse {

  VALID_STREAM=0

  while read LINE
  do
     WORDS=($LINE)
     CHECK=${WORDS[0]}
     #  Duration: 00:00:06.55, start: 0.008333, bitrate: 1068 kb/s
     if [ "$CHECK" = "Duration:" ] ; then


        IFS=',' read -ra PARSE_TEMP <<< "${WORDS[1]}"
        DURATION_HHMMSS="${PARSE_TEMP[0]}"


        IFS=':' read -ra HMS <<< "${DURATION_HHMMSS}"
        DURATION_HH="${HMS[0]}"
        DURATION_MM="${HMS[1]}"
        DURATION_SS="${HMS[2]}"

        DURATION_SECONDS=$(echo "($DURATION_HH * 3600.0) + ($DURATION_MM * 60.0) + $DURATION_SS" | bc)

        echo "$DURATION_SECONDS" > "$MOVIE.duration.txt"


        if [ "${WORDS[2]}" = "start:" ] ; then

            IFS=',' read -ra PARSE_TEMP <<< "${WORDS[3]}"
            PLAY_START_SECONDS="${PARSE_TEMP[0]}"
            DURATION_SECONDS_ADJUSTED=$(echo "($DURATION_SECONDS - $PLAY_START_SECONDS)" | bc)
            if [ $QUIET -eq 0 ] ; then

                echo "offset start seconds is $PLAY_START_SECONDS"

                echo  "Total play duration is $DURATION_SECONDS_ADJUSTED seconds - $DURATION_HHMMSS minus $PLAY_START_SECONDS seconds"

            fi
        else
            DURATION_SECONDS_ADJUSTED="$DURATION_SECONDS"
            if [ $QUIET -eq 0 ] ; then
                echo  "Total play duration is $DURATION_SECONDS_ADJUSTED seconds"
            fi
        fi 



     #    Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, smpte170m), 480x480, 1005 kb/s, 23.96 fps, 48.17 tbr, 600 tbn, 1200 tbc (default)
     elif [ "$CHECK" = "Stream" ] ; then

        VALID_STREAM=0
        IFS=' ' read -ra PARSE_TEMP <<< "${LINE}"

        for CHECK2 in "${PARSE_TEMP[@]}"; 
        do

            if [ "$CHECK2" = "Video:" ] ; then 
                VALID_STREAM=1
            else 
                if [ "$CHECK2" = "Audio:" ] ; then 
                    VALID_STREAM=0
                else
                    if [ "$CHECK2" = "fps," ] && [ $VALID_STREAM -eq 1 ] ; then 

                        FPS="$FPS_TEMP"
                        if [ $QUIET -eq 0 ] ; then
                            echo "detected stream fps: $FPS"
                        fi
                        break

                    fi
                fi

                FPS_TEMP="$CHECK2"
            fi

        done

        if [ $VALID_STREAM -eq 1 ] ; then 

            IFS= read -r -d $'\r' ignore 2> /dev/null
            break;  

        fi
     fi


   done

}

function ffplay_parse {


  ffprobe_parse

  if [ $QUIET -eq 0 ] ; then
    echo "playing $DURATION_SECONDS seconds of video..."
  fi

  PERCENT_FUDGE=$(echo "$DURATION_SECONDS / 100" | bc -l)
   while IFS= read -r -d $'\r' LINE
    do
      WORDS=($LINE)
      STAMP=${WORDS[0]}
      if [ "$STAMP" != "Seek" ] && [ "$STAMP" != "nan" ]  && [ "${WORDS[1]}" != "@" ] ; then


         if [ $(echo "$STAMP <= 0.0" | bc) -eq 1 ] ; then
            STAMP=0.0
         elif [ $(echo "$STAMP >= $DURATION_SECONDS" | bc) -eq 1 ] ; then
            STAMP="$DURATION_SECONDS"
         fi

         PERCENT=$(echo "($STAMP / $PERCENT_FUDGE)" | bc)
         echo $STAMP > $NOW_STAMP

        if [ $QUIET -eq 0 ] ; then
            echo -n $'\r' "Playing $MOVIE @ seconds = $STAMP, $PERCENT% of duration"
        fi
      fi
    done

}


ffplay -i "$MOVIE" -window_title "Playing"    3>&1 1>&2 2>&3 | ffplay_parse &

MOVIE_PID=$!

if [ $QUIET -eq 0 ] ; then
    echo "
    Started player for $MOVIE, PID is $MOVIE_PID

    You can use:

    kill -9 $MOVIE_PID

    to kill player.

    "

fi

echo $MOVIE_PID > "$MOVIE.pid.txt"

if [ $QUIET -eq 0 ] ; then
    wait $MOVIE_PID

    echo ""
    echo "Done"

fi

答案2

我有一个 Python 程序,每次按下暂停/播放按钮时,都会有 0.35 到 0.89 秒的开销。因此,之前播放时间的内部计算存在偏差。

使用这个答案从 shell 中(虽然尚未合并到脚本中)我可以使用:

$ ps aux | grep -v grep | grep ffplay
rick     16075  0.2  0.1 949956 45384 pts/22   Tl+  09:28   0:02 ffplay -autoexit /media/rick/SANDISK128/Music/Alice Cooper/Welcome To My Nightmare/01 Welcome To My Nightmare.m4a -nodisp

$ sudo strace -p16075 -s9999 -e write 
strace: Process 16075 attached
write(2, "  44.44 M-A:  0.000 fd=   0 aq=   23KB vq=    0KB sq=    0B f=0/0   \r", 69) = 69
write(2, "  44.47 M-A:  0.000 fd=   0 aq=   23KB vq=    0KB sq=    0B f=0/0   \r", 69) = 69
write(2, "  44.49 M-A:  0.000 fd=   0 aq=   23KB vq=    0KB sq=    0B f=0/0   \r", 69) = 69
write(2, "  44.54 M-A:  0.000 fd=   0 aq=   23KB vq=    0KB sq=    0B f=0/0   \r", 69) = 69
write(2, "  44.56 M-A:  0.000 fd=   0 aq=   23KB vq=    0KB sq=    0B f=0/0   \r", 69) = 69
write(2, "  44.59 M-A: -0.000 fd=   0 aq=   23KB vq=    0KB sq=    0B f=0/0   \r", 69) = 69
write(2, "  44.64 M-A:  0.000 fd=   0 aq=   23KB vq=    0KB sq=    0B f=0/0   \r", 69) = 69
write(2, "  44.66 M-A:  0.000 fd=   0 aq=   23KB vq=    0KB sq=    0B f=0/0   \r", 69) = 69
write(2, "  44.68 M-A:  0.000 fd=   0 aq=   23KB vq=    0KB sq=    0B f=0/0   \r", 69) = 69
write(2, "  44.72 M-A: -0.000 fd=   0 aq=   22KB vq=    0KB sq=    0B f=0/0   \r", 69) = 69
write(2, "  44.75 M-A: -0.000 fd=   0 aq=   22KB vq=    0KB sq=    0B f=0/0   \r", 69) = 69
write(2, "  44.77 M-A:  0.000 fd=   0 aq=   22KB vq=    0KB sq=    0B f=0/0   \r", 69) = 69
write(2, "  44.82 M-A: -0.000 fd=   0 aq=   21KB vq=    0KB sq=    0B f=0/0   \r", 69) = 69
^Cstrace: Process 16075 detached

第一个变量是经过的秒数,或者44.82在这种情况下。

相比之下,在 Python 程序中,暂停/播放被点击了十几次,计算出来的时间是53.31相差 8 秒半。

需要进行一些微调才能在strace无需sudo权限的情况下进行调用并仅在转储最后一行后退出。

相关内容