#!/usr/bin/bash

_usage(){
cat <<EOF
$(basename "${0}")

Visually display and/or generate xml and sidecars of errors in DV file.
In visual display, error concealment data  in frames will be displayed
as yellow. This script is part of the dvrescue project.

Usage:
 $(basename "${0}") [options] file.dv

Options:
 -m         (Inverse of standard display)
 -x         (create output xml and jpgs)
 -g         (create gif from error jpgs)
 -o OUTPUT  (select a custom location for output files)

 -O FILE    (provide a path to a single output file. When set a single frame will be exported, depending on
             if -b or -t is set.)
 -b OFFSET  (provide a byte offset of the frame to examine, otherwise the first frame is default)
 -t PTS     (provide a timestamp to examine, otherwise the first frame is default. Ignored if '-b OFFSET' is set)

 -h         (Displays this help)
 -B BLOCKS  (draw a box around a specific DIF Block(s). Use a comma-delimited list for more than one,
             such as '-B 0,1348,1349')

 -F <path> (provide a custom ffmpeg path)
 -D <path> (provide a custom dvrescue path)
 -X <path> (provide a custom xmlstarlet path)
 -d <path> (provide a custom path to a DVRescue XML that corresponds to the
            input file)
EOF
exit
}

_report(){
    local RED="$(tput setaf 1)"    # Red      - For Warnings
    local GREEN="$(tput setaf 2)"  # Green    - For Declarations
    local BLUE="$(tput setaf 4)"   # Blue     - For Questions
    local MAGENTA="$(tput setaf 5)" # Magenta - For Verbose Statements
    local NC="$(tput sgr0)"        # No Color
    local COLOR=""
    local STARTMESSAGE=""
    local ECHOOPT=""
    local VERBOSE_CHECK=false
    OPTIND=1
    while getopts "vqdwstn" opt ; do
        case "${opt}" in
            v) VERBOSE_CHECK=true ;
               COLOR="${MAGENTA}" ;
               STARTMESSAGE+="#" ;; # only output the message if DV_VERBOSE=true
            q) COLOR="${BLUE}" ;;                        # question mode, use color blue
            d) COLOR="${GREEN}" ;;                       # declaration mode, use color green
            w) COLOR="${RED}" ;;                         # warning mode, use color red
            s) STARTMESSAGE+=([${SCRIPTNAME}] ) ;;       # prepend scriptname to the message
            t) STARTMESSAGE+=($(_get_iso8601) '- ' ) ;;  # prepend timestamp to the message
            n) ECHOOPT="-n" ;;                           # to avoid line breaks after echo
        esac
    done
    shift "$((OPTIND-1))"
    MESSAGE="${1}"
    if ! "${VERBOSE_CHECK}" || ( "${DV_VERBOSE}" && "${VERBOSE_CHECK}" ) ; then
        if [[ "${DISABLE_COLORED_LOGGING}" = "Y" ]] ; then
            >&2 echo ${ECHOOPT} "${STARTMESSAGE[@]}${MESSAGE}"
        else
            >&2 echo ${ECHOOPT} "${COLOR}${STARTMESSAGE[@]}${MESSAGE}${NC}"
        fi
    fi
}

OPTIND=1
while getopts ":t:b:mxgF:D:X:d:hB:o:O:" OPT ; do
    case "${OPT}" in
        t) FFMPEG_INPUT_OPTS=(-ss ${OPTARG}) ; PTS="$OPTARG" ;;
        b) FFMPEG_INPUT_OPTS=(-skip_initial_bytes ${OPTARG}) ; OFFSET="$OPTARG" ;;
        m) MASK_ONLY="Y" ;;
        x) ERROR_REVIEW="Y" ;;
        g) GIF_OUTPUT="Y" ;;
        F) FFMPEG_PATH="${OPTARG}" ;;
        D) DVRESCUE_PATH="${OPTARG}" ;;
        X) XMLSTARLET_PATH="${OPTARG}" ;;
        d) DVRESCUE_XML="${OPTARG}" ;;
        h) _usage ;;
        B) BLOCKS="${OPTARG}" ;;
        o) OUTPUTDIR="${OPTARG}";;
        O) OUTPUTFILE="${OPTARG}" ; ERROR_REVIEW="Y" ;;
        :) echo "Option -${OPTARG} requires an argument" ; exit 1 ;;
        *) echo "bad option -${OPTARG}" ; _usage ; exit 1 ;;
    esac
done
shift $((OPTIND - 1))

if [[ -z "${FFMPEG_PATH}" ]] ; then
    FFMPEG_PATH="$(which ffmpeg)"
fi
if [[ ! -f "${FFMPEG_PATH}" ]] ; then
    _report -d "The ffmpeg command-line tool is not found, but needed."
    _report -d "Please install a ffmpeg CLI  or provide a path to mediainfo with the -F argument."
else
    FFPLAY_PATH="$(dirname "${FFMPEG_PATH}")/ffplay"
    FFPROBE_PATH="$(dirname "${FFMPEG_PATH}")/ffprobe"
fi

cat > /tmp/dvplay_display.xsl << 'DISPLAY_XSL'
<?xml version="1.0"?>
<!-- WIP -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dv="https://mediaarea.net/dvrescue" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:x="http://www.w3.org/1999/xhtml" version="1.0" extension-element-prefixes="xsi" exclude-result-prefixes="dv x" >
<xsl:output encoding="UTF-8" method="html" version="1.0" indent="yes" doctype-system="about:legacy-compat"/>
<xsl:template name="substring-after-last">
  <xsl:param name="string"/>
  <xsl:param name="char"/>
  <xsl:choose>
    <xsl:when test="contains($string, $char)">
      <xsl:call-template name="substring-after-last">
        <xsl:with-param name="string" select="substring-after($string, $char)"/>
        <xsl:with-param name="char" select="$char"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$string"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>
<xsl:template match="/dv:dvrescue">
  <html>
    <head>
      <style type="text/css">
        body {
          font-family: "PT Sans", Helvetica, Arial, sans-serif;
          display: grid;
          justify-content: center;
          justify-items: center;
          overflow-wrap: anywhere;
        }
        h1 {
          font-weight: 800;
          font-style: italic;
        }
        table {
          border: 0.2em solid black;
        }
        img {
          max-width: 350px;
          height: inherit;
        }
        th {
          background-color: black;
          color: white;
          font-weight: bold;
          font-size: 1.5em;
        }
        td {
          padding-left: 2em;
          padding-right: 2em;
        }
        dt {
          font-weight: 800;
          font-style: italic;
        }
        .frames {
          display: flex;
          flex-wrap: wrap;
          justify-content: center;
        }
        .frameError {
          border: 0.2em solid black;
          margin: 0.1em;
          width: 350px;
        }
        .frameError p {
          padding-left: 0.5em;
          padding-right: 0.5em;
          margin: 0.25em;
        }
        .tc {
          background-color: black;
          color: white;
          font-weight: bold;
          font-size: 1.5em;
          text-align: center;
          padding: 0;
          margin: 0 !important;
        }
        .green {
          border-top: 0.1em solid green;
          display: grid;
          grid-template-columns: repeat(2, auto);
        }
        .red {
          border: 0.1em solid red;
          color: red;
        }
        .errorNum {
          text-decoration: underline wavy;
        }
        .errorNum:hover .tooltip {
          display: block;
        }
        .tooltip {
          display: none;
          background-color: black;
          color: white;
          font-weight: bold;
          margin-left: 1em;
          border-radius: 5px;
          padding: 0.3em;
          position: absolute;
          z-index: 1000;
        }
      </style>
    </head>
    <body>
      <xsl:for-each select="dv:media">
        <header>
          <h1>DVRescue Report</h1>
          <h2><xsl:value-of select="@ref"/></h2>
        </header>
        <xsl:for-each select="dv:frames">
          <section class="metadata">
            <table>
              <thead><tr><th colspan="4">Frames metadata</th></tr></thead>
              <tbody>
                <tr>
                  <td>
                    <dl>
                      <xsl:if test="@count"><dt>Count</dt><dd><xsl:value-of select="@count"/></dd></xsl:if>
                      <xsl:if test="@scan_type"><dt>Scan type</dt><dd><xsl:value-of select="@scan_type"/></dd></xsl:if>
                      <xsl:if test="@size"><dt>Size</dt><dd><xsl:value-of select="@size"/></dd></xsl:if>
                    </dl>
                  </td>
                  <td>
                    <dl>
                      <xsl:if test="@pts"><dt>Start timestamp</dt><dd><xsl:value-of select="@pts"/></dd></xsl:if>
                      <xsl:if test="@end_pts"><dt>End timestamp</dt><dd><xsl:value-of select="@end_pts"/></dd></xsl:if>
                    </dl>
                  </td>
                  <td>
                    <dl>
                      <xsl:if test="@video_rate"><dt>Video rate</dt><dd><xsl:value-of select="@video_rate"/></dd></xsl:if>
                      <xsl:if test="@aspect_ratio"><dt>Aspect ratio</dt><dd><xsl:value-of select="@aspect_ratio"/></dd></xsl:if>
                      <xsl:if test="@chroma_subsampling"><dt>Chroma subsampling</dt><dd><xsl:value-of select="@chroma_subsampling"/></dd></xsl:if>
                    </dl>
                  </td>
                  <td>
                    <dl>
                      <xsl:if test="@audio_rate"><dt>Audio rate</dt><dd><xsl:value-of select="@audio_rate"/></dd></xsl:if>
                      <xsl:if test="@channels"><dt>Channels</dt><dd><xsl:value-of select="@channels"/></dd></xsl:if>
                    </dl>
                  </td>
                </tr>
              </tbody>
            </table>
          </section>
          <section class="frames">
            <xsl:for-each select="dv:frame">
              <xsl:variable name="filename">
                <xsl:call-template name="substring-after-last">
                  <xsl:with-param name="string" select="../../@ref"/>
                  <xsl:with-param name="char" select="'/'"/>
                </xsl:call-template>
              </xsl:variable>
              <xsl:variable name="tc_display">
                <xsl:choose>
                  <xsl:when test="@tc">
                      <xsl:value-of select="@tc"/>
                  </xsl:when>
                  <xsl:otherwise>
                      <xsl:text>XX:XX:XX:XX</xsl:text>
                  </xsl:otherwise>
                </xsl:choose>
              </xsl:variable>
              <xsl:variable name="tc_filename_safe">
                <xsl:value-of select="translate($tc_display,':','-')"/>
              </xsl:variable>
              <xsl:variable name="jpg_name">
                <xsl:value-of select="$filename"/>
                <xsl:text>_n</xsl:text>
                <xsl:value-of select="substring(string(1000000 + @n), 2)"/>
                <xsl:text>_</xsl:text>
                <xsl:value-of select="$tc_filename_safe"/>
                <xsl:text>.jpg</xsl:text>
              </xsl:variable>
              <div class="frameError">
                <xsl:if test="dv:dseq">
                  <img>
                    <xsl:attribute name="src">
                      <xsl:value-of select="$jpg_name"/>
                    </xsl:attribute>
                  </img>
                </xsl:if>
                <xsl:if test="$tc_display"><p class="tc"><xsl:value-of select="$tc_display"/></p></xsl:if>
                <xsl:if test="@n"><p class="tc"><xsl:value-of select="@n"/></p></xsl:if>
                <xsl:if test="@rec_start"><p>Recording start</p></xsl:if>
                <xsl:if test="@rec_end"><p>Recording end</p></xsl:if>
                <xsl:if test="@rdt">
                  <p><strong>Recorded Date Time </strong>
                    <xsl:value-of select="@rdt"/>
                    <xsl:if test="@rdt_r"> (repeating) </xsl:if>
                    <xsl:if test="@rdt_nc"> (non-consecutive) </xsl:if>
                  </p>
                </xsl:if>
                <xsl:if test="@arb">
                  <p><strong>Arbitrary data </strong>
                    <xsl:value-of select="@arb"/>
                    <xsl:if test="@arb_r"> (repeating)</xsl:if>
                    <xsl:if test="@arb_nc"> (non-consecutive)</xsl:if>
                  </p>
                </xsl:if>
                <xsl:for-each select="dv:sta">
                    <xsl:call-template name="staType"/>
                </xsl:for-each>
                <xsl:for-each select="dv:aud">
                    <xsl:call-template name="audType"/>
                </xsl:for-each>
              </div>
            </xsl:for-each>
          </section>
        </xsl:for-each>
      </xsl:for-each>
      <footer><xsl:value-of select="dv:creator/dv:program"/> v.<xsl:value-of select="dv:creator/dv:version"/></footer>
    </body>
  </html>
  </xsl:template>
  <xsl:template match="dv:sta" name="staType">
    <xsl:if test="@t">
      <p class="errorNum">Error #<xsl:value-of select="@t"/>
        <span class="tooltip">
          <xsl:choose>
            <xsl:when test="@t=0">No error, what a nice DV macroblock.</xsl:when>
            <xsl:when test="@t=2">Replaced a macroblock with the one of the same position of the previous frame (guaranteed continuity).</xsl:when>
            <xsl:when test="@t=4">Replaced a macroblock with the one of the same position of the next frame (guaranteed continuity).</xsl:when>
            <xsl:when test="@t=6">A concealment method is used but not specified (guaranteed continuity).</xsl:when>
            <xsl:when test="@t=7">Error with an error code within the macro block.</xsl:when>
            <xsl:when test="@t=10">Replaced a macroblock with the one of the same position of the previous frame (no guaranteed continuity).</xsl:when>
            <xsl:when test="@t=12">Replaced a macroblock with the one of the same position of the next frame (no guaranteed continuity).</xsl:when>
            <xsl:when test="@t=14">A concealment method is used but not specified (no guaranteed continuity).</xsl:when>
            <xsl:when test="@t=15">Error with unknown position.</xsl:when>
            <xsl:otherwise>
              Unknown error
            </xsl:otherwise>
          </xsl:choose>
        </span>
      </p>
    </xsl:if>
    <xsl:if test="(number(@n) - number(@n_even)) > 1">
      <p class="red"><strong>Error within playback device</strong></p>
    </xsl:if>
  </xsl:template>
  <xsl:template match="dv:aud" name="audType">
      <p class="green"><strong>Frame Audio</strong></p>
      <xsl:if test="(number(@n) - number(@n_even)) > 1">
        <p class="red"><strong>Error within playback device</strong></p>
      </xsl:if>
  </xsl:template>
</xsl:stylesheet>
DISPLAY_XSL

# fill color handling
_convert_array_to_macroblock(){
  LUMA_AC="ffffffffffffffffffffff"
  CHROMA_AC="ffffffffffffff"
  COLOR_POINT="${1}"
  echo "${COLOR_POINT:0:6}${LUMA_AC}${COLOR_POINT:0:6}${LUMA_AC}${COLOR_POINT:0:6}${LUMA_AC}${COLOR_POINT:0:6}${LUMA_AC}${COLOR_POINT:6:6}${CHROMA_AC}${COLOR_POINT:12:6}${CHROMA_AC}"
  # get dv color data via
  # ffmpeg -f lavfi -i color=s=720x480:r=30000/1001:color=yellow -vframes 1 -f rawvideo -c:v dvvideo -pix_fmt yuv411p - | xxd -ps -c 80 | tail -n 1 | cut -c 9-14,121-126,141-146
}

_get_iso8601(){
    date +%FT%T
}

# font selection
if [[ -f "/Library/Fonts/Andale Mono.ttf" ]] ; then
  DEFAULTFONT="/Library/Fonts/Andale Mono.ttf"
elif [[ -f "/System/Library/Fonts/Supplemental/Andale Mono.ttf" ]] ; then
  DEFAULTFONT="/System/Library/Fonts/Supplemental/Andale Mono.ttf"
elif [[ -f "/System/Library/Fonts/Monaco.dfont" ]] ; then
  DEFAULTFONT="/System/Library/Fonts/Monaco.dfont"
elif [[ -f "/Library/Fonts/Microsoft/Lucida Console.ttf" ]] ; then
  DEFAULTFONT="/Library/Fonts/Microsoft/Lucida\Console.ttf"
elif [[ -f "/Library/Fonts/LetterGothicStd.otf" ]] ; then
  DEFAULTFONT="/Library/Fonts/LetterGothicStd.otf"
elif [[ -f "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf" ]] ; then
  DEFAULTFONT="/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf"
else
  _report -wt "$(basename "${0}") can't find a preferred font to use :("
fi

DV_YELLOW="5206ff1216ff9016ff"
DV_RED="d106ff7016ffda16ff"
FILL=$(_convert_array_to_macroblock "${DV_YELLOW}")
if [[ "${MASK_ONLY}" = "Y" ]] ; then
  FIND="(?<=9[0-9a-f]{5}[0][0-9a-f])[0-9a-f]{152}"
else
  FIND="(?<=9[0-9a-f]{5}[^0][0-9a-f])[0-9a-f]{152}"
fi

# filter handling
_get_filters(){
TILE_V="8"
TILE_H="4"
LESSONE="$((${TILE_V}*${TILE_H}-1))"
if [[ -n "${BLOCKS}" ]] ; then
    IFS=, read -ra BLOCK <<< "${BLOCKS}"
    FORMAT="format=yuv444p,"
    for BLOCK in "${BLOCK[@]}" ; do
        BLO=$((BLOCK%135))
        SEQ=$((BLOCK/135))
        if [[ "${HEIGHT}" == "576" ]] ; then
            SEQCOUNT=12
        else
            SEQCOUNT=10
        fi
        BLO_M5=$((BLO%5))
        if [[ "${BLO_M5}" == "0" ]] ; then
            I5=2 ; J=2
        elif [[ "${BLO_M5}" == "1" ]] ; then
            I5=6 ; J=1
        elif [[ "${BLO_M5}" == "2" ]] ; then
            I5=8 ; J=3
        elif [[ "${BLO_M5}" == "3" ]] ; then
            I5=0 ; J=0
        else
            I5=4 ; J=4
        fi
        I=$(((I5+SEQ)%SEQCOUNT))
        K=$(((BLOCK/5)%27))
        if [[ "${PIX_FMT}" = "yuv411p" && ( "${J}" -lt "4" || ( "${J}" -eq "4" && "${K}" -lt "24" )) ]] ; then
            W=32 ; H=8
        else
            W=16 ; H=16
        fi
        if [[ "${PIX_FMT}" = "yuv411p" ]] ; then
            WL=32 ; MACROBLOCK_ROWS=6 ; MBX_OFFSET=$(((J%2)*3))
        else
            WL=16 ; MACROBLOCK_ROWS=3 ; MBX_OFFSET=0
        fi
        MBx=$(((K+MBX_OFFSET)/MACROBLOCK_ROWS))
        if [[ "$((MBx%2))" -eq "0" ]] ; then
            MByt=$((K+MBX_OFFSET))
        else
            MByt=$((K+MBX_OFFSET+MACROBLOCK_ROWS-1-(((K+MBX_OFFSET)%MACROBLOCK_ROWS)*2)))
        fi
        MBy=$((MByt%MACROBLOCK_ROWS))
        if [[ "${PIX_FMT}" = "yuv411p" && "$((J%2))" -eq "1" ]] ; then
            SBx=$((J*144-16))
        else
            SBx=$((J*144))
        fi
        X=$((SBx+(WL*MBx)))
        Y=$(((I*48)+(MBy*H)))
        FILTER+="drawbox=w=${W}:h=${H}:x=${X}:y=${Y}:color=white@0.5:t=1,"
    done
    # remove trailing comma
    FILTER="${FILTER%?}"
elif [[ -n "${OUTPUTFILE}" ]] ; then
    FILTER="copy"
else
    FILTER="scale=iw/4:ih/4,transpose=2,tile=layout=${TILE_V}x${TILE_H}:init_padding=${LESSONE}:overlap=${LESSONE}:padding=1,transpose=1,setsar=1/1"
fi
}

_play_dv(){
  "${FFMPEG_PATH}" "${INPUT_OPTS[@]}" -i "${1}" -c:v copy -f rawvideo - | \
  xxd -p -c 80 | \
  perl -pe "s|${FIND}|${FILL}|g" | \
  xxd -r -p | \
  "${FFPLAY_PATH}" - -vf "${FILTER}"
}

_make_dvrescue_xml(){
  if [[ -z "${DVRESCUE_PATH}" ]] ; then
    DVRESCUE_PATH="$(which dvrescue)"
  fi
  if [[ ! -f "${DVRESCUE_PATH}" ]] ; then
    _report -w "The dvrescue command-line tool is not found."
    exit 1
  fi
  if [[ ! -f "${DVRESCUE_XML}" ]] ; then
    echo "Assessing $(basename "${DVFILE}")..."
    _mkdir2 "${SIDECAR_DIR}"
    "${DVRESCUE_PATH}" "${DVFILE}" > "${DVRESCUE_XML}"
  fi
}

_maketemp(){
    mktemp -q "/tmp/$(basename "${0}").XXXXXX"
    if [ "${?}" -ne 0 ]; then
        echo "${0}: Can't create temp file, exiting..."
        _writeerrorlog "_maketemp" "was unable to create the temp file, so the script had to exit."
        exit 1
    fi
}

_mkdir2(){
    local DIR2MAKE=""
    while [ "${*}" != "" ] ; do
        DIR2MAKE="${1}"
        if [ ! -d "${DIR2MAKE}" ] ; then
            mkdir -p "${DIR2MAKE}"
            if [ "${?}" -ne 0 ]; then
                _report -wt "${0}: Can't create directory at ${DIR2MAKE}"
                exit 1
            fi
        fi
        shift
    done
}

