Sunday, July 18, 2021

Converting RTSP to an MJPEG stream on demand using ffmpeg

Background

I'm using a cheap Chinese IP Camera that only has an RTSP stream to monitor my 3D printer via Octoprint/Octoapp, which requires a MJPEG stream over HTTP.

This approach uses lighttpd and cgi-bin as the server. Similar could be done using nginx + fastcgi, or in python -- perhaps even an Octoprint plugin. You might be able to get systemd start ffmpeg directly, but I had trouble getting the output stream to be sent to the socket, and wasn't sure how to stop the process when the socket was closed.

As it converts between video formats it requires a bit of CPU power on the host, though that can be tuned by configuring the resolution and framerate of the original RTSP stream, as well as resizing the output stream if required.

A 1080p stream at 10FPS on an Intel Core i5-8259U uses about 5-10% CPU and consumes 256MB of RAM. This approach is not efficient, so if you have two devices viewing the stream then the CPU load is doubled. Once the web browser closes its connection, or the camera goes offline, the ffmpeg process does seem to reliably stop.

A tool like ONVIF Device Manager may help figuring out the RTSP stream URL if you can't find it in the documentation for your camera (look at the bottom of the "live video" screen).

Environment

Apart from getting the paths right to suit your setup, nothing here should be too specific to Linux or a particular distribution. This was done using:

  • Debian GNU/Linux 10 (buster)
  • lighttpd/1.4.53 (ssl)
  • ffmpeg version 4.1.6-1~deb10u1
  • CPU: Intel Core i5-8259U

lighttpd

Install lighttpd:

apt-get install lighttpd

Enable cgi-bin:

cd /etc/lighttpd/conf-enabled/
ln -s ../conf-available/10-cgi.conf

Configure the cgi-bin folder, and set lighttpd to not buffer the entire file before starting to send:

Alter /etc/lighttpd/conf-available/10-cgi.conf:

server.modules += ( "mod_cgi" )

$HTTP["url"] =~ "^/cgi-bin/" {
        server.stream-response-body = 2
        cgi.assign = ( "" => "" )
        alias.url += ( "/cgi-bin/" => "/var/www/cgi-bin/" )
}

Restart lighttpd to pick up the configuration change:

systemctl restart lighttpd

Create the cgi-bin folder:

mkdir /var/www/cgi-bin

Scripts

Create the scripts that'll generate a single frame and stream, adjust the IP address and RTSP stream URL to suit your particular camera:

Create /var/www/cgi-bin/webcamframe:

#!/bin/bash

echo "Content-Type: image/jpeg"
echo "Cache-Control: no-cache"
echo ""
ffmpeg -i "rtsp://192.168.60.13:554/user=admin&password=SECRET&channel=1&stream=0.sdp" -vframes 1 -f image2pipe -an -

Create /var/www/cgi-bin/webcamstream:

#!/bin/bash

echo "Content-Type: multipart/x-mixed-replace;boundary=ffmpeg"
echo "Cache-Control: no-cache"
echo ""
ffmpeg -i "rtsp://192.168.60.13:554/user=admin&password=SECRET&channel=1&stream=0.sdp" -c:v mjpeg -q:v 1 -f mpjpeg -an -

Make the two scripts executable (otherwise you'll get a 500 Internal Server Error)

chmod +x /var/www/cgi-bin/webcamframe
chmod +x /var/www/cgi-bin/webcamstream

Complete

Now you should be able to access these two URLs on your server:

http://192.168.60.10/cgi-bin/webcamstream
http://192.168.60.10/cgi-bin/webcamframe

Both of these take 1-2 seconds to start, which I think is a combination of getting the RTSP stream going, and an inherent delay in generating the MJPEG output. Once it is running, there is about a one second delay on the video stream, which I gather is normal for ffmpeg generating MJPEG.

Troubleshooting

If you get distorted/smeared/artifacts on the output stream, try adding at the start of the ffmpeg arguments -rtsp_transport tcp  to force RTSP over TCP. Apparently there may be a UDP buffer issue in ffmpeg and/or Linux that can cause frames to get truncated. Other options to try out are here.

You can troubleshoot the scripts on the command line like this, which will let you see the output of ffmpeg and the start of what is sent to the web client:

cd /var/www/cgi-bin
./webcamframe | hd | head

Sample output of it working correctly is shown below. The conversion and pipe errors are OK, they are just due to head stopping the output early.

 

Extra Reading

Also have a look a this post on how to take individual JPG frames an turn them into MJPEG.


 

Thursday, February 01, 2018

AVR/Atmel Studio: Specify a smaller program space due to setting BOOTSZ0/BOOTSZ1 fuses

In AVR Studio version 7.0, if you're using the BOOTSZ fuses, you can add something like this to the custom linker flags, adjusting for your size requirements:

-Wl,--defsym=__TEXT_REGION_LENGTH__=30720

There is a symbol used (and defined if not already set) in the default linker script, that sets the size of the text (complied code) section.

For the curious, look in this file to see what's happening (and what else you can tweak):

C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\avr\lib\ldscripts\avr5.xn

Sunday, October 09, 2016

Gary Jules and Michael Andrews - Mad World (arr. Tony Dao)

Version by the Pianocian.  Unfortunately, just a scan, as I no longer have the original PDF, nor can I find it anywhere on the web: Download

Listen to it being played here: YouTube

Thursday, November 26, 2015

Thursday, October 15, 2015

Fix for "Item not found" when renaming a folder

There is a Windows Update that causes a problem that any time I try to rename a folder.   I get an error "Item not found" when trying to rename a folder.  If I choose to retry, it then works.

The fix (which I've had to do twice on two computers now), is described here: http://tevyawashburn.com/post/fix-item-not-found-regarding-folders-in-windows-7-64bit/ (and many other places).

To make it easy, here is a registry file to make the changes for you: FolderItemNotFoundFix.reg

After applying the registry fix, reboot (or maybe logout/login again).

Friday, April 03, 2015

DIY conversion of an AfroFlight Acro Naze32 to the full version

Introduction

This guide applies to at least rev4 and rev5 of the PCB, however only rev5 has the dataflash option.

This will guide you in adding:
  • Barometer
  • Magnetometer
  • Dataflash (EEPROM)
  • Capacitors to suit the above
This is a "DIY" guide, but most of it requires surface mount soldering experience and equipment, i.e. solder paste, hot air gun, tweezers, flux, and good eyesight.

The Naze Schematic PDF is here: https://code.google.com/p/afrodevices/downloads/list

I have included links to Element 14 (Farnell), but you can use octopart.com, digikey.commouser.com, or your favourite component supplier to get the parts.

Hints

  • Remove any existing solder from the pads before you start.
  • Do one section at a time, testing with USB connection to Cleanflight as you go.
  • If you use IPA to clean the board, it will mess up the barometer until it dries out.  The barometer's datasheet warns against getting anything in it at all!

Shopping list

Dataflash (EEPROM)

Part: M25P16 - http://au.element14.com/micron/m25p16-vmn6p/memory-flash-serial-16mbit-8nsoic/dp/1734973
Cost: $2
Datasheet: http://www.farnell.com/datasheets/158118.pdf
Decoupling capacitor: 100nF 0603  (see below)
Orientation: Pin 1 is on the side with the bevelled edge.  It goes by the indicated pin on the PCB.
Skill level: Medium-easy.  Can be done with a soldering iron, but the capacitor can be a bit fiddly if you don't have fine tipped tweezers.

Note that this a 16Mb (megabit) chip, giving 2 megabytes of storage.  A few other chips, up to 128Mbit, are supported by the Cleanflight firmware.  See lines 48 to 52 of the source code here: https://github.com/cleanflight/cleanflight/blob/master/src/main/drivers/flash_m25p16.c -- currently the list is: M25P16, N25Q064, W25Q64, N25Q128, and W25Q128.

Barometer

Cost: $12
Datasheet: http://www.farnell.com/datasheets/1756128.pdf
Decoupling capacitor: 100nF 0603 (see below)
Orientation: Pin 1 is the pin on the underside with an extra dot beside it, and there is a corresponding dot on the top of the package.  This pin goes towards the inside of the Naze PCB.
Skill level: Medium.  Requires hot-air gun, solder paste, and some experience with this sort of job.

Magnetometer

Part: HMC5883L - http://au.element14.com/honeywell-m-ps/hmc5883l-tr/magnetic-sensor-on-tapereel/dp/1886419
Cost: $4
Datasheet: http://www.honeywell.com/sites/servlet/com.merx.npoint.servlets.DocumentServlet?docid=DCB000D72-C325-A8BE-588A-322B3EC915DE
Decoupling capacitors: Two of 100nF 0603 (see below)
Other capacitors: 
Orientation: Pin 1 is marked on the package with a dot, and goes on the innermost edge of the footprint.
Skill Level: Advanced.  The pads on this package are tiny, and are completely underneath.

Decoupling Capacitors

For all decoupling capacitors, use a 100nF 0603.  For example:

What Goes Where

Overview

To get a general idea of what goes where, see the following.  The cleanflight firmware detects what is present when it starts up, so you can do as many or as few of these as you wish.


Dataflash

The dataflash and decoupling capacitor:


Magnetometer

The magnetometer, decoupling capacitors, and two other capacitors used by the chip:

Barometer

The barometer, and decoupling capacitor:

Finished

All components fitted:


Magnetometer and Barometer readings in Cleanflight:



Saturday, February 07, 2015

Disable hoverzoom (and hoverfree) for hangouts

Add this to the "Disable for specific sites" list:

  chrome-extension://nckgahadagoaajjgafhacjanaoiihapd

Reload hangouts, and it should be good.

Wednesday, April 16, 2014

Levenberg–Marquardt fitting to complex data and/or with complex parameters

Assuming you have a working LM fitter for real numbers, the clues are on these two pages:

The tricks are:
  • You're trying to fit a curve to the points plotted on the Real/Imaginary plane (like in the second graph below).
  • Handle the data and parameters as real & imaginary, not magnitude & phase.  Even if that isn't the most "natural" way to interpret your data for your problem/field.
  • Split each complex parameter into two.  One for the real and one for the imaginary part.  If your parameters are real only, nothing needs to be done here.
  • Similarly, split the complex data into two parts, doubling the number of data points you have.  Doesn't matter if they are interleaved, or separate.
  • The error function is calculated using one of the formulae from the second URL above.
  • Due to the splitting of the complex data, the partial derivatives are done separately for the real and imaginary parts.  If you are working on a real data point, use just the real part of the partial derivative.  For the imaginary part, do the same.

Examples:
  • Two parameters { 3+4i, 5+6i } become four real parameters, { 3, 4, 5, 6 }.
  • Data points { 1+2i, 8+9i } become the new data series { 1, 2, 8, 9 } or { 1, 8, 2, 9 }.
  • Example of raw and fitted data, fitting an equivalent circuit model to captured EIS (Electrochemical Impedance Spectroscopy) data:


Tuesday, October 16, 2012

Yet another guide to setting up RTL-SDR, Zadig Drivers, and SDR# on Windows

NOTE: This was written some time ago and hasn't been checked or updated since, so things may be slightly different for recent versions.

One-time driver setup

Don't install the "official" USB drivers that came with your RTL-SDR device.  No harm if you do, but they're not used as the "Zadig" step below tells Windows to use a different driver instead.

Plug in your RTL-SDR device, don't let Windows install any drivers for you.

Download, unzip and run " ExtIO_USRP+FCD+RTL2832+BorIP-BETA_Setup.zip" from here: http://wiki.spench.net/wiki/USRP_Interfaces#Installer

Minimal selection is:
- Support files
- Libusb
- VC++ Runtime

Run "Zadig", if it isn't run by the setup program.

Select your RTL-SDR device, and hit "Install Driver".

Close Zadig.


SDR# Installation

Download the SDR# application and the RTLSDR plugin from here: http://sdrsharp.com/index.php/downloads

Unzip SDR# to somewhere.

Unzip RTLSDR plugin to the same place.

From the "config" folder in the plugin zip, copy the SDRSharp.exe.config to the main folder, replacing the existing configuration file.  This enables the option of choosing the RTLSDR plugin for input.

Download this: http://sdr.osmocom.org/trac/raw-attachment/wiki/rtl-sdr/RelWithDebInfo.zip

Open that, and find the file "rtl-sdr-release\x32\rtlsdr.dll".  (x32, even if you're using 64 bit Windows).  Put that DLL file in the SDR# folder as well.  This is the DLL that the plugin uses.  Due to licensing reasons, it isn't bundled with the plugin.


Quick Start

Run SDRSharp.exe.

Choose "RTL-SDR / USB" at the top.

Check that the center and frequency is set to something sensible (not 0).  e.g. "94500000".

Click "Play".  An easy test is a FM radio station, so tune to its frequency, and choose "WFM" (Wide FM).

If you're doing signal strength comparisons, turn off the two AGC options in the dialog that opens when you click "Configure" at the top.

If you have limited CPU power, turn down the sample rate in the "Configure" dialog, and choose a lower resolution on the FFT.


Extra Information

A guide to SDR#, including the installation steps, is here: http://www.atouk.com/SDRSharpQuickStart.html

Tuesday, February 01, 2011

Search contents of all files in Windows XP Search

From here:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\ContentIndex]
"FilterFilesWithUnknownExtensions"=dword:00000001