Use GStreamer to pack existing h264 stream and send it over network to VLC - raspberry-pi

I'm trying to stream from Raspberry PI camera over network using raspivid and gstreamer cli. I want to be able to view the stream using VLC "open network stream" on the client.
This is related to question GStreamer rtp stream to vlc however mine it is not quite the same. Instead of encoding the raw output from my PI camera, my idea is to leverage the existing the h264 output of raspivid, mux it into an appropriate container and send it over TCP or UDP.
I was able to successfully capture the h264 output from raspivid into an mp4 file (with correct fps and length information) using this pipeline:
raspivid -n -w 1280 -h 720 -fps 24 -b 4500000 -a 12 -t 30000 -o - | \
gst-launch-1.0 -v fdsrc ! video/x-h264, width=1280, height=720, framerate=24/1 ! \
h264parse ! mp4mux ! filesink location="videofile.mp4"
However, when I try to stream this over a network:
raspivid -n -w 1280 -h 720 -fps 24 -b 4500000 -a 12 -t 0 -o - | \
gst-launch-1.0 -v fdsrc ! video/x-h264, width=1280, height=720, framerate=24/1 ! \
h264parse ! mpegtsmux ! rtpmp2tpay ! udpsink host=192.168.1.20 port=5000
...and try to open the stream using rtp://192.168.1.20:5000 on VLC, it reports an error.
Edit: Ok, I was mistaken to assume that the udpsink listens for incoming connections. However, after changing the last part of the pipeline to use my client's IP address ! udpsink host=192.168.1.77 port=5000 and tried opening that with udp://#:5000 on the VLC, the player does not display anything (both the PI and the receiving computer are on the same LAN and I can see the incoming network traffic on the client).
Does anyone know how to properly construct a gstreamer pipeline to transmit existing h264 stream over a network which can be played by vanilla VLC on the client?

Assuming this is due to missing SPS/PPS data. E.g. probably it works if you start VLC first and then the video pipeline on the Raspberry PI. By default the SPS/PPS headers are most likely send only once at the beginning of the stream.
If the receiver misses SPS/PPS headers it will not be able to decode the H.264 stream. I guess this can be fixed by using the config-interval=-1 property of h264parse.
With that option SPS/PPS data should be send before each IDR-frame which should occur every couple of seconds - depending on the encoder.
Another thing is that you don't need to use rtpmp2tpay block. Just sending MPEG TS over UDP directly should be enough.
Having said that, the pipeline should look like this:
raspivid -n -w 1280 -h 720 -fps 24 -b 4500000 -a 12 -t 0 -o - | \
gst-launch-1.0 -v fdsrc ! \
video/x-h264, width=1280, height=720, framerate=24/1 ! \
h264parse config-interval=-1 ! mpegtsmux ! udpsink host=192.168.1.77 port=5000
The 192.168.1.77 is the IP address of the client running VLC at udp://#5000. Also, make sure no firewalls are blocking the incoming UDP trafict towards the client (Windows firewall, in particular).

Related

How does OpenCV handle TCP Connections?

I setup a NetCat Video Stream from my RPi and I am accessing it with OpenCV in the following way:
videoStream = cv2.VideoCapture("tcp://#<my_ip>:<my_port>/")
...
videoStream.release()
Unfortunately I cannot connect to the Stream multiple times without reinitializing it. How does OpenCV tread my tcp connection? Does .release() properly close the socket or what is the right way to close it?
I would comment but I do not have enough points. I had a similar issue. Ultimately, what worked for me is the run netcat with the -k option, which does allow reconnecting:
on RPI:
/opt/vc/bin/raspivid -n -t 0 -w 640 -h 360 -fps 30 -ih -fl -l -o - | /bin/nc -klvp 5000
for nc, the -k option keeps the port listening after the first client disconnects, thereby allowing you to reconnect. You won't need the -v option, it just adds some verbosity.
Another alternative is to
on receiver (Ubuntu, Win10):
nc x.x.x.x 5000 | mplayer -fps 200 -demuxer h264es -
or
gst-launch-1.0 -v tcpclientsrc host=10.60.66.237 port=5000 ! decodebin ! autovideosink
Python code with opencv:
import cv2
cap = cv2.VideoCapture("tcp://10.60.66.237:5000")
while(True):
ret, frame = cap.read()
cv2.imshow('frame', frame)
# the 'q' button is set as the
# quitting button you may use any
# desired button of your choice
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
Disconnect and reconnect all you want :)

