#!/bin/bash
#set -n		# read but do not execute commands (check on syntax errors)
#
# File: /usr/local/bin/mediashow-frames
#
# Show frames of a video file.
#
#    Copyright (c) 2019 Juergen Kaesmann (JK)
#
##############################################################################
# GPL NOTICE
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
##############################################################################
# FIND SAMPLES
##############################################################################
# FILTER SAMPLES
##############################################################################
# AWK SAMPLES
##############################################################################
# SED SAMPLES
##############################################################################
# RSYNC OPTIONS
##############################################################################
# DIALOG SAMPLES
##############################################################################
# REPLACE STRINGS
##############################################################################
# EXIT CODES

##############################################################################
# SOURCE FILES
#
. /usr/local/etc/main.conf				# config main
#. $LLIBDIR/libfuncerr-sh				# functions error
. $LLIBDIR/libfuncstd-sh				# functions standard
. $LLIBDIR/libfuncmath-sh				# functions math
#. $LLIBDIR/libfuncip-sh				# functions IP
#. /usr/local/etc/sample.conf				# config sample
#
#if [ ! -e ~/.samplerc ]; then				# install config user
#	cp /usr/local/share/ksm-sample/samplerc ~/.samplerc
#fi
#. ~/.samplerc						# config user

##############################################################################
# DECLARATION OF STANDARD CONSTANTS AND VARIABLES
#
readonly package=Multimedia				# package name
readonly package_file=ksm-multimedia			# package file name
readonly vinfopath="/usr/local/share/$package_file"	# path to package dir
readonly version=$(/bin/cat $vinfopath/VERSION)		# package version
readonly release=$(/bin/cat $vinfopath/RELEASE)		# package release
readonly scriptname=$(basename $0)			# name of script
readonly tempfile=$TEMPDIR/$scriptname.$UID.tmp		# temporary file name
#tempfile=$(mktemp $TEMPDIR/$scriptname.$UID.XXXXXX)	# temporary file name
readonly lockfile=$TEMPDIR/lock/$scriptname.$UID.lock	# lock file name
readonly debuglog="/usr/bin/logger -p user.debug -t $scriptname -- DEBUG:"	# log dbg msg
readonly errlog="/usr/bin/logger -p user.err -t $scriptname -- ERROR:"		# log err msg
readonly infolog="/usr/bin/logger -p user.info -t $scriptname -- INFO:"		# log inf msg
cmd=''							# sub command
debug=no						# debug=yes/no
verbose=''						# verbose=yes/''/no
err=${_ERR_OK_}						# error code

##############################################################################
# USER FILL IN AT FIRST RUN
##############################################################################
# SYSTEM
##############################################################################
# USER-CONSTANTS
##############################################################################
# USER-VARIABLES
#
# STRINGS
#args=''				# all args from cmdline
arg1=''					# 1. arg from cmdline
#opt_o=''				# option -o (yes)
					# option --output (yes)
opt_i=''				# option -i (arg)
					# option --infile (arg)
#opt_o=''				# option -o (arg)
					# option --outfile (arg)
#opt_p=''				# option -p (arg)
					# option --pages (arg)
opt_I=''				# option -I (yes)
opt_n=''				# option -n (arg)
opt_w=''				# option -w (yes)
opt_adur=''				# option -adur (arg)
opt_probs=''				# option -probs (arg)
gs=''
gts=''
lgs=''
lgts=''

# NUMBERS
i_first=0				# first time
i_last=0				# last time
fsecs=0
lsecs=0

# ARRAYS
# Indexed arrays are always zero based string arrays.
# If index starts with 1 and all members are assigned then
# count of members of array = last index of array
#declare -a arr
#maxarr="${#arr[@]}"			# get number of elements in arr
#unset arr[@]				# remove the entire array
#
##############################################################################
# LANGUAGE SUPPORT
##############################################################################
# SIGNAL HANDLING

