Picamera Livestream und Zeitraffer Bild Aufnahmen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Gerriman
User
Beiträge: 3
Registriert: Freitag 13. November 2020, 09:05

Moin zusammen,
ich Versuche zur Zeit mit meinem Raspberry und einer Picamera einen Livestream in meinem Heimnetz zu starten. Das funktioniert soweit auch ganz gut, aber über die selbe Kamera würde ich gerne auch regelmäßig Bilder speichern lassen um später daraus eine Zeitraffer Aufnahme erstellen zu können.

Mit dem folgenden Code hat es funktioniert, aber jetzt nach einer Testnacht hat das Script einfach aufgehört zu arbeiten, aber auch keinen Fehler ausgegeben.

Vielleicht kann einer von euch mir weiterhelfen oder hat eine bessere Idee.
Hier die beiden Scripts, hab das meiste aus dem Netz, da ich noch ein Neuling bin.

MfG
G

Stream.py

Code: Alles auswählen

# W# Web streaming example
# Source code from the official PiCamera package
# http://picamera.readthedocs.io/en/latest/recipes2.html#web-streaming

import io
import threading, os, signal
import picamera
import logging
import socketserver
import subprocess
import sys
import glob
from threading import Condition
from http import server
from datetime import datetime, timedelta
from subprocess import check_call, call
from select import select

PAGE="""\
<html>
<head>
<title>G-Cam</title>
</head>
<body>
<center><h1>G-Cam</h1></center>
<center><img src="stream.mjpg" width="1280" height="720"></center>
</body>
</html>
"""

ipath = "/home/pi/Capture.py"    #CHANGE PATH TO LOCATION OF mouse.py

def thread_second():
    call(["python3", ipath])

def check_kill_process(pstring):
    for line in os.popen("ps ax | grep " + pstring + " | grep -v grep"):
        fields = line.split()
        pid = fields[0]
        os.kill(int(pid), signal.SIGKILL)

class StreamingOutput(object):
    def __init__(self):
        self.frame = None
        self.buffer = io.BytesIO()
        self.condition = Condition()

    def write(self, buf):
        if buf.startswith(b'\xff\xd8'):
            # New frame, copy the existing buffer's content and notify all
            # clients it's available
            self.buffer.truncate()
            with self.condition:
                self.frame = self.buffer.getvalue()
                self.condition.notify_all()
            self.buffer.seek(0)
        return self.buffer.write(buf)

