Building a TV Server in a CHROOT Environment on a Synology NAS

1. Work Environment

NAS:  Synology DS213 with DSM 4.2-­â€3211
OS for Cross Compiling:  CentOS 6.3

Before you begin:

Enable SSH.

If you have a battery backup unit then enable UPS.

Enable guest account.

Enable Web Station (for channel icons).

Create Windows Share folders (temp, recordings, documents, pictures, music, & videos)

You will need to donate $20 to to get a version of the software that will run on your Synology DS213 which has an Arm processor and won’t run the standard x86 version that you can download from the site.

You will also need a subscription to Schedules Direct.

2. Bootstrap

DiskStation> cd /volume1/@tmp

DiskStation> wget

DiskStation> chmod +x syno-mvkw-bootstrap_1.2-7_arm-ds111.xsh

DiskStation> sh syno-mvkw-bootstrap_1.2-7_arm-ds111.xsh

#– needed since DSM 4.0

DiskStation> vi /root/.profile

#– add /opt/bin:/opt/sbin: after PATH=

#– PATH=/opt/bin:/opt/sbin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/syno/…

DiskStation> reboot

3. Setup Debian

First, we need to build a version of Debian for the ARM processor.  A prebuilt version of Debian Wheezy for the ARM can be downloaded here.

PRE.cjk { font-family: “WenQuanYi Micro Hei”,monospace; }PRE.ctl { font-family: “Lohit Hindi”,monospace; }P { margin-bottom: 0.08in; }TT.cjk { font-family: “WenQuanYi Micro Hei”,monospace; }TT.ctl { font-family: “Lohit Hindi”,monospace; }A:link { }

3.1 Building and Installing QEMU

  • Download the QEMU source (0.12.4, the current release, is available here).  Your linux distribution may already have this package available so that you don’t have to compile it (yum install qemu-system):root@centos> wget
  • Unpack the tar ball:root@centos> tar -xvvf qemu-0.12.4.tar.gz
  • Install the required packages to build QEMU:root@centos> yum install build-dep qemu
  • Build and install QEMU:root@centos> cd qemu-0.12.4 root@centos> ./configure root@centos> make root@centos> make install

3.2 Install Debian Wheezy in QEMU

  • Change to the directory you want to build your VM in:root@centos> mkdir ~/arm root@centos> cd ~/arm
  • Download the current build of the Debian Wheezy ARMEL kernel (vmlinuz) and installer (initrd) images from a local Debian mirror:root@centos> wget root@centos> wget
  • Create a disk image for QEMU (more details on qemu-img).
    Importantly, the raw format will allow you to mount the image from Ubuntu once its populated:root@centos> qemu-img create -f raw armdisk.img 8G
  • Start the Debian install with QEMU:root@centos> qemu-system-arm -m 256 -M versatilepb -kernel ~/arm/vmlinuz-3.2.0-4-versatile -initrd ~/arm/initrd.gz -hda ~/arm/armdisk.img -append “root=/dev/ram”QEMU will open a terminal window and within that window the Wheezy installer will kick into action. Follow the installer’s directions and allow the install to begin. Installation will be slower than normal. Allow 4 or 5 hours for it to complete.
  • As the install completes you’ll be informed no boot loader is present, don’t worry QEMU takes the place of the boot loader. Once the install completes the VM will reboot kicking off the installer again, don’t proceed, just kill QEMU.

3.3 Running your ARM Wheezy install in QEMU

  • Once the installation is complete you will need to copy the initrd from the installed system. To do this you must mount the QEMU disk image.root@centos> mkdir ~/arm/mount/
  • Use fdisk to find out the sector where the first disk partition begins and then mount the image.root@centos> fdisk -l ~/arm/armdisk.img root@centos> mount -o loop,offset=$((2048 * 512)) ~/arm/armdisk.img ~/arm/mount root@centos> cp ~/arm/mount/boot/initrd.img-3.2.0-4-versatile ~/arm/. root@centos> umount ~/arm/mount((2048 * 512)) is not just a random number, it’s the sector where the first disk partition begins.
  • Boot your Debian Wheezy VM:root@centos> qemu-system-arm -m 256 -M versatilepb -kernel ~/arm/vmlinuz-3.2.0-4-versatile -initrd ~/arm/initrd.img-3.2.0-4-versatile -hda ~/arm/armdisk.img -append “root=/dev/sda1”

Now you have a running ARM VM to do with as you please.

To get started with debootstrap you must first install it:

root@debian:~# apt-get install build-essential debootstrap

Once installed you can start experimenting with it. A simple invocation would look like this:

root@debian:# mkdir /@debian root@debian:# debootstrap wheezy /@debian

Here we’re telling debootstrap that we wish to have a fresh installation of Wheezy made into the directory /@debian. The process will take a while since it will involve downloading packages from the Debian mirrors, as you can see from the following output:

root@debian:# debootstrap wheezy /@debian I: Retrieving Release I: Retrieving Packages I: Validating Packages I: Resolving dependencies of required packages… I: Resolving dependencies of base packages… I: Found additional required dependencies: libtext-iconv-perl zlib1g I: Checking component main on… I: Retrieving adduser I: Validating adduser I: Retrieving apt I: Validating apt ….

Once finished, create an archive of the entire folder and copy it over to your Synology NAS.

root@debian:# cd /@debian root@debian:# tar cvzf debian.tgz root@debian:# mkdir /mnt/temp root@debian:# mount -t cifs -o //diskstation/temp /mnt/temp root@debian:# cp debian.tgz /mnt/temp #– Now go back to your Synology DiskStation and move the debian.tgz file. DiskStation> mv /volume1/Temp/debian.tgz /volume1 DiskStation> cd /volume1 #– Extract the tarball DiskStation> tar xvzf debian.tgz DiskStation> ipkg update DiskStation> ipkg upgrade DiskStation> ipkg install bash DiskStation> ipkg install nano DiskStation> nano /volume1/@debian/etc/debian_chroot #– Type the word “Debian” w/o quotes and save. DiskStation> nano /volume1/@debian/etc/resolv.conf #– Change the nameserver to your router’s IP address. DiskStation> nano /opt/etc/init.d/S10modules #!/opt/bin/bash export CHROOTDIR=/volume1/@debian mount -o bind /proc ${CHROOTDIR}/proc mount -o bind /dev ${CHROOTDIR}/dev mount -o bind /sys ${CHROOTDIR}/sys mount -t devpts devpts ${CHROOTDIR}/dev/pts mount -o bind /volume1/recordings ${CHROOTDIR}/root/recordings chroot ${CHROOTDIR} /root/start_tvheadend DiskStation> chmod ug+x /opt/etc/init.d/S10modules DiskStation> nano /volume1/@debian/etc/apt/sources.list deb wheezy main contrib non-free # deb-src wheezy main deb wheezy/updates main contrib non-free # deb-src wheezy/updates main DiskStation> chroot /volume1/@debian /bin/bash (Debian)DiskStation> mkdir /root/recordings (Debian)DiskStation> apt-get update (Debian)DiskStation> apt-get install build-essential (Debian)DiskStation> apt-get install pkg-config (Debian)DiskStation> apt-get install python (Debian)DiskStation> apt-get install git (Debian)DiskStation> apt-get install cmake (Debian)DiskStation> apt-get install libssl-dev

4. SiliconDust Driver & Tool

(Debian)DiskStation> cd /usr/src (Debian)DiskStation> wget (Debian)DiskStation> tar -xpf libhdhomerun_20120405.tgz (Debian)DiskStation> cd /usr/src/libhdhomerun (Debian)DiskStation> make

5. DVB Drivers

The following steps will build kernel modules for your Synology NAS. You can save time by downloading the files here.

5.1 Kernel Part (compiled with CentOS 6.3)

#– CentOS 6.3 needs the package ncurses-devel #– ‘make menuconfig’ requires the ncurses libraries root@centos> yum install ncurses-devel root@centos> cd /home/administrator/Downloads #– Synology Kernel Sources — has to match with the cpu in your NAS root@centos> wget #– DSM Tool Chain — has to match with the cpu in your NAS root@centos> wget root@centos> tar -xvzf gcc421_glibc25_88f6281-GPL.tgz -C /usr/local/ root@centos> tar -xvjf synogpl-2636-6281.tbz C /usr/local/arm-none-linuxgnueabi/ #– compile DVB Core Driver root@centos> cd /usr/local/arm-none-linux-gnueabi/source/linux-2.6.32/ root@centos> cp /usr/local/arm-none-linux-gnueabi/source/linux-2.6.32/synoconfigs/88f6281 /usr/local/arm-none-linux-gnueabi/source/linux-2.6.32/.config root@centos> make ARCH=arm CROSS_COMPILE=/usr/local/arm-none-linux-gnueabi/bin/arm-none-linux-gnueabi- menuconfig #– a menu appears, where you have to choose the device drivers for the tuners. #– select “Device Drivers”. #– go to “Multimedia support”, press Y to include #– select “Multimedia support”. #– go to “Video For Linux”, press M to include as module. #– go to “DVB for Linux”, press M to include as module. #– select “Customize analog and hybrid tuner modules to build” and make sure that everything is selected in that section. #– go back to “Multimedia Support” and select “Video Capture Adapters”. #– go to “Conexant cx23416/cx23415 MPEG encoder/decoder support”, press M to include as module. #– select “V4L USB devices” and place an M next to “USB Video Class (UVC)”, “Hauppage WinTV-PVR USB2 support”, and “Conexant cx231xx USB video capture support”. #– go back to main screen and exit (yes to save the new config). root@centos> make ARCH=arm CROSS_COMPILE=/usr/local/arm-none-linux-gnueabi/bin/arm-none-linux-gnueabi- prepare scripts root@centos> make ARCH=arm CROSS_COMPILE=/usr/local/arm-none-linux-gnueabi/bin/arm-none-linux-gnueabi- modules #– compile DVB Drivers for HDHomeRun root@centos> cd /home/administrator/src root@centos> cvs -z3 co -P dvbhdhomerun root@centos> cd /home/administrator/src/dvbhdhomerun/kernel #– edit the Makefile root@centos> nano Makefile #– change KERNEL_VERSION #– KERNEL_VERSION := #– change KERNEL_DIR #– KERNEL_DIR := /usr/local/arm-none-linux-gnueabi/source/linux-2.6.32 root@centos> make ARCH=arm CROSS_COMPILE=/usr/local/arm-none-linux-gnueabi/bin/arm-none-linux-gnueabi- #– V4L modules are located at: #– /usr/local/arm-none-linux-gnueabi/source/linux-2.6.32/drivers/media #– (with the exception of the i2c files which are located in the i2c folder under drivers) #– dvb-core.ko is located at: #– /usr/local/arm-none-linux-gnueabi/source/linux-2.6.32/drivers/media/dvb/dvb-core #– dvb_hdhomerun_core.ko #– dvb_hdhomerun_fe.ko #– dvb_hdhomerun.ko are located at: #– /home/administrator/src/dvbhdhomerun/kernel (Debian)DiskStation> mkdir /usr/lib/modules (Debian)DiskStation> mkdir /usr/lib/modules/3.2.0 (Debian)DiskStation> mkdir /usr/src/dvb_native (Debian)DiskStation> mkdir /root/.xmltv

Copy all of the V4L KO files within the media folder (including the i2c folder under drivers) to /usr/lib/modules/3.2.0 of your NAS. Copy dvb-core.ko, dvb_hdhomerun_core.ko, dvb_hdhomerun_fe.ko, and dvb_hdhomerun.ko to /usr/src/dvb_native of your NAS.  Exit out of the chroot environment and copy the firmware files to /usr/syno/hotplug/firmware of your NAS.

5.2. Userspace Part

Go back into the chroot environment and copy the dvbhdhomerun folder from /home/administrator/src to /usr/src of your NAS.

#– edit the dvbhdhomerun config file (Debian)DiskStation> nano /usr/src/dvbhdhomerun/etc/dvbhdhomerun #– change the [XXXXYYYY-Z] to the serial #’s of your adapters. #– [10343B98-0], [10343B98-1], [10368D88-0], & [10368D88-1] #– change tuner_type=ATSC and save to /etc/dvbhdhomerun. #– compile userspace part with cmake (Debian)DiskStation> cd /usr/src/dvbhdhomerun/userhdhomerun #– edit CMakeLists.txt (Debian)DiskStation> nano CMakeLists.txt #– change LIBHDHOMERUN_PATH to where the #– compiled SiliconDust driver/tools are #– SET(LIBHDHOMERUN_PATH /usr/src/libhdhomerun) (Debian)DiskStation> make

6. Scripts

Create the following scripts in their respective locations and make them executable (ie. chmod ug+x /script/path).

6.1. /root/start_hauppauge

#!/bin/sh # Original script has been written by Davy Leggieri (hey another French guy 🙂 # Modified by Charles-Henri Hallard on April 2012 to fit with my configuration # MODULES_DIR=”/usr/lib/modules/3.2.0″ MAINMODULE=”i2c-core.ko” SUBMODULES=”i2c-algo-bit.ko tuner-xc2028.ko tuner-types.ko tuner-simple.ko mt20xx.ko tea5767.ko tea5761.ko tda9887.ko tda827x.ko tda18271.ko tda8290.ko xc5000.ko mt2060.ko mt2266.ko qt1010.ko mt2131.ko mxl5005s.ko mxl5007t.ko mc44s803.ko ir-common.ko v4l1-compat.ko videodev.ko v4l2-int-device.ko v4l2-common.ko tuner.ko saa7115.ko saa717x.ko saa7127.ko msp3400.ko cs53l32a.ko m52790.ko wm8775.ko wm8739.ko vp27smpx.ko cx25840.ko upd64031a.ko upd64083.ko tveeprom.ko videobuf-core.ko videobuf-vmalloc.ko cx231xx.ko cx2341x.ko pvrusb2.ko ivtv.ko uvcvideo.ko ir-kbd-i2c.ko” start_modules(){   echo “— Load modules —”   for i in $MAINMODULE $SUBMODULES; do     echo “Loading $i”     insmod $MODULES_DIR/$i   done   # Create the Video Devices (4 should be enough for me)   if [ ! -c /dev/video0 ]; then     mknod /dev/video0 c 81 0     mknod /dev/video1 c 81 1     mknod /dev/video2 c 81 2     mknod /dev/video3 c 81 3     # Set permissions     chown root:root /dev/video*   fi } stop_modules(){   echo “— Unload modules —”   for i in $SUBMODULES $MAINMODULE; do     echo “Unloading $i”    rmmod $MODULES_DIR/$i   done } case “$1” in start)   start_modules   ;; stop)   stop_modules   ;; *)   echo “usage: $0 { start | stop }” >&2   exit 1   ;; esac

6.2. /root/start_homerun

#!/bin/sh # Load Core modules # insmod /usr/src/dvb_native/dvb-core.ko insmod /usr/src/dvb_native/dvb_hdhomerun_core.ko # # Load BE & FE modules # insmod /usr/src/dvb_native/dvb_hdhomerun_fe.ko insmod /usr/src/dvb_native/dvb_hdhomerun.ko # #lsmod to check if everything is running #grep -i dvb /proc/devices # DYNAMIC_ID=$(grep hdhomerun_control /proc/misc | awk “{print $1}”) DYNAMIC_ID=${DYNAMIC_ID:0:4} if [ “$DYNAMIC_ID” != “” ]; then   echo “making node hdhomerun_control” $DYNAMIC_ID   mknod /dev/hdhomerun_control c 10 $DYNAMIC_ID else   echo “Unable to detect hdhomerun_control inside /proc/misc.” fi # Set permissions chmod 666 /dev/hdhomerun_control chown root:root /dev/hdhomerun_control # # Clear userhdhomerun log rm -f “/usr/src/dvbhdhomerun/dvbhdhomerun.log” # # Run userhdhomerun with LD_PRELOAD /usr/src/dvbhdhomerun/userhdhomerun/build/userhdhomerun -f -u root -g root -l “/usr/src/dvbhdhomerun/dvbhdhomerun.log” # sleep 1 # # Retrieve the major device number for DVB # (normally it should be 212) DYNAMIC_ID=$(grep DVB /proc/devices | awk “{print $1}”) DYNAMIC_ID=${DYNAMIC_ID:0:4} if [ “$DYNAMIC_ID” != “” ]; then         echo “Creating DVB device nodes to major device #$DYNAMIC_ID…”         # Create device nodes for DVB         mkdir -p /dev/dvb/adapter0         DYNAMIC_ID2=$(cut -f2 -d’:’ /sys/class/dvb/dvb0.frontend0/dev)         mknod /dev/dvb/adapter0/frontend0 c $DYNAMIC_ID $DYNAMIC_ID2         DYNAMIC_ID2=$(cut -f2 -d’:’ /sys/class/dvb/dvb0.demux0/dev)         mknod /dev/dvb/adapter0/demux0 c $DYNAMIC_ID $DYNAMIC_ID2         DYNAMIC_ID2=$(cut -f2 -d’:’ /sys/class/dvb/dvb0.dvr0/dev)         mknod /dev/dvb/adapter0/dvr0 c $DYNAMIC_ID $DYNAMIC_ID2         mkdir -p /dev/dvb/adapter1         DYNAMIC_ID2=$(cut -f2 -d’:’ /sys/class/dvb/dvb1.frontend0/dev)         mknod /dev/dvb/adapter1/frontend0 c $DYNAMIC_ID $DYNAMIC_ID2         DYNAMIC_ID2=$(cut -f2 -d’:’ /sys/class/dvb/dvb1.demux0/dev)         mknod /dev/dvb/adapter1/demux0 c $DYNAMIC_ID $DYNAMIC_ID2         DYNAMIC_ID2=$(cut -f2 -d’:’ /sys/class/dvb/dvb1.dvr0/dev)         mknod /dev/dvb/adapter1/dvr0 c $DYNAMIC_ID $DYNAMIC_ID2         mkdir -p /dev/dvb/adapter2         DYNAMIC_ID2=$(cut -f2 -d’:’ /sys/class/dvb/dvb2.frontend0/dev)         mknod /dev/dvb/adapter2/frontend0 c $DYNAMIC_ID $DYNAMIC_ID2         DYNAMIC_ID2=$(cut -f2 -d’:’ /sys/class/dvb/dvb2.demux0/dev)         mknod /dev/dvb/adapter2/demux0 c $DYNAMIC_ID $DYNAMIC_ID2         DYNAMIC_ID2=$(cut -f2 -d’:’ /sys/class/dvb/dvb2.dvr0/dev)         mknod /dev/dvb/adapter2/dvr0 c $DYNAMIC_ID $DYNAMIC_ID2         mkdir -p /dev/dvb/adapter3         DYNAMIC_ID2=$(cut -f2 -d’:’ /sys/class/dvb/dvb3.frontend0/dev)         mknod /dev/dvb/adapter3/frontend0 c $DYNAMIC_ID $DYNAMIC_ID2         DYNAMIC_ID2=$(cut -f2 -d’:’ /sys/class/dvb/dvb3.demux0/dev)         mknod /dev/dvb/adapter3/demux0 c $DYNAMIC_ID $DYNAMIC_ID2         DYNAMIC_ID2=$(cut -f2 -d’:’ /sys/class/dvb/dvb3.dvr0/dev)         mknod /dev/dvb/adapter3/dvr0 c $DYNAMIC_ID $DYNAMIC_ID2      DYNAMIC_ID=$(grep hdhomerun_data /proc/devices | awk “{print $1}”) DYNAMIC_ID=${DYNAMIC_ID:0:4}     if [ “$DYNAMIC_ID” != “” ]; then         rm -rf /dev/hdhomerun_data*         echo “Making node hdhomerun_data” $DYNAMIC_ID         mknod /dev/hdhomerun_data0 c $DYNAMIC_ID 0         mknod /dev/hdhomerun_data1 c $DYNAMIC_ID 1         mknod /dev/hdhomerun_data2 c $DYNAMIC_ID 2         mknod /dev/hdhomerun_data3 c $DYNAMIC_ID 3         chmod 666 /dev/hdhomerun_data*         chown root:root /dev/hdhomerun_data*     else         echo “Unable to detect hdhomerun_data inside /proc/devices.”     fi         # Set permissions         chmod 755 /dev/dvb/adapter*         chmod 666 /dev/dvb/adapter*/*         chown root:root /dev/dvb/adapter*/* else         echo “ERROR: Unable to detect DVB inside /proc/devices; dvb-core.k$”         exit 10 fi

6.3. /root/start_tvheadend

/root/start_hauppauge start sleep 1 /root/start_homerun sleep 10 /usr/src/tvheadend/bin/tvheadend -C -f -u root -g root

6.4. /root/.xmltv/grab_listings (Grab listings from Schedules Direct)

/volume1/@debian/root/.xmltv/mc2xml -T [username]:[password] -D /volume1/@debian/root/.xmltv/mc2xml.dat -o /volume1/@debian/root/.xmltv/xmltv.xml

7. TVHeadend

(Debian)DiskStation> mkdir -p /usr/src/tvheadend (Debian)DiskStation> git clone /usr/src/tvheadend (Debian)DiskStation> cd /usr/src/tvheadend #– edit the src/v4l.c file (Debian)DiskStation> nano src/v4l.c #– Search [Ctrl-W] for ‘can_mpeg’ and change the value to 1. #– int can_mpeg = 1; #– Also search for’v4l2_std_id’ and change the value to V4L2_STD_NTSC; #– v4l2_std_id std = V4L2_STD_NTSC; #– edit the Makefile (Debian)DiskStation> nano Makefile #– add bash after MKBUNDLE = #– MKBUNDLE = bash $(CURDIR)/support/mkbundle #– configure compilation (Debian)DiskStation> export CC=gcc (Debian)DiskStation> bash configure –host=armle-unknown-linux –target=armle-unknown-linux –build=i686-pc-linux –disable-avahi –release –prefix=/usr/src/tvheadend (Debian)DiskStation> make (Debian)DiskStation> make install #– start TVDeadend for testing purposes (-C for login without user/pwd) (Debian)DiskStation> /usr/src/tvheadend/bin/tvheadend -C #– http://DiskStation:9981 and create an admin user

8. Setup Channel Listings

Place ‘tv_grab_file’ into /usr/bin.  Copy the mc2xml software to /root/.xmltv of your NAS.

#– set permissions (Debian)DiskStation> chmod ug+x /usr/bin/tv_grab_file (Debian)DiskStation> chmod ug+x /root/.xmltv/mc2xml #– Exit out of chroot environment (Debian)DiskStation> exit DiskStation> nano /etc/crontab 0       1       *       *       *       root    /volume1/@debian/root/.xmltv/grab_listings DiskStation> synoservice –restart crond #– try it out DiskStation> /volume1/@debian/root/.xmltv/grab_listings

9. XBMC Media Center

Download and install XBMC to the frontend computers. You can download the Pandora add-on here.