Wednesday, 28 December 2016

Stream hardware-encoded H.264 video from a Raspberry Pi to a web page using WebRTC

I use the wonderful 3D printing distribution OctoPi (which in turn uses OctoPrint) on a Raspberry Pi Zero to start and monitor my 3D prints. It has built-in webcam functionality, which means you can monitor your printer and see in the web interface if the print is going well or not - really nice! The problem with the webcam is that video is encoded to MJPEG (Motion JPEG), which can be displayed in the web interface <img> tag, but is a bandwidth hog. Streaming a 320x240 picture at 10fps generates about 800kB/s of traffic. The good thing is that the RPi hardware JPEG encoder is used, so CPU usage is very low (~2%). My 3D printer is in the basement and a WiFi connection from there is only possible using an external antenna and with only a really low bandwidth available.
Knowing the RPi has an H.264 hardware encoder I set out to find a solution to stream H.264 video onto the OctoPrint web interface. These instructions apply to a Debian Jessie based Raspbian / OctoPi 0.13.
But first things first:

Video / audio formats and container format

A generally misunderstood part of digital video is codecs and container formats. Video and audio codecs define how video or audio is encoded / compressed. These are formats like MPEG2, AVC/H.264, VP8/9, WMV9, etc. for video, and e.g. MP3 or AAC for audio and they generate raw data packets. These data packets are put (multiplexed or "muxed") into a container (together with other streams like subtitles etc.) to save it to a file or stream it via a network. These container formats are e.g. MPEG-TS, AVI, MP4, MKV, FLV etc.

Streaming formats and web browser video support

Streaming video systems are fragmented and often proprietary. There is streaming via HTML (a web browser requests a resource via a regular HTTP GET request), RTP/RSTP (older streaming format), RTMP (A proprietary format used by Flash), HSL (Newer streaming protocol not supported very well yet) and more. All of these system support different codecs internally.

The <video> element

Now the problem is that modern web browsers support the MP4 / H.264 video format, but the MP4 container format is as-it-is not suitable for streaming it to web browsers via the <video> element. Let that sink in - It is simply not possible. You need browser plugins or external programs. You can play a "finished" MP4 video file via the web browser, which will do a regular HTTP GET request, download, cache and play the file, but you can not STREAM every possible format.
The standard for the <video> element only defines "open" container formats to be supported in the browser: WEBM and OGG. It supports video/audio codecs like VP8, AVC/H.264, Theora, Vorbis.

Streaming Theora / OGG video to VLC with GStreamer

To stream video with with GStreamer first install the necessary packages with:
sudo apt-get install gstreamer1.0-omx gstreamer1.0-tools gstreamer1.0-plugins-good gstreamer1.0-plugins-bad libgstreamer1.0-0 libgstreamer1.0-dev libgstreamer-plugins-base1.0-0 libgstreamer-plugins-base1.0-dev
gstreamer1.0-omx gives us the GStreamer filter omxh264enc which enables H.264 hardware-encoding. gstreamer1.0-tools provides gst-launch1.0 which is used to build a GStreamer pipeline and start playing / streaming it. You can now try to start streaming in Theora / OGG format:
gst-launch-1.0 -v v4l2src device=/dev/video0 ! 'video/x-raw,width=320,height=240,framerate=10/1' ! theoraenc ! oggmux ! tcpserversink host=RPI_IP port=7272
Streaming Theora, 320x240@10fps, data rate ~150kb/s, 90-100% CPU
To stream in H.264 / FLV format, use:
gst-launch-1.0 v4l2src ! 'video/x-raw,width=320,height=240,framerate=10/1' ! omxh264enc target-bitrate=500000 control-rate=1 ! 'video/x-h264,profile=high' ! h264parse ! flvmux ! tcpserversink host=RPI_IP port=7272
Streaming H.264, 320x240@10fps, data rate ~360kb/s, ~20% CPU
You could even increase the compression in sacrifice of image quality, which will produce a data rate of ~200kb/s. Image quality is okish:
gst-launch-1.0 v4l2src ! 'video/x-raw,width=320,height=240,framerate=10/1' ! omxh264enc target-bitrate=100000 control-rate=1 ! 'video/x-h264,profile=high' ! h264parse ! flvmux ! tcpserversink host=RPI_IP port=7272

You can watch both streams in VLC when you open the address "tcp://RPI_IP:7272".
Note that the Theora stream creates a lower data rate stream, but a very high CPU usage. The video is very jerky, so I suspect it drops frames, because the CPU can not sustain encoding at 10fps, which in turn lowers the data rate...
The H.264-encoded video is smooth though and visually ok for the data rate.

Using WebRTC via Janus / Nginx

Now we know the RPi can hardware-encode and stream H.264 video. But how do we manage to view our video on a webpage?
The Firefox API page mentions RTP/RTSP as a source for the <video> tag, but I couldn't get that to work. After searching the internet for a while I ran across WebRTC, which is a realtime audio / video communication standard and seems to be supported in all major browsers. I decided to give it a try and followed these instructions and it worked:

Streaming H.264 using WebRTC
Note that you need to stop the haproxy and octoprint services before installing and starting nginx and janus, otherwise it won't work!

Using WebRTC in OctoPrint?

Ok. Now we know this works, but how can we integrate that into OctoPrint?! It is a bit unfortunate to use Janus and Nginx, another web server. OctoPrint already uses the Tornado web server, so we have to convert the example page from above to use that. I found this example on how to set up a WebRTC chat application and went from that...

To be continued...

Wednesday, 20 July 2016

Setting up the XYZ Da Vinci 1.0a 3D printer with RepetierHost and Slic3r on Ubuntu

I finally bought a 3D printer. It's a used one and entry level, but printing parts is good fun. Here's how to set it up on Ubuntu 14.04:

Install Repetier firmware

The new firmware will give you much more control over the printing process. Mine was already installed (v0.92), so I upgrading to the 0.92.10 alpha was as easy as cloning the github repo, starting the Arduino IDE and flashing the printer. This version supposedly has better bed leveling, though I'd recommend to manually level the bed anyway (paper method).
Get the firmware here. You'll also need to have the the Arduino IDE 1.6.7+ for installing and updating it.

Install RepetierHost

  • Download RepetierHost for Linux.
  • Unpack it to the directory you want to install us to, e.g. ~/RepetierHost.
  • Drop to the command line and run "sh"
  • If your user can not access the serial port, add it to the dialout group using "usermod -a -G dialout YOURUSERNAME".
More information about the installation is here

Install Slic3r

  • Download Slic3r for Linux.
  • Unpack it to the RepetierHost installation directory under "/plugins/Slic3r".
  • Install the prerequisites using "sudo apt-get install build-essential libgtk2.0-dev libwxgtk2.8-dev libwx-perl libmodule-build-perl".
  • Start RepetierHost and add Slic3r in the "slicer" tab under "Manager". Select "Slic3r" in the drop-down entry and enter "slic3r" and its name. Click "Add Slicer". Enter "/home/YOURUSERNAME/.slic3r" as the configuration directory and the path to the slic3r executable you installed before and press "Apply".
Now you have RepetierHost and and Slic3r and can connect to the printer, so let's set it up:

RepetierHost settings

Printer settings

  • Connection - Port: /dev/ttyACM0 (this may vary on your system)
  • Connection - Baud rate: 230400 (Check you printers settings via the menu)
  • Connection - Transfer protocol: "Repetier Protocol"
  • Connection - Reset on Emergency: "Send emergency command and reconnect"
  • Connection - Receive Cache Size: 202
  • Connection - Use Ping-Pong Communication: Turn on
  • Printer Shape - X Max: 200
  • Printer Shape - Y Max: 200
  • Printer Shape - Print Area Width: 200
  • Printer Shape - Print Area Depth: 200
  • Printer Shape - Print Area Height: 200
  •  Extruder - Extruder 1 Diameter: 0.4

Slic3r settings

Print settings (for all layer heights, add settings if they don't exist)

  • Layers and Perimeters - Perimeters (minimum): 3
  • Layers and Perimeters - Solid layers: Top 3, Bottom 3
  • Layers and Perimeters - Avoid crossing perimeters: Turn on
  • Speed - Perimeters: 50 mm/s
  • Speed - Small perimeters: 10 mm/s
  • Speed - External perimeters: 50%
  • Speed - Infill: 70 mm/s
  • Speed - Solid infill: 50 mm/s
  • Speed - Top solid infill: 30 mm/s
  • Speed - Support material: 30 mm/s
  • Speed - Support material interface: 100%
  • Speed - Bridges: 50 mm/s
  • Speed - Gap fill: 15 mm/s
  • Speed - Travel: 150 mm/s
  • Speed - First layer speed: 30%
  • Advanced - Solid infill: 85% 
  • Advanced - Top solid infill: 85%

Filament settings (add filaments if you don't exist):

  • Filament (ABS) - Temperature - Extruder: 235° / 230°
  • Filament (ABS) - Temperature - Bed: 95° / 90°
  • Cooling (ABS) - Fan speed: 80% / 100%
  • Cooling (ABS) - Slow down if layer time is below: 15s
  • Filament (PLA) - Temperature - Extruder: 200° / 195°
  • Filament (PLA) - Temperature - Bed: 75° / 70°
  • Cooling (PLA) - Fan speed: 40% / 100%
  • Cooling (PLA) - Slow down if layer time is below: 15s

Printer settings

  • General - Set up the bed shape to 200x200mm.
  • G-code flavor must be "RepRap (Marlin/Sprinter/Repetier)".
  • Custom G-code - Start:
M140 S[first_layer_bed_temperature] ; Bed (no wait)
M104 S[first_layer_temperature] ; Extruder (no wait)
M106 S255 ; Start fan
G90 ; set absolute coordinates
G28 ; home all axis
M190 S[first_layer_bed_temperature] ; Bed (wait)
M109 S[first_layer_temperature] ; Extruder (wait)
M117 Start
M300 s1000 p400 ; Beep
M300 s1500 p400
M300 s2000 p400
M300 s2500 p400
M117 Cleaning
M100 ; Cleaning
G1 Z5 F1500
G1 X0 Y15 F1000
G1 X5 Y35 F1000
G92 E0 ; reset extrusion distance
G1 Z[first_layer_height] F4800.000
G1 X5 Y175 E14 F1000
G1 X5 Y190 F1000
M117 Printing
  • Custom G-code - End:
M117 Done
G92 E0 ; reset extrusion distance
M104 S0 ; turn off extruder
M140 S0 ; turn off Bed
G90 ; Absolute
G28 X0 Y0 ; home
M117 Down Bed
G1 Z200 ; Lower bed
M117 Cleaning
M100 ; Cleaning
M84 ; Disable motors
M117 Cooling
M190 S55 ; Bed (cooling)
; M116 ; Wait for all temperatures
M140 S0 ; turn off Bed
M117 Pickup piece
M300 s2500 p400 ; Beep
M300 s2000 p400
M300 s1500 p400
M300 s1000 p400
M84 ; Disable motors
M117 Printer ready
  • Extruder 1 - Nozzle diameter: 0.4mm
  • Extruder 1 - Retraction length: 2
  • Extruder 1 - Retraction Speed: 40mm/s
Now you should be good to go and print some parts.

Friday, 17 June 2016

Hiding the mouse cursor in Kodi

I use Kodi with a touchscreen and wanted to hide the mouse cursor, but NOT disable mouse input. This can be done by using a 1x1 transparent PNG file as the mouse cursor. Find out what skin you're using and where your skin directory is. For me this is estouchy and its directory is /usr/share/kodi/addons/skin.estouchy. You need to download the PNG first:


Then move it to the skins media directory (or where ever the skin gets its cursors from):

sudo mv 1x1.png /usr/share/kodi/addons/skin.estouchy/media/pointer_1x1.png

Then edit the Pointer.xml file:

sudo nano /usr/share/kodi/addons/skin.estouchy/xml/Pointer.xml

And replace all "width" and "height" values with 1 and all "texture" values with the name of the 1x1 texture:


Now your cursor should be invisible.

Thursday, 16 June 2016

Properly setting up a 5" HDMI touchscreen for Kodi on Raspbian

Wow. This was a royal pita. I wanted to build this wake-up-light-alarm-clock-media-thingy for my girlfriend. Well, I got my hands on a RPi Zero and needed an LCD display. I found this nice-looking "WaveShare 4" IPS display" on Ebay and spent days trying to get it to work properly. You want a hint? DONT DO IT! BUY A HDMI SCREEN! Refresh rate sucks, Kodi is not working with hardware-acceleration, Framebuffer copying never worked. Short: It sucked!

So. Next chapter: Bought a 5" HDMI screen here. It has an HDMI input and connects to the RPi GPIO pins for power and touch functionality... and works ALMOST out of the box on a fresh Raspbian install (from 5/2016). Nice!

Set up screen resolution and touchscreen


 Edit /boot/config.txt:

hdmi_cvt 800 480 60 6 0 0 0


This gets the display and the touchscreen up and running. You can test if the touchscreen does anything using:

cat /dev/input/mouse0
cat /dev/input/event0

Setting up the touchscreen for X


This should give you weird output whenever you touch the screen. Fine.
Now you want to calibrate it. To do that install the calibration utility:

sudo apt-get install xinput_calibrator

Then start the GUI. You should now have an entry "Calibrate touchscreen" in your menu. Start it and tap the points. When finished the screen should be calibrated.
Or, to do the calibration from the command line, run:


You can also do this from SSH, if you don't have a keyboard attached:

DISPLAY=:0 xinput_calibrator

Tap the points and when finished, the tool will output some calibration information:

Section "InputClass"
        Identifier      "calibration"
        MatchProduct    "ADS7846 Touchscreen"
        Option  "Calibration"   "114 3982 226 3883"
        Option  "SwapAxes"      "0"

Paste the calibration info into "/usr/share/X11/xorg.conf.d/99-calibration.conf".

Setting up the touchscreen for Kodi


Now you have a calibrated X input device, so the Desktop works nicely, but Kodi still does not. When starting it from X, there is a cursor, but the calibration is way off. When starting it standalone, there is not even touch input...
Fix this by installing tslib and evtest:

sudo apt-get install evtest tslib libts-bin 
Additionally you will need Then calibrate the touchscreen using:

TSLIB_TSDEVICE=/dev/input/event0 ts_calibrate

Touch the 5 crosses and you're done. You can test the calibration using:

TSLIB_TSDEVICE=/dev/input/event0 ts_test

You might also need to add the "kodi" user to the "input" user group:

sudo usermod -a -G input kodi

If you have Kodi version >= 17 ("Krypton") you cannow set up scale factors for the display so the cursor is properly displayed.

Setting display scale factors in Kodi >= v17


Test if Kodi can use touch input now. Start Kodi and touch the upper left corner of the screen. You will see a cursor and can move it, but only in 1/5th of the screen. The problem is that the coordinates /dev/input/event0 sends are touch device coordinates (in the range you see in the calibration values above), but Kodi expects pixel screen coordinates (0-800,0-480). Kodi starts to support touchscreen calibration out-of-the-box as of v17 aka "Krypton".
Edit the file advancedsettings.xml in your users userdata folder, e.g. /home/kodi/.kodi/userdata or ~/.kodi/userdata. If it does not exist, create it and add the following entries:

        <x_offset>-32</x_offset> <!-- cursor pixel x offset
        <y_offset>-35</y_offset> <!-- cursor pixel y offset
        <x_stretch_factor>0.209</x_stretch_factor> <!-- stretch factor
        <y_stretch_factor>0.131</y_stretch_factor> <!-- stretch factor

Good start values can be calculated by dividing the screen resolution by the X11 calibration values above (e.g. for x: 800/3982=~0.2 and 480/3883=~0.124). Note that you have to restart Kodi after editing the values to see any changes.

Installing a touchscreen calibration fix


When you have an older Kodi version and can not use advancedsettings.xml, there are also ways to properly calibrate your screen. Read here about using a tslib fork and ts_uinput_touch for this.

Fixing the double-click issue

A remaining problem is that Kodi wants a double-click to activate a function. This is not good as we want to activate functions with a single click or tap. We can change this by editing the file /usr/share/kodi/system/keymaps/mouse.xml. Change the entries in the mouse section to:

  <doubleclick id="0">noop</doubleclick>
  <longclick id="0">contextmenu</longclick>

P.S. Find out how to hide the cursor here.
P.P.S. You can also add backlight control to the screen...

Wednesday, 15 June 2016

Adding GPIO PWM backlight control to a 5" HDMI screen (and Kodi)

So the screen from here is working in Kodi now, but it draws a lot of power when the backlight is on (~200mA). We want to turn at least the backlight off, leaving the touchscreen active so we can interact and wake it up again. Buuut the LCD has no backlight control which is a pity (would have cost only cents). Good thing is: We can easily add it.
What you'll need:
  • IRF7104 P-Channel MOSFET
  • 10 kOhm resistor
The displays backlight power supply runs on 5V and already has an on/off switch. We cut the trace leading from the switch to the backlight power supply circuit:

Then solder the IRF7104 there (pin 3 (Source) right, pin 6 (Drain) left). Pin 1 of the MOSFET is the pin next to the little dent. The IRF will switch power to the backlight on and off and should handle currents of up to ~1.5A.
Now we need a circuit to connect the Gate (pin 4) of the MOSFET to the GPIO pin. I used GPIO #18 / PWM0 (pin 12) on my RPi Zero. NOTE: This pin may be connected to the audio out on other RPis, so you might need to choose a different pin...
We connect the Gate pin to a 10k Ohm resistor and connect that to our GPIO pin. The final circuit is in the image below:

Now when you start the RPi it should turn the screen on by default. You can use the commands:

gpio -g mode 18 out
gpio -g write 18 1

to turn the screen off. You need WiringPi for that, so if you don't have it, install it... To control backlight brightness by PWM you can do:

gpio -g mode pwm
gpio -g pwm 18 x (x takes values from 0 (full on), to 1023 (off))

To turn the screen back on do:

gpio -g mode 18 out
gpio -g mode 18 0

For the following instructions, use the home directory of the user you want to run Kodi from. If you make Kodi autostart by editing /etc/default/kodi, this is the user "kodi" (used here), else it is probably the user "pi".

Now to integrate support for the backlight into Kodi, we need to run those commands when the Kodi screensaver starts or ends. For that we need a service addon called "service.xbmc.callbacks". Download the script from the releases section and unzip it into /home/kodi/.kodi/addons. Then create two script files in the /home/kodi directory:
gpio -g mode 18 out
gpio -g write 18 1
gpio -g mode 18 out
gpio -g write 18 0

Make those scripts executable:

chmod +x

Now start Kodi and add those two scripts in the addon configuration for screensaver start / exit:

Your backlight should now turn off / on with the screen saver.

Saturday, 23 April 2016

Building a mobile magnet lamp / flashlight from repurposed parts

I needed a mobile "flashlight" in my car you could simple attach somewhere to the chassis where you'd need it. The are plenty of offers on the interwebs, so could have simply bought one, but I (as usual) had some parts lying around...
I had:
  • A spare 12Wh Li-Ion battery left over from my Kodi car entertainment project.
  • Two broken 1W 12V LED "bulbs", meant as Halogen bulb replacements.
  • Some magnets from old computer harddisks.
I knew I could build lamp with that. For the final design I also used:
First thing were the LED lamps. The glass and plug were shattered, but electrically they were ok. I tested them and one of them turned on at ~4V. I desoldered the regulator PCB disc from the other one and connected the + and - regulator output terminals from the one that still had the regulator PCB to the other one. While I was at it I removed the rectifier diodes. The are not needed when you use DC and connect the leads correctly. It worked, but the LEDs weren't bright enough. The regulator is a constant current supply and thus it still delivered the same amount of current to two parallel LED arrays now. The chip used is a XL6003 LED constant current driver. The typical application circuit in Figure 5 from the data sheet seemed to match my PCB. The resistor RS used to adjust the current had a value of 5.6 Ohm. The calculations in the datasheet of RS = 0.22 / ILED worked just as an estimate for me, so after some testing I settled on a 10 and 4.7 Ohm resistor in parallel = 3.2 Ohm, which almost doubled the current.

UPDATE: You can simply connect the battery to the lamp input! No step-up regulator needed! This makes the runtime even longer! The lamp will grow dimmer when the Li-Ion voltage drops and I've not seen it go below ~3.2V.
I've added a 100 Ohm potentiometer in series to the combined 3.2 Ohm resistor so you can adjust the brightness really easy.

Then I built a shutdown circuit for the 5V step-up regulator U1V11F5 to turn off power to the LEDs when the Li-Ion voltage drops below ~3.2V to save the battery from dying. The regulator has a SHDN pin to turn it on/off. For > 1.5V input voltage you have to apply < 0.4V to the SHDN pin to turn the regulator off and > 1.2V to turn it on. The pin is already internally connected to VIN through a 100 kOhm resitor and thus floats at input voltage and turns on the regulator by default. The shutdown circuit:

You can find the simulation project here, but note that the simulation is not 100% correct, because the transistor model does not use the proper BC557C values. The rightmost resistor is the regulators internal 100 kOhm resistor. The pin connected to the volt meter (transistor collector) should be connected to the U1V11F5 SHDN pin.
Edit: When testing the lamps maximum running time I found it would not reliably shutdown with a 22 kOhm resistor. You may need a lower value to make the lamp shut down earlier. Also the XL6003s is rated down to 3.6V input voltage, so I will try connecting the battery directly and see if it shuts down by itself anyway...

The rest is just connecting the charger to the Li-Ion battery, connecting a switch to turn on/off power to the circuit above and the regulator, and then connecting the regulator VOUT pin to the LED PCB input pin.

Voila, a mobile Li-Ion lamp. I think I'll build a nice wooden enclosure for it...

Friday, 25 March 2016

Building a Kodi in-car entertainment system using a Motorola Atrix Lapdock and an Odroid C0

Watching movies in the car is great fun. It is even better when you have a camper and lie in your comfy sleeping bag - I needed an in-car entertainment system.
I have a stereo in the car already that can even play videos, but the screen is small, codec support is limited and it is in the front whereas you're sleeping in the back. Tablets with big screen are expensive and have rather bad sound quality. Also I still had this Motorola Atrix Lapdock lying around I wanted to use for a build and try out the Odroid C0 board.
The Lapdock is nice for a Raspberry Pi like SoC. It is basically a 11.5" HDMI screen with a 1366x768 resolution, a touchpad and keyboard, speakers (audio via HDMI), 2-port-USB-hub, and a 36Wh 3-cell Li-Ion-battery built in. It originally connected to a smartphone via a male micro-USB and micro-HDMI plug. To connect the Lapdock to a computer you'll most likely need a micro-HDMI-D (female) to HDMI-A (male) adapter. It comes with a 19V AC/DC power supply, but wanted to power it from the 13V car battery. I had to butcher it...
Taking apart the thing is not so hard. It is the usual small-screws-and-plastic-clips system all laptops use. When you're done the "mainboard" looks like this:

You find the battery connected to a 6-pin connector labeled "JP2". The system needs a 3.3V and >5.5V power supply. The 5.5V voltage sounds strange, but it was measured when the system ran via the 19V AC/DC adapter. With anything below 5.5V USB devices might not work, because then USB supply voltage is < 3.3V and most USB devices do not work below that. I found 5.6V to work fine. Here's the pinout of JP2:

Supplying power is not enough to make the Lapdock display turn on. When you have disconnected the touchpad cable it will not turn anymore, because the touchpad has a reed switch or hall sensor that detects when the Lapdock lid is closed or opened. If you want the mainboard and display to turn on immediately when you supply power, simply bridge two pins on the JTP1 connector:

Bridge the pins marked in green and blue here.
Audio can be sent to the Lapdock via HDMI, so make sure your SoC supports that. The Lapdock has a small audio amplifier that drives the microscopic built-in speakers. If you want to route audio to a better amplifier etc. you have to tap the pins on the APA2031 audio amplifier IC. The typical application circuit from the specs give a hint on where to find the audio signals. The left channel is on LIN- (pin 5), the right one on RIN- (pin 17). GND can be found in a lot of places:

I connected a switch to the pins, so can either use built-in speakers or route audio to the main stereo for better sound quality. Soldering to the IC pins can be quite a pita, because it's quite small...
Now you should be mostly ready to roll. On to the Odroid C0.

The Odroid C0 is a small board sporting an Amlogic S805 1.5GHz dual-core SoC with a Mali 450MP2 GPU (decodes H265/HEVC) and 1GB of DDR3 RAM. The board is as bare-bone as it gets, having only a power and HDMI connector, which gives it a great form-factor. You should order a heat sink though and maybe the connector kit if you want to add a USB-connector, GPIO pins or the IR receiver. If you want a board version with all connectors and Gigabit Ethernet, go with the C1+ which has the same SoC. Hardkernel also sells a small remote for the IR receiver which works quite well (and even out-of-the-box) with the Hardkernel Lubuntu 14.04.03 image.
What is really important though is to get an SD card that works with the board! Not all cards do. Make sure you read this and this before you buy one!
Copying the image to the SD card can be done in Linux with a simple:
sudo dd if=<THE_IMAGE_FILE> of=<YOUR_SDCARD_DEVICE>; sync
Don't forget to properly unmount the card. Now insert the SD card into the device and supply power. On the first boot the image is expanded to the whole card, so give it some time and wait for the C0 to reboot. Now you are greeted with a LXDE desktop. You can adjust the display settings via the "odroid utility". The natural choice would be 1360x768, but that gave me wrong colors and a screwed-up display, but I found 720p to work well. If you know how to use the native 1366x768 resolution, let me know in the comments. The utility also lets you update the kernel and firmware to a current version. Kodi is already installed and can be auto-started by adding it to the Desktop preferences. See here how.
The end result looks like this, and yes, it still needs an enclosure: