|
@@ -5,6 +5,7 @@ import os
|
|
|
import stat
|
|
import stat
|
|
|
import sys
|
|
import sys
|
|
|
import gi
|
|
import gi
|
|
|
|
|
+import paho.mqtt.client as mqtt
|
|
|
gi.require_version('Gst', '1.0')
|
|
gi.require_version('Gst', '1.0')
|
|
|
gi.require_version('GstNet', '1.0')
|
|
gi.require_version('GstNet', '1.0')
|
|
|
from gi.repository import Gst, GstNet
|
|
from gi.repository import Gst, GstNet
|
|
@@ -14,21 +15,20 @@ HEIGHT = 720
|
|
|
|
|
|
|
|
SCREEN_WIDTH = 800
|
|
SCREEN_WIDTH = 800
|
|
|
SCREEN_HEIGHT = 600
|
|
SCREEN_HEIGHT = 600
|
|
|
|
|
+zoom = 1
|
|
|
|
|
|
|
|
-def bus_call(bus, msg, *args):
|
|
|
|
|
- if msg.type == Gst.MessageType.EOS:
|
|
|
|
|
- print("End-of-stream")
|
|
|
|
|
- loop.quit()
|
|
|
|
|
- return
|
|
|
|
|
- elif msg.type == Gst.MessageType.ERROR:
|
|
|
|
|
- print("GST ERROR", msg.parse_error())
|
|
|
|
|
- loop.quit()
|
|
|
|
|
- return
|
|
|
|
|
- return True
|
|
|
|
|
|
|
|
|
|
-zoom = 1
|
|
|
|
|
-def quit():
|
|
|
|
|
- pipeline.send_event(Gst.Event.new_eos())
|
|
|
|
|
|
|
+# def bus_call(bus, msg, *args):
|
|
|
|
|
+# if msg.type == Gst.MessageType.EOS:
|
|
|
|
|
+# print("End-of-stream")
|
|
|
|
|
+# loop.quit()
|
|
|
|
|
+# return
|
|
|
|
|
+# elif msg.type == Gst.MessageType.ERROR:
|
|
|
|
|
+# print("GST ERROR", msg.parse_error())
|
|
|
|
|
+# loop.quit()
|
|
|
|
|
+# return
|
|
|
|
|
+# return True
|
|
|
|
|
+
|
|
|
|
|
|
|
|
def set_preview(val):
|
|
def set_preview(val):
|
|
|
if val == 0:
|
|
if val == 0:
|
|
@@ -38,6 +38,7 @@ def set_preview(val):
|
|
|
videosrc.set_property("preview-x", 0)
|
|
videosrc.set_property("preview-x", 0)
|
|
|
videosrc.set_property("preview-y", 0)
|
|
videosrc.set_property("preview-y", 0)
|
|
|
|
|
|
|
|
|
|
+
|
|
|
def set_zoom(target):
|
|
def set_zoom(target):
|
|
|
global zoom
|
|
global zoom
|
|
|
if target < zoom:
|
|
if target < zoom:
|
|
@@ -45,10 +46,10 @@ def set_zoom(target):
|
|
|
else:
|
|
else:
|
|
|
direction = 1
|
|
direction = 1
|
|
|
|
|
|
|
|
- target=min(target, 1)
|
|
|
|
|
- target=max(target, 0.40)
|
|
|
|
|
|
|
+ target = min(target, 1)
|
|
|
|
|
+ target = max(target, 0.40)
|
|
|
|
|
|
|
|
- while abs(target-zoom) > 0.01: #fuck IEEE floats
|
|
|
|
|
|
|
+ while abs(target-zoom) > 0.01: # fuck IEEE floats
|
|
|
zoom = zoom + direction*0.015
|
|
zoom = zoom + direction*0.015
|
|
|
zoom = min(zoom, 1)
|
|
zoom = min(zoom, 1)
|
|
|
zoom = max(zoom, 0.4)
|
|
zoom = max(zoom, 0.4)
|
|
@@ -58,35 +59,32 @@ def set_zoom(target):
|
|
|
videosrc.set_property("roi-h", zoom)
|
|
videosrc.set_property("roi-h", zoom)
|
|
|
time.sleep(0.03)
|
|
time.sleep(0.03)
|
|
|
|
|
|
|
|
|
|
+# The callback for when the client receives a CONNACK response from the server.
|
|
|
|
|
+def on_connect(client, userdata, flags, rc):
|
|
|
|
|
+ print("Connected with result code "+str(rc))
|
|
|
|
|
+
|
|
|
|
|
+ # Subscribing in on_connect() means that if we lose the connection and
|
|
|
|
|
+ # reconnect then subscriptions will be renewed.
|
|
|
|
|
+ client.subscribe("video/cam1/#")
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+# The callback for when a PUBLISH message is received from the server.
|
|
|
|
|
+def on_message(client, userdata, msg):
|
|
|
|
|
+ print(msg.topic+" "+str(msg.payload))
|
|
|
|
|
+
|
|
|
|
|
+ if msg.topic == "video/cam1/preview":
|
|
|
|
|
+ set_preview(int(msg.payload))
|
|
|
|
|
+ elif msg.topic == "video/cam1/zoom":
|
|
|
|
|
+ set_zoom(float(msg.payload))
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+client = mqtt.Client()
|
|
|
|
|
+client.on_connect = on_connect
|
|
|
|
|
+client.on_message = on_message
|
|
|
|
|
+
|
|
|
|
|
+client.connect("192.168.2.123", 1883, 60)
|
|
|
|
|
|
|
|
-def control():
|
|
|
|
|
- FIFO="/tmp/picamfifo"
|
|
|
|
|
- if os.path.exists(FIFO):
|
|
|
|
|
- if stat.S_ISFIFO(os.stat(FIFO).st_mode):
|
|
|
|
|
- pass
|
|
|
|
|
- else:
|
|
|
|
|
- os.remove(FIFO)
|
|
|
|
|
- os.mkfifo(FIFO)
|
|
|
|
|
- else:
|
|
|
|
|
- os.mkfifo(FIFO)
|
|
|
|
|
|
|
|
|
|
- while True:
|
|
|
|
|
- with open(FIFO) as fifo:
|
|
|
|
|
- line=fifo.read().strip()
|
|
|
|
|
- print("Got: ", line)
|
|
|
|
|
- if "=" not in line:
|
|
|
|
|
- print("Invalid line.")
|
|
|
|
|
- continue
|
|
|
|
|
- key = line.split("=")[0]
|
|
|
|
|
- val = line.split("=")[1]
|
|
|
|
|
-
|
|
|
|
|
- if key == "preview":
|
|
|
|
|
- set_preview(int(val))
|
|
|
|
|
-
|
|
|
|
|
- if key == "zoom":
|
|
|
|
|
- set_zoom(float(val))
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
if __name__ == "__main__":
|
|
if __name__ == "__main__":
|
|
|
if 'LD_LIBRARY_PATH' not in os.environ:
|
|
if 'LD_LIBRARY_PATH' not in os.environ:
|
|
|
os.environ['LD_LIBRARY_PATH'] = '/usr/local/lib'
|
|
os.environ['LD_LIBRARY_PATH'] = '/usr/local/lib'
|
|
@@ -97,40 +95,36 @@ if __name__ == "__main__":
|
|
|
videocodec = "video/x-h264, width=%d, height=%d, framerate=25/1, profile=high ! h264parse" % (WIDTH, HEIGHT)
|
|
videocodec = "video/x-h264, width=%d, height=%d, framerate=25/1, profile=high ! h264parse" % (WIDTH, HEIGHT)
|
|
|
p = "rpicamsrc sensor-mode=4 bitrate=0 quantisation-parameter=12 do-timestamp=true keyframe-interval=5 name=src ! "+videocodec+" ! matroskamux streamable=true ! tcpserversink host=0.0.0.0 port=5000 sync-method=next-keyframe blocksize=16384"
|
|
p = "rpicamsrc sensor-mode=4 bitrate=0 quantisation-parameter=12 do-timestamp=true keyframe-interval=5 name=src ! "+videocodec+" ! matroskamux streamable=true ! tcpserversink host=0.0.0.0 port=5000 sync-method=next-keyframe blocksize=16384"
|
|
|
print(p)
|
|
print(p)
|
|
|
- #
|
|
|
|
|
- pipeline = Gst.parse_launch (p)
|
|
|
|
|
- if pipeline == None:
|
|
|
|
|
- print ("Failed to create pipeline")
|
|
|
|
|
|
|
+ pipeline = Gst.parse_launch(p)
|
|
|
|
|
+ if pipeline is None:
|
|
|
|
|
+ print("Failed to create pipeline")
|
|
|
sys.exit(0)
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
clock = GstNet.NetClientClock.new('CamVoctoClock', '192.168.2.123', 9998, 0)
|
|
clock = GstNet.NetClientClock.new('CamVoctoClock', '192.168.2.123', 9998, 0)
|
|
|
- #print("Waiting for clock sync")
|
|
|
|
|
- #clock.wait_for_sync(Gst.CLOCK_TIME_NONE)
|
|
|
|
|
- #clock.do_wait(Gst.CLOCK_TIME_NONE)
|
|
|
|
|
- #print("Clock synced")
|
|
|
|
|
|
|
+ # FIXME: add clock support
|
|
|
|
|
+ # print("Waiting for clock sync")
|
|
|
|
|
+ # clock.wait_for_sync(Gst.CLOCK_TIME_NONE)
|
|
|
|
|
+ # clock.do_wait(Gst.CLOCK_TIME_NONE)
|
|
|
|
|
+ # print("Clock synced")
|
|
|
pipeline.set_start_time(Gst.CLOCK_TIME_NONE)
|
|
pipeline.set_start_time(Gst.CLOCK_TIME_NONE)
|
|
|
if clock is not None:
|
|
if clock is not None:
|
|
|
pass
|
|
pass
|
|
|
- #pipeline.use_clock(clock)
|
|
|
|
|
|
|
+ # pipeline.use_clock(clock)
|
|
|
|
|
|
|
|
- videosrc = pipeline.get_by_name ("src")
|
|
|
|
|
|
|
+ videosrc = pipeline.get_by_name("src")
|
|
|
videosrc.set_property("preview", 1)
|
|
videosrc.set_property("preview", 1)
|
|
|
videosrc.set_property("preview-w", SCREEN_WIDTH)
|
|
videosrc.set_property("preview-w", SCREEN_WIDTH)
|
|
|
videosrc.set_property("preview-h", SCREEN_HEIGHT)
|
|
videosrc.set_property("preview-h", SCREEN_HEIGHT)
|
|
|
videosrc.set_property("fullscreen", False)
|
|
videosrc.set_property("fullscreen", False)
|
|
|
- #videosrc.set_property("bitrate", 14000000)
|
|
|
|
|
# videosrc.set_property("bitrate", 25000000)
|
|
# videosrc.set_property("bitrate", 25000000)
|
|
|
videosrc.set_property("rotation", 180)
|
|
videosrc.set_property("rotation", 180)
|
|
|
set_preview(0)
|
|
set_preview(0)
|
|
|
|
|
|
|
|
-
|
|
|
|
|
- # run
|
|
|
|
|
pipeline.set_state(Gst.State.PLAYING)
|
|
pipeline.set_state(Gst.State.PLAYING)
|
|
|
- t = threading.Thread(target=control, daemon=True)
|
|
|
|
|
|
|
+ t = threading.Thread(target=client.loop_forever, daemon=True)
|
|
|
t.start()
|
|
t.start()
|
|
|
while True:
|
|
while True:
|
|
|
- time.sleep(10000)
|
|
|
|
|
|
|
+ client.publish("video/heartbeat", "cam1")
|
|
|
|
|
+ time.sleep(10)
|
|
|
|
|
|
|
|
- # cleanup
|
|
|
|
|
pipeline.set_state(Gst.State.NULL)
|
|
pipeline.set_state(Gst.State.NULL)
|
|
|
-
|
|
|