bottle - streamen von .jpg
@Sirius3
An der Kamera LED bzw die Kamera läuft weiter und bei einem wiederholten Aufruf der /stream url bzw test.mjpg kommt folgende Fehlermeldung:
Eigentlich schliesst ja das ``with`` Statement automatisch. Nun weiss ich nicht, liegt es am Browser, am gevent-Server oder an der Bottle Funktion...
An der Kamera LED bzw die Kamera läuft weiter und bei einem wiederholten Aufruf der /stream url bzw test.mjpg kommt folgende Fehlermeldung:
Code: Alles auswählen
mmal: mmal_vc_component_enable: failed to enable component: ENOSPC
Error: 500 Internal Server Error
Sorry, the requested URL 'http://10.0.2.114:8080/test.mjpg' caused an error:
Unhandled exception
Exception:
PiCameraMMALError(u"Camera component couldn't be enabled: Out of resources (other than memory)",)
Traceback:
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/bottle.py", line 923, in _cast
first = next(iout)
File "app.py", line 108, in mjpeg
camera = picamera.PiCamera()
File "/usr/lib/python2.7/dist-packages/picamera/camera.py", line 419, in __init__
self.STEREO_MODES[stereo_mode], stereo_decimate)
File "/usr/lib/python2.7/dist-packages/picamera/camera.py", line 551, in _init_camera
prefix="Camera component couldn't be enabled")
File "/usr/lib/python2.7/dist-packages/picamera/exc.py", line 133, in mmal_check
raise PiCameraMMALError(status, prefix)
PiCameraMMALError: Camera component couldn't be enabled: Out of resources (other than memory)
@lackschuh: Der Traceback passt nicht zum Code. Im Code benutzt Du ``with``, im Traceback ganz offensichtlich nicht.
@BlackJack
Ups, da hast du recht. Das war aus der falschen Datei kopier... das Problem ist jedoch das selbe
Ups, da hast du recht. Das war aus der falschen Datei kopier... das Problem ist jedoch das selbe
Code: Alles auswählen
@app.route('/test.mjpg')
def mjpeg():
response.content_type = 'multipart/x-mixed-replace;boundary=%s' % BOUNDARY
stream = io.BytesIO()
yield BOUNDARY+'\r\n'
with picamera.PiCamera() as camera:
#camera.led = False
camera.exposure_mode = 'night'
#camera.exposure_mode ='auto'
camera.rotation = 180
camera.resolution = (640, 480)
camera.start_preview()
camera.annotate_background = True
time.sleep(2)
while True:
camera.capture(stream,'jpeg')
camera.annotate_text = dt.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
yield BOUNDARY+'\r\n'
yield 'Content-Type: image/jpeg\r\nContent-Length: %s\r\n\r\n' % len(stream.getvalue())
yield stream.getvalue()
stream.seek(0)
stream.truncate()
time.sleep(.1)
Code: Alles auswählen
mmal: mmal_vc_component_enable: failed to enable component: ENOSPC
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/gevent/pywsgi.py", line 508, in handle_one_response
self.run_application()
File "/usr/local/lib/python2.7/dist-packages/gevent/pywsgi.py", line 495, in run_application
self.process_result()
File "/usr/local/lib/python2.7/dist-packages/gevent/pywsgi.py", line 484, in process_result
for data in self.result:
File "app.py", line 111, in mjpeg
with picamera.PiCamera() as camera:
File "/usr/lib/python2.7/dist-packages/picamera/camera.py", line 419, in __init__
self.STEREO_MODES[stereo_mode], stereo_decimate)
File "/usr/lib/python2.7/dist-packages/picamera/camera.py", line 551, in _init_camera
prefix="Camera component couldn't be enabled")
File "/usr/lib/python2.7/dist-packages/picamera/exc.py", line 133, in mmal_check
raise PiCameraMMALError(status, prefix)
PiCameraMMALError: Camera component couldn't be enabled: Out of resources (other than memory)
{'GATEWAY_INTERFACE': 'CGI/1.1',
'HTTP_ACCEPT': 'image/webp,*/*;q=0.8',
'HTTP_ACCEPT_ENCODING': 'gzip, deflate',
'HTTP_ACCEPT_LANGUAGE': 'de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4',
'HTTP_CACHE_CONTROL': 'max-age=0',
'HTTP_CONNECTION': 'keep-alive',
'HTTP_COOKIE': 'session_id=1424874671-gryved',
'HTTP_HOST': '10.0.2.114:8080',
'HTTP_REFERER': 'http://10.0.2.114:8080/stream',
'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.4 Safari/537.36',
'PATH_INFO': '/test.mjpg',
'QUERY_STRING': '',
'REMOTE_ADDR': '10.0.2.112',
'REMOTE_PORT': '56329',
'REQUEST_METHOD': 'GET',
'SCRIPT_NAME': '',
'SERVER_NAME': '10.0.2.114',
'SERVER_PORT': '8080',
'SERVER_PROTOCOL': 'HTTP/1.1',
'SERVER_SOFTWARE': 'gevent/1.0 Python/2.7',
'bottle.app': <bottle.Bottle object at 0xb654cc10>,
'bottle.raw_path': '/test.mjpg',
'bottle.request': <LocalRequest: GET http://10.0.2.114:8080/test.mjpg>,
'bottle.request.urlparts': SplitResult(scheme='http', netloc='10.0.2.114:8080', path='/test.mjpg', query='', fragment=''),
'bottle.route': <GET '/test.mjpg' <function mjpeg at 0xb645ec70>>,
'route.handle': <GET '/test.mjpg' <function mjpeg at 0xb645ec70>>,
'route.url_args': {},
'wsgi.errors': <open file '<stderr>', mode 'w' at 0xb6d090d0>,
'wsgi.input': <gevent.pywsgi.Input object at 0xb22a0050>,
'wsgi.multiprocess': False,
'wsgi.multithread': False,
'wsgi.run_once': False,
'wsgi.url_scheme': 'http',
'wsgi.version': (1, 0)} failed with PiCameraMMALError
10.0.2.112 - - [2015-02-25 15:52:29] "GET /test.mjpg HTTP/1.1" 200 168 0.097336
10.0.2.112 - - [2015-02-25 15:52:29] "GET /static/fonts/glyphicons-halflings-regular.woff HTTP/1.1" 304 66 0.007707
Das with schließt die Kamera aber auch nur dann, wenn das with jemals verlassen wird. Du hast da allerdings ein schönes while-True, in welchem keine Abbruchbedingung definiert ist.
Das Leben ist wie ein Tennisball.
@EyDu: Die Frage ist also wie man in dem Generator mitbekommt das niemals mehr etwas davon abgefragt werden wird.
Ich kenne mich mit den Interna von Bottle nicht besonders aus und weiß nicht, ob für so etwas ein Mechanismus vorgesehen ist, aber im Prinzip sollte doch ein Thread für die Kamera genügen, welcher immer das letzte (oder die letzten k) zeitgestempelten Bilder vorhält. Daraus könnte sich dann die mjpeg-Methode bedienen. Klar es gibt ein paar Randfälle zu beachten, aber zumindest stört es dann nicht weiter, wenn ein Client mal nicht mehr antwortet.
Das Leben ist wie ein Tennisball.
Nach ca. 15min bricht die Verbindung ab - sofern kein Client mehr da ist. Geht das von Bottle oder von gevent aus (laut Traceback eher vom gevent Server):
Kann man dieses ``error: [Errno 110] Connection timed out``auch manuell auf zB ca. 1min runtersetzen oder was wäre der einfachste Weg?
Code: Alles auswählen
10.0.2.112 - - [2015-02-25 16:33:58] "GET /home HTTP/1.1" 200 6392 0.055557
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/gevent/pywsgi.py", line 508, in handle_one_response
self.run_application()
File "/usr/local/lib/python2.7/dist-packages/gevent/pywsgi.py", line 495, in run_application
self.process_result()
File "/usr/local/lib/python2.7/dist-packages/gevent/pywsgi.py", line 486, in process_result
self.write(data)
File "/usr/local/lib/python2.7/dist-packages/gevent/pywsgi.py", line 376, in write
self._write(data)
File "/usr/local/lib/python2.7/dist-packages/gevent/pywsgi.py", line 369, in _write
self._sendall(data)
File "/usr/local/lib/python2.7/dist-packages/gevent/pywsgi.py", line 355, in _sendall
self.socket.sendall(data)
File "/usr/local/lib/python2.7/dist-packages/gevent/socket.py", line 458, in sendall
data_sent += self.send(_get_memory(data, data_sent), flags)
File "/usr/local/lib/python2.7/dist-packages/gevent/socket.py", line 443, in send
return sock.send(data, flags)
error: [Errno 110] Connection timed out
{'GATEWAY_INTERFACE': 'CGI/1.1',
'HTTP_ACCEPT': 'image/webp,*/*;q=0.8',
'HTTP_ACCEPT_ENCODING': 'gzip, deflate',
'HTTP_ACCEPT_LANGUAGE': 'de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4',
'HTTP_CONNECTION': 'keep-alive',
'HTTP_COOKIE': 'session_id=1424874671-gryved',
'HTTP_HOST': '10.0.2.114:8080',
'HTTP_REFERER': 'http://10.0.2.114:8080/stream',
'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.4 Safari/537.36',
'PATH_INFO': '/test.mjpg',
'QUERY_STRING': '',
'REMOTE_ADDR': '10.0.2.112',
'REMOTE_PORT': '56821',
'REQUEST_METHOD': 'GET',
'SCRIPT_NAME': '',
'SERVER_NAME': '10.0.2.114',
'SERVER_PORT': '8080',
'SERVER_PROTOCOL': 'HTTP/1.1',
'SERVER_SOFTWARE': 'gevent/1.0 Python/2.7',
'bottle.app': <bottle.Bottle object at 0xb654cc10>,
'bottle.raw_path': '/test.mjpg',
'bottle.request': <LocalRequest: GET http://10.0.2.114:8080/test.mjpg>,
'bottle.request.urlparts': SplitResult(scheme='http', netloc='10.0.2.114:8080', path='/test.mjpg', query='', fragment=''),
'bottle.route': <GET '/test.mjpg' <function mjpeg at 0xb645ec70>>,
'route.handle': <GET '/test.mjpg' <function mjpeg at 0xb645ec70>>,
'route.url_args': {},
'wsgi.errors': <open file '<stderr>', mode 'w' at 0xb6d090d0>,
'wsgi.input': <gevent.pywsgi.Input object at 0xb63576b0>,
'wsgi.multiprocess': False,
'wsgi.multithread': False,
'wsgi.run_once': False,
'wsgi.url_scheme': 'http',
'wsgi.version': (1, 0)} failed with error
10.0.2.112 - - [2015-02-25 16:46:09] "GET /test.mjpg HTTP/1.1" socket 74372860 1249.888520
Apache hat einen Timeout von 5 Sekunden(!) an dieser Stelle. 
Vielleicht hilft es ja wenn Du den Header ``Connection: close`` mitsendest. Wenn der Browser daraufhin die Verbindung abbrechen sollte, dann merkt der Server das schneller.

Vielleicht hilft es ja wenn Du den Header ``Connection: close`` mitsendest. Wenn der Browser daraufhin die Verbindung abbrechen sollte, dann merkt der Server das schneller.
@lackschuh: Bei meinen Tests mit gunicorn bricht die Methode in weniger als 1 Sekunde ab, wenn das Browserfenster geschlossen wird.
Der Traceback ist fast identisch, der Fehler aber "[Errno 32] Broken pipe" statt "[Errno 110] Connection timed out":
Der Traceback ist fast identisch, der Fehler aber "[Errno 32] Broken pipe" statt "[Errno 110] Connection timed out":
Code: Alles auswählen
Traceback (most recent call last):
File "/../gevent-1.0.1-py2.7-macosx-10.8-intel.egg/gevent/pywsgi.py", line 508, in handle_one_response
self.run_application()
File "/../geventwebsocket/handler.py", line 84, in run_application
return super(WebSocketHandler, self).run_application()
File "/../gevent-1.0.1-py2.7-macosx-10.8-intel.egg/gevent/pywsgi.py", line 495, in run_application
self.process_result()
File "/../gevent-1.0.1-py2.7-macosx-10.8-intel.egg/gevent/pywsgi.py", line 486, in process_result
self.write(data)
File "/../gevent-1.0.1-py2.7-macosx-10.8-intel.egg/gevent/pywsgi.py", line 376, in write
self._write(data)
File "/../gevent-1.0.1-py2.7-macosx-10.8-intel.egg/gevent/pywsgi.py", line 369, in _write
self._sendall(data)
File "/../gevent-1.0.1-py2.7-macosx-10.8-intel.egg/gevent/pywsgi.py", line 355, in _sendall
self.socket.sendall(data)
File "/../gevent-1.0.1-py2.7-macosx-10.8-intel.egg/gevent/socket.py", line 458, in sendall
data_sent += self.send(_get_memory(data, data_sent), flags)
File "/../gevent-1.0.1-py2.7-macosx-10.8-intel.egg/gevent/socket.py", line 435, in send
return sock.send(data, flags)
error: [Errno 32] Broken pipe
{'GATEWAY_INTERFACE': 'CGI/1.1',
'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'HTTP_ACCEPT_ENCODING': 'gzip, deflate, sdch',
'HTTP_ACCEPT_LANGUAGE': 'de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4',
'HTTP_CONNECTION': 'keep-alive',
'HTTP_HOST': 'localhost:8081',
'HTTP_USER_AGENT': 'Mozilla/5.0',
'PATH_INFO': '/xy',
'QUERY_STRING': '',
'REMOTE_ADDR': '127.0.0.1',
'REMOTE_PORT': '60606',
'REQUEST_METHOD': 'GET',
'SCRIPT_NAME': '',
'SERVER_NAME': '1.0.0.127.in-addr.arpa',
'SERVER_PORT': '8081',
'SERVER_PROTOCOL': 'HTTP/1.1',
'SERVER_SOFTWARE': 'gevent/1.0.1 gunicorn/18.0',
'bottle.app': <bottle.Bottle object at 0x10177ff50>,
'bottle.raw_path': '/xy',
'bottle.request': <LocalRequest: GET http://localhost:8081/xy>,
'bottle.request.urlparts': SplitResult(scheme='http', netloc='localhost:8080', path='/xy', query='', fragment=''),
'bottle.route': <GET '/xy' <function xy at 0x101935230>>,
'route.handle': <GET '/xy' <function xy at 0x101935230>>,
'route.url_args': {},
'wsgi.errors': <open file '<stderr>', mode 'w' at 0x1010f91e0>,
'wsgi.input': <gevent.pywsgi.Input object at 0x101948a50>,
'wsgi.multiprocess': False,
'wsgi.multithread': False,
'wsgi.run_once': False,
'wsgi.url_scheme': 'http',
'wsgi.version': (1, 0)} failed with error
Hallo Sirius3
Ich hab mir gunicorn mal installiert aber der Server hat eine Reaktion wie eine Schlaftablette. Für das Login brauch der schon mindestens 2 min.
Könntest du mir ggf. sagen, wie ich da vorzugehen habe?
mfg
PS:
- Die Methode bricht wirklich sehr schnell ab. Jedoch dauert ein Aufruf viel zu lange....
- Mit CherryPyServer dauert der Abbruch 7 Sekunden. Dies wäre noch zu verkraften.
Ich hab mir gunicorn mal installiert aber der Server hat eine Reaktion wie eine Schlaftablette. Für das Login brauch der schon mindestens 2 min.
Code: Alles auswählen
run(app, debug=True, reloader=True, host='10.0.2.114', server='gunicorn', port=8080)
mfg
PS:
- Die Methode bricht wirklich sehr schnell ab. Jedoch dauert ein Aufruf viel zu lange....
- Mit CherryPyServer dauert der Abbruch 7 Sekunden. Dies wäre noch zu verkraften.
Hallo
@snafu (eigentlich an alle
)
@snafu (eigentlich an alle

Könnte mir jemand diesbezüglich einen Denkanstoß geben? Wie könnte im Groben so eine "Wrapper-Klasse" aussehen?snafu hat geschrieben: Ich würde da eigentlich nur das aktuelle Bild puffern, sofern ein Live-Zugriff auf die Kamera angedacht ist. In einer Schleife wird dann halt alle 100 Millisekunden ein neues Bild abgelegt und die verschiedenen Clients fragen deinen Kamera-Wrapper nach dem aktuellen Bild. Dann muss sich die Kamera an sich nicht weiter damit beschäftigen, sondern sie liefert stumpf in gleichbleibenden Abständen das Bildmaterial, welches von der Wrapper-Klasse erfragt wird. Wenn gerade kein Client ein Bild sehen will, dann wird das ungenutzte Bild halt wieder verworfen.