IP cameras that just send HTTP streamsPosted June 8, 2011
How to fake an rtsp stream from http cameras
We've all seen them. Inexpensive IP cameras that promise to send h264 streams in their specifications. Panasonic and Planet cameras have okay web based viewers, and claim to send h264 out, but the reality is that they don't. You can view through the camera's web interface, and that's it. The thing works, but doesn't shoot h264. How to actually restream HTTP mjpeg, like the example below; this is from a Planet camera that only puts out HTTP.
Having done it a couple of times, let me start by saying it's got to be done with a specific way to keep the stream going, all the time (I use Proc::Daemon with perl), and you have to be able to get to the HTTP source reliably (I use lynx), and you have to transcode the stream and send it to rtsp on a wowza server using ffmpeg.
I'll deal with the perl daemon wrapper after I talk about getting the stream, and transcoding it. I choose lynx, instead of curl or libwww, because I can build the appropriate url with "?" url parameters, and I can pass username and password, and optionally install a certificate. I also wrote all the SSL documentation for lynx, so I'm declaring my bias.
In perl you need the ip address of your camera. I have a nice hack if you are behind a dynamic dns service, which I'll write about when I talk about the Panasonic cameras. This works with a Planet:
my $location = 'http://1.2.3.4';We can print out this command to our screen and see if it will work. Run it and see if you get a big ugly video stream on your command prompt screen. In case you're wondering, lynx works just fine in windows too. If I run the command without -dump -source, I see the lynx prompt:
# this uri pulls the Planet mjpeg stream over http
# 'http://1.2.3.4/video.cgi?resolution=4cif&random=0.07799162343144417'
my $uri = "/" . "video.cgi" . '?' . "resolution" . '=' . "4cif";
# build url
my $url = "$location" . "$uri";
my $lynx_string="lynx -nopause -dump -source ";
# got all the bits, assemble it
my $lynxcmd="$lynx_string" . "$url";
which is okay. I can transcode that. Panasonics declare mjpeg.
If we run with -dump -source, we get a stream. Now to transcode with ffmeg.
Pipe $lynxcmd into ffmpeg, tell ffmpeg what it's getting, and send it to wowza as rtsp. Simple to say, hard to do, and different for every camera. Fun.
We need in perl:
system("$lynxcmd | /usr/local/bin/ffmpeg "); What arguments do we need for ffmpeg? Different for every camera. ICA-H312 worked with this:
ffmpeg -r 3 -f mjpeg -an -force_key_frames 0.2 5 -s 4cif -b 1024k -g 30 -vb 150000 -strict experimental -i - -ac 1 -vcodec libx 264 -vpre medium -r 3 -g 30 -b 150000 -f rtsp -muxdelay 0.5 rtsp://127.0.0.1:1935/train/_definst_/camera.sdp
Which means, pipe the continuous HTTP stream from lynx, into ffmpeg. In ffmpeg, say that rate is 3, force the format to be interpreted as mjpeg, ignore audio (-an), use 4cif size, a 1024k buffer, (and a couple more options), and with this input from STDIN, transcode it to h264, again at rate 3, formatted for rtsp, to the listening rtsp application we have created on our wowza server.
Which will work, as long as the camera keeps sending. We keep it running forever with Proc::Daemon. Wrap the few lines of perl in this:
use Proc::Daemon;
Proc::Daemon::Init;
my $continue = 1;
$SIG{TERM} = sub { $continue = 0 };
while ($continue) {
# all our perl is here...
}
This will now pull your Planet camera's lousy 4cif HTTP stream, that you thought would only ever work on their camera web page, into wowza, so you can send it to your iPhone or desktop, limited only by the number of streams your wowza servers can support.






