2

I'd like some way to pipe the console output of ffplay to a bash script that parses it and isolates the current seek time and saves that number to a text file (I can put it in a RAM disk). It's so I can then grab that number and use it for an ad hoc quick and dirty editor I am making to stitch together rough cuts of stereoscopic gopro files without having to import the whole lot into a bloatware editor. So far my scripts work and it reads a file which has lists of file names and time stamps, but it's a lot of work cutting and pasting

I can easily make a bash script that builds this list, but I need a way to grab that number in real time whenever I hit a key in my other script

Anyone seen anything like this?

Ie pipe ffplay to script that grep / awk / sed / perl whatevers the frame time to a file?

2 Answers 2

0

Ok, I worked out a solution.

This is pretty crude, but is enough to show you how I did it.

As a bonus there is the ffprobe_parse function that you can also use to parse the output of ffprobe, to get the duration and frame rate, it happens to be the same format as the same information printed by ffplay, so I wrapped it in a function to make that part reusable.

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

I have a python program that has .35 to .89 second overhead every time the pause/play button is pressed. As such the internal calculation for how much time has been previously played is being skewed.

Using this answer from the shell (not yet incorporated into a script though) I can use:

$ 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

The first variable is the amount of seconds passed, or 44.82 in this case.

In contrast in the python program where pause/play has been clicked a dozen times the calculated time is 53.31 a difference of 8 1/2 seconds.

Some fine-tuning is required to call strace without sudo permissions and to have it exit after dumping the last line only.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .