Skip to content
sgjava edited this page Apr 20, 2014 · 36 revisions

Installation

You assume all the risks that come with flashing an Android device. It's very painless and hard to screw up, but if you do brick your Mini PC you are on your own!

I had problems using mjpg-streamer, uvccapture, fswebcam which return VIDIOC_DQBUF: Invalid argument or something similar. Cheese, gstreamer and vlc player (cvlc) worked. gstreamer worked the best, so that's what we are going to use here.

  1. Test USB camera under the original ROM
    • Boot up Mini PC with original ROM and configure your Google account
    • Download camera app if your ROM doesn't have one
    • Plug in your camera and take a picture
    • If that worked then there's a good chance it will work under Linux!
  2. Install Finless 1.7 ROM on MK808. If you have another Mini PC model check for Finless on that model (you can skip to step 3, but Finless makes the reboot process easier) For RK3188 devices install a NEOTV ROM.
  3. Install Ubuntu
    • My project Ubuntu Mini will let you build kernels and Ubuntu distribution
    • PicUntu
    • Some other Ubuntu based distribution.
    • When complete reboot using terminal with original ROM or Reboot app in Finless Rom (use bootloader option)
    • If using a RK3188 you have to create an init.d script as detailed in Flash kernel
    • Make sure networking is working (ping gateway, etc.)
  4. Test camera
    • SSH into Mini PC as root/12qwaszx (for PicUntu or whatever user you created)
    • sudo apt-get install usbutils
    • lsusb
      • You should see something like:
      Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
        Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
        Bus 002 Device 002: ID 03f0:a707 Hewlett-Packard
      • Note "Hewlett-Packard" is my camera
    • Add non-privileged user
      • adduser <username>
      • adduser <username> sudo
      • usermod -a -G video <username>
    • Install gstreamer
    apt-get install python-gi python3-gi \
         gstreamer1.0-tools \
         gir1.2-gstreamer-1.0 \
         gir1.2-gst-plugins-base-1.0 \
         gstreamer1.0-plugins-good \
         gstreamer1.0-plugins-ugly \
         gstreamer1.0-plugins-bad \
         gstreamer1.0-libav
    • Install uvcdynctrl
    apt-get install uvcdynctrl
    • reboot
    • SSH in as user you just created
    • Get camera information
      • export GST_DEBUG="*v4l2*:5"
      • gst-launch-1.0 -v v4l2src num-buffers=1 ! fakesink&>debug.txt
      • nano debug.txt
      • Find out what formats are supported (MJPG support, excellent, no encoding required for gstreamer):
      getting src format enumerations
        got 6 format(s):
           YUYV
           MJPG
           YU12 (emulated)
           YV12 (emulated)
           BGR3 (emulated)
           RGB3 (emulated)
      • Find resolutions, frame rates, etc. in debug.txt
      probed caps: video/x-raw, format=(string)YUY2, width=(int)1280, height=(int)720, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 15/2, 5/1 }; video/x-raw, format=(string)YUY2, width=(int)800, height=(int)600, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 15/1, 10/1, 5/1 }; video/x-raw, format=(string)YUY2, width=(int)640, height=(int)480, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)YUY2, width=(int)352, height=(int)288, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)YUY2, width=(int)320, height=(int)240, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)YUY2, width=(int)176, height=(int)144, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)YUY2, width=(int)160, height=(int)120, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; image/jpeg, width=(int)1280, height=(int)720, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; image/jpeg, width=(int)800, height=(int)600, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; image/jpeg, width=(int)640, height=(int)480, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; image/jpeg, width=(int)352, height=(int)288, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; image/jpeg, width=(int)320, height=(int)240, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; image/jpeg, width=(int)176, height=(int)144, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; image/jpeg, width=(int)160, height=(int)120, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)I420, width=(int)1280, height=(int)720, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)I420, width=(int)800, height=(int)600, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)I420, width=(int)640, height=(int)480, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)I420, width=(int)352, height=(int)288, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)I420, width=(int)320, height=(int)240, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)I420, width=(int)176, height=(int)144, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)I420, width=(int)160, height=(int)120, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)YV12, width=(int)1280, height=(int)720, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)YV12, width=(int)800, height=(int)600, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)YV12, width=(int)640, height=(int)480, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)YV12, width=(int)352, height=(int)288, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)YV12, width=(int)320, height=(int)240, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)YV12, width=(int)176, height=(int)144, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)YV12, width=(int)160, height=(int)120, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)BGR, width=(int)1280, height=(int)720, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)BGR, width=(int)800, height=(int)600, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)BGR, width=(int)640, height=(int)480, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)BGR, width=(int)352, height=(int)288, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)BGR, width=(int)320, height=(int)240, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)BGR, width=(int)176, height=(int)144, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)BGR, width=(int)160, height=(int)120, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)RGB, width=(int)1280, height=(int)720, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)RGB, width=(int)800, height=(int)600, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)RGB, width=(int)640, height=(int)480, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)RGB, width=(int)352, height=(int)288, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)RGB, width=(int)320, height=(int)240, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)RGB, width=(int)176, height=(int)144, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }; video/x-raw, format=(string)RGB, width=(int)160, height=(int)120, interlace-mode=(string)progressive, pixel-aspect-ratio=(fraction)1/1, framerate=(fraction){ 30/1, 25/1, 20/1, 15/1, 10/1, 5/1 }
      • For a more consice list use uvcdynctrl -f
      Listing available frame formats for device video0:
        Pixel format: YUYV (YUV 4:2:2 (YUYV); MIME type: video/x-raw-yuv)
          Frame size: 640x480
            Frame rates: 30, 25, 20, 15, 10, 5
          Frame size: 352x288
            Frame rates: 30, 25, 20, 15, 10, 5
          Frame size: 320x240
            Frame rates: 30, 25, 20, 15, 10, 5
          Frame size: 176x144
            Frame rates: 30, 25, 20, 15, 10, 5
          Frame size: 160x120
            Frame rates: 30, 25, 20, 15, 10, 5
          Frame size: 800x600
            Frame rates: 15, 10, 5
          Frame size: 1280x720
            Frame intervals: 2/15, 1/5
        Pixel format: MJPG (MJPEG; MIME type: image/jpeg)
          Frame size: 640x480
            Frame rates: 30, 25, 20, 15, 10, 5
          Frame size: 352x288
            Frame rates: 30, 25, 20, 15, 10, 5
          Frame size: 320x240
            Frame rates: 30, 25, 20, 15, 10, 5
          Frame size: 176x144
            Frame rates: 30, 25, 20, 15, 10, 5
          Frame size: 160x120
            Frame rates: 30, 25, 20, 15, 10, 5
          Frame size: 800x600
            Frame rates: 30, 25, 20, 15, 10, 5
          Frame size: 1280x720
            Frame rates: 30, 25, 20, 15, 10, 5
    • Let's see if we can record a 500 frame video
      • export GST_DEBUG="*v4l2*:0"
      • gst-launch-1.0 v4l2src num-buffers=500 ! image/jpeg ! avimux ! filesink location=video.avi
      • Don't worry about libv4l2: error dequeuing buf: Success messages since we will mute those later on
      • SCP video to your desktop PC and see if it recorded correctly
  5. Test streaming over HTTP
    • Run GStreamerMjpeg Python class
      • Copy streamer package to your home dir
      • export PYTHONPATH=/home/<username>/streamer
      • python -u /home/<username>/streamer/GStreamerMjpeg.py
      Launching camera server on port 1337
        Launch input stream thread
        Httpd serve foreverWaiting for input stream from gstreamer...
    • Start another SSH session and run gstreamer pipeline
      • gst-launch-1.0 v4l2src, timeout=5 ! image/jpeg, framerate=30/1, width=320, height=240 ! multipartmux boundary=cvp ! tcpclientsink port=9999&>/dev/null
      Accepted input stream from ('127.0.0.1', 39999)
    • Go to http://192.168.1.69:1337 (change to the IP address to that of the Mini PC)
      192.168.1.106 - - [22/May/2013 22:19:21] "GET / HTTP/1.1" 200 166
    • At this point you have a streaming MJPEG webcam. You can stop here or you can proceed to step 6 to make your Mini PC an intelligent camera system.
  6. Add network checking script. Since wifi connections will have connectivity problems for a number of reasons it's prudent to monitor the connection from the device. Checking every five minutes will usually be enough for most scenarios. You can go down to every minute resolution with Cron. Using this script has made my BYOC cameras as or more reliable than my stand alone network cameras.
    • sudo su -
    • wget https://raw.github.com/sgjava/byoc/master/scripts/checknet.sh
    • mkdir -p /opt/scripts
    • cp checknet.sh /opt/scripts/checknet.sh
    • chmod a+x /opt/scripts/checknet.sh
    • crontab -e
    • Add */5 * * * * bash /opt/scripts/checknet.sh
    • Exit/save from editor
  7. CVP is a Python based system that takes input from video sources such as network cameras, web cams, files, etc. and makes intelligent decisions based on analyzing each frame.
  8. Make copies of linuxroot sd (this will save a huge amount of time). Note that this will only work on similar Mini PC hardware. You can also make a base install to revert back to in case you screw it up some how. Compress with permissions:
    • sudo tar -pzcf /home/<username>/linuxroot.tar.gz -C /media/linuxroot .
      • Change and SDHC location as needed. Extract with permissions:
    • sudo tar -pzxf /home/<username>/linuxroot.tar.gz -C /media/linuxroot
      • Change and SDHC location as needed.
  9. If you flashed Finless ROM you can reboot into recovery which will cause PicUntu to boot instead of Android. You will not be able to get back to Android again without reflashing (pressing the reset button on MK808). Otherwise you should reboot into bootloader until you are ready for PicUntu only.
Clone this wiki locally