##############################################################################
# FUNCTIONS
##############################################################################
#
##############################################################################
# HELP
#
#=============================================================================
function helptext ()
{
# Output helptext
# Uses cat, echo, logger
# Return codes:
# Standard

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG helptext: $# $@" >&2
	$debuglog helptext: $# $@
fi

cat <<EOT
NAME
$scriptname - Show frames of a video file.

SYNOPSIS
$scriptname [options] [file]

DESCRIPTION
Show frames of a video file in the PAGER.

Frames are output in a frame set (for each frame one set):
Frame set for MP4 video streams is 23 entries.
Frame set for MPG(2) video streams is 28 entries with side data else
  23 entries without side data.
Frame set for audio streams is 17 entries.

We discard the side data from mpeg2video streams. It will not be shown
in the listings but only in the raw video frame data.

OUTPUT
Overview.

  The first entry is the frame number.
  The second entry is the frame type (I, i, P, B).
    The difference between I and i (H264 only):
    'I' means an IDR-frame, 'i' means a normal I-frame. Cutting is
    better done on an IDR-frame because a normal I-frame could be
    overjumped from a backward reference and therefore this information
    would be lost.
  The other entries have descriptive names and values.

Defaults:  Show MP4 video stream info from an H264 encoded video file
           (-n 600)

OPTIONS
Gnu style options:

  -h|--help    = Output help, then exit.
  -V|--version = Output version info, then exit.
  -d|--debug   = Turn on DEBUG mode.
  -q|--quiet   = Be quiet.
  -v|--verbose = Be verbose.
  -I -i|-n     = Show only IDR/I-Frames (video stream). Needs -i or -n.
  -a           = Show audio info from the file.
  --adur=and   = Analyze duration <and> in microseconds 100M|...
                 (default = 5000000).
  --probs=psiz = Probesize <psiz> in Bytes 32 - n, 100M|...
                 (default = 5000000).
  -m -i|-n     = Show mpg (mpeg2) video stream info from a video file.
                 Needs -i or -n.
  -i frst,last = Process interval from <frst> to <last>.
                 frst=start-time last=stop-time. Don't give -n !
  -n num       = Show first <num> frames. Start at the begin of <file>.
                 Don't give -i !
  -w           = Show wide listing (all fields).
  --ra -i      = Output stream of raw audio frame data (needs -i).
  --rv -i      = Output stream of raw video frame data (needs -i).
  --           = End of options.

ARGUMENTS
Give if needed:

  file = Media file which can ffmpeg recognize (mp4/mpg/flv/...).

EXIT STATUS
On program exit:

  Code 0 = OK

  See output of 'showerrmsg'.

SEE ALSO
Related manpages:

  showerrmsg(1), ffmpeg(1), ffprobe(1).

AUTHORS
Juergen Kaesmann <juergen@kaesmann-online.de>
EOT
#  -o|--output  = Output to STDOUT.
#  -i f         = Input from file <f>.
#  --infile=f   = Input from file <f>.
#  -o f         = Output to file <f>.
#  --outfile=f  = Output to file <f>.
#  -p s,e       = Pages s=START e=END.
#  --pages=s,e  = Pages s=START e=END.

#EXAMPLES
#For instance:
#
#  Do it:
#  $scriptname

#FILES
#Used directories and files:
#
#  Config Global = /usr/local/etc/sample.conf
#  Config User   = ~/.samplerc

return
}