class StreamingHandler(server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/stream.mjpg':
            self.send_response(200)
            self.send_header('Age', 0)
            self.send_header('Cache-Control', 'no-cache, private')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
            self.end_headers()
            try:
                while True:
                    with output.condition:
                        output.condition.wait()
                        frame = output.frame
                    self.wfile.write(b'--FRAME\r\n')
                    self.send_header('Content-Type', 'image/jpeg')
                    self.send_header('Content-Length', len(frame))
                    self.end_headers()
                    self.wfile.write(frame)
                    self.wfile.write(b'\r\n')
            except Exception as e:
                logging.warning(
                    'Removed streaming client %s: %s',
                    self.client_address, str(e))
        else:
            self.send_error(404)
            self.end_headers()

class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
    allow_reuse_address = True
    daemon_threads = True

with picamera.PiCamera() as camera:
    output = StreamingOutput()
    # Uncomment the next line to change your Pi's Camera rotation (in degrees)
    # camera.rotation = 90
    camera.start_recording(output, format='mjpeg')

    try:
        address = ('', 8000)
        server = StreamingServer(address, StreamingHandler)
        check_kill_process('Capture.py')
        processThread = threading.Thread(target=thread_second)
        processThread.start()
        server.serve_forever()
    finally:
        camera.stop_recording()
Capture.py

Code: Alles auswählen

#!/usr/bin/python3
import io
import threading
import os
import signal
import picamera
import logging
import socketserver
import time
from datetime import datetime, timedelta, date
from select import select
from threading import Condition
from http import server
import subprocess
from subprocess import check_call, call
import sys
import glob

ipath = "/home/pi/Stream.py"

def thread_second():
    call(["python3", ipath])

def check_kill_process(pstring):
    for line in os.popen("ps ax | grep " + pstring + " | grep -v grep"):
        fields = line.split()
        print(fields)
        pid = fields[0]
        print(pid)
        os.kill(int(pid), signal.SIGKILL)
# run script continuosly
while True:
            now = date.today() and datetime.now()

            dt_string = now.strftime("%d_%m_%Y_%H_%M_%S")
            # only activate code when button is pressed (not released)
            print('cap active')
            # time.sleep(21600)  # Alle 6std
            time.sleep(1800)     # Alle halbe Stunde
            print('timer um')
            # wait()

            # end livestream
            check_kill_process('Stream.py')
            print("Stream ended.")

            # take picture with camera
            with picamera.PiCamera() as camera:
                camera.start_preview()
                time.sleep(2)
                camera.capture("/home/pi/Pictures/" + str(dt_string) + '.jpg')
                print('Captured' + str(dt_string))
                # run live stream again
                processThread = threading.Thread(target=thread_second)
                processThread.start()
                print("Stream running. Refresh page.")


# print in the command line instead of file's cons
if __name__ == '__main__':
    main()
    
Sirius3
User
Beiträge: 18274
Registriert: Sonntag 21. Oktober 2012, 17:20

Warum so kompliziert.
Du hast schon einen Stream, der regelmäßig Bilder speichert, die mußt Du doch nur noch auf Platte speichern.

Da wird sehr viel Zeugs importiert, was gar nicht gebraucht wird und auch nicht benutzt werden sollte.
Was soll denn das i an ipath? Konstanten schreibt man komplett GROSS. Der Kommentar ist auch falsch.
os.popen sollte man nicht verwenden, vor allem nicht, wenn man ungeprüft Strings hineinstückelt.
Was Du da mit buffer machst, ist falsch und auch unnötig kompliziert und von der Reihenfolge total verquer. Statt bei einem neuen Bild mit einem neuen Buffer anzufangen, überschreibst Du nur die alten Daten um dann zum Schluß per truncate die Daten vom vorherigen Bild abzuschneiden. Bis ich das kapiert habe, verging ne ganze Weile.

In capture.py: was denkst Du macht `date.today() and datetime.now()`? Der erste Ausdruck ist immer wahr, es wird also immer der zweite als Ergebnis genommen.
Datumsangaben in Dateinamen werden immer im Format Jahr-Monat-Tag gespeichert, damit sie auch einfach sortiert werden können.

Code: Alles auswählen

import io
import picamera
import logging
import socketserver
from threading import Condition
from http import server
from datetime import datetime


SERVER_ADDRESS = ('', 8000)

PAGE="""\
<html>
<head>
<title>G-Cam</title>
</head>
<body>
<center><h1>G-Cam</h1></center>
<center><img src="stream.mjpg" width="1280" height="720"></center>
</body>
</html>
"""

class StreamingOutput(object):
    def __init__(self):
        self.frame = None
        self.buffer = io.BytesIO()
        self.condition = Condition()
        self.last_capture_time = datetime.now()

    def write(self, buf):
        if buf.startswith(b'\xff\xd8'):
            # New frame, copy the existing buffer's content and notify all
            # clients it's available
            with self.condition:
                self.frame = self.buffer.getvalue()
                self.condition.notify_all()
                now = datetime.now()
                if (now - self.last_capture_time).total_seconds() > 60:
                    self.save_picture(now)
                    self.last_capture_time = now
            self.buffer.seek(0)
            self.buffer.truncate()
        return self.buffer.write(buf)

    def save_picture(time):
        with open(f"/home/pi/Pictures/{time:%Y%m%d_%H%M%S}.jpg", "wb") as output:
            output.write(self.frame)

class StreamingHandler(server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/stream.mjpg':
            self.send_response(200)
            self.send_header('Age', 0)
            self.send_header('Cache-Control', 'no-cache, private')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
            self.end_headers()
            try:
                while True:
                    with output.condition:
                        output.condition.wait()
                        frame = output.frame
                    self.wfile.write(b'--FRAME\r\n')
                    self.send_header('Content-Type', 'image/jpeg')
                    self.send_header('Content-Length', len(frame))
                    self.end_headers()
                    self.wfile.write(frame)
                    self.wfile.write(b'\r\n')
            except Exception as e:
                logging.warning(
                    'Removed streaming client %s: %s',
                    self.client_address, str(e))
        else:
            self.send_error(404)
            self.end_headers()

class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
    allow_reuse_address = True
    daemon_threads = True

with picamera.PiCamera() as camera:
    output = StreamingOutput()
    # Uncomment the next line to change your Pi's Camera rotation (in degrees)
    # camera.rotation = 90
    camera.start_recording(output, format='mjpeg')

    try:
        server = StreamingServer(SERVER_ADDRESS, StreamingHandler)
        server.serve_forever()
    finally:
        camera.stop_recording()
Gerriman
User
Beiträge: 3
Registriert: Freitag 13. November 2020, 09:05

Danke für die Antwort. Ich habe den meisten Code nur kopiert wie gesagt weil ich mich damit nicht auskenne.
Ich kann leider nicht mehr den Stream sehen wenn ich jetzt darauf zu greife und es kommt diese Meldung vom Programm.
[13/Nov/2020 13:14:07] "GET /index.html HTTP/1.1" 200 -
[13/Nov/2020 13:14:07] "GET /stream.mjpg HTTP/1.1" 200
Also die Seite öffnet sich aber es ist kein Bild zu sehen.
Leider erstellt es auch keine Bilder. Wenn ich das richtig verstanden habe hast du 60s als intervall eingestellt oder?

Wäre cool wenn du mir nochmal helfen könntest.
Sirius3 hat geschrieben: Freitag 13. November 2020, 10:54 Warum so kompliziert.
Du hast schon einen Stream, der regelmäßig Bilder speichert, die mußt Du doch nur noch auf Platte speichern.

Da wird sehr viel Zeugs importiert, was gar nicht gebraucht wird und auch nicht benutzt werden sollte.
Was soll denn das i an ipath? Konstanten schreibt man komplett GROSS. Der Kommentar ist auch falsch.
os.popen sollte man nicht verwenden, vor allem nicht, wenn man ungeprüft Strings hineinstückelt.
Was Du da mit buffer machst, ist falsch und auch unnötig kompliziert und von der Reihenfolge total verquer. Statt bei einem neuen Bild mit einem neuen Buffer anzufangen, überschreibst Du nur die alten Daten um dann zum Schluß per truncate die Daten vom vorherigen Bild abzuschneiden. Bis ich das kapiert habe, verging ne ganze Weile.

In capture.py: was denkst Du macht `date.today() and datetime.now()`? Der erste Ausdruck ist immer wahr, es wird also immer der zweite als Ergebnis genommen.
Datumsangaben in Dateinamen werden immer im Format Jahr-Monat-Tag gespeichert, damit sie auch einfach sortiert werden können.

Code: Alles auswählen

import io
import picamera
import logging
import socketserver
from threading import Condition
from http import server
from datetime import datetime


SERVER_ADDRESS = ('', 8000)

PAGE="""\
<html>
<head>
<title>G-Cam</title>
</head>
<body>
<center><h1>G-Cam</h1></center>
<center><img src="stream.mjpg" width="1280" height="720"></center>
</body>
</html>
"""

class StreamingOutput(object):
    def __init__(self):
        self.frame = None
        self.buffer = io.BytesIO()
        self.condition = Condition()
        self.last_capture_time = datetime.now()

    def write(self, buf):
        if buf.startswith(b'\xff\xd8'):
            # New frame, copy the existing buffer's content and notify all
            # clients it's available
            with self.condition:
                self.frame = self.buffer.getvalue()
                self.condition.notify_all()
                now = datetime.now()
                if (now - self.last_capture_time).total_seconds() > 60:
                    self.save_picture(now)
                    self.last_capture_time = now
            self.buffer.seek(0)
            self.buffer.truncate()
        return self.buffer.write(buf)

    def save_picture(time):
        with open(f"/home/pi/Pictures/{time:%Y%m%d_%H%M%S}.jpg", "wb") as output:
            output.write(self.frame)

class StreamingHandler(server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/stream.mjpg':
            self.send_response(200)
            self.send_header('Age', 0)
            self.send_header('Cache-Control', 'no-cache, private')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
            self.end_headers()
            try:
                while True:
                    with output.condition:
                        output.condition.wait()
                        frame = output.frame
                    self.wfile.write(b'--FRAME\r\n')
                    self.send_header('Content-Type', 'image/jpeg')
                    self.send_header('Content-Length', len(frame))
                    self.end_headers()
                    self.wfile.write(frame)
                    self.wfile.write(b'\r\n')
            except Exception as e:
                logging.warning(
                    'Removed streaming client %s: %s',
                    self.client_address, str(e))
        else:
            self.send_error(404)
            self.end_headers()

class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
    allow_reuse_address = True
    daemon_threads = True

with picamera.PiCamera() as camera:
    output = StreamingOutput()
    # Uncomment the next line to change your Pi's Camera rotation (in degrees)
    # camera.rotation = 90
    camera.start_recording(output, format='mjpeg')

    try:
        server = StreamingServer(SERVER_ADDRESS, StreamingHandler)
        server.serve_forever()
    finally:
        camera.stop_recording()
Benutzeravatar
__blackjack__
User
Beiträge: 14053
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Thema gibt es auch in diesem Forum: https://forum-raspberrypi.de/forum/thre ... post458186
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Antworten