Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/libraries/AP_Camera/examples/gst_udp_to_wx.py
Views: 1799
""""1Capture a UDP video stream and display in wxpython23Usage4-----561. udpsink78gst-launch-1.0 -v videotestsrc ! 'video/x-raw,format=I420,width=640,height=480,framerate=50/1' ! queue ! videoconvert ! x264enc bitrate=800 speed-preset=6 tune=4 key-int-max=10 ! rtph264pay ! udpsink host=127.0.0.1 port=56009102. display in wxpython1112python ./gst_udp_to_wx.py1314Acknowledgments15---------------1617Video class to capture GStreamer frames18https://www.ardusub.com/developers/opencv.html1920ImagePanel class to display openCV images in wxWidgets21https://stackoverflow.com/questions/14804741/opencv-integration-with-wxpython22"""2324import copy25import cv226import gi27import numpy as np28import threading29import wx303132gi.require_version("Gst", "1.0")33from gi.repository import Gst343536class VideoStream:37"""BlueRov video capture class constructor3839Attributes:40port (int): Video UDP port41video_codec (string): Source h264 parser42video_decode (string): Transform YUV (12bits) to BGR (24bits)43video_pipe (object): GStreamer top-level pipeline44video_sink (object): Gstreamer sink element45video_sink_conf (string): Sink configuration46video_source (string): Udp source ip and port47latest_frame (np.ndarray): Latest retrieved video frame48"""4950def __init__(self, port=5600):51"""Summary5253Args:54port (int, optional): UDP port55"""5657Gst.init(None)5859self.port = port60self.latest_frame = self._new_frame = None6162# [Software component diagram](https://www.ardusub.com/software/components.html)63# UDP video stream (:5600)64self.video_source = "udpsrc port={}".format(self.port)65# [Rasp raw image](http://picamera.readthedocs.io/en/release-0.7/recipes2.html#raw-image-capture-yuv-format)66# Cam -> CSI-2 -> H264 Raw (YUV 4-4-4 (12bits) I420)67self.video_codec = (68"! application/x-rtp, payload=96 ! rtph264depay ! h264parse ! avdec_h264"69)70# Python don't have nibble, convert YUV nibbles (4-4-4) to OpenCV standard BGR bytes (8-8-8)71self.video_decode = (72"! decodebin ! videoconvert ! video/x-raw,format=(string)BGR ! videoconvert"73)74# Create a sink to get data75self.video_sink_conf = (76"! appsink emit-signals=true sync=false max-buffers=2 drop=true"77)7879self.video_pipe = None80self.video_sink = None8182self.run()8384def start_gst(self, config=None):85""" Start gstreamer pipeline and sink86Pipeline description list e.g:87[88'videotestsrc ! decodebin', \89'! videoconvert ! video/x-raw,format=(string)BGR ! videoconvert',90'! appsink'91]9293Args:94config (list, optional): Gstreamer pileline description list95"""9697if not config:98config = [99"videotestsrc ! decodebin",100"! videoconvert ! video/x-raw,format=(string)BGR ! videoconvert",101"! appsink",102]103104command = " ".join(config)105self.video_pipe = Gst.parse_launch(command)106self.video_pipe.set_state(Gst.State.PLAYING)107self.video_sink = self.video_pipe.get_by_name("appsink0")108109@staticmethod110def gst_to_opencv(sample):111"""Transform byte array into np array112113Args:114sample (TYPE): Description115116Returns:117TYPE: Description118"""119buf = sample.get_buffer()120caps_structure = sample.get_caps().get_structure(0)121array = np.ndarray(122(caps_structure.get_value("height"), caps_structure.get_value("width"), 3),123buffer=buf.extract_dup(0, buf.get_size()),124dtype=np.uint8,125)126return array127128def frame(self):129"""Get Frame130131Returns:132np.ndarray: latest retrieved image frame133"""134if self.frame_available:135self.latest_frame = self._new_frame136# reset to indicate latest frame has been 'consumed'137self._new_frame = None138return self.latest_frame139140def frame_available(self):141"""Check if a new frame is available142143Returns:144bool: true if a new frame is available145"""146return self._new_frame is not None147148def run(self):149"""Get frame to update _new_frame"""150151self.start_gst(152[153self.video_source,154self.video_codec,155self.video_decode,156self.video_sink_conf,157]158)159160self.video_sink.connect("new-sample", self.callback)161162def callback(self, sink):163sample = sink.emit("pull-sample")164self._new_frame = self.gst_to_opencv(sample)165166return Gst.FlowReturn.OK167168169class ImagePanel(wx.Panel):170def __init__(self, parent, video_stream, fps=30):171wx.Panel.__init__(self, parent)172173self._video_stream = video_stream174175# Shared between threads176self._frame_lock = threading.Lock()177self._latest_frame = None178179print("Waiting for video stream...")180waited = 0181while not self._video_stream.frame_available():182waited += 1183print("\r Frame not available (x{})".format(waited), end="")184cv2.waitKey(30)185print("\nSuccess! Video stream available")186187if self._video_stream.frame_available():188# Only retrieve and display a frame if it's new189frame = copy.deepcopy(self._video_stream.frame())190191# Frame size192height, width, _ = frame.shape193194parent.SetSize((width, height))195frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)196197self.bmp = wx.Bitmap.FromBuffer(width, height, frame)198199self.timer = wx.Timer(self)200self.timer.Start(int(1000 / fps))201202self.Bind(wx.EVT_PAINT, self.OnPaint)203self.Bind(wx.EVT_TIMER, self.NextFrame)204205def OnPaint(self, evt):206dc = wx.BufferedPaintDC(self)207dc.DrawBitmap(self.bmp, 0, 0)208209def NextFrame(self, event):210if self._video_stream.frame_available():211frame = copy.deepcopy(self._video_stream.frame())212213# Convert frame to bitmap for wxFrame214frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)215self.bmp.CopyFromBuffer(frame)216self.Refresh()217218219def main():220221# create the video stream222video_stream = VideoStream(port=5600)223224# app must run on the main thread225app = wx.App()226wx_frame = wx.Frame(None)227228# create the image panel229image_panel = ImagePanel(wx_frame, video_stream, fps=30)230231wx_frame.Show()232app.MainLoop()233234235if __name__ == "__main__":236main()237238239