Rotating per packets receiving by TCPDUMP

How can I use 'tcpdump' command to capture and save each received packets to separate files (having rotatation per packet without losing any packets).
How about saving dump to a file and then splitting that to separate files?
$ sudo tcpdump -c 10 -w mycap.pcap
tcpdump: data link type PKTAP
tcpdump: listening on pktap, link-type PKTAP (Packet Tap), capture size 65535 bytes
10 packets captured
you'll need to have wireshark installed for this to work (e.g. with brew install wireshark on Mac or apt-get on Ubuntu)
$ editcap -c 1 mycap.pcap output.pcap
10 packets captured -> 10 files created
$ ls -la output* | wc -l
10

Raspberry Pi / Octopi USB Camera Setup: What does this mean and how do I use it?

I'm very new to Raspberry Pi, and have no prior notable experience with Linux so this is all new to me...
Octoprint is a 3D printer spooler that you can run on your raspberry pi. One of the features on Octoprint is the ability to setup a USB camera to view either still images or a stream of your print.
I am using the Octopi prepackaged Octoprint image.
Octoprint's github contains the following info referring to my USB camera. But I have no idea how to implement this.
Hama PC-Webcam "AC-150" on Raspberry Pi
./mjpg_streamer -o output_http.so -w ./www -i input_uvc.so -y -r 640x480 -f 10
https://github.com/foosel/OctoPrint/wiki/Webcams-known-to-work
I'm guessing this is an easy command that I enter via console, but I've winged few commands with no luck. Can someone shed some light on how I use this? Like I said I'm an absolute beginner with the pi...
Any help is greatly appreciated!
Try this:
camera_usb_options="-r VGA -f 10 -y"
sudo service octoprint stop
fuser /dev/video0
/dev/video0: **1871m**
$ ps axl | grep **1871** *Change this number by yours*
$ kill -9 **1871**
./mjpg_streamer -i "input_uvc.so $camera_usb_options" -o "output_http.so -w ./www"
sudo service octoprint start

GStreamer streaming has to start client first

I am able to stream h264 or MPEG4 video. Client (player) has to be started first and then start streaming (start server).
What I need is to be able to connect to the already playing stream (start client after server).
Both server and client run on same i.MX6 device.
Server example:
gst-launch-0.10 -vvv
filesrc location=bruce.mp4 typefind=true \
! qtdemux name=demux \
demux.video_00 \
! queue ! h264parse split-packetized=true \
! mpegtsmux ! rtpmp2tpay ! gdppay \
! udpsink host=239.255.1.1 port=5004
Client example:
gst-launch-0.10 -vvv
udpsrc port=5004 multicast-group=239.255.1.1 caps="application/x-gdp" \
! gdpdepay ! gstrtpjitterbuffer \
! rtpmp2tdepay ! mpegtsdemux name=demux \
! queue max-size-buffers=0 max-size-time=0 \
! vpudec low-latency=true framedrop=true \
! mfw_isink sync=false

Gstreamer how to record, take screenshot of a stream

I am streaming video from my raspberry using gstreamer and h264 decoder as below:
raspivid -t 999999 -h 720 -w 1080 -fps 25 -hf -b 2000000 -o - | gst-launch-1.0 -v fdsrc ! h264parse ! rtph264pay config-interval=1 pt=96 ! gdppay ! tcpserversink host=192.168.2.7 port=5000
From my desktop I am able to stream the video as below:
gst-launch-1.0 -v tcpclientsrc host=192.168.2.7 port=5000 ! gdpdepay ! rtph264depay ! avdec_h264 ! videoconvert ! gdkpixbufoverlay location=gstreamer-logo.svg offset-x=20 offset-y=20 ! autovideosink sync=false
I am looking for the following , any help is appreciated.Thanks.
Capture the screenshot of the video while streaming
Record the stream to a local file
I was able to logo overlay using gdkpixbufoverlay, want to add time also. Tried clockoverlay, but the stream got struck.