Friday, February 26, 2016

Compile & Install Gstreamer on Raspberry Pi


Prerequisite


sudo apt-get install libglib2.0-dev bison flex libtool 
autoconf automake autopoint gtk-doc-tools libx264-dev liborc-0.4-dev 
nasm yasm cmake libmicrohttpd-dev libjansson-dev libnice-dev librtmp-dev
Download these
* gstreamer/gstreamer
* gstreamer/gst-plugins-base
* gstreamer/gst-plugins-good
* gstreamer/gst-plugins-bad
* gstreamer/gst-plugins-ugly
from GStreamer source, at the time writing this post, the latest version I use is 1.4.1
For gst-plugins-basegst-plugins-good and gst-plugins-ugly, simply
./autogen.sh
make -j
sudo make install
For gst-plugins-bad, there’s a little problem during normal installation. In old times, gst-plugins-gl was required for gst-plugins-bad and now it is merged into gst-plugins-bad, at least they claim so, but somehow there’s some bug in there at this moment, which causegst-plugins-bad could not find gst-plugins-gl and gst-plugins-gl cannot be installed due to the fact that the author thinks there’s no need to install it since it has been merged intogst-plugins-bad.
So we need some hack for this. Fortunately, this thread has already worked it out. Follow those steps and you should get rid off the trouble.

Edit environment variable

in ~/.bashrc add a line
export LD_LIBRARY_PATH=/usr/local/lib
and reload bash file:
exec bash

Test command:

If you’ve installed rpicamsrc:
gst-launch-1.0 rpicamsrc bitrate=2000000 rotation=90 ! video/x-h264,width=1080,height=760,framerate=25/1 ! h264parse ! udpsink host=localhost port=5000
else:
raspivid  -t 0 -h 720 -w 1080 -fps 25 -b 2000000 -o - | gst-launch-1.0 -v fdsrc ! h264parse !  rtph264pay config-interval=1 pt=96 ! gdppay ! tcpserversink host=0.0.0.0 port=5000

Sunday, February 21, 2016

Howto - Stream HTML5 video - H264 encoded video encapsulated in MP4 from the Raspberry Pi to any web browser














At the time of writing I'm developing a Bootstrap/Web interface for the Raspberry Pi camera module, to transform a Raspberry Pi into an easily configurable IP Camera.
As we all come to know it, the GPU module which comes with the Raspberry Pi supports several hardware assisted encoding formats.

Two of the more popular format's include H264, - and MJPEG encoding, my little project consists only of these two encoding formats.

In the IP camera which i'm developing I wanted to make both standards easily available for external connection like video recording software/hardware, this while preserving the capability to display the video feed of the camera on the web interface itself.
To display an MJPEG feed on a web page, this is very easy, as you can just insert an <img> tag in your html page which links up to your MJPEG stream and you're off, upon loading your web page this feed will play.

Example:
<img src="http://raspberryip/?action=stream" alt=""/>

Displaying the raw H264 feed from the Raspberry IP camera on a web page was a lot more difficult.
We need to make use of the HTML5 video tag to display H264 encoded video on a web page.

The H264 encoded data stream which comes off the Raspberry Pi's GPU is a raw bytestream and cannot be delivered by direct means to the web page, we need to encapsulate the stream in MP4 container format to subsequently deliver it over HTTP to the web browser's video tag for playing.

If we split this whole task in bite size chunks we can distract a few distinct pieces:

  1. Getting the raw H264 data feed from the Raspberry Pi's GPU.
  2. Wrap the raw H264 data feed in MP4 container chunk format.
  3. Transfer these MP4 container chunks to the browser on demand.

1. Getting the raw H264 data stream from the GPU is well documented and easy.
You can use the raspivid tool (which comes with the Raspberry Pi) to dump out the raw H264 data stream.   To dump this stream to standard output you can use below command:
$ raspivid -w 1920 -h 1080 -fps 30 -pf high -n -t 0 -o -

2. Getting this raw output into MP4 container format was a bit more difficult, and involves the use of gstreamer.  Gstreamer is like a swiss army knife if you want to transcode media data, and is highly modular, it supports a lot of media data types. 
Raspbian already contains a version of gstreamer in it's repository, and is installable with aptitude.

To install gstreamer:
$ sudo apt-get -y install gstreamer1.0
And afterwards use gstreamer to transcode our stream:
$ gst-launch-1.0 -e -q fdsrc fd=0 ! video/x-h264,width=1920,height=1080,framerate=30/1,stream-format=byte-stream ! h264parse ! mp4mux streamable=true fragment-duration=10 presentation-time=true ! filesink location=/dev/stdout'
3. Transferring our containerized MP4 data stream to the browser involves on demand transfer over http to the video element in our browser.   For this we can use a small python script, which runs a simple web server to transfer our transcoded data to the browser.  Upon get request from our browser our MP4 will be send to the browser, and the browser will play the video data through the HTML5 video tag.
import subprocess # for piping
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler

class RequestHandler(BaseHTTPRequestHandler):
    def _writeheaders(self):
        self.send_response(200) # 200 OK http response
        self.send_header('Content-type', 'video/mp4')
        self.end_headers()

    def do_HEAD(self):
        self._writeheaders()

    def do_GET(self):
        self._writeheaders()

        DataChunkSize = 10000

        command = '(echo "--video boundary--"; raspivid -w 1920 -h 1080 -fps 30 -pf high -n -t 0 -o -;) | gst-launch-1.0 -e -q fdsrc fd=0 ! video/x-h264,width=1920,height=1080,framerate=30/1,stream-format=byte-stream ! h264parse ! mp4mux streamable=true fragment-duration=10 presentation-time=true ! filesink location=/dev/stdout'
        print("running command: %s" % (command, ))
        p = subprocess.Popen(command, stdout=subprocess.PIPE, bufsize=-1, shell=True)

        print("starting polling loop.")
        while(p.poll() is None):
            print "looping... "
            stdoutdata = p.stdout.read(DataChunkSize)
            self.wfile.write(stdoutdata)

        print("Done Looping")

        print("dumping last data, if any")
        stdoutdata = p.stdout.read(DataChunkSize)
        self.wfile.write(stdoutdata)

if __name__ == '__main__':
    serveraddr = ('', 8765) # connect to port 8765
    srvr = HTTPServer(serveraddr, RequestHandler)
    srvr.serve_forever()

Let's say we save this script to a file called httpserver, then we need to run this file with python:
$ python httpserver

The only thing that remains now is to build a simple web page with the HTML5 video element which will connect to this web server for the video feed.
$ <!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>HTML5 Video Tag Test</title>
</head>

<video width="1920" height="1080" controls>
  <source src="http://192.168.20.147:8765" type="video/mp4">

Your browser does not support the video tag.
</video>

<body>
</body>
</html>





Tuesday, February 2, 2016

HOWTO - Manage system services on Raspbian Jessie


List defined services

Print active services and their corresponding states in human readable form.
$ sudo systemctl list-units -t service
UNIT                               LOAD   ACTIVE SUB     DESCRIPTION
acpid.service                      loaded active running ACPI event daemon
atd.service                        loaded active running Deferred execution scheduler
console-setup.service              loaded active exited  LSB: Set console font and keymap
cron.service                       loaded active running Regular background program processing daemon
dbus.service                       loaded active running D-Bus System Message Bus
exim4.service                      loaded active running LSB: exim Mail Transport Agent
[...]

LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.

31 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.
Print active services and their corresponding states without legend/headers.
$ sudo systemctl list-units -t service --no-legend
acpid.service                      loaded active running ACPI event daemon
atd.service                        loaded active running Deferred execution scheduler
console-setup.service              loaded active exited  LSB: Set console font and keymap
cron.service                       loaded active running Regular background program processing daemon
dbus.service                       loaded active running D-Bus System Message Bus
exim4.service                      loaded active running LSB: exim Mail Transport Agent
[...]
Print all services and their corresponding states.
$ sudo systemctl list-units -t service --no-legend --all 
acpid.service                        loaded    active   running ACPI event daemon
atd.service                          loaded    active   running Deferred execution scheduler
auditd.service                       not-found inactive dead    auditd.service
clamav-daemon.service                not-found inactive dead    clamav-daemon.service
console-screen.service               not-found inactive dead    console-screen.service
console-setup.service                loaded    active   exited  LSB: Set console font and keymap
cron.service                         loaded    active   running Regular background program processing daemon
dbus.service                         loaded    active   running D-Bus System Message Bus
debian-fixup.service                 loaded    inactive dead    Various fixups to make systemd work better on Debian
display-manager.service              not-found inactive dead    display-manager.service
emergency.service                    loaded    inactive dead    Emergency Shell
exim4.service                        loaded    active   running LSB: exim Mail Transport Agent
[...]

Manage services on running system

Print status of single service.
$ sudo systemctl status cron
● cron.service - Regular background program processing daemon
   Loaded: loaded (/lib/systemd/system/cron.service; enabled)
   Active: active (running) since sob 2015-03-28 12:41:18 CET; 5h 46min ago
     Docs: man:cron(8)
 Main PID: 373 (cron)
   CGroup: /system.slice/cron.service
           └─373 /usr/sbin/cron -f

mar 28 14:17:01 debian CRON[1187]: pam_unix(cron:session): session opened for user root by (uid=0)
mar 28 14:17:01 debian CRON[1188]: (root) CMD (   cd / && run-parts --report /etc/cron.hourly)
mar 28 15:17:01 debian CRON[1318]: pam_unix(cron:session): session opened for user root by (uid=0)
mar 28 15:17:01 debian CRON[1319]: (root) CMD (   cd / && run-parts --report /etc/cron.hourly)
mar 28 16:17:01 debian CRON[1336]: pam_unix(cron:session): session opened for user root by (uid=0)
mar 28 16:17:01 debian CRON[1337]: (root) CMD (   cd / && run-parts --report /etc/cron.hourly)
mar 28 17:17:01 debian CRON[1542]: pam_unix(cron:session): session opened for user root by (uid=0)
mar 28 17:17:02 debian CRON[1543]: (root) CMD (   cd / && run-parts --report /etc/cron.hourly)
mar 28 18:17:01 debian CRON[1624]: pam_unix(cron:session): session opened for user root by (uid=0)
mar 28 18:17:01 debian CRON[1625]: (root) CMD (   cd / && run-parts --report /etc/cron.hourly)
Check if service is active.
$ systemctl is-active --quiet atd; \
  if [ "$?" -eq "0" ]; then echo "service is active"; fi
service is active
Check if service failed.
$ systemctl is-failed --quiet atd; \
  if [ "$?" -eq "0" ]; then echo "service failed"; fi
Start service.
$ sudo systemctl start ssh
Stop service.
$ sudo systemctl stop ssh
Reload service's configuration.
$ sudo systemctl reload ssh
Restart service.
$ sudo systemctl restart ssh
Restart service if it is running.
$ sudo systemctl try-restart ssh
Reload service if it supports it, restart otherwise. Start if it is not running.
$ sudo systemctl  reload-or-restart ssh
Reload service if it supports it, restart otherwise.
$ sudo systemctl reload-or-try-restart ssh
Send SIGTERM signal to service.
$ sudo systemctl kill ssh
Send SIGHUP signal to main process of specified service.
$ sudo systemctl kill --signal=HUP --kill-who=main ssh

Manage startup services

Enable service.
$ sudo systemctl enable ssh
Disable service.
$ sudo systemctl disable ssh
Check if specified service is enabled.
$ systemctl is-enabled --quiet cron; \
  if [ "$?" -eq "0" ]; then echo "service is enabled"; fi
Mask service so it cannot be activated at boot time or by manual action.
$ sudo systemctl mask ssh
Unmask service.
$ sudo systemctl unmask ssh