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:

  rtsp://admin:000000@<hostname>/PSIA/Streaming/channels/1.

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 example.py 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 example.py:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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 example.py 10.17.4.118 1 10 out.264 
if len(sys.argv) != 5:
  print()
  print('Usage: python3 example.py cameraIP channel seconds fileOut')
  print()
  sys.exit(1)
  
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=())
t.setDaemon(True)
t.start()

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

# Tell Live555's event loop to stop:
live555.stopEventLoop()

# Wait for the background thread to finish:
t.join()


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!

74 comments:

  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.

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

    ReplyDelete
  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 setup.py 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!

    ReplyDelete
  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

    ReplyDelete
  5. You hit that compilation error when running "python3 setup.py build"? That's strange: setup.py 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?

    ReplyDelete
  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!

    ReplyDelete
    Replies
    1. Hi Luis,

      Can you post the compile lines that setup.py 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.

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

      Delete
  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 setup.py 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


    ReplyDelete
    Replies
    1. Hi Gerry,

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

      Delete
  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

    ReplyDelete
  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, setup.py, module.cpp, example.py 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.

    /Gerry

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

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

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

    Not sure what I have done wrong.

    /Gerry

    ReplyDelete
    Replies
    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: https://forum.videolan.org/viewtopic.php?f=14&t=12530

      Try that?

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

    ReplyDelete
  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.

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

    ReplyDelete
    Replies
    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.: http://www.raspberrypi.org/camera

      Delete
  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?

    ReplyDelete
    Replies
    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.

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

      Delete
  16. Hi Michael,

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

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


    ReplyDelete
    Replies
    1. Something went wrong when you build the live555.cpython-32mu.so, because this symbol is defined in libBasicUsageEnvironment.a, which is one of the libraries we link against (in setup.py).

      When I run "nm live555.cpython-32mu.so" in my build I can see that symbol is defined.

      Delete
    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 live555.cpython-32mu.so | grep _ZN18BasicTaskScheduler9createNewEj
      U _ZN18BasicTaskScheduler9createNewEj

      what can i do?

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

      Delete
    4. pi@raspberrypi ~ $ cd pylive555
      pi@raspberrypi ~/pylive555 $ ls
      build example.py live module.cpp README.txt setup.py
      pi@raspberrypi ~/pylive555 $ sudo rm -rf build
      pi@raspberrypi ~/pylive555 $ ls
      example.py live module.cpp README.txt setup.py
      pi@raspberrypi ~/pylive555 $ python3 setup.py 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/live555.cpython-32mu.so
      pi@raspberrypi ~/pylive555 $

      Delete
    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?

      Delete
    6. ok, I run this..

      pi@raspberrypi ~ $ sudo find / -name 'libBasicUsageEnvironment.a'
      /home/pi/pylive555/live/BasicUsageEnvironment/libBasicUsageEnvironment.a
      /usr/local/lib/libBasicUsageEnvironment.a
      /usr/lib/libBasicUsageEnvironment.a

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

      pi@raspberrypi ~ $ sudo nano /home/pi/pylive555/live/BasicUsageEnvironment/libBasicUsageEnvironment.a
      http://screencast.com/t/Sj1jVnVWqJA
      http://screencast.com/t/WWGf5pG1g3fW

      pi@raspberrypi ~ $ sudo nano /usr/local/lib/libBasicUsageEnvironment.a
      http://screencast.com/t/DTwq0OvM
      http://screencast.com/t/3hjnbOlPJEBu

      pi@raspberrypi ~ $ sudo nano /usr/lib/libBasicUsageEnvironment.a
      http://screencast.com/t/qAC61Sd5

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

      Thank you for your kind and quick response

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

      Delete
    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 (http://attn.ph/shop/step1.php?number=54)
      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?

      Thanks

      Delete
    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 ...

      Delete
  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 example.py 88.101.39.191 1 10 test12.avi
    [URL:"rtsp://admin:admin@88.101.39.191/cam/realmonitor?channel=1&subtype=0/"]: Initiated the "video/H264" subsession (client ports 49430-49431)
    [URL:"rtsp://admin:admin@88.101.39.191/cam/realmonitor?channel=1&subtype=0/"]: Set up the "video/H264" subsession (client ports 49430-49431)
    [URL:"rtsp://admin:admin@88.101.39.191/cam/realmonitor?channel=1&subtype=0/"]: Created a data sink for the "video/H264" subsession
    [URL:"rtsp://admin:admin@88.101.39.191/cam/realmonitor?channel=1&subtype=0/"]: Started playing session...

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

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

    ReplyDelete
  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.

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

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

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

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

    ReplyDelete
  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
    PyModuleDef_HEAD_INIT,
    ^
    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

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

      Delete
  23. Hi Michael,

    I'm getting this error when I try to run example.py 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/live555.so

    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

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

      Delete
  24. Had to add "BasicUsageEnvironment" to library_dirs in setup.py (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!

    ReplyDelete
  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 setup.py 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!

    Gustavo

    ReplyDelete
    Replies
    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.

      Delete
    2. This comment has been removed by the author.

      Delete
    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?

      Thanks!

      Gustavo

      Delete
    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 setup.py build:

      module.cpp:592:3: error: use of undeclared identifier 'PyModuleDef_HEAD_INIT'
      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!

      Gustavo

      Delete
  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 example.py 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.

    Thanks.

    ReplyDelete
  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 setup.py 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 "msvc9compiler.py" 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.

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

      Delete
  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?

    ReplyDelete
  29. By the way, I am using this file:
    http://download.openbricks.org/sample/H264/h264_die_neuen_paradiese_03.mpg

    ReplyDelete
  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 !
    Andy

    ReplyDelete
  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

    ReplyDelete
  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 ;)

    ReplyDelete
    Replies
    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,
      &frameFinished,
      &packet);

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

      Delete
    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.

      Delete
    3. Hi Winston,

      ffmpeg takes care of "remembering" the last i frame and doing the delta decode for me ... I don't in any way see the deltas, because I just pull out a fully decoded bitmap on each frame. But maybe there are alternative ffmpeg APIs letting you see the deltas?

      Delete
    4. Thanks a lot, Michael.
      I will dig deeper and keep you updated with my findings.
      Thank you again.

      Delete
    5. Michael,

      Hey there (I'm a friend of Winston). I got this running and love it. I am using https://github.com/mikemccand/pylive555 to connect to an rtsp stream exactly as you describe here.

      However, I am noticing that there are only 3 methods exposed:
      - StartRTSP
      - runEventLoop
      - StopEventLoop

      I'm then decoding using GStreamer (Live555 is faster at connecting than gstreamer's built in uri connector, plus provides better access to the raw data).

      Question is--is there a way to connect to multiple RTSP endpoints and then disconnect from one? Or is this a 1-per process library (i.e., spin up a separate process to connect to another feed and the event loop must be started and killed for that camera 1:1 in its process?

      Thanks!

      Delete
    6. Hi Dave S,

      I'm glad you got it working!

      You can pull from multiple RTSP streams at once; I'm doing just that.

      Just call runEventLoop once up front from a separate Python thread, then startRTSP for each connection. Hmm I didn't expose a stopRTSP right? Pull requests welcome!

      Also see e.g. this comment: https://github.com/mikemccand/pylive555/blob/master/module.cpp#L90-L93

      Delete
    7. Hey there, I'm reasonably ( 12 months) new to Python at any level of depth (used it 20 years ago, but that doesn't really count), so working on the cPython stuff was a little out of my league for starters.

      Instead of exposing more, I ended up running the pylive555 libraries in a separate subprocess using Popen and then passing the data back and forth using a queue. In this way, each connection uses the global scheduler reasonably well, and can be started/stopped using the process methods (a little heavy-handed but it works for now).

      I will take a look at the comments and if I get a little time on Friday, I'll take a look at working on a PR. Would love to be helpful and contribute if I can. The library is very solid--FFMpeg-level quality from what I can see and lightning fast when I've compared with others.

      Thanks,
      Selly

      Delete
    8. Hi Selly,

      Yeah the multi-process solution should work!

      I've found single-process works pretty well too ... I was able to get to ~10 RTSP cameras in a single Python process on a wimpyish cpu (Intel(R) Core(TM) i5-2405S CPU @ 2.50GHz) before it seemed to saturate. (Plus, this app is doing a fair amount of python work besides just pulling bytes from the cameras).

      Exposing a stopRTSP should be pretty simple ... just copy what I did for startRTSP, I think...

      Delete
    9. Mike, hey there. So, it turns out python's multiprocess library works great. MOST of the time. That said, it has been giving me a little bit of trouble working with FLASK, so I went ahead and I'm actually working on a pull request for you right now. https://github.com/daveselinger/pylive555/tree/add_stop_rtsp

      CAVEAT: It has been almost 15-20 years since I've done any real C++ programming (had to google 'create array of object pointers in C++'), but it was kinda fun getting back into it.

      I'll test this over the next little bit. If you have any initial feedback (like "Hey you're an idiot because of X, Y or Z") please feel free to share. Otherwise, I'll keep plugging along and will let you know once I've got it reasonably tested. Cheerio.

      Delete
    10. OK, I've got multiple monitors working on a single RTSP process. Submitted the PR and looking forward to your feedback!

      Delete
  33. Hello Michael,
    My problem same as Leo's problem.

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

    I can't run pylive555 in my system (Windows 8.1, Python 3.5 (Anaconda), VS 2012).
    I've read Leo's question, but I don't know how to solve my problem.
    I've browse in internet for my problem, for hours, but I don't get its solution, yet.
    Can you tell me how to solve my problem, in detail?

    Thanks in advance.

    ReplyDelete
  34. Hi! Michael
    I need to grab IP camera h.264 encoded stream frame by frame.And then on each and every frame i want to do the followings
    1. Decode the frame
    2. Hard Sub some data
    3. Encode back
    4. Save in avi container

    Is there any way to grab the h.264 encoded frames from rtsp stream and then write on those frames and encode again ??
    Thanks
    Shivraj

    ReplyDelete
  35. Hi Micheal
    Beginner here....
    Do you have a step by step install for this?
    I have only Lorex Cams here on the island and our controller got flooded by hurricane Irma. I want to setup a Ubuntu 16.04 system .. Please help

    Bart

    ReplyDelete
  36. DVD to Flash Video Converter enables you to easily transform your video(s) into powerful marketing tools. Many users search for various VDOs on the Web: training, demos, solutions - it is a great opportunity for you Free Online Video Downloader generate a lot more traffic. In the following article you will find out how you can easily encode and play movie files on any of your own WebPages.

    ReplyDelete