Playing stream of jpeg at 2 pictures / seconds
#1
Hi,

I try to write a addon to interface Motion (http://www.lavrsen.dk/foswiki/bin/view/Motion/WebHome).
My probleme when starting to play webcam view xbmc start to put in cache, and at 2 pictures/sec is verry long.
I want to disable buffering of this url, but i don t find how to do.

thank you.
Reply
#2
Afaik it is not possible to disable URL caching atm, have a look to this PR: https://github.com/xbmc/xbmc/pull/3130#i...t-23205199

What kind of add-on do you work on? Plugin, Script with dedicated GUI (xml)?
My GitHub. My Add-ons:
Image
Reply
#3
Its my first plugin/addon, and i learn python too Smile

its a simple xbmcgui.Windows derivate.

Code:
# import the XBMC libraries so we can use the controls and functions of XBMC
import xbmc, xbmcgui, xbmcaddon, xbmcvfs
import urllib2, urllib, re

debug = 1
__addon__   = xbmcaddon.Addon()
__addonid__ = __addon__.getAddonInfo('id')

Image_path = xbmc.translatePath('special://profile/addon_data/%s' % __addonid__)
if not xbmcvfs.exists(Image_path):
    xbmcvfs.mkdir(Image_path)

class MyClass(xbmcgui.Window):
    def __init__(self):
        Camera = {} # va contenir la liste des url des cameras (sous forme de dictionnaire)
        
        self.Addon = xbmcaddon.Addon (__addonid__)
        if debug : xbmc.log("start.")

        # create a password manager
        password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
        
        # Add the username and password.
        # If we knew the realm, we could use it instead of None.
        url_ctl = self.Addon.getSetting('url_ctl')
        url_base = re.search ("(.*):.*", url_ctl)
        url_base = url_base.group(1)
        
        password_mgr.add_password(None, url_ctl, self.Addon.getSetting('username'), self.Addon.getSetting('password'))
        handler = urllib2.HTTPBasicAuthHandler(password_mgr)
        
        #TODO: traiter les codes d'erreur particulierement 404 et 401
        
        # create "opener" (OpenerDirector instance)
        opener = urllib2.build_opener(handler)
        
        # use the opener to fetch a URL
        response = opener.open(url_ctl)
        
        # Install the opener.
        # Now all calls to urllib2.urlopen use our opener.
        urllib2.install_opener(opener)
        the_page = response.read()
        
        cams = re.findall("<a href='/([1-9]+[0-9]*)/'>.*</a><br>", the_page, re.MULTILINE)
        if debug : xbmc.log ('liste des cams :' + str(cams) )
        for cam in cams:
            if debug : xbmc.log ('pour la cam: '+ cam + ' => ' + url_ctl + cam + '/config/get?query=webcam_port')
            #port
            response = opener.open(url_ctl + cam + '/config/get?query=webcam_port' )
            the_page = response.read()
            port = re.search(".*webcam_port\s*=\s*([0-9]*).*", the_page, re.MULTILINE)
            port = port.group(1)
            if debug : xbmc.log ('pour la cam: '+ cam + ' => port:' + port)
            #Nom sur text_left
            if debug : xbmc.log ('pour la cam: '+ cam + ' => ' + url_ctl + cam + '/config/get?query=text_left')
            response = opener.open(url_ctl + cam + '/config/get?query=text_left' )
            the_page = response.read()
            name = re.search(".*text_left\s*=\s*(.*?)\s(&nbsp;)+", the_page, re.MULTILINE)
            name = name.group(1)
            if debug : xbmc.log ('pour la cam: '+ cam + ' => name:' + name)
            Camera[name] = (url_base + ":" + port + '?video_name=stream.mjpg')
            
            #imagefile = Image_path + "/" + cam + ".jpg"
            #urllib.urlretrieve(str(url_base + ":" + port), imagefile)
            #self.addControl(xbmcgui.ControlImage(1+ int(500 * int(cam)-1), 1, 250, 250, imagefile))
        if debug : xbmc.log ('Lecture: ' + str(Camera['CAMERA 2']))
        xbmc.Player( xbmc.PLAYER_CORE_AUTO ).playStream(Camera['CAMERA 2'])
        #label = xbmcgui.ControlLabel (100, 250, 1000, 1000, str(Camera))
        #self.addControl(label)
    
  
mydisplay = MyClass()
mydisplay.doModal()

del mydisplay
Reply
#4
You use the mjpeg format which is some kind of video. I don't think that XBMC has any control about the frame-rate, the player just handles the stream like your camera creates it.

What happens when you play this stream "http://user:password@webcam_ip:webcam_port?video_name=stream.mjpg" in a browser? Do you get a higher frame-rate?
My GitHub. My Add-ons:
Image
Reply
#5
It s not an ip cam, the webserver is an Motion feature (all my webcam are usb).

for each cam motion make a listen port : 8081, 8082, ... (by default)

so my first cam is http://MotionIP:8081/ (with no auth), the second http://MotionIP:8082/ ....

i have added "?video_name=stream.mjpg" because i have read to do this is better, but not relevant change.

playing url on chrome on my computer never show image, and never finish to download webpage. But playing url on my chrome on my android work fine.

But for my addon, i have an idea:

i wil fork thread for each cam, and each thread will download image every 2sec and show it under an image control.
Reply
#6
(2013-08-24, 11:39)mmaura Wrote: i wil fork thread for each cam, and each thread will download image every 2sec and show it under an image control.

Yes, this sounds like a good idea. I never tried this but if you walk into XBMC's internal cache problems resulting in the image doesn't get updated because its URLs is always equal, just append some random GET-Parameter value e.g. "&random_value=2234234234".

And btw, I don't think that you have to download the image yourself, just update the ControlImage's filename-property in your update thread.

Good luck!
My GitHub. My Add-ons:
Image
Reply
#7
Thank you for your help

i have found:

multithread image, with url content analyse (found on the web and adapted)
I must make it better but it s good.

Code:
# import the XBMC libraries so we can use the controls and functions of XBMC
import xbmc, xbmcgui, xbmcaddon, xbmcvfs
import urllib2, urllib, re, threading, time, random

debug = 1

__addon__   = xbmcaddon.Addon()
__addonid__ = __addon__.getAddonInfo('id')

Image_path = xbmc.translatePath('special://profile/addon_data/%s' % __addonid__)
if not xbmcvfs.exists(Image_path):
    xbmcvfs.mkdir(Image_path)

Camera = {} # va contenir la liste des url des cameras (sous forme de dictionnaire)
Thread = list() # stock les threads

class ImageThread(threading.Thread):
    def __init__(self ,name, url, img, delay =  2 ):
        threading.Thread.__init__(self)
        self.url = url
        self.name = name
        self.img = img
        self.delay = delay
        self._stopevent = threading.Event( )

    def run(self):
       stream = urllib2.urlopen(self.url)
       while not self._stopevent.isSet():
            rd = random.sample(xrange(10), 10)
            rd = ''.join(str(rd))
            #TODO convert rd to real string value
            tmp_file_name = ('special://temp/' + self.name + rd + '.jpg')
        
            if debug : xbmc.log ('tmp_file = '+ tmp_file_name )

            tmp_file = xbmcvfs.File(tmp_file_name, 'w')

            boundaryStr = stream.readline()
            while boundaryStr != '--BoundaryString\r\n' :
              boundaryStr = stream.readline()
              if debug : xbmc.log ( 'Bad boundary: ' + boundaryStr)

            ContentType = stream.readline()
            if ContentType != ' image/jpeg\r\n':
                if debug : xbmc.log ( 'Bad ContentType: ' + ContentType)
        
            lengthStr = stream.readline()
            if not lengthStr.startswith('Content-Length: '):
                if debug : xbmc.log ( 'Bad length: ' + lengthStr)
        
            length = int(lengthStr.strip().split()[1])
        
            emptyStr = stream.readline()
        
            if debug : xbmc.log ( 'Good frame, length %d' % length)
            rawData = stream.read(length)
            
            if len(rawData) == length:
                try:
                    tmp_file.write(rawData)
                except IOError:
                    if debug : xbmc.log ( 'erreur d ecriture: ' + lengthStr)
            else:
                if debug : xbmc.log ( 'Bad read length: %d' % len(rawData))

            #img.setImage('')
            self.img.setImage(tmp_file_name)
#            time.sleep (refresh)
            xbmcvfs.delete(tmp_file_name)
            self._stopevent.wait(self.delay)

    def stop(self):
        self._stopevent.set( )
    


class MyClass(xbmcgui.Window):
  
    def __init__(self):
        
        self.Addon = xbmcaddon.Addon (__addonid__)
        if debug : xbmc.log("start.")

        # create a password manager
        password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
        
        # Add the username and password.
        # If we knew the realm, we could use it instead of None.
        url_ctl = self.Addon.getSetting('url_ctl')
        url_base = re.search ("(.*):.*", url_ctl)
        url_base = url_base.group(1)
        
        password_mgr.add_password(None, url_ctl, self.Addon.getSetting('username'), self.Addon.getSetting('password'))
        handler = urllib2.HTTPBasicAuthHandler(password_mgr)
        
        #TODO: traiter les codes d'erreur particulierement 404 et 401
        
        # create "opener" (OpenerDirector instance)
        opener = urllib2.build_opener(handler)
        
        # use the opener to fetch a URL
        response = opener.open(url_ctl)
        
        # Install the opener.
        # Now all calls to urllib2.urlopen use our opener.
        urllib2.install_opener(opener)
        the_page = response.read()
        
        cams = re.findall("<a href='/([1-9]+[0-9]*)/'>.*</a><br>", the_page, re.MULTILINE)
        if debug : xbmc.log ('liste des cams :' + str(cams) )
        i = 0
        for cam in cams:

            #port
            if debug : xbmc.log ('pour la cam: '+ cam + ' => ' + url_ctl + cam + '/config/get?query=webcam_port')
            response = opener.open(url_ctl + cam + '/config/get?query=webcam_port' )
            the_page = response.read()
            port = re.search(".*webcam_port\s*=\s*([0-9]*).*", the_page, re.MULTILINE)
            port = port.group(1)
            if debug : xbmc.log ('pour la cam: '+ cam + ' => port:' + port)

            #Nom sur text_left
            if debug : xbmc.log ('pour la cam: '+ cam + ' => ' + url_ctl + cam + '/config/get?query=text_left')
            response = opener.open(url_ctl + cam + '/config/get?query=text_left' )
            the_page = response.read()
            name = re.search(".*text_left\s*=\s*(.*?)\s(&nbsp;)+", the_page, re.MULTILINE)
            name = name.group(1)
            if debug : xbmc.log ('pour la cam: '+ cam + ' => name:' + name)
            
            #refresh
            #TODO: get webcamrefresh time
            #Camera[name] = (url_base + ":" + port + '?video_name=stream.mjpg?no-cache=1?')
            url = (url_base + ":" + port)
            if debug : xbmc.log ('for each '+ name )
          
            img = xbmcgui.ControlImage(1+ int(500 * i), 1, 250, 250, '')
            self.addControl(img)
            
            #Thread.append(threading.Thread(None, self.RefreshCam, None, (name, img, 2)))
            Thread.append(ImageThread(name,url,img,2))
            i = i + 1

        #creation des bouton
        for t in Thread:
            t.start()
            
  
mydisplay = MyClass()

mydisplay.doModal()

if debug : xbmc.log ('Sortie de Modal')
for t in Thread:
    if debug : xbmc.log ('Stop thread')
    t.stop()

time.sleep(15)

del mydisplay
Reply

Logout Mark Read Team Forum Stats Members Help
Playing stream of jpeg at 2 pictures / seconds0