
| home | AJAX (8) || C#.NET (7) || Coldfusion Development (16) || DHTML (15) || Flash Development (19) || jQuery (8) || MSSQL (2) || UNIX (10) |
| 1.22.07 | Live Streaming of a Webcam Feed from CANON VB-C10/C50 From a Relay Proxy Server |
UPDATE 10/01/2007 found out that if the input from the cam is 6FPS and the output to SWF via FFSERVER is 4FPS - there’s no lag in camera controls. The scripts below have been changed to pull the MJPEG images from the camera at 6FPS and keep the flash SWF output as 4FPS.
The controllable IP Network cameras form Canon are great. They helped start an odd yet somewhat accepted precedent on the web facilitating user-controlled cameras through the web.
Naturally all the IP Network cameras’ UI Module are written in Java - and have remained unchanged for a some time. This is the point of contention for this write-up and all the digging I have done to find an alternative to this Java UI module.
The crux of these cameras - in a high-availability scenario - is that they offer no proxy of sorts. There are several products that facilitate the replication of a single stream from said IP cameras and duplicate them as part of a streaming server. Again - all of these offerings only support re-use of the java UI Module from either Canon of Sony - a kludge of software and very “closed” in the sense that it’s not very reusable.
With the crux being known, I set out to find an alternative route to interface with the cameras. I must disclaim that this is a proof of concept - yet is not far from being a production-quality piece (similar to Perl-ish kludge-hackery fashion).
My first milestone was to be able to stream the live feed from a Canon VB-C10R Network Camera into Flash Video without relying on the custom Canon UI module so affectionately referred to as “LiveView”.
My second milestone was to be able to “proxy” the live stream as pulled from the camera. This means we’ll only be pulling the stream from the camera once and the proxy server handling all the external requests - naturally a large number of requests.
The first milestone was to figure out how to pull the live video stream from the Canon VB-C10R. To begin - I “sniffed” incoming requests from the LiveApplet example using tools such as tcpdump, ngrep, and snort.
More background information: The Canon VB-C10R (and the VB-C family) offer two methods of accessing the live stream from the camera, via a specialized port, or via HTTP. I didn’t want to setout to try and use the HTTP port because it is actually a slower protocol because it adds a HTTP header for every request. The only advantage of the HTTP protocol to access the stream is so that it’s more accessible over popular firewall configurations. In this case - it’s a direct unprotected link to the camera (private network). This also makes pulling the images as fast as possible. The proprietary port in question for the live stream is 65310. The format for the stream is simple and widely accepted MJPEG (Motion JPEG) video format.
In order to figure out how to communicate in this proprietary format, I used the following snort command (snort worked the best out of all the sniffers to figure out the communication method…) :
# snort -dvq host 10.0.0.1
With the following return set (10.0.0.1 = the server 10.0.0.20 = the camera):
Do not forget that 10.0.0.1 = the server 10.0.0.20 = the camera.
I dissected the protocol and highlighted the requests and acknowledgments in red. The outline of the pulling the stream is a simple process (pseudo code):
MODE 0\0AVERSION\0ASTART\0AWebView/Livescope Video Capture...\0A\0A\0A\0A\0A\0A\0A\0ABefore the MJPEG “header” is send over this protocol - there is a send “\0A\0A\0A\0A” with a response of “100″ - which is meaningless as far as I can tell. I still write it to my MJPEG stream in the end without fail.
I wrote the following PHP script to pull the MJPEG stream directly from the CB-V10 camera on it’s native 65310 streaming port:
Download this code: streaming_php-pull.phps
This writes the stream as pulled directly from the VB-C10 through its native video streaming port and outputs it directly to STDOUT. PHP was chosen because of simplicity - and is simple enough to port to a more robust C application. That’s on the list of things todo. I would not fear using this in a live production environment so long as there were protective measures in place to ensure this would be daemonized indefinitely.
To output the VB-C10 video stream directly to STDOUT, run this PHP script through PHP-CLI via:
# php -f pull_stream.php
This will flood your terminal if you do not direct STDOUT, but is good for testing to make sure all is well. Don’t forget to reset your terminal if it has been “flashed” - i.e. all the characters are now “funky”.
As per the code - you can change the socket_read() function to attempt to pull a specific amount of data as per the configuration of your camera. Depending on the quality of your images as setup in the camera settings - each frame pulled via this script will be that size. If you get corrupted images in your stream, increase this number. If you want a better framerate than 4 frames per second, as I have chosen, minimize the usleep() function as per how many micro-seconds between frames.
I must disclaim that this PHP script is merely a proof-of-concept and will not pull the exact FPS desired, nor will it be a completely reliable proxy to pull the camera’s stream. Not only that, it cannot gracefully handle disconnects of the camera or the like.
We now have a way to capture the live MJPEG stream from the camera - now what to do with it…? My second milestone was to take the MJPEG stream and convert into native flash streaming video format. FFMPEG and FFSERVER opensource programs are absolutely amazing pieces of work. Not only that, but they manifest my second milestone perfectly.
More detail on the milestone: I want to dynamically take the MJPEG stream and convert it to FLV on the fly. I also want to make the product FLV something that can be streamed from countless clients. FFMPEG does the on the fly conversion and FFSERVER provides streaming functionality.
In sum - I have tweaked and configured FFMPEG and FFSERVER to produce a replicated proxy server that takes the VB-C10 MJPEG stream and duplicates it in FLV real-time to be served to a much wider audience.
FFMPEG and FFSERVER must be configure to work in concert and here are the following commands and configuration I gave to produce the final product:
FFMPEG
# php -f pull_stream.php | ffmpeg -an -f mjpeg -maxrate 500 -r 6 -i - -r 6 http://localhost:8090/feed1.ffm
NOTES: I run the “daemonized” pull_stream.php script, pipe STDOUT directly to ffmpeg via the “… -i - …” arguments. The -i denotes an input file and - for a filename denotes STDIN . The -f denotes forcing of the MJPEG format for the input stream seeing as it will not be obvious to ffmpeg coming from STDIN. The -maxrate 500 limits the bitrate for the input file to 500kb/s. The -r 4 limits both the input and output frame-rate to 4fps (before the -i - affects the input stream and after affects the output stream). Then the output is the last argument is a URI which points to the FFSERVER’s configured default stream feed running on the same server.
FFSERVER - /etc/ffserver.conf snippet
<Feed feed1.ffm>
File /tmp/feed1.ffm
FileMaxSize 5M
</Feed>
# SWF output - great for testing
<Stream test.swf>
# the source feed
Feed feed1.ffm
# the output stream format - SWF = flash
Format swf
# this must match the ffmpeg -r argument
VideoFrameRate 4
# generally leave this is a large number
VideoBufferSize 80000
# another quality tweak
VideoBitRate 500
# quality ranges - 1-31 (1 = best, 31 = worst)
VideoQMin 1
VideoQMax 5
VideoSize 320x240
# this sets how many seconds in past to start
PreRoll 0
# wecams don't have audio
NoAudio
</Stream>
# FLV output - good for streaming
<Stream test.flv>
# the source feed
Feed feed1.ffm
# the output stream format - FLV = FLash Video
Format flv
VideoCodev flv
# this must match the ffmpeg -r argument
VideoFrameRate 4
# generally leave this is a large number
VideoBufferSize 80000
# another quality tweak
VideoBitRate 500
# quality ranges - 1-31 (1 = best, 31 = worst)
VideoQMin 1
VideoQMax 5
VideoSize 320x240
# this sets how many seconds in past to start
PreRoll 0
# wecams don't have audio
NoAudio
</Stream>
<Stream stat.html>
Format status
</Stream>
<Redirect index.html>
# credits!
URL http://ffmpeg.sourceforge.net/
</Redirect>
Download this code: streaming_ffserver_config.xml
This is a limited yet functional ffserver.conf file.
To prove Milestone 1 and Milestone 2 working in concert and to get a stream working, ffserver must be running before running the ffmpeg command.
The next two projects will be:
As always — More to come…
| IvanV on 9.13.07 at 5am |
|
Hi, thanks for this post, its helped me out a lot with a little project I’m working on. |
| Bj on 10.7.07 at 3pm |
|
Very nice tut.. Is it possible to stream with full size like 640×480? |
| Jim Palmer on 10.8.07 at 10am |
|
BJ I think 640×480 would be fine. Even a faster framerate. Getting it just right would require tweaking all the settings just right. You need to make sure bandwidth is plentiful as well considering even 4FPS for 640×480 of MJPEG video even at quality 8 is a lot of bandwidth. As far as I can tell FFMPEG/FFSERVER would be fine supporting it in terms of CPU and load. If you wanted to keep the 4FPS I would only change the resolution that the camera can output and up the bitrate on the ffmpeg to something like 1200 (from ~500) at least. |
| Bj on 10.11.07 at 12pm |
|
Thx mate.. I just tryed to find a good way to “record” the streams so I can leave out the flash part.. |
| Jim Palmer on 10.12.07 at 11am |
|
If all you want to do is save the stream to a file you don’t need FFSERVER. All you need is the PHP script pushing directly to FFMEG. The syntax would resemble something of the sort: php -f pull_stream.php | ffmpeg -an -f mjpeg -maxrate 500 -r 6 -i - -r 6 -f avi output.avi Check your FFMPEG installation to see what formats are supported using the: |
| Bj on 10.15.07 at 4pm |
|
oki, Did try to just direct stream from the cam server -> webserver -> to my pc and it did seem to work “ok” |
| Bj on 10.15.07 at 4pm |
|
BTW. Can the bitrate/framrate be diffrence between CB-V10 and the VB-50iR ? Maby that the problem with the x2 speed playback? |
| Jim Palmer on 10.18.07 at 9am |
|
The bitrate and quality setting for ffmpeg shouldn’t affect the speed of playback. The speed of playback is controlled solely by the framerate, i.e. the “-r 6″ setting should force the input and output video in ffmpeg to be 6 FPS. Ensure the the PHP script is pulling an image from the cam at that rate by setting the sleep function to usleep for 1666666 milliseconds. This also might be a problem with using the AVI output format. Have you tried different output formats? I’ve honestly still only been using the SWF output format through FFSERVER which doesn’t seem to have the problem you have. Sounds like a little tweak/testing is in order! |
| Bj on 10.28.07 at 11am |
|
Hi, Not tryed other outputs because I dont use the ffmpeg part. I just use the php script to “download” the stream (record) to my computer. But is there a way to stream to my webserver for like 5min and then it stops to stream? I tryed wget to stream to my webserver but only one problem. It never stops. :D lol… Sorry, I’m a noob when it comes to things like this. It seems my download speed is to low to get more then 1-2 fps at 320×256. |
| Nikolaj on 11.9.07 at 7pm |
#!/usr/bin/python
# If you wanted to do it in python
import socket
from time import sleep
s=socket.socket(socket.AF_INET)
s.connect(("10.0.0.20", 65310))
s.send("START\\r\\n")
r=s.recv(12000)
while True:
s.send("\\x0a"*3)
print s.recv(80000)
sleep(1.0/6)
|
| Bj on 11.13.07 at 10am |
|
Is there a way to make a cgi , perl or php script who makes a output file like stream.mjpeg or something like that? Also maby with a stop option or a timeout? Sorry, I’m no “real” programmer. :D |
| dk on 12.17.07 at 3am |
|
hi everybody, really surpriced to see simple code to capture video from webcam using PHP…friends cant it be run in internet also… hope i’l get an immed’t reply |
| John on 12.28.07 at 7am |
|
dk, to be honest, you don’t sound like you know enough about the subject/Linux to be able to create this kind of solution. That may sound harsh, but from reading your post that is the impression I get. I recommend you try using either Skype or a Polycom video conferencing unit. If you are needing a Windows streaming solution, Windows media server may be more appropriate. |
| d_blessed_one on 2.5.08 at 4am |
|
hello all, |
| kate on 3.3.08 at 7pm |
|
Is it possible to use Windows Media Server and pull a stream of video directly from the camera? I see on the Axis cameras there’s code out there to do it. I’m trying to pull in video from a VB-C50ir camera to a server then multi-cast it from there as not to eat up the small bandwidth the camera is connected to remotely. |
| Jim Palmer on 3.5.08 at 4pm |
|
Lots of interest in the Windows Media Server - yes the FFMPEG and FFSERVER are more suited for Linux, but they can run on Windows. I would honestly see if there was a way to replicate the PHP script in a native windows language, i.e. C#, VB or the like, and “pipe” the data to a Windows Media Server hook. I can only assume that there is a WMS SDK out there. It still comes down to the simple fact that the VB-C’s use Motion JPEG - which I know can be converted into WMS native encoding. Start by exploring FFMEG on windows. Another thing - if you want to save the stream from the camera to a file - I don’t think there is anything wrong with routing the output of the PHP script to write to a .MJPEG file. |
| shekar on 3.12.08 at 6am |
|
Hi, |
| Steve on 3.25.08 at 6pm |
|
Hi folks, Also, has any more progress been made with this so that a Canon camera can be streamed to a web page? |
| Fred J.G. on 4.9.08 at 7pm |
|
Hi Jim Palmer, I read in the manual of the vb-c50 that it uses software based on GPL licenses as quoted here from the manual: “This product uses software based on the GNU General Public License (GPL), GNU Lesser General Maybe by getting the sources you can get better control cheers, |
| Ebbe on 4.11.08 at 7pm |
|
Just want to point out that you can probably use native linux commands to read the video feed before piping it into ffmpeg. for example curl or wget could probably do the job: curl $stream | ffmpeg param….. correct me if im wrong. |
| dirk maas on 4.12.08 at 12pm |
|
Maybe the “AXIS Video Server PTZ Drivers” will be helpful for reverse engeneering, as Canon seems to be a 213 PTZ OEM. |
| dirk maas on 4.12.08 at 1pm |
|
This is a nice fake: |
| Krishnan on 7.14.08 at 11am |
|
Great post! Reverse engineering the controls would be great! |
| Jim Palmer on 7.14.08 at 3pm |
|
Ebbe Krishnan |
| Krishnan on 8.17.08 at 5am |
|
Great, this is too good. No words enough to thank ye… :-) |
| Krishnan on 8.17.08 at 5am |
|
I am working on video processing at a university. It would therefore be nice to control the camera as the target moves. it may sound terribly foolish but is it possible to control/get packets through a C/C++ program? |
26 Comments