Friday, November 29, 2013

Pulling H264 video from an IP camera using Python

IP cameras have come a long ways, and recently I upgraded some old cameras to these new Lorex cameras (model LNB2151/LNB2153) and I'm very impressed.

These cameras record 1080p wide-angle video at 30 frames per second, use power over ethernet (PoE), can see when it's dark using builtin infrared LEDs and are weather-proof. The video quality is impressive and they are surprisingly inexpensive. The camera can deliver two streams at once, so you can pull a lower resolution stream for preview, motion detection, etc., and simultaneously pull the higher resolution stream to simply record it for later scrutinizing.

After buying a few of these cameras I needed a simple way to pull the raw H264 video from them, and with some digging I discovered the cameras speak RTSP and RTP which are standard protocols for streaming video and audio from IP cameras. Many IP cameras have adopted these standards.

Both VLC and MPlayer can play RTSP/RTP video streams; for the Lorex cameras the default URL is:


After more digging I found the nice open-source (LGPL license) Live555 project, which is a C++ library for all sorts of media related protocols, including RTSP, RTP and RTCP. VLC and MPlayer use this library for their RTSP support. Perfect!

My C++ is a bit rusty, and I really don't understand all of Live555's numerous APIs, but I managed to cobble together a simple Python extension module, derived from Live555's testRTSPClient.cpp example, that seems to work well.

I've posted my current source code in a new Google code project named pylive555. It provides a very simple API (only 3 functions!) to pull frames from a remote camera via RTSP/RTP; Live555 has many, many other APIs that I haven't exposed.

The code is thread-friendly (releases the global interpreter lock when invoking the Live555 APIs).

I've included a simple Python program, that shows how to load H264 video frames from the camera and save them to a local file. You could start from this example and modify it to do other things, for example use the ffmpeg H264 codec to decode individual frames, use a motion detection library to trigger recording, parse each frame's metadata to find the keyframes, etc. Here's the current

import time
import sys
import live555
import threading

# Shows how to use live555 module to pull frames from an RTSP/RTP
# source.  Run this (likely first customizing the URL below:

# Example: python3 1 10 out.264 
if len(sys.argv) != 5:
  print('Usage: python3 cameraIP channel seconds fileOut')
cameraIP = sys.argv[1]
channel = sys.argv[2]
seconds = float(sys.argv[3])
fileOut = sys.argv[4]

# NOTE: the username & password, and the URL path, will vary from one
# camera to another!  This URL path works with the Lorex LNB2153:
url = 'rtsp://admin:000000@%s/PSIA/Streaming/channels/%s' % (cameraIP, channel)

fOut = open(fileOut, 'wb')

def oneFrame(codecName, bytes, sec, usec, durUSec):
  print('frame for %s: %d bytes' % (codecName, len(bytes)))
  fOut.write(b'\0\0\0\1' + bytes)

# Starts pulling frames from the URL, with the provided callback:
useTCP = False
live555.startRTSP(url, oneFrame, useTCP)

# Run Live555's event loop in a background thread:
t = threading.Thread(target=live555.runEventLoop, args=())

endTime = time.time() + seconds
while time.time() < endTime:

# Tell Live555's event loop to stop:

# Wait for the background thread to finish:

Installation is very easy; see the README.txt. I've only tested on Linux with Python3.2 and with the Lorex LNB2151 cameras.

I'm planning on installing one of these Lorex cameras inside a bat house that I'll build with the kids this winter. If we're lucky we'll be able to view live bats in the summer!


  1. This is awesome. Great job. I have been using live555 with ctypes in Python. I like what you did, it's a better solution.

  2. This is one of the best security camera. I am also using ip camera.

  3. I downloaded the live555 CPP library, then installed it and everything worked fine. Then I downloaded your python library, put the files inside my "live" folder, and when I run the "python3 build" it says that the file "liveMedia.hh" does not exist (even though it does) and then gives me an error. How can I fix that?

    Thanks for your help in advanced!

  4. well, I guess this error when I try to compile it with python3:

    module.cpp:22:20: fatal error: Python.h: No such file or directory

  5. You hit that compilation error when running "python3 build"? That's strange: takes care of setting up the flags for the compiler. What compile lines are actually executed? Where is Python.h on your system?

    Maybe you don't have the python-dev package installed?

  6. I still can't fix it even though I have python-dev already. I don't know if it might be a compatibility issue between pylive555 and the newest version of live555 ( live.2014.02.04.tar.gz - 04-Feb-2014 <--- date)?
    Maybe you can email me your live555 version?

    Also, let me make sure from the instructions:
    Download pylive555, then download live555 and put the folder "live" inside the pylive555 folder? Or is the other way around?

    Thank you!

    1. Hi Luis,

      Can you post the compile lines that is running? Somehow it's not finding your Python.h header.

      You had it right the first time: download/checkout pylive555, then download live555 and unpack it into the "live" sub-directory.

      My version of live555 is from 11/28/2013, but I don't think that's your problem (yet). You need to solve the missing Python.h header first.

    2. make sure you have python3-dev (python-dev may be the python 2 dev)

  7. Hi Michael,

    Really looking forward to trying your code out but......

    I seem to be having the same problem with not finding python.h

    root@raspbx:~/live# python3 build
    running build
    running build_ext
    building 'live555' extension
    creating build
    creating build/temp.linux-armv6l-3.2
    gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -D_FORTIFY_SOURCE =2 -g -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-securi ty -fPIC -I./live/liveMedia/include -I./live/BasicUsageEnvironment/include -I./l ive/UsageEnvironment/include -I./live/groupsock/include -I/usr/include/python3.2 mu -c module.cpp -o build/temp.linux-armv6l-3.2/module.o
    cc1plus: warning: command line option ‘-Wstrict-prototypes’ is valid for Ada/C/O bjC but not for C++ [enabled by default]
    module.cpp:22:20: fatal error: Python.h: No such file or directory
    compilation terminated.
    error: command 'gcc' failed with exit status 1

    Hope you can help.

    Thanks Gerry

    1. Hi Gerry,

      I think you need to install the python-dev package on your box?

  8. Michael,

    I did install python-dev but got same error. I think I have been playing around with some many different applications, it's best I do a clean install.

    Get back with my results later

  9. Hi Michael,

    I think I have misread your instructions somewhere as now I have a bigger problem.

    My directory structure is as follows:
    home/pi/pylive555 (here are readme.txt,, module.cpp, and live555-latest.tar.gz)
    including the other directories:- live, build and git

    I started from
    /pylive555/live $ ./genMakefiles linux
    /pylive555/live $ export CPPFLAGS=-fPIC CFLAGS=-fPIC
    /pylive555/live $ make install
    After many lines.....
    I got these errors
    install -d /usr/local/include/liveMedia /usr/local/lib
    install: cannot change permissions of ' /usr/local(include/liveMedia' : No such file or directory
    install: cannot change permissions of ' /usr/local/lib' : Operation not permitted
    make[1] : *** [install1] Error 1
    make[1] : Leaving directory ' /home/pi/pylive555/live/liveMedia'
    make: *** [install] Error 2
    back at /pylive555/live

    Not sure where to go from here.


    1. You should do "sudo make install", ie that step must be done as root. See if that works?

  10. If I run python3, I get in traceback ImportError: No module named live555

  11. Hi Michael,
    Finally got it installed without any errors. Checked my RTSP string using VLC to my Grandstream camera before changing Get the video file created but unfortunately cannot open it with VLC.
    Below is a copy of 1st line from video file:

    Not sure what I have done wrong.


    1. Hmm, I'm able to play my file using mplayer. When I try to use VNC, it does have trouble, unless I force it to open a raw H264 file ... these instructions worked for me:

      Try that?

  12. sorry but this blog has removed my copied text from video file

  13. I used mplayer and managed to play the files, unfortunately footage is nearly all green with some form of image in the background. At least now I know I am getting stream from the camera and will play a little more with the RTSP string as there are a number available for the Grandstream cameras.

  14. Could this be adapted to run on a Raspberry Pi and Foscam cameras?

    1. Hi Gilson,

      I don't have any experience with Raspberry Pi nor Foscam, so I'm really not sure. This is only useful if the Foscam speaks RTSP/RTP, which I believe is more and more common in IP cameras these days. But I think the more typically approach with the Pi is to pull frames directly from an attached camera (not via an ethernet connection)? I.e.:

  15. Hi Michael,

    I understand that script produces a binary file with H264 frames...
    Is it possible to create some proper container like AVI or MP4 or MKV so the file is playable with media player?

    1. Hi Anton,

      This is definitely possible; I think there are python bindings around ffmpeg so you could go that route. In my usage, I just spawn a sub-process and invoke ffmpeg from the command line, something like:

      ffmpeg -i - -vcodec copy -f mp4 video.mp4

      Then I send the bytes to that pipe, close it, and video.mp4 holds the H264 in an MP4 container.

    2. as I implement this? Can you show me an example?

  16. Hi Michael,

    I can't solve this problem in raspberry pi env..
    please comment..

    pi@raspberrypi ~/pylive555 $ python3 1 10 out.264
    Traceback (most recent call last):
    File "", line 3, in
    import live555
    ImportError: /usr/local/lib/python3.2/dist-packages/ undefined symbol: _ZN18BasicTaskScheduler9createNewEj
    pi@raspberrypi ~/pylive555 $

    1. Something went wrong when you build the, because this symbol is defined in libBasicUsageEnvironment.a, which is one of the libraries we link against (in

      When I run "nm" in my build I can see that symbol is defined.

    2. Thanks for your quick reply..

      I run 'nm' command but that simbol is 'undefinded'

      pi@raspberrypi /usr/local/lib/python3.2/dist-packages $ nm | grep _ZN18BasicTaskScheduler9createNewEj
      U _ZN18BasicTaskScheduler9createNewEj

      what can i do?

    3. Can you remove your "build" subdirectory, run python3 build, and post the commands here? Somehow it's not linking properly against the live555 libs.

    4. pi@raspberrypi ~ $ cd pylive555
      pi@raspberrypi ~/pylive555 $ ls
      build live module.cpp README.txt
      pi@raspberrypi ~/pylive555 $ sudo rm -rf build
      pi@raspberrypi ~/pylive555 $ ls live module.cpp README.txt
      pi@raspberrypi ~/pylive555 $ python3 build
      running build
      running build_ext
      building 'live555' extension
      creating build
      creating build/temp.linux-armv6l-3.2
      gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -D_FORTIFY_SOURCE=2 -g -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -fPIC -I./live/liveMedia/include -I./live/BasicUsageEnvironment/include -I./live/UsageEnvironment/include -I./live/groupsock/include -I/usr/include/python3.2mu -c module.cpp -o build/temp.linux-armv6l-3.2/module.o
      cc1plus: warning: command line option ‘-Wstrict-prototypes’ is valid for Ada/C/ObjC but not for C++ [enabled by default]
      creating build/lib.linux-armv6l-3.2
      g++ -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-z,relro build/temp.linux-armv6l-3.2/module.o -L./live/liveMedia -L./live/UsageEnvironment -L./live/groupsock -lliveMedia -lgroupsock -lBasicUsageEnvironment -lUsageEnvironment -o build/lib.linux-armv6l-3.2/
      pi@raspberrypi ~/pylive555 $

    5. That looks correct; I can see in the last line that it's linking against BasicUsageEnvironment. Can you confirm you have a libBasicUsageEnvironment.a, and that it does in fact define that symbol?

    6. ok, I run this..

      pi@raspberrypi ~ $ sudo find / -name 'libBasicUsageEnvironment.a'

      and then open editor and search '_ZN18BasicTaskScheduler9createNewEj'.
      capture that result screen.

      pi@raspberrypi ~ $ sudo nano /home/pi/pylive555/live/BasicUsageEnvironment/libBasicUsageEnvironment.a

      pi@raspberrypi ~ $ sudo nano /usr/local/lib/libBasicUsageEnvironment.a

      pi@raspberrypi ~ $ sudo nano /usr/lib/libBasicUsageEnvironment.a

    7. so I rename '/usr/lib/libBasicUsageEnvironment.a' as /usr/lib/libBasicUsageEnvironment.a.bak.
      and then I run build command.
      Now runs successfully!

      Thank you for your kind and quick response

    8. Ahh, so you had an older libBasicUsageEnvironment.a in your path? Phew, thanks for bringing closure :) I'm glad you solved it.

    9. Adding this comment since Blogger's spam filters seem to have removed it:

      Hi Michael

      I have another problem.

      My ip camera is ATTN ops-bip720p like this (
      How can I find camera's rtsp url like example code (rtsp://admin:ecofence@%s/PSIA/Streaming/channels/%s)

      Buyer don't know about this and I can't find manufacturer ATTN web site or Technical Information.

      my question is that
      Where do you find rtsp url path of your camera Lorex LNB2153?

      Is it possible to get only from manufacturer?


    10. I don't know much about RTSP; perhaps the URL path that the camera must accept is part of the standard?

      In my case, after some Googling, I found documents that listed these paths for my camera ...

  17. Dear friends, may I ask for help regarding this topic? I tried to run the example and it does something but after all the result file is 0byte sized... Do you think where could be the problem? The output of the script is below.

    root@pb4540s:/home/karl/Downloads# python3 1 10 test12.avi
    [URL:"rtsp://admin:admin@"]: Initiated the "video/H264" subsession (client ports 49430-49431)
    [URL:"rtsp://admin:admin@"]: Set up the "video/H264" subsession (client ports 49430-49431)
    [URL:"rtsp://admin:admin@"]: Created a data sink for the "video/H264" subsession
    [URL:"rtsp://admin:admin@"]: Started playing session...

  18. Will this work with Lorex HR118000? the cameras don't have an IP just the DRV. Running Linux Mint.

  19. Sorry, I don't know anything about the Lorex HR118000.

  20. I get some problem linking: /usr/bin/ld: ./live/liveMedia/libliveMedia.a(Media.o): relocation R_X86_64_32S against `_ZTV6Medium' can not be used when making a shared object; recompile with -fPIC

    I look inside your code and uncommented extra_compile_args = ['-fPIC'], but not compiled.
    Thanks for share this piece of code with us though.

    1. Oh, did the -fPIC fix your issue or not? Or you hit different errors?

    2. Sorry, I had not seen the text 'export CPPFLAGS=-fPIC CFLAGS=-fPIC' in the README file. Worked after I exported these flags. Thanks.

  21. I'm getting this 'error' for this command on this camera. (AirCam Dome firmw v3.0.9)

    python3 1 10 asd.mp4
    [URL:"rtsp://"]: Initiated the "video/H264" subsession (client ports 52244-52245)
    [URL:"rtsp://"]: Failed to set up the "video/H264" subsession: 461 Unsupported Transport
    [URL:"rtsp://"]: Initiated the "audio/MPEG4-GENERIC" subsession (client ports 55122-55123)
    [URL:"rtsp://"]: Failed to set up the "audio/MPEG4-GENERIC" subsession: 461 Unsupported Transport
    [URL:"rtsp://"]: Failed to start playing session: No RTSP session is currently in progress

    1. I think you should ask on the live devel list?

  22. Hi Micheal, can you help me solve the following problem:

    running build
    running build_ext
    building 'live555' extension
    creating build/temp.linux-i686-2.7
    i686-linux-gnu-gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I./live/liveMedia/include -I./live/BasicUsageEnvironment/include -I./live/UsageEnvironment/include -I./live/groupsock/include -I/usr/include/python2.7 -c module.cpp -o build/temp.linux-i686-2.7/module.o
    cc1plus: warning: command line option ‘-Wstrict-prototypes’ is valid for C/ObjC but not for C++ [enabled by default]
    module.cpp:1180:27: error: variable ‘PyModuleDef module’ has initializer but incomplete type
    static struct PyModuleDef module = {
    module.cpp:1182:2: error: ‘PyModuleDef_HEAD_INIT’ was not declared in this scope
    module.cpp: In function ‘void PyInit_live555()’:
    module.cpp:1208:29: error: ‘PyModule_Create’ was not declared in this scope
    m = PyModule_Create(&module);
    In file included from /usr/include/wchar.h:51:0,
    from /usr/include/python2.7/unicodeobject.h:120,
    from /usr/include/python2.7/Python.h:85,
    from module.cpp:43:
    module.cpp:1212:10: error: return-statement with a value, in function returning 'void' [-fpermissive]
    return NULL;
    module.cpp:1218:56: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
    error = PyErr_NewException("live555.error", NULL, NULL);
    module.cpp:1234:9: error: return-statement with a value, in function returning 'void' [-fpermissive]
    return m;
    error: command 'i686-linux-gnu-gcc' failed with exit status 1

    1. Sorry, I'm not sure offhand; maybe this is a Python 2 vs 3 issue?

  23. Hi Michael,

    I'm getting this error when I try to run after following the instructions on your readme.txt:

    "Import Error: No module named 'live555' "

    I believe this has to do with setting the path. I am running on Mac OS X and I modified my ~/.bash_profile file by adding this line to it:

    export PYTHONPATH=$PYTHONPATH:/Documents/[long_path_here]/pylive555/build/lib.macosx-10.6-intel-3.4/

    Do you know if this problem is caused by setting the path wrong? And if so, do you see anything wrong with the line above ? I'm not sure if I'm doing this right, I'm not really an expert in unix.

    Thank you!

    Gustavo Rodriguez

    1. Update: I was able to solve this problem and now it all seems to work fine. Thanks!

  24. Had to add "BasicUsageEnvironment" to library_dirs in (I had unpacked the cpp/py outside of the live dir), otherwise works great. Now I need to wrap the data into a playable container... Thanks!

  25. Hello,

    Is there a way to make this work using python 2 rather than python 3? I was able to make it work with python3 just fine, but whenever I try to run python build, I get this output on terminal:

    running build
    running build_ext
    building 'live555' extension
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I./live/liveMedia/include -I./live/BasicUsageEnvironment/include -I./live/UsageEnvironment/include -I./live/groupsock/include -I/usr/include/python2.7 -c module.cpp -o build/temp.linux-armv7l-2.7/module.o
    cc1plus: warning: command line option ‘-Wstrict-prototypes’ is valid for Ada/C/ObjC but not for C++ [enabled by default]
    module.cpp:590:27: error: variable ‘PyModuleDef module’ has initializer but incomplete type
    module.cpp:591:3: error: ‘PyModuleDef_HEAD_INIT’ was not declared in this scope
    module.cpp: In function ‘void PyInit_live555()’:
    module.cpp:604:30: error: ‘PyModule_Create’ was not declared in this scope
    module.cpp:606:12: error: return-statement with a value, in function returning 'void' [-fpermissive]
    module.cpp:609:57: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
    module.cpp:617:10: error: return-statement with a value, in function returning 'void' [-fpermissive]
    error: command 'gcc' failed with exit status 1

    Thank you!


    1. Hi, I haven't tried to get pylive555 working with Python2 but I suspect it would not be too hard ... module.cpp is quite contained.

    2. This comment has been removed by the author.

    3. Thank you for your answer Mike. I was wondering if you could get me started so that I can run pylive555 with Python 2. I'm assuming that the reason I'm getting these errors is that when I #include Python.h, the Python 3 header file is what gets included and not the Python 2 header file. Do you know what changes I need to make (maybe to my system path?) in order for the Python 2 header to be the one included? And can you think of anything else that I need to do in order to make pylive555 work with Python 2?



    4. Hi Mike,

      I don't believe it to be possible to use this extension module with Python2 since many of the variables used in module.cpp are PyModuleDef variables which are only defined in Python3's moduleobject.h, but not in Python 2. I just thought I would give you an update of what I found and see if maybe you knew a way to get around this. These are the errors I get when I try to run python build:

      module.cpp:592:3: error: use of undeclared identifier 'PyModuleDef_HEAD_INIT'
      module.cpp:591:27: error: variable has incomplete type 'struct PyModuleDef'
      static struct PyModuleDef module = {
      module.cpp:591:15: note: forward declaration of 'PyModuleDef'
      static struct PyModuleDef module = {
      module.cpp:607:5: error: void function 'PyInit_live555' should not return a value [-Wreturn-type]
      return NULL;
      ^ ~~~~
      module.cpp:610:30: warning: conversion from string literal to 'char *' is deprecated [-Wc++11-compat-deprecated-writable-strings]
      error = PyErr_NewException("live555.error", NULL, NULL);
      module.cpp:618:3: error: void function 'PyInit_live555' should not return a value [-Wreturn-type]
      return m;

      Thank you!


  26. Hi Michael,

    Is it possible to connect to 2 different IP cameras simultaneously, each on a separate thread, using this module extension? And if so, how would you change the code to do so? I tried to do it on a python script but I got a segmentation fault as soon as I tried to log in to the second camera.


  27. Hello,
    First of all - thanx for your work (though I couldn't make it run)

    Second: How to install it on Windows? I have Windows 7x64, Python 3.5, Visual Studio 2008.

    D:\dist\live555-1.0>python install
    running install
    running build
    running build_ext
    building 'live555' extension
    error: Unable to find vcvarsall.bat

    That's what I get. Please help.

    P.S. When trying to find "vcvarsall.bat" with "" from c:\Python35\Lib\distutils\ - everything is ok. So, I guess that it is YOUR program can't find it. Where is it looking for the file? Where should I put it or which part of what file should I change?

    Thanx in advance.

    1. You need vcvarsall.bat to be on the execution path in the windows shell where you ran .. I think Visual Studio 2008 likely has a script you can run to fixup the path.

  28. Hi Michael,

    thanks for your inspiring idea. Based on your code I would like to decode the video frames with ffmpeg and
    then render the images. I have the h264 decoder ffmpeg initialized and ready, however when I call
    ffmpegs decoding function with the buffer (fReceiveBuffer) in

    void DummySink::afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes,
    struct timeval presentationTime, unsigned durationInUS);

    the h264 decoder tells me:
    [h264 @ 0x1917020] no frame!

    Could you please elaborate on what data "fReceiveBuffer" contains?

  29. By the way, I am using this file:

  30. Mike.
    This is awesome !
    My question as a new comer to the field:
    The live555 seems to be a great C++ library.
    To build video streaming servers when would you use Python and when would you stay with C++.
    For a new comer what is the best learning path ?
    Thanks !

  31. Other libs are able to fetch, apart from the below one
    LINK : fatal error LNK1181: cannot open input file 'libBasicUsageEnvironment.lib'
    error: command 'C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\BIN\\link.exe' failed with exit status 1181

  32. Hi Michael,

    Thank you for the great post and pylive555. I was able to get raw bytes out of web cams.

    However, you mentioned in the post about using ffmpeg H264 codec to decode and process the bytes. Do you mind sharing more info about that?

    1. Are you still using python when it comes to decoding i/p/b frames? If so, what lib are you currently using?
    2. What function are you using to decode i/p/b frames from bytes? Do you have an example?

    Thanks a lot ;)

    1. Hi Winston,

      I am still using it.

      I created a very simple wrapper around ffmpeg APIs to e.g. let me init a decoder, and then send the decoder a new frame to decode, and it returns an RGB bitmap.

      Here's how I init ffmpeg codec:

      o->cxt = avcodec_alloc_context3(pCodec);

      and here's how I add one frame to it:

      // Decode the next chunk of data
      int bytesDecoded = avcodec_decode_video2(self->cxt, self->frame,

      But likely these APIs have changed over time ... I'm using a very old ffmpeg at this point.

    2. Hi Michael,

      Thanks a million. I will try avcodec_alloc_context3 and avcodec_decode_video2 out.

      Just curious, when it comes to p frame and b frame, do you decode the entire frame out with the information from i frame?

      I am just trying to get the delta from p frame and b frame only :)

      Many thanks again.