How to convert videos/movies for the VTech Innotab using FFMPEG (SOLVED)

The VTech Innotab is a young children’s tablet for learning. When I picked up two of them from the local Target, we installed the six free games but was rather disappointed with the video capabilities listed in the manual:

  • File Type: AVI
  • Resolution: 480 x 272
  • Video Codec: MJPEG
  • Video Bit rate: 2400kbps
  • Frame rate: 15fps
  • Audio Sampling Rate: 22.05kHz
  • Audio Channel: Mono
  • Audio Encoder: PCM

MJPEG is a very poor codec as it produces quite large files and tends to be very blocky with any type of motion. After a bit of research, I discovered that the Innotab would accept MPEG4 video but the audio still had to be PCM mono. So the MPEG4 video file specification:

  • File Type: AVI
  • Resolution: 480 x 272
  • Video Codec: MPEG4 with a video tag of “XVID”
  • Video Bit rate: variable or a maximum of 3000kbps
  • Frame rate: 29.997fps
  • Audio Sampling Rate: 22.05kHz
  • Audio Channel: Mono
  • Audio Encoder: PCM

I chose to use ffmpeg as it is available on all major platforms. There are a few steps that need to be performed to create a working video:

Convert the video. We use “-1” for the height as we want to keep the aspect of the original video

ffmpeg -i "input.wmv" -r 65535/2733 -vcodec mpeg4 -vtag XVID -q:v 8 -vf "scale=480:-1" -an -y "video_out.mp4"

Extract the audio to mp3 format. This is necessary as the pcm_s16le codec is very finicky on the audio input

ffmpeg -i "input.wmv" -r 65535/2733 -vn -c:a libmp3lame -ar 22050 -ac 1 -ab 128k -y "audio_out.mp3"

Increase the volume (if necessary). Change the “10” if it is too loud or quiet

mp3gain -g 10 "audio_out.mp3"

Convert the mp3 to PCM and combine with the video to produce the avi file

ffmpeg -i "video_out.mp4" -i "audio_out.mp3" -r 65535/2733 -vcodec copy -map 0:0 -c:a pcm_s16le -ar 22050 -ac 1 -map 1:0 -y video_ready_for_innotab.avi

HINT: you get three free games for each Innotab device but the games, ebooks, etc are tied to the VTech account not to each device. This allows you to save $$ if you have more than one Innotab device.

Share Button

Howto convert an entire directory of videos to play on your Sony Playstation 3 using ffmpeg

I think a lot of people have been struggling with mass converting of videos for the ps3…
I’ve been searching for a way to mass convert my videos (mostly podcasts) to play on my Sony PlayStation 3 over the wire with Mediatomb.  For a long time I’ve been using a hodpodge of mp4box and mencoder to convert the videos.  The problem was that mp4box more often then not would crash or get stuck in a loop where it fills up a 1TB harddrive converting a 20mb file.  There had to be a better way.

If your ffmpeg doesn’t support x264 (video) or aac (audio) encoding, like all Ubuntu Linux distributions, then you will have to recompile ffmpeg.  Don’t worry, it is easier then you think!

FakeOutdoorsman over on the Ubuntu Forums posted the method to build ffmpeg from scratch:

Choose your Ubuntu

0.The instructions on the page are for Ubuntu Jaunty Jackalope 9.04 and Ubuntu Intrepid Ibex 8.10. Separate instructions are also available for other releases:

* Install FFmpeg and x264 on Ubuntu Hardy Heron 8.04 LTS
* Install FFmpeg and x264 on Ubuntu Dapper Drake 6.06 LTS

Getting the Dependencies

1. Uninstall x264, libx264-dev, and ffmpeg if they are already installed. Open a terminal and run the following:

sudo apt-get purge ffmpeg x264 libx264-dev

2. Next, get all of the packages you will need to install FFmpeg and x264 (you may need to enable the universe and multiverse repositories):

Code:

sudo apt-get update
sudo apt-get install build-essential subversion git-core checkinstall yasm texi2html libfaac-dev libfaad-dev libmp3lame-dev libsdl1.2-dev libtheora-dev libx11-dev libxvidcore4-dev zlib1g-dev

Install x264
3. Get the most current source files from the official x264 git repository, compile, and install. You can run “./configure –help” to see what features you can enable/disable. If you are behind a firewall or unable to use git, then daily source tarballs are also available.

cd
git clone git://git.videolan.org/x264.git
cd x264
./configure
make
sudo checkinstall --fstrans=no --install=yes --pkgname=x264 --pkgversion "1:0.svn`date +%Y%m%d`-0.0ubuntu1" --default

Install FFmpeg
4. Get the most current source files from the official FFmpeg svn, compile, and install. Run “./configure –help” to see what features you can enable/disable. If you are behind a firewall or unable to use subversion, then nightly FFmpeg snapshots are also available.

cd
svn checkout svn://svn.ffmpeg.org/ffmpeg/trunk ffmpeg
cd ffmpeg
./configure --enable-gpl --enable-nonfree --enable-pthreads --enable-libfaac --enable-libfaad --enable-libmp3lame --enable-libtheora --enable-libx264 --enable-libxvid --enable-x11grab
make
sudo checkinstall --fstrans=no --install=yes --pkgname=ffmpeg --pkgversion "3:0.svn`date +%Y%m%d`-12ubuntu3" --default 

That’s it for installation. You can keep the ~/x264 and ~/ffmpeg directories if you later want to update the source files to a new revision. See “Updating Your Installation” below for more details.

Now that we have a working ffmpeg, we can go on to the converting the video files (convert_videos.sh):

#!/bin/bash

function print_usage {
  echo "============================================================================================="
  echo "        convert_videos.sh [file|directory] [output directory] {bb|bb_storm|ps3} {file prefix}" 
  echo "============================================================================================="
}

function verify_file {
  echo j
}

function process_file {
  ORIG_FILE="$1"
  DEST_DIR="$2"

  if [[ -z ${BLACKBERRY} ]]; then
    DEST_FILE=${DEST_DIR}/${FILE_PREFIX}$( basename "${ORIG_FILE}" | perl -ne 's/\.(?:[a-z,A-Z,0-9]{3,4})$/\.mp4/; print $_' )
  else
    DEST_FILE=${DEST_DIR}/${FILE_PREFIX}$( basename "${ORIG_FILE}" | perl -ne 's/\.(?:[a-z,A-Z,0-9]{3,4})$/_bb\.mp4/; print $_' )
  fi

  if [[ -f "${DEST_FILE}" ]]; then
    echo "    We already processed \"${ORIG_FILE}\" ... skipping"
  else
    VID_INFO_FPS=$( mplayer -identify -nosound -vo null -nocache -really-quiet -frames 1 "${ORIG_FILE}" 2>/dev/null | grep FPS ) 
    VID_INFO_FPS=${VID_INFO_FPS#*=}
    VID_INFO_WIDTH=$( mplayer -identify -nosound -vo null -nocache -really-quiet -frames 1 "${ORIG_FILE}" 2>/dev/null | grep WIDTH ) 
    VID_INFO_WIDTH=${VID_INFO_WIDTH##*=}
    VID_INFO_HEIGHT=$( mplayer -identify -nosound -vo null -nocache -really-quiet -frames 1 "${ORIG_FILE}" 2>/dev/null | grep HEIGHT ) 
    VID_INFO_HEIGHT=${VID_INFO_HEIGHT##*=}
    VID_INFO_ASPECT=$( mplayer -identify -nosound -vo null -nocache -really-quiet -frames 1 "${ORIG_FILE}" 2>/dev/null | grep ASPECT ) 
    VID_INFO_ASPECT=${VID_INFO_ASPECT##*=}

    AUD_INFO_FORMAT=$( mplayer -identify -ao null -vo null -nocache -really-quiet -frames 1 "${ORIG_FILE}" 2>/dev/null | grep AUDIO_FORMAT ) 
    AUD_INFO_FORMAT=${AUD_INFO_FORMAT##*=}
    AUD_INFO_CHANNELS=$( mplayer -identify -ao null -vo null -nocache -really-quiet -frames 1 "${ORIG_FILE}" 2>/dev/null | grep AUDIO_NCH ) 
    AUD_INFO_CHANNELS=${AUD_INFO_CHANNELS##*=}
    AUD_INFO_BITRATE=$( mplayer -identify -ao null -vo null -nocache -really-quiet -frames 1 "${ORIG_FILE}" 2>/dev/null | grep ID_AUDIO_BITRATE ) 
    AUD_INFO_BITRATE=${AUD_INFO_BITRATE##*=}

    if (( ${AUD_INFO_BITRATE} < 163840 )); then
      AUD_INFO_BITRATE=160
    else
      AUD_INFO_BITRATE=$( expr ${AUD_INFO_BITRATE} / 1024 )
    fi

    ###############
    #  We need to make the frame rate an acceptible amoun
    ###############
    case ${VID_INFO_FPS} in
      60.000)
        # HD
        VID_INFO_FPS=59.94
        ;;
      30.000)
        # NTSC
        VID_INFO_FPS=29.97
        ;;
      24.000)
        # PAL
        VID_INFO_FPS=23.97
        ;;
    esac 

    ###############
    #  We need to make the video resolution a multiple of 16 for it to be properly compressed
    ###############
    if (( ${VID_INFO_HEIGHT} % 16 )); then
      VID_BORDER_VERTICAL=$( expr 16 - ${VID_INFO_HEIGHT} % 16 )
      VID_BORDER_VERTICAL=$( expr ${VID_BORDER_VERTICAL} / 2 )

      if (( ${VID_BORDER_VERTICAL} % 2 )); then
        let VID_BORDER_VERTICAL_TOP+=$( expr ${VID_BORDER_VERTICAL} - 1 )
        let VID_BORDER_VERTICAL_BOTTOM+=$( expr ${VID_BORDER_VERTICAL} + 1 )
      else
        VID_BORDER_VERTICAL_TOP=${VID_BORDER_VERTICAL}
        VID_BORDER_VERTICAL_BOTTOM=${VID_BORDER_VERTICAL}
      fi
    else
      VID_BORDER_VERTICAL_TOP=0
      VID_BORDER_VERTICAL_BOTTOM=0
    fi
 
    if (( ${VID_INFO_WIDTH} % 16 )); then
      VID_BORDER_HORIZONTAL=$( 16 - ${VID_INFO_WIDTH} % 16 )
      VID_BORDER_HORIZONTAL=$( ${VID_INFO_WIDTH} / 2 )

      if (( ${VID_BORDER_HORIZONTAL} % 2 )); then
        let VID_BORDER_HORIZONTAL_RIGHT+=$( expr ${VID_BORDER_HORIZONTAL} + 1 )
        let VID_BORDER_HORIZONTAL_LEFT+=$( expr ${VID_BORDER_HORIZONTAL} - 1 )
      else
        VID_BORDER_HORIZONTAL_RIGHT=${VID_BORDER_HORIZONTAL}
        VID_BORDER_HORIZONTAL_LEFT=${VID_BORDER_HORIZONTAL}
      fi
    else
      VID_BORDER_HORIZONTAL_LEFT=0
      VID_BORDER_HORIZONTAL_RIGHT=0
    fi

    if &#91;&#91; -z ${VID_INFO_ASPECT} &#93;&#93; || &#91;&#91; ${VID_INFO_ASPECT} == "0.0000" &#93;&#93;; then
      VID_INFO_ASPECT="16:9"
    fi

    if &#91;&#91; -z ${AUD_INFO_CHANNELS} &#93;&#93;; then
      AUD_INFO_CHANNELS=2
    fi


    ##############
    # If we're not converting for the blackberry, perform a normal conversion 
    ##############
    if &#91;&#91; -z ${BLACKBERRY} &#93;&#93;; then
      VID_INFO_RESOLUTION="${VID_INFO_WIDTH}x${VID_INFO_HEIGHT}"

      convert_file_first_pass 

      if &#91;&#91; ! -z ${FIRST_PASS_BITRATE} &#93;&#93;; then
        BITRATE=${FIRST_PASS_BITRATE}
      fi
    else
      ############
      # if we have a blackberry, set the resolution appropriately
      ############
      case ${BB_TYPE} in
        STORM)
          VID_INFO_RESOLUTION="480x360"
          ;;
        *)
          VID_INFO_RESOLUTION="240x180"
          ;;
      esac
    fi

    convert_file_second_pass 
  fi
}

function process_directory {
 ORIG_VIDEO_DIR="$1"
 DEST_VIDEO_DIR="$2"

  if &#91;&#91; -d "${ORIG_VIDEO_DIR}" &#93;&#93; && &#91;&#91; -d "${DEST_VIDEO_DIR}" &#93;&#93;; then
    IFS=$'\n'

    for ORIG_VIDEO_FILE in $( find "${ORIG_VIDEO_DIR}" -depth -maxdepth 1 -type f -readable -iregex '.*\.\(3gp\|3g2\|avi\|divx\|flv\|m4v\|mj2\|mov\|mp1\|mp2\|mp4\|mpe\|mpeg\|mpeg4\|mpg\|mkv\|mv\|ogm\|rm\|rmvb\|rv\|qt\|wmv\)' ); do
      process_file "${ORIG_VIDEO_FILE}" "${DEST_VIDEO_DIR}"
    done
  fi 
}

function convert_file_first_pass {
  echo "----------------------------------------------------"
  echo "   First pass: ${ORIG_FILE}"
  echo "ffmpeg -i \"${ORIG_FILE}\" -an -pass 1 \
    -vcodec libx264 -flags +loop -cmp +chroma -partitions +parti4x4+partp8x8+partb8x8 \
    -me_method epzs -subq 1 -trellis 0 -refs 1 -bf 3 -b_strategy 1 -level 31 -coder 1 -me_range 16 -g 250 -keyint_min 25 \
    -sc_threshold 40 -i_qfactor 0.71 -bt 200kb -rc_eq 'blurCplx^(1-qComp)' -qcomp 0.6 -qmin 1 -qmax 51 -qdiff 4 \
    -padtop ${VID_BORDER_VERTICAL_TOP} -padbottom ${VID_BORDER_VERTICAL_BOTTOM} \
    -padleft ${VID_BORDER_HORIZONTAL_LEFT} -padright ${VID_BORDER_HORIZONTAL_RIGHT} \
    -threads 2 \
    -s ${VID_INFO_RESOLUTION} -aspect ${VID_INFO_ASPECT} -f rawvideo -y /dev/null" 

  ffmpeg -i "${ORIG_FILE}" -an -pass 1 \
    -vcodec libx264 -flags +loop -cmp +chroma -partitions +parti4x4+partp8x8+partb8x8 \
    -me_method epzs -subq 1 -trellis 0 -refs 1 -bf 3 -b_strategy 1 -level 31 -coder 1 -me_range 16 -g 250 -keyint_min 250 \
    -sc_threshold 40 -i_qfactor 0.71 -bt 200kb -rc_eq 'blurCplx^(1-qComp)' -qcomp 0.6 -qmin 1 -qmax 51 -qdiff 4 \
    -padtop ${VID_BORDER_VERTICAL_TOP} -padbottom ${VID_BORDER_VERTICAL_BOTTOM} \
    -padleft ${VID_BORDER_HORIZONTAL_LEFT} -padright ${VID_BORDER_HORIZONTAL_RIGHT} \
    -threads 2 \
    -s ${VID_INFO_RESOLUTION} -aspect ${VID_INFO_ASPECT} -f rawvideo -y /dev/null 2>&1 | tee pass2.out

  BITRATE=$( grep -e "\[libx264.*kb\/s" pass2.out )
  BITRATE=${BITRATE##*:}
  BITRATE=${BITRATE/.*}

  echo "average first pass bitrate: ${BITRATE}"

  if [[ -n ${BITRATE} ]]; then
    if (( ${BITRATE} % 16 )); then
      let BITRATE+=$( expr ${BITRATE} % 16 )
    fi
  else
    if (( ${VID_INFO_WIDTH} > 1024 )); then
       BITRATE=15360
    elif (( ${VID_INFO_WIDTH} > 900 )); then
       BITRATE=10240 
    elif (( ${VID_INFO_WIDTH} > 719 )); then
       BITRATE=8192
    elif (( ${VID_INFO_WIDTH} > 620 )); then
       BITRATE=2560
    else
       BITRATE=512
    fi
  fi

  MAX_BITRATE=$( expr ${BITRATE} + 512 )
}

function convert_file_second_pass {
  echo "----------------------------------------------------"
  echo "   Second pass: ${ORIG_FILE}"

  if [[ -n ${BLACKBERRY} ]]; then
    echo "ffmpeg -i \"${ORIG_FILE}\" -vcodec mpeg4 -vtag XVID -s ${VID_INFO_RESOLUTION} \
      -qscale 10 -ab 48k -ar 22050 -ac 2 -acodec libmp3lame -deinterlace \
      -b 512kb -qmin 1 -qmax 51 \
      -padtop ${VID_BORDER_VERTICAL_TOP} -padbottom ${VID_BORDER_VERTICAL_BOTTOM} \
      -padleft ${VID_BORDER_HORIZONTAL_LEFT} -padright ${VID_BORDER_HORIZONTAL_RIGHT} \
      -aspect ${VID_INFO_ASPECT} \"${DEST_FILE}\""

    ffmpeg -i "${ORIG_FILE}" -vcodec mpeg4 -vtag XVID -s ${VID_INFO_RESOLUTION} \
      -ab 48k -ar 22050 -ac 2 -acodec libmp3lame -deinterlace \
      -b 512kb -qmin 1 -qmax 51 \
      -padtop ${VID_BORDER_VERTICAL_TOP} -padbottom ${VID_BORDER_VERTICAL_BOTTOM} \
      -padleft ${VID_BORDER_HORIZONTAL_LEFT} -padright ${VID_BORDER_HORIZONTAL_RIGHT} \
      -aspect ${VID_INFO_ASPECT} "${DEST_FILE}"
  else
    echo "ffmpeg -i \"${ORIG_FILE}\" -acodec libfaac -ar 44100 -ac ${AUD_INFO_CHANNELS} \
      -async 1 -f mp4 -pass 2 -vcodec libx264 -vtag XVID -flags +loop+ilme -cmp +chroma \
      -partitions +parti4x4+partp8x8+partb8x8 -flags2 +mixed_refs -me_method umh -subq 5 \
      -trellis 1 -refs 5 -bf 3 -b_strategy 1 -level 31 -coder 1 -me_range 16 \
      -g 250 -keyint_min 250 -sc_threshold 40 -i_qfactor 0.71 -bt 200kb \
      -rc_eq 'blurCplx^(1-qComp)' -qcomp 0.6 -qmin 3 -qmax 15 -qdiff 4 \
      -s ${VID_INFO_RESOLUTION} -aspect ${VID_INFO_ASPECT} \
      -padtop ${VID_BORDER_VERTICAL_TOP} -padbottom ${VID_BORDER_VERTICAL_BOTTOM} \
      -padleft ${VID_BORDER_HORIZONTAL_LEFT} -padright ${VID_BORDER_HORIZONTAL_RIGHT} \
      -b ${BITRATE}kb -maxrate ${MAX_BITRATE}kb \
      -bufsize ${MAX_BITRATE}kb -ab ${AUD_INFO_BITRATE}kb \
      -threads 2 \
      -r ${VID_INFO_FPS} \"${DEST_FILE}\""

    ffmpeg -i "${ORIG_FILE}" -acodec libfaac -ar 44100 -ac ${AUD_INFO_CHANNELS} \
      -async 1 -f mp4 -pass 2 -vcodec libx264 -vtag XVID -flags +loop+ilme -cmp +chroma \
      -partitions +parti4x4+partp8x8+partb8x8 -flags2 +mixed_refs -me_method umh -subq 5 \
      -trellis 1 -refs 5 -bf 3 -b_strategy 1 -level 31 -coder 1 -me_range 16 \
      -g 250 -keyint_min 250 -sc_threshold 40 -i_qfactor 0.71 -bt 200kb \
      -rc_eq 'blurCplx^(1-qComp)' -qcomp 0.6 -qmin 1 -qmax 51 -qdiff 4 \
      -s ${VID_INFO_RESOLUTION} -aspect ${VID_INFO_ASPECT} \
      -padtop ${VID_BORDER_VERTICAL_TOP} -padbottom ${VID_BORDER_VERTICAL_BOTTOM} \
      -padleft ${VID_BORDER_HORIZONTAL_LEFT} -padright ${VID_BORDER_HORIZONTAL_RIGHT} \
      -b ${BITRATE}kb -maxrate ${MAX_BITRATE}kb \
      -bufsize ${MAX_BITRATE}kb -ab ${AUD_INFO_BITRATE}kb \
      -threads 2 \
      -r ${VID_INFO_FPS} "${DEST_FILE}"
  fi
}

if [[ -n "$1" ]] && [[ -n "$2" ]]; then
  if [[ -n "$3" ]]; then
    case "$3" in
      bb)
        BLACKBERRY=1
        BB_TYPE="norm"
        ;;
      bb_storm)
        BLACKBERRY=1
        BB_TYPE="STORM"
        ;;
      ps3)
        ;;
      *)
        ;;
    esac
  fi

  if [[ -n "$4" ]]; then
    FILE_PREFIX="${4}_"
  else
    FILE_PREFIX=""
  fi

  if [[ -f "$1" ]]; then
    process_file "$1" "$2"
  elif [[ -d "$1" ]]; then
    process_directory "$1" "$2"
  fi
else
  print_usage
  exit
fi

The ffmpeg parameters are based off of Using ffmpeg to transcode video for the PS3. Hope his works for you too.

Share Button

RealNetworks releases RealDVD – waste of money?

On Twitter, Jim Louderback @louderb pointed out that RealNetworks released a controversial new product called RealDVD.  What is RealDVD?  It will copy your dvd movie, bit for bit, on to your harddrive with the CSS encryption intact.  For your enjoyment, it slaps on a DRM scheme as the dvd is being transferred to your computer.  That’s 4GB to 9GB of space taken up by a single movie.

Does this mean you can take the dvd copy you made and put it on your iPod or video player?  Nope.  The iPod and most portable mp4 players have no way to interpret the dvd copy.  So, what can you do with the dvd copy made by RealDVD?  Well, you can play it on your computer and possibly burn it to a dvd blank.  You can even play it on up to 4 other computers.  Forget about copying to other people even if you are able to strip the DRM, the dvd copy is watermarked with your information.

There are several FREE programs that will allow you to copy a dvd movie, bit for bit, without the DRM being added.  There are others, such as Handbreak, that will even rip the dvd and present you with a file ready to be uploaded to your iPod.

At this point, RealDVD doesn’t appear to be of any real value for us.  It does bring a lot of attention on to RealNetworks though.  Makes me wonder if this is nothing more than a marketing ploy.

The only way the MPAA will sanction this will be as direct competition to the iTunes movie Store.

Share Button

Using AviDemux 2.4.1 to convert a video to h.264 mpeg4 for the Sony Playstation 3

Hi all,

After trial and error, I finally figured out how to convert an old divx 3 (you know, the old hacked version of the codec) video file to a format that my Sony Playstation 3 (PS3) could handle.  Why is it that Sony has made the PS3 to be such a finicky beast when it comes to reading video files, I will never know:

How to convert a video file using AviDemux v2.4.1 on Ubuntu 8.04 (Hardy Heron):

  • Load the original video file into AviDemux
  • Auto -> PSP (H.264) – choose defaults

  • Video -> Configure -> 2 Pass

  • Format -> MP4

  • Save with the extension “.mp4”

If you’re going to put the video on an USB thumbdrive, you will need to create a folder:

  • On the USB Thumbdrive:   VIDEO
  • Group videos with subdirectories:  VIDEO / SCIFI
Share Button