#!/bin/bash

# Vid2Mob - Video 2 Mobile converter
# Copyright (c) 2009 - Luis León Cárdenas Graide < lcardena [@] nic [.] cl >
#
# 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 3 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. There is NO WARRANTY,
# to the extent permitted by law. 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, see <http://www.gnu.org/licenses/>.
#
#
# If you think this is useful, you can donate to the author:
# https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=1290721
# Thank you, very much.

# Comando corto
# ffmpeg -i video.wmv -s 352x288 -r 12 -ac 1 -ar 8000 -b 30k -ab 12k -t 60 -acodec copy video.mp4
#
# Comandos largos
# mencoder undo.mpg -nosound -ovc lavc -lavcopts vcodec=mpeg4 -vf expand=176:144,scale=176:-2 -o movie.avi -ofps 12
# mplayer -vo null -ao pcm -af resample=8000,volume=+4db:sc undo.mpg
# ffmpeg -i movie.avi -i audiodump.wav -b 48 -ac 1 -ab 12 -map 0.0 -map 1.0 undo.3gp

set -o nounset

declare -i AUDIO_BITRATE_KBPS=12
declare -i AUDIO_HERTZ=8000
declare -i VIDEO_BITRATE_KBPS=48
declare -i VIDEO_FPS=12
declare VIDEO_RESOLUTION='352:288' # cif

declare tmpdir

function noext() {
  local name="${1:?}"
  if [[ "$name" =~ ^(.*)\.[^.]+$ ]]; then
    name="${BASH_REMATCH[1]}"
  fi
  printf '%s' "$name"
}

function cleanup() {
  rm -rfv "$tmpdir"
}

function execute() {
  local -a cmd="$@"
  set -x
  time ${cmd[@]}
  local err=$?
  set +x
  return $err
}

function fresh_filename() {
  local basefile="${1:?}"
  local ext="${2:-}"
  if ! [ -z "$ext" ]; then
    ext=".$ext"
  fi
  local file="$basefile$ext"
  local -i n=0
  while [ -f "$file" ]; do
    file="$basefile"-"$n$ext"
    : $(( n++ ))
  done
  printf '%s' "$file"
}

function video_reencode() {
  local video_in="${1:?}"
  local video_out="${2:?}"
  execute ffmpeg -i "$video_in" -acodec copy -vcodec copy "$video_out"
}

function audio_extract() {
  local video_in="${1:?}"
  local audio_out="${2:?}"
  execute mplayer -vo null -vc null -ao pcm:file='%'${#audio_out}'%'"$audio_out" -af resample="$AUDIO_HERTZ":volnorm:sc "$video_in"
}

function audio_convert() {
  local audio_wav="${1:?}"
  local audio_aac="${2:?}"
  execute faac -b "$AUDIO_BITRATE_KBPS" -c "$AUDIO_HERTZ" -w -o "$audio_aac" "$audio_wav"
}

function video_extract() {
  local video_in="${1:?}"
  local video_out="${2:?}"
  execute mencoder "$video_in" -nosound -ovc lavc -lavcopts vcodec=mpeg4:vbitrate="$VIDEO_BITRATE_KBPS" -vf expand="$VIDEO_RESOLUTION",scale="$VIDEO_RESOLUTION" -o "$video_out" -ofps "$VIDEO_FPS" -idx
}

function merge_av() {
  local audio_in="${1:?}"
  local video_in="${2:?}"
  local video_out="${3:?}"
  execute ffmpeg -i "$video_in" -i "$audio_in" -ac 1 -map 0.0 -map 1.0 -acodec copy -vcodec copy "$video_out"
}

declare self="$( basename "$0" )"
self="$( noext "$self" )"

declare video_in="${1:-}"

if [ -z "$video_in" ]; then
  echo Missing input video
  echo Usage: "$self" 'input_video [ destination_directory ]'
  echo
  echo 'Vid2Mob - Video 2 Mobile converter
version 1.0
Copyright (c) 2009 Luis León Cárdenas Graide < lcardena [@] nic [.] cl >
License  GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>'
  exit 1
fi

declare video_base="$( basename "$video_in" )"
video_base="$( noext "$video_base" )"
echo BASE = "$video_base"

tmpdir="$( mktemp -d ."$self".$$."${video_base:0:8}".XXXXXX )" || {
  echo Can\'t create temp dir
  exit 2
}
echo TMP = "$tmpdir"

declare dest_dir="${2:-.}"
echo DEST_DIR = "$dest_dir"

echo
echo Reencoding...
declare tmp_video_reencoded="$tmpdir"/video.wmv
video_reencode "$video_in" "$tmp_video_reencoded"

echo
echo Extrayendo audio...
declare tmp_audio="$tmpdir"/audiodump.wav
audio_extract "$tmp_video_reencoded" "$tmp_audio" || {
  declare err=$?
  echo ERROR extracting audio
  cleanup
  exit $err
}

echo
echo Convirtiendo audio...
declare tmp_audio2="$tmpdir"/audiodump.aac
audio_convert "$tmp_audio" "$tmp_audio2" || {
  echo ERROR converting audio
  cleanup
  exit 3
}
rm -vf "$tmp_audio"

echo
echo Extrayendo video...
declare tmp_video="$tmpdir"/moviedump.mp4
video_extract "$tmp_video_reencoded" "$tmp_video" || {
  declare err=$?
  echo ERROR extracting video
  cleanup
  exit $err
}
rm -vf "$tmp_video_reencoded"

echo
echo Mezclando A/V...
declare video_out="$( fresh_filename "$dest_dir"/"$video_base" mp4 )"
echo OUT = "$video_out"
merge_av "$tmp_audio2" "$tmp_video" "$video_out" || {
  echo ERROR merging video
  cleanup
  exit 4
}

cleanup

echo "Converted $video_in -> $video_out"
ls -l "$video_in" "$video_out"