#=============================================================================
function HMS2Secs ()
{
# Transform a time from HH:MM:SS[.ss] to seconds.
# par1 = HH:MM:SS[.ss]
# Uses echo, logger
# I OK then output result to STDOUT.
# Return codes:
# Standard

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG HMS2Secs: $# $@" >&2
	$debuglog HMS2Secs: $# $@
fi

local tm="$1" a=''
local h=0 m=0 s=0 result=0 half=0 secs=0 ret=0

if [ -n "$tm" ]; then					# if not empty
	a=${tm#*:}
	if [ "$a" != "$tm" ]; then			# contains :
		if [ $ret -eq 0 ]; then
			# get HH and set to secs
			h=${tm:0:2}
			# secs = h * 3600
			secs=$(X_mul_Y $h 3600)
			ret=$?

			# get MM and summ to secs
			m=${tm:3:2}
			# secs =  m * 60 + secs
			half=$(X_mul_Y $m 60)
			ret=$?
			result=$(X_plus_Y $half $secs)
			ret=$?
			secs=$result

			# get SS[.ss] and summ to secs
			s=${tm:6}
			result=$(X_plus_Y $s $secs)
			ret=$?
			secs=$result
			echo "$secs"
		fi
	else							# secs always in var
		ret=0
	fi
else
	ret=10
fi

return $ret
}

#=============================================================================
function rawaproc ()
{
# Output the whole audio stream.
# par1 = 
# Uses echo, logger
# Return codes:
# Standard

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG rawaproc: $# $@" >&2
	$debuglog rawaproc: $# $@
fi

local ret=0

ffprobe -hide_banner -i $arg1 -read_intervals ${i_first}%${i_last} \
	-show_frames -select_streams a:0 -print_format flat
ret=$?

return $ret
}

#=============================================================================
function rawvproc ()
{
# Output the whole video stream.
# par1 = 
# Uses echo, logger
# Return codes:
# Standard

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG rawvproc: $# $@" >&2
	$debuglog rawvproc: $# $@
fi

local ret=0

ffprobe -hide_banner -i $arg1 -read_intervals ${i_first}%${i_last} \
	-show_frames -select_streams v:0 -print_format flat
ret=$?

return $ret
}

#=============================================================================
function audioproc_i ()
{
# Make listing of audio frames of a video file.
# par1 = 
# Uses echo, logger
# Return codes:
# Standard

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG audioproc_i: $# $@" >&2
	$debuglog audioproc_i: $# $@
fi

local start=no reply=''
local fr=0 j=0 ret=0
local -a arr
#maxarr="${#arr[@]}"			# get number of elements in arr
#unset arr[@]				# remove the entire array

j=0						# zähler für 1-23 frames
ffprobe -hide_banner -i $arg1 -read_intervals ${i_first}%${i_last} \
	-show_frames -select_streams a:0 -print_format flat | \
while read; do
	reply=${REPLY#frames.frame.}		# reply = beautf. entry
	reply=${reply#*.}			# reply = fr.var.
	if [ "${reply%=*}" == media_type ]; then # look for start
		start=yes
	fi

	if [ "$start" == yes ]; then		# start of 1. frame
		let ++j				# inc fr.var. cnt
		arr[$j]=$reply			# put fr var in array
		if [ "$j" -eq 17 ]; then	# whole set got
			j=0			# reset fr.var. cnt
			fr=${REPLY#frames.frame.} # reply = beautf. entry
			fr=${fr%%.*}		# get frame number
			RSet 4 $fr
			ret=$?
			if [ "$ret" -eq 0 ]; then
				Pop fr
			fi
			if [ -n "$opt_w" ]; then
				echo "$fr  ${arr[1]}  ${arr[2]}  ${arr[3]}  ${arr[4]}  ${arr[5]}  ${arr[6]}  ${arr[7]}  ${arr[8]}  ${arr[9]}  ${arr[10]}  ${arr[11]}  ${arr[12]}  ${arr[13]}  ${arr[14]}  ${arr[15]}  ${arr[16]}  ${arr[17]}"
			else
				echo "$fr  ${arr[5]}  ${arr[7]}  ${arr[16]}"
			fi
		fi
	fi
done | $PAGER
ret=$?

return $ret
}

#=============================================================================
function audioproc_n ()
{
# Make listing of audio frames of a video file.
# par1 = 
# Uses echo, logger
# Return codes:
# Standard

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG audioproc_n: $# $@" >&2
	$debuglog audioproc_n: $# $@
fi

local start=no reply=''
local fr=0 j=0 k=0 ret=0
local -a arr
#maxarr="${#arr[@]}"			# get number of elements in arr
#unset arr[@]				# remove the entire array

j=0						# zähler für 1-23 frames
k=0						# zähler für opt_n frames
ffprobe -hide_banner -i $arg1 -show_frames -select_streams a:0 \
	-print_format flat | \
while read; do
	reply=${REPLY#frames.frame.}		# reply = beautf. entry
	reply=${reply#*.}			# reply = fr.var.
	if [ "${reply%=*}" == media_type ]; then # look for start
		start=yes
	fi

	if [ "$start" == yes ]; then		# start of 1. frame
		let ++j				# inc fr.var. cnt
		arr[$j]=$reply			# put fr var in array
		if [ "$j" -eq 17 ]; then	# whole set got
			j=0			# reset fr.var. cnt
			let ++k			# k = frame cnt
			fr=${REPLY#frames.frame.} # reply = beautf. entry
			fr=${fr%%.*}		# get frame number
			RSet 4 $fr
			ret=$?
			if [ "$ret" -eq 0 ]; then
				Pop fr
			fi
			if [ -n "$opt_w" ]; then
				echo "$fr  ${arr[1]}  ${arr[2]}  ${arr[3]}  ${arr[4]}  ${arr[5]}  ${arr[6]}  ${arr[7]}  ${arr[8]}  ${arr[9]}  ${arr[10]}  ${arr[11]}  ${arr[12]}  ${arr[13]}  ${arr[14]}  ${arr[15]}  ${arr[16]}  ${arr[17]}"
			else
				echo "$fr  ${arr[5]}  ${arr[7]}  ${arr[16]}"
			fi
			if [ -n "$opt_n" ]; then
				if [ "$k" -ge $opt_n ]; then
					break
				fi
			fi
		fi
	fi
done | $PAGER
ret=$?

return $ret
}

#=============================================================================
function audioproc ()
{
# select between the various audio codecs.
# par1 = 
# Uses echo, logger
# Return codes:
# Standard

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG audioproc: $# $@" >&2
	$debuglog audioproc: $# $@
fi

local ret=0

if [ -n "$opt_i" ]; then
	audioproc_i
else
	audioproc_n
fi
ret=$?

return $ret
}

#=============================================================================
function mpeg2video_i ()
{
# Make listing of video frames of an mpeg2 encoded video file or 
# transport stream.
# par1 = 
# Uses echo, logger
# Return codes:
# Standard

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG mpeg2video_i: $# $@" >&2
	$debuglog mpeg2video_i: $# $@
fi

local ft='' start=no reply=''
local fr=0 j=0 ret=0
local -a arr
#maxarr="${#arr[@]}"			# get number of elements in arr
#unset arr[@]				# remove the entire array

echo "START: ($i_first = $fsecs s) END: ($i_last = $lsecs s) FILE: $arg1" > $tempfile

j=0						# zähler für 1-23 frames
ffprobe -hide_banner -i $arg1 -read_intervals ${i_first}%${i_last} \
	-show_frames -select_streams v:0 -print_format flat | \
while read; do
	reply=${REPLY#frames.frame.}		# cut off frames.frame.
	reply=${reply#*.}			# cut off frame number
	if [ "$start" != yes ] && [ "${reply%=*}" == media_type ]; then # look for start
		start=yes
	fi

	if [ "$start" == yes ]; then		# start from 1. frame of set
		if [ "${reply:0:4}" != side ]; then
			let ++j				# inc fr.var. cnt
			arr[$j]=$reply			# put fr var in array

			if [ "$j" -eq 23 ]; then	# whole set got
				j=0			# reset fr.var. cnt
				fr=${REPLY#frames.frame.} # reply = beautf. entry
				fr=${fr%%.*}		# get frame number
				RSet 4 $fr
				ret=$?
				if [ "$ret" -eq 0 ]; then
					Pop fr
				fi
				ft=${arr[18]}		# ft=framte type I B P
				ft=${ft#*=}
				ft=${ft:1:1}
				if [ -z "$opt_I" ] || [ "$ft" == I ]; then
					if [ -n "$opt_w" ]; then
						echo "$fr  $ft  ${arr[1]}  ${arr[2]}  ${arr[3]}  ${arr[4]}  ${arr[5]}  ${arr[6]}  ${arr[7]}  ${arr[8]}  ${arr[9]}  ${arr[10]}  ${arr[11]}  ${arr[12]}  ${arr[13]}  ${arr[14]}  ${arr[15]}  ${arr[16]}  ${arr[17]}  ${arr[19]}  ${arr[20]}  ${arr[21]}  ${arr[22]}  ${arr[23]}  ${arr[24]}  ${arr[25]}  ${arr[26]}  ${arr[27]}  ${arr[28]}"
					else
						echo "$fr  $ft  ${arr[5]}  ${arr[7]}  ${arr[19]}"
					fi
				fi
			fi
		fi
	fi
done >> $tempfile
ret=$?
$PAGER $tempfile
rm -f $tempfile

return $ret
}

#=============================================================================
function mpeg2video_n ()
{
# Make listing of video frames of an mpeg2 encoded video file or 
# transport stream.
# par1 = 
# Uses echo, logger
# Return codes:
# Standard

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG mpeg2video_n: $# $@" >&2
	$debuglog mpeg2video_n: $# $@
fi

local ft='' start=no reply=''
local fr=0 j=0 k=0 ret=0
local -a arr
#maxarr="${#arr[@]}"			# get number of elements in arr
#unset arr[@]				# remove the entire array

echo "START: ($i_first = $fsecs s) END: ($i_last = $lsecs s) FILE: $arg1" > $tempfile

j=0						# zähler für 1-23 frames
k=0						# zähler für opt_n frames
ffprobe -hide_banner -i $arg1 -show_frames -select_streams v:0 \
	-print_format flat | \
while read; do
	reply=${REPLY#frames.frame.}		# cut off frames.frame.
	reply=${reply#*.}			# cut off frame number
	if [ "$start" != yes ] && [ "${reply%=*}" == media_type ]; then # look for start
		start=yes
	fi

	if [ "$start" == yes ]; then		# start from 1. frame of set
		if [ "${reply:0:4}" != side ]; then
			let ++j				# inc fr.var. cnt
			arr[$j]=$reply			# put fr var in array

			if [ "$j" -eq 23 ]; then	# whole set got
				j=0			# reset fr.var. cnt
				let ++k			# k = frame cnt f.opt_n
				fr=${REPLY#frames.frame.} # reply = beautf. entry
				fr=${fr%%.*}		# get frame number
				RSet 4 $fr
				ret=$?
				if [ "$ret" -eq 0 ]; then
					Pop fr
				fi
				ft=${arr[18]}		# ft=framte type I B P
				ft=${ft#*=}
				ft=${ft:1:1}
				if [ -z "$opt_I" ] || [ "$ft" == I ]; then
					if [ -n "$opt_w" ]; then
						echo "$fr  $ft  ${arr[1]}  ${arr[2]}  ${arr[3]}  ${arr[4]}  ${arr[5]}  ${arr[6]}  ${arr[7]}  ${arr[8]}  ${arr[9]}  ${arr[10]}  ${arr[11]}  ${arr[12]}  ${arr[13]}  ${arr[14]}  ${arr[15]}  ${arr[16]}  ${arr[17]}  ${arr[19]}  ${arr[20]}  ${arr[21]}  ${arr[22]}  ${arr[23]}  ${arr[24]}  ${arr[25]}  ${arr[26]}  ${arr[27]}  ${arr[28]}"
					else
						echo "$fr  $ft  ${arr[5]}  ${arr[7]}  ${arr[19]}"
					fi
				fi
				if [ -n "$opt_n" ]; then
					if [ "$k" -ge $opt_n ]; then
						break
					fi
				fi
			fi
		fi
	fi
done >> $tempfile
ret=$?
$PAGER $tempfile
rm -f $tempfile

return $ret
}

#=============================================================================
function mpegproc ()
{
# select between the various video codecs.
# par1 = 
# Uses echo, logger
# Return codes:
# Standard

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG mpegproc: $# $@" >&2
	$debuglog mpegproc: $# $@
fi

local ret=0

if [ -n "$opt_i" ]; then
	mpeg2video_i
else
	mpeg2video_n
fi
ret=$?

return $ret
}

#=============================================================================
function h264_i ()
{
# Make listing of video frames of a h264 encoded video file.
# par1 = 
# Uses echo, logger
# Return codes:
# Standard

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG h264_i: $# $@" >&2
	$debuglog h264_i: $# $@
fi

local ft='' start=no reply=''
local fr=0 j=0 kf=0 ret=0
local -a arr
#maxarr="${#arr[@]}"			# get number of elements in arr
#unset arr[@]				# remove the entire array

echo "START: ($i_first = $fsecs s) END: ($i_last = $lsecs s) FILE: $arg1" > $tempfile

j=0						# index für eingehende zeilen
ffprobe -hide_banner $opt_adur $opt_probs -i $arg1 \
	-read_intervals ${i_first}%${i_last} -show_frames -select_streams v:0 \
	-print_format flat | \
while read; do
	reply=${REPLY#frames.frame.}		# reply = beautf. entry
	reply=${reply#*.}			# reply = fr.var.
	if [ "${reply%=*}" == media_type ]; then # look for start
		start=yes
		j=0
	fi

	if [ "$start" == yes ]; then		# start of 1. frame
		let ++j				# inc fr.var. cnt
		if [ ${reply:0:9} != side_data ]; then
			arr[$j]=$reply			# put fr var in array
			if [ "$j" -eq 28 ]; then	# whole set got
				fr=${REPLY#frames.frame.} # reply = beautf. entry
				fr=${fr%%.*}		# get frame number
				RSet 4 $fr
				ret=$?
				if [ "$ret" -eq 0 ]; then
					Pop fr
				fi
				kf=${arr[3]}		# key-frame: 0=norm.I-frame=i, 1=IDR-frame=I
				kf=${kf#*=}
				kf=${kf:0:1}
				ft=${arr[18]}		# ft=framte type I B P
				ft=${ft#*=}
				ft=${ft//\"/}
				if [ "$ft" == I ] && [ "$kf" == 0 ]; then
					ft=i
				fi
				if [ -z "$opt_I" ] || [ "$ft" == I ] || [ "$ft" == i ]; then
					if [ -n "$opt_w" ]; then
						echo "$fr  $ft  ${arr[1]}  ${arr[2]}  ${arr[3]}  ${arr[4]}  ${arr[5]}  ${arr[6]}  ${arr[7]}  ${arr[8]}  ${arr[9]}  ${arr[10]}  ${arr[11]}  ${arr[12]}  ${arr[13]}  ${arr[14]}  ${arr[15]}  ${arr[16]}  ${arr[17]}  ${arr[19]}  ${arr[20]}  ${arr[21]}  ${arr[22]}  ${arr[23]}  ${arr[24]}  ${arr[25]}  ${arr[26]}  ${arr[27]}  ${arr[28]}"
					else
						echo "$fr  $ft  ${arr[5]}  ${arr[7]}  ${arr[19]}"
					fi
				fi
			fi
		fi
	fi
done >> $tempfile
ret=$?
$PAGER $tempfile
rm -f $tempfile

return $ret
}

#=============================================================================
function h264_n ()
{
# Make listing of video frames of a h264 encoded video file.
# par1 = 
# Uses echo, logger
# Return codes:
# Standard

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG h264_n: $# $@" >&2
	$debuglog h264_n: $# $@
fi

local ft='' start=no reply=''
local fr=0 j=0 k=0 kf=0 ret=0
local -a arr
#maxarr="${#arr[@]}"			# get number of elements in arr
#unset arr[@]				# remove the entire array

echo "START: ($i_first = $fsecs s) END: ($i_last = $lsecs s) FILE: $arg1" > $tempfile

j=0						# zähler für 1-23 frames
k=0						# zähler für opt_n frames
ffprobe -hide_banner $opt_adur $opt_probs -i $arg1 -show_frames \
	-select_streams v:0 -print_format flat | \
while read; do
	reply=${REPLY#frames.frame.}		# reply = beautf. entry
	reply=${reply#*.}			# reply = fr.var.
	#if [ "$start" != yes ] && [ "${reply%=*}" == media_type ]; then # look for start
	if [ "${reply%=*}" == media_type ]; then # look for start
		start=yes
		j=0
	fi

	if [ "$start" == yes ]; then		# start of 1. frame
		let ++j				# inc fr.var. cnt
		if [ ${reply:0:9} != side_data ]; then
			arr[$j]=$reply			# put fr var in array
			if [ "$j" -eq 28 ]; then	# whole set got
				let ++k			# k = frame cnt f.opt_n
				fr=${REPLY#frames.frame.} # reply = beautf. entry
				fr=${fr%%.*}		# get frame number
				RSet 4 $fr
				ret=$?
				if [ "$ret" -eq 0 ]; then
					Pop fr
				fi
				kf=${arr[3]}		# key-frame: 0=norm.I, 1=IDR
				kf=${kf#*=}
				kf=${kf:0:1}
				ft=${arr[18]}		# ft=framte type I B P
				ft=${ft#*=}
				ft=${ft//\"/}
				if [ "$ft" == I ] && [ "$kf" == 0 ]; then
					ft=i
				fi
				if [ -z "$opt_I" ] || [ "$ft" == I ] || [ "$ft" == i ]; then
					if [ -n "$opt_w" ]; then
						echo "$fr  $ft  ${arr[1]}  ${arr[2]}  ${arr[3]}  ${arr[4]}  ${arr[5]}  ${arr[6]}  ${arr[7]}  ${arr[8]}  ${arr[9]}  ${arr[10]}  ${arr[11]}  ${arr[12]}  ${arr[13]}  ${arr[14]}  ${arr[15]}  ${arr[16]}  ${arr[17]}  ${arr[19]}  ${arr[20]}  ${arr[21]}  ${arr[22]}  ${arr[23]}  ${arr[24]}  ${arr[25]}  ${arr[26]}  ${arr[27]}  ${arr[28]}"
					else
						echo "$fr  $ft  ${arr[5]}  ${arr[7]}  ${arr[19]}"
					fi
				fi
				if [ -n "$opt_n" ]; then
					if [ "$k" -ge $opt_n ]; then
						break
					fi
				fi
			fi
		fi
	fi
done >> $tempfile
ret=$?
$PAGER $tempfile
rm -f $tempfile

return $ret
}

#=============================================================================
function mainproc ()
{
# select between the various video codecs.
# par1 = 
# Uses echo, logger
# Return codes:
# Standard

if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG mainproc: $# $@" >&2
	$debuglog mainproc: $# $@
fi

local ret=0
#local -a arr
#maxarr="${#arr[@]}"			# get number of elements in arr
#unset arr[@]				# remove the entire array

if [ -n "$opt_i" ]; then
	h264_i
else
	h264_n
fi
ret=$?

return $ret
}

##############################################################################
# GET OPTIONS
##############################################################################
# Give 2 strings and all cmdline_args to func GetOpt
# (POSIX_options Gnu_long_options cmdline_args):
# GetOpt 'hVdqvi:m:' 'help version debug quiet verbose infile= myval=' $@
#
# A ':' after a POSIX option means this option needs an arg.
# A '=' after a Gnu long option means this option needs an arg.
#
# All cmd/options have to be initialised to ''!
#
# POSIX options are classified in 2 categories:
#   a) cmds (mutually exclusive). All cmds are given to var 'cmd'.
#   b) options (as many as you like). Each option is given to it's own var.
# As a general rule: If cmds/options are given multiple then last given wins.
#
# Options can take 1 argument (no whitespace in arg). If you want to give more
# than 1 arg or want to use multiple strings as 1 arg then concatenate them
# together with a delimiter like ',' or ';' or '.'
# Use a delimiter which will not be part of the arg:
# sampleprog -m val1,val2
# sampleprog --myval=val1,val2
# It's at the programmers responsibility to do meaningfull things with the
# content of the options.
#
# If err != 0 then all args are processed, else continue to look for options.
# When GetOpt finishes then all options are removed from cmdline.
#
if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG Parse Commandline: $# $@" >&2
	$debuglog Parse Commandline: $# $@
fi
#
err=${_ERR_OK_}
while [ "$err" -eq 0 ]; do
	GetOpt 'hVdqvaIi:mn:w' 'help version debug quiet verbose ra rv adur= probs=' $@
	err=$?
	#echo "DEBUG GET OPTIONS: err=${err}  _OPTNAME_=${_OPTNAME_}  _OPTVAL_=${_OPTVAL_}  _OPTPOS_=${_OPTPOS_}  _OPTIDX_=${_OPTIDX_}" >&2
	if [ $err -eq 0 ]; then
		case "$_OPTNAME_" in
		    h|help)	cmd="-h";;
		    V|version)	cmd="-V";;
		    a)		cmd="-${_OPTNAME_}";;
		    m)		cmd="-${_OPTNAME_}";;
		    ra)		cmd="-${_OPTNAME_}";;
		    rv)		cmd="-${_OPTNAME_}";;
		    d|debug)	debug=yes;;
		    q|quiet)	verbose=no;;
		    v|verbose)	verbose=yes;;
		    I)		opt_I=yes;;
		    w)		opt_w=yes;;
#		    o|output)	opt_o=yes;;
#		    i|infile)	opt_i="${_OPTVAL_}";;
#		    o|outfile)	opt_o="${_OPTVAL_}";;
#		    p|pages)	opt_p="${_OPTVAL_}";;
		    i)		opt_i="${_OPTVAL_}";;
		    n)		opt_n="${_OPTVAL_}";;
		    adur)	opt_adur="-analyzeduration $_OPTVAL_";;
		    probs)	opt_probs="-probesize $_OPTVAL_";;
		    --)		break;;
		    :)	Show_Err ${_ERR_MISSING_ARG_FOR_OPT_} "-${_OPTVAL_}"
			exit ${_ERR_MISSING_ARG_FOR_OPT_};;
		    ?)	Show_Err ${_ERR_UNKNOWN_OPT_} "-${_OPTVAL_}"
			exit ${_ERR_UNKNOWN_OPT_};;
		    *)	Show_Err ${_ERR_UNKNOWN_ERR_} "_OPTNAME_=${_OPTNAME_} _OPTVAL_=${_OPTVAL_}"
			exit ${_ERR_UNKNOWN_ERR_};;
		esac
	fi
done
err=${_ERR_OK_}
shift ${_OPTIDX_}				# rm all opts from cmdline
#
# Uncomment if giving a cmd is mandatory
#if [ -z "$cmd" ]; then					# error no cmd given
#	Show_Err ${_ERR_MISSING_SUB_CMD_} ""
#	exit ${_ERR_MISSING_SUB_CMD_}
#fi

##############################################################################
# CHECK LINK NAMES
##############################################################################
# CHECK OPTIONS
#
#-----------------------------------------------------------------------------
# check not allowed option for sub commands
#case "$cmd" in
#    -l|-p)						# for these cmds
#	if [ -n "$opt_z" ]; then			# option -z not allowed
#		if [ "$verbose" != no ]; then
#			echo "${ErrMsg[${_ERR_OPT_NOT_ALLOWED_}]} -z" >&2
#		else
#			$errlog ${ErrMsg[${_ERR_OPT_NOT_ALLOWED_}]} -z
#		fi
#		exit ${_ERR_OPT_NOT_ALLOWED_}
#	fi
#	;;
#    *)							# for all other cmds
#	:
#	;;
#esac
#
#-----------------------------------------------------------------------------
# check allowed option for sub commands
#if [ -n "$opt_z" ]; then
#	case "$cmd" in
#	    -l|-p)					# for these cmds
#		:					# option -z allowed
#		;;
#	    *)						# for all other cmds
#		if [ "$verbose" != no ]; then
#			echo "${ErrMsg[${_ERR_OPT_NOT_ALLOWED_}]} -z" >&2
#		else
#			$errlog ${ErrMsg[${_ERR_OPT_NOT_ALLOWED_}]} -z
#		fi
#		exit ${_ERR_OPT_NOT_ALLOWED_}
#		;;
#	esac
#fi
#
#-----------------------------------------------------------------------------
# check needed option for sub commands
#case "$cmd" in
#    -l|-p)						# for these cmds
#	if [ -z "$opt_z" ]; then			# option -z needed
#		if [ "$verbose" != no ]; then
#			echo "${ErrMsg[${_ERR_MISSING_ARG_FOR_OPT_}]} -z" >&2
#		else
#			$errlog ${ErrMsg[${_ERR_MISSING_ARG_FOR_OPT_}]} -z
#		fi
#		exit ${_ERR_MISSING_ARG_FOR_OPT_}
#	fi
#	;;
#    *)							# for all other cmds
#	:
#	;;
#esac
#
#-----------------------------------------------------------------------------
# check options which are mutually exclusive
if [ -n "$opt_i" ] && [ -n "$opt_n" ]; then		# don't give both opts
		if [ "$verbose" != no ]; then
			echo "${ErrMsg[${_ERR_OPT_NOT_ALLOWED_}]} -i and -n given" >&2
		else
			$errlog ${ErrMsg[${_ERR_OPT_NOT_ALLOWED_}]} -i and -n given
		fi
		exit ${_ERR_OPT_NOT_ALLOWED_}
fi
#
#-----------------------------------------------------------------------------
# check option which needs another option
if [ -n "$opt_I" ]; then				# opt_I given
	if [ -n "$opt_i" ] || [ -n "$opt_i" ] || [ -z "$cmd" ] ; then	# error - opt_I needs opt_i or opt_n
		:
	else
		if [ "$verbose" != no ]; then
			echo "${ErrMsg[${_ERR_GENERAL_}]} -I needs -i or -n or defaults!" >&2
		else
			$errlog ${ErrMsg[${_ERR_GENERAL_}]} -I needs -i or -n or defaults
		fi
		exit ${_ERR_GENERAL_}
	fi
fi
#
#-----------------------------------------------------------------------------
# check options which needs to give at least one of them
#case "$cmd" in
#   ''|-m)
#	if [ -z "$opt_i" ] && [ -z "$opt_n" ]; then	# no option given
#		if [ "$verbose" != no ]; then
#			echo "${ErrMsg[${_ERR_GENERAL_}]} give -i or -n" >&2
#		else
#			$errlog ${ErrMsg[${_ERR_GENERAL_}]} give -i or -n
#		fi
#		exit ${_ERR_GENERAL_}
#	fi
#esac
#
#-----------------------------------------------------------------------------
# get values from arg of option -i to vars i_first i_last
if [ -n "$opt_i" ]; then
	i_first="${opt_i%,*}"
	i_last="${opt_i#*,}"
fi
##############################################################################
# CHECK VERSION
##############################################################################
# CHECK ARGUMENTS
#
case "$cmd" in
    ''|-a|-m|-ra|-rv)
	if [ "$#" -eq 1 ]; then				# parameter count ok
		arg1="$1"
		shift
		#args="$@"
		#shift $#
	else						# error in param count
		if [ "$verbose" != no ]; then
			echo "${ErrMsg[${_ERR_WRONG_PAR_COUNT_}]}" >&2
		else
			$errlog ${ErrMsg[${_ERR_WRONG_PAR_COUNT_}]}
		fi
		exit ${_ERR_WRONG_PAR_COUNT_}
	fi
	;;
    *)
	if [ "$#" -ne 0 ]; then				# error in param count
		if [ "$verbose" != no ]; then
			echo "${ErrMsg[${_ERR_WRONG_PAR_COUNT_}]}" >&2
		else
			$errlog ${ErrMsg[${_ERR_WRONG_PAR_COUNT_}]}
		fi
		exit ${_ERR_WRONG_PAR_COUNT_}
	fi
	;;
esac
#
##############################################################################
# LOCK

##############################################################################
# MAINPROGRAM
##############################################################################
#
if [ "$debug" == "yes" ]; then				# DEBUG
	echo "DEBUG Main: $# $@" >&2
	$debuglog Main: $# $@
fi
#
if [ -z "$opt_i" ] && [ -z "$opt_n" ]; then
	opt_n=600
fi
# get opt_i in secs
gs=${i_first#*:}
gts=${i_first#* }					# extract time
if [ "$gs" != "$i_first" ]; then			# contain :
	fsecs=$(HMS2Secs $gts)
	if [ "$?" -ne 0 ]; then exit; fi
else							# are seconds
	fsecs=$gts
fi
lgs=${i_last#*:}
lgts=${i_last#* }					# extract time
if [ "$lgs" != "$i_last" ]; then			# contain :
	lsecs=$(HMS2Secs $lgts)
	if [ "$?" -ne 0 ]; then exit; fi
else							# are seconds
	lsecs=$lgts
fi
#
# Check what to do (sub commands, options and args are removed from cmdline)
case "$cmd" in
    '')
	mainproc
	err=$?
	;;
    -h)
	helptext
	exit 0
	;;
    -V)
	echo "${scriptname}: (${package}) $package_file ${version}-${release}"
	exit 0
	;;
    -a)
	audioproc
	err=$?
	;;
    -m)
	mpegproc
	err=$?
	;;
    -ra)
	rawaproc
	err=$?
	;;
    -rv)
	rawvproc
	err=$?
	;;
    *)							# error
	Show_Err ${_ERR_SUB_CMD_NOT_FOUND_} ""
	err=${_ERR_SUB_CMD_NOT_FOUND_}
	;;
esac

#rm -f $lockfile

exit $err