while [[ "${@}" != "" ]] ; do
  DVFILE="${1}"
  shift
  IFS="|" read CODEC_NAME HEIGHT PIX_FMT < <("${FFPROBE_PATH}" -v 0 "${DVFILE}" -select_streams v:0 -show_entries stream=codec_name,height,pix_fmt -of compact=p=0:nk=1)
  _get_filters
  BASENAME="$(basename "${DVFILE}")"
  DIRNAME="$(dirname "${DVFILE}")"
  DV_IMAGE_DIR="${BASENAME//./_}_dvrescue_images"
  if [[ -n "${OUTPUTDIR}" ]] && [[ -d "${OUTPUTDIR}" ]] ; then
    SIDECAR_DIR="${OUTPUTDIR}"
  elif [[ -n "${OUTPUTDIR}" ]] ; then
    echo "User selected output is not a valid directory. Exiting"
    exit 1
  else
    SIDECAR_DIR="${DIRNAME}"
  fi
  IMAGE_DIR="${SIDECAR_DIR}/${DV_IMAGE_DIR}"
  DVRESCUE_HTML="${SIDECAR_DIR}/${DV_IMAGE_DIR}/${BASENAME}.dvrescue.html"
  if [[ ! -s "${DVRESCUE_XML}" ]] ; then
    DVRESCUE_XML="${SIDECAR_DIR}/${BASENAME}.dvrescue.xml"
  fi

  if [[ -n "${OUTPUTFILE}" ]]  ; then
    JPG_OUTPUT="${OUTPUTFILE}"
    FRAMES=(-frames:v 1)
    "${FFMPEG_PATH}" -nostdin "${FFMPEG_INPUT_OPTS[@]}" -i "${DVFILE}" -vframes:v 1 -c:v copy -f rawvideo - | \
    xxd -p -c 80 | \
    perl -pe "s|${FIND}|${FILL}|g" | \
    xxd -r -p | \
    "${FFMPEG_PATH}" -nostdin -y -i - "${FRAMES[@]}" -vf "${FILTER}" "${JPG_OUTPUT}"
  elif [[ "${ERROR_REVIEW}" = "Y" ]] || [[ "${GIF_OUTPUT}" = "Y" ]] ; then
    _make_dvrescue_xml
    if [[ -z "${XMLSTARLET_PATH}" ]] ; then
      XMLSTARLET_PATH="$(which xmlstarlet)"
    fi
    if [[ ! -f "${XMLSTARLET_PATH}" ]] ; then
      _report -w "The xmlstarlet command-line tool is not found."
      exit 1
    fi
    echo "Making jpegs of errors within $(basename "${DVFILE}")..."
    TOTAL_FRAMES="$("${XMLSTARLET_PATH}" sel -N d="https://mediaarea.net/dvrescue" -t -m "d:dvrescue/d:media" -v "sum(d:frames/@count)" -n "${DVRESCUE_XML}")"
    COUNTER=1
    "${XMLSTARLET_PATH}" sel -N d="https://mediaarea.net/dvrescue" -t -m "d:dvrescue/d:media/d:frames/d:frame[d:sta]" -v @n -o "," -v @pts -o "," -v @tc -n "${DVRESCUE_XML}" | while read error_frame ; do
      N="$(echo "${error_frame}" | cut -d "," -f1)"
      PTS="$(echo "${error_frame}" | cut -d "," -f2)"
      TC="$(echo "${error_frame}" | cut -d "," -f3)"
      if [[ -n "${TC}" ]] ; then
        TC_E="$(echo "${TC}" | sed 's|:|\\:|g')"
      else
        TC_E="XX\\:XX\\:XX\\:XX"
      fi
      TC_FILENAME_SAFE="n$(printf "%06d" ${N})_$(echo "${TC:-XX:XX:XX:XX}" | sed 's|:|-|g')"
      PTS_E="$(echo "${PTS}" | sed 's|:|\\:|g')"
      if [[ "${GIF_OUTPUT}" = "Y" ]] ; then
        _mkdir2 "${IMAGE_DIR}/dvrescue_tmp"
        JPG_OUTPUT="${IMAGE_DIR}/dvrescue_tmp/${BASENAME}_$(echo "$COUNTER" | awk '{ printf("%06i", $1) }').jpg"
      else
        _mkdir2 "${IMAGE_DIR}"
        JPG_OUTPUT="${IMAGE_DIR}/${BASENAME}_${TC_FILENAME_SAFE}.jpg"
      fi
      "${FFMPEG_PATH}" -nostdin -ss "${PTS}" -i "${DVFILE}" -vframes:v 1 -c:v copy -f rawvideo - | \
      xxd -p -c 80 | \
      perl -pe "s|${FIND}|${FILL}|g" | \
      xxd -r -p | \
      "${FFMPEG_PATH}" -nostdin -y -i - -vf "pad=w=iw:h=ih+24:x=0:y=24:color=gray,drawbox=t=fill:w=iw*(${N}/${TOTAL_FRAMES}):h=24:c=silver:x=0:y=0,drawtext=fontfile=${DEFAULTFONT}:y=4:x=4:text='PTS=${PTS_E} TC=${TC_E} Frame=${N}'" "${JPG_OUTPUT}"
      ((COUNTER=COUNTER+1))
    done
    if [[ "${GIF_OUTPUT}" = "Y" ]] ; then
      GIF_PALETTE="$(_maketemp)"
      "${FFMPEG_PATH}" -nostdin -f image2 -i "${IMAGE_DIR}/dvrescue_tmp/${BASENAME}_%06d.jpg" -vf palettegen "${GIF_PALETTE}.png"
      "${FFMPEG_PATH}" -nostdin -f image2 -i "${IMAGE_DIR}/dvrescue_tmp/${BASENAME}_%06d.jpg" -i "${GIF_PALETTE}.png" -filter_complex paletteuse "${IMAGE_DIR}/${BASENAME}_error.gif"
      rm -r "${IMAGE_DIR}/dvrescue_tmp" "${GIF_PALETTE}.png"
    else
      xsltproc /tmp/dvplay_display.xsl "${DVRESCUE_XML}" > "${DVRESCUE_HTML}"
    fi
  else
    _play_dv "${DVFILE}"
  fi
done
