cam.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. #!/usr/bin/python3
  2. import time
  3. import threading
  4. import os
  5. import stat
  6. import sys
  7. import gi
  8. import paho.mqtt.client as mqtt
  9. gi.require_version('Gst', '1.0')
  10. gi.require_version('GstNet', '1.0')
  11. from gi.repository import Gst, GstNet
  12. WIDTH = 1280
  13. HEIGHT = 720
  14. SCREEN_WIDTH = 800
  15. SCREEN_HEIGHT = 600
  16. zoom = 1
  17. not_exited = True
  18. # def bus_call(bus, msg, *args):
  19. # if msg.type == Gst.MessageType.EOS:
  20. # print("End-of-stream")
  21. # loop.quit()
  22. # return
  23. # elif msg.type == Gst.MessageType.ERROR:
  24. # print("GST ERROR", msg.parse_error())
  25. # loop.quit()
  26. # return
  27. # return True
  28. def set_preview(val):
  29. if val == 0:
  30. videosrc.set_property("preview-x", SCREEN_WIDTH)
  31. videosrc.set_property("preview-y", SCREEN_HEIGHT)
  32. else:
  33. videosrc.set_property("preview-x", 0)
  34. videosrc.set_property("preview-y", 0)
  35. def set_zoom(target):
  36. global zoom
  37. if target < zoom:
  38. direction = -1
  39. else:
  40. direction = 1
  41. target = min(target, 1)
  42. target = max(target, 0.40)
  43. while abs(target-zoom) > 0.01: # fuck IEEE floats
  44. zoom = zoom + direction*0.015
  45. zoom = min(zoom, 1)
  46. zoom = max(zoom, 0.4)
  47. videosrc.set_property("roi-x", (1-zoom)/2)
  48. videosrc.set_property("roi-y", (1-zoom)/2)
  49. videosrc.set_property("roi-w", zoom)
  50. videosrc.set_property("roi-h", zoom)
  51. time.sleep(0.03)
  52. # The callback for when the client receives a CONNACK response from the server.
  53. def on_connect(client, userdata, flags, rc):
  54. print("Connected with result code "+str(rc))
  55. # Subscribing in on_connect() means that if we lose the connection and
  56. # reconnect then subscriptions will be renewed.
  57. client.subscribe("video/cam1/#")
  58. # The callback for when a PUBLISH message is received from the server.
  59. def on_message(client, userdata, msg):
  60. global not_exited
  61. print(msg.topic+" "+str(msg.payload))
  62. if msg.topic == "video/cam1/preview":
  63. set_preview(int(msg.payload))
  64. elif msg.topic == "video/cam1/zoom":
  65. set_zoom(float(msg.payload))
  66. elif msg.topic == "video/cam1/restart":
  67. print("Restarting!")
  68. not_exited = False
  69. client = mqtt.Client()
  70. client.on_connect = on_connect
  71. client.on_message = on_message
  72. client.connect("192.168.2.123", 1883, 60)
  73. if __name__ == "__main__":
  74. if 'LD_LIBRARY_PATH' not in os.environ:
  75. os.environ['LD_LIBRARY_PATH'] = '/usr/local/lib'
  76. os.execv(sys.argv[0], sys.argv)
  77. # initialization
  78. Gst.init(None)
  79. videocodec = "video/x-h264, width=%d, height=%d, framerate=25/1, profile=high ! h264parse" % (WIDTH, HEIGHT)
  80. 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"
  81. print(p)
  82. pipeline = Gst.parse_launch(p)
  83. if pipeline is None:
  84. print("Failed to create pipeline")
  85. sys.exit(0)
  86. clock = GstNet.NetClientClock.new('CamVoctoClock', '192.168.2.123', 9998, 0)
  87. # FIXME: add clock support
  88. # print("Waiting for clock sync")
  89. # clock.wait_for_sync(Gst.CLOCK_TIME_NONE)
  90. # clock.do_wait(Gst.CLOCK_TIME_NONE)
  91. # print("Clock synced")
  92. pipeline.set_start_time(Gst.CLOCK_TIME_NONE)
  93. if clock is not None:
  94. pass
  95. # pipeline.use_clock(clock)
  96. videosrc = pipeline.get_by_name("src")
  97. videosrc.set_property("preview", 1)
  98. videosrc.set_property("preview-w", SCREEN_WIDTH)
  99. videosrc.set_property("preview-h", SCREEN_HEIGHT)
  100. videosrc.set_property("fullscreen", False)
  101. # videosrc.set_property("bitrate", 25000000)
  102. videosrc.set_property("rotation", 180)
  103. set_preview(0)
  104. pipeline.set_state(Gst.State.PLAYING)
  105. t = threading.Thread(target=client.loop_forever, daemon=True)
  106. t.start()
  107. counter = 0
  108. while not_exited:
  109. time.sleep(1)
  110. counter += 1
  111. if counter >= 10:
  112. client.publish("video/heartbeat", "cam1")
  113. pipeline.set_state(Gst.State.NULL)
  114. print("Pipeline dead. Bye")