mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-02-27 20:26:31 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
40be0c20e2 | ||
|
|
f1e9d4568c | ||
|
|
f4f57cce38 | ||
|
|
c87ad5703c | ||
|
|
95df13b7cb |
@@ -1,7 +1,7 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
commit = True
|
commit = True
|
||||||
tag = True
|
tag = True
|
||||||
current_version = 5.24
|
current_version = 5.25
|
||||||
parse = (?P<major>\d+)\.(?P<minor>\d+)
|
parse = (?P<major>\d+)\.(?P<minor>\d+)
|
||||||
serialize =
|
serialize =
|
||||||
{major}.{minor}
|
{major}.{minor}
|
||||||
|
|||||||
4
.github/workflows/docker-alpine-image.yaml
vendored
4
.github/workflows/docker-alpine-image.yaml
vendored
@@ -59,8 +59,8 @@ jobs:
|
|||||||
-
|
-
|
||||||
name: Test
|
name: Test
|
||||||
run: |
|
run: |
|
||||||
echo version: $(docker run --rm -e NO_EDID=1 -t ustreamer --version)
|
echo version: $(docker run --rm -t ustreamer --version)
|
||||||
echo -e "features:\n$(docker run --rm -e NO_EDID=1 -t ustreamer --features)"
|
echo -e "features:\n$(docker run --rm -t ustreamer --features)"
|
||||||
-
|
-
|
||||||
name: Build multi arch
|
name: Build multi arch
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v3
|
||||||
|
|||||||
28
README.md
28
README.md
@@ -81,35 +81,57 @@ $ ./ustreamer \
|
|||||||
|
|
||||||
You can always view the full list of options with ```ustreamer --help```.
|
You can always view the full list of options with ```ustreamer --help```.
|
||||||
|
|
||||||
|
-----
|
||||||
# Docker (Raspberry Pi 4 HDMI)
|
# Docker (Raspberry Pi 4 HDMI)
|
||||||
## Preparations
|
|
||||||
|
|
||||||
|
## Preparations
|
||||||
Add following lines to /boot/firmware/usercfg.txt:
|
Add following lines to /boot/firmware/usercfg.txt:
|
||||||
|
|
||||||
```
|
```
|
||||||
gpu_mem=128
|
gpu_mem=128
|
||||||
dtoverlay=tc358743
|
dtoverlay=tc358743
|
||||||
```
|
```
|
||||||
|
|
||||||
Check size of CMA:
|
Check size of CMA:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ dmesg | grep cma-reserved
|
$ dmesg | grep cma-reserved
|
||||||
[ 0.000000] Memory: 7700524K/8244224K available (11772K kernel code, 1278K rwdata, 4320K rodata, 4096K init, 1077K bss, 281556K reserved, 262144K cma-reserved)
|
[ 0.000000] Memory: 7700524K/8244224K available (11772K kernel code, 1278K rwdata, 4320K rodata, 4096K init, 1077K bss, 281556K reserved, 262144K cma-reserved)
|
||||||
```
|
```
|
||||||
|
|
||||||
If it is smaller than 128M add following to /boot/firmware/cmdline.txt:
|
If it is smaller than 128M add following to /boot/firmware/cmdline.txt:
|
||||||
|
|
||||||
```
|
```
|
||||||
cma=128M
|
cma=128M
|
||||||
```
|
```
|
||||||
|
|
||||||
Save changes and reboot.
|
Save changes and reboot.
|
||||||
|
|
||||||
## Launch
|
## Launch
|
||||||
Start container:
|
Start container:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ docker run --device /dev/video0:/dev/video0 -p 8080:8080 pikvm/ustreamer:latest
|
$ docker run --device /dev/video0:/dev/video0 -e EDID=1 -p 8080:8080 pikvm/ustreamer:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
Then access the web interface at port 8080 (e.g. http://raspberrypi.local:8080).
|
Then access the web interface at port 8080 (e.g. http://raspberrypi.local:8080).
|
||||||
|
|
||||||
|
## Custom config
|
||||||
|
```bash
|
||||||
|
$ docker run --rm pikvm/ustreamer:latest \
|
||||||
|
--format=uyvy \
|
||||||
|
--workers=3 \
|
||||||
|
--persistent \
|
||||||
|
--dv-timings \
|
||||||
|
--drop-same-frames=30
|
||||||
|
```
|
||||||
|
|
||||||
## EDID
|
## EDID
|
||||||
Container will set HDMI EDID before starging ustreamer. Use `-e NO_EDID=1` to not set EDID. Use `-e EDID_HEX=xx` to specify custom EDID data.
|
Add `-e EDID=1` to set HDMI EDID before starging ustreamer. Use together with `-e EDID_HEX=xx` to specify custom EDID data.
|
||||||
|
|
||||||
-----
|
-----
|
||||||
# Raspberry Pi Camera Example
|
# Raspberry Pi Camera Example
|
||||||
|
|
||||||
Example usage for the Raspberry Pi v1 camera:
|
Example usage for the Raspberry Pi v1 camera:
|
||||||
```bash
|
```bash
|
||||||
$ sudo modprobe bcm2835-v4l2
|
$ sudo modprobe bcm2835-v4l2
|
||||||
|
|||||||
29
docs/h264.md
29
docs/h264.md
@@ -78,6 +78,17 @@ memsink: {
|
|||||||
EOF
|
EOF
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If you're using a TC358743-based video capture device that supports audio capture, run the following command to enable audio streaming:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cat << EOF >> /opt/janus/lib/janus/configs/janus.plugin.ustreamer.jcfg
|
||||||
|
audio: {
|
||||||
|
device = "hw:1"
|
||||||
|
tc358743 = "/dev/video0"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
### Start µStreamer and the Janus WebRTC Server
|
### Start µStreamer and the Janus WebRTC Server
|
||||||
|
|
||||||
For µStreamer to share the video stream with the µStreamer Janus plugin, µStreamer must run with the following command-line flags:
|
For µStreamer to share the video stream with the µStreamer Janus plugin, µStreamer must run with the following command-line flags:
|
||||||
@@ -111,13 +122,14 @@ The client-side JavaScript application uses the following control flow:
|
|||||||
1. The client instructs the Janus server to attach the µStreamer Janus plugin.
|
1. The client instructs the Janus server to attach the µStreamer Janus plugin.
|
||||||
1. On success, the client obtains a plugin handle through which it can send requests directly to the µStreamer Janus plugin. The client processes responses via the `attach` callbacks:
|
1. On success, the client obtains a plugin handle through which it can send requests directly to the µStreamer Janus plugin. The client processes responses via the `attach` callbacks:
|
||||||
- `onmessage` for general messages
|
- `onmessage` for general messages
|
||||||
- `onremotetrack` for the H.264 video stream
|
- `onremotetrack` for the H.264 video stream and (optionally) an Opus audio stream
|
||||||
1. The client issues a `watch` request to the µStreamer Janus plugin, which initiates the H.264 stream in the plugin itself.
|
1. The client issues a `watch` request to the µStreamer Janus plugin, which initiates the H.264 stream in the plugin itself.
|
||||||
- It takes a few seconds for uStreamer's video stream to become available to Janus. The first `watch` request may fail, so the client must retry the `watch` request.
|
- It takes a few seconds for uStreamer's video stream to become available to Janus. The first `watch` request may fail, so the client must retry the `watch` request.
|
||||||
1. The client and server negotiate the underlying parameters of the WebRTC session. This procedure is called JavaScript Session Establishment Protocol (JSEP). The server makes a `jsepOffer` to the client, and the client responds with a `jsepAnswer`.
|
1. The client and server negotiate the underlying parameters of the WebRTC session. This procedure is called JavaScript Session Establishment Protocol (JSEP). The server makes a `jsepOffer` to the client, and the client responds with a `jsepAnswer`.
|
||||||
1. The client issues a `start` request to the µStreamer Janus plugin to indicate that the client wants to begin consuming the video stream.
|
1. The client issues a `start` request to the µStreamer Janus plugin to indicate that the client wants to begin consuming the video stream.
|
||||||
1. The µStreamer Janus plugin delivers the H.264 video stream to the client via WebRTC.
|
1. The µStreamer Janus plugin delivers the H.264 video stream and (optionally) an Opus audio stream to the client via WebRTC.
|
||||||
1. The Janus client library invokes the `onremotetrack` callback. The client attaches the video stream to the `<video>` element, rendering the video stream in the browser window.
|
1. The Janus client library invokes the `onremotetrack` callback with the video stream. The client attaches the video stream to the `<video>` element, rendering the video stream in the browser window.
|
||||||
|
1. (if an audio track is available) The Janus client library invokes the `onremotetrack` callback with the Opus audio stream. The client adds the audio stream to the `<video>` element, rendering the audio in the browser window.
|
||||||
|
|
||||||
### Sample Code
|
### Sample Code
|
||||||
|
|
||||||
@@ -176,7 +188,7 @@ The client-side JavaScript application uses the following control flow:
|
|||||||
// successfully.
|
// successfully.
|
||||||
success: function (pluginHandle) {
|
success: function (pluginHandle) {
|
||||||
uStreamerPluginHandle = pluginHandle;
|
uStreamerPluginHandle = pluginHandle;
|
||||||
// Instruct the µStreamer Janus plugin to initiate the video stream.
|
// Instruct the µStreamer Janus plugin to initiate streaming.
|
||||||
uStreamerPluginHandle.send({ message: { request: "watch" } });
|
uStreamerPluginHandle.send({ message: { request: "watch" } });
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -211,16 +223,17 @@ The client-side JavaScript application uses the following control flow:
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Callback function, for when the video stream arrives.
|
// Callback function, for when a media stream arrives.
|
||||||
onremotetrack: function (mediaStreamTrack, mediaId, isAdded) {
|
onremotetrack: function (mediaStreamTrack, mediaId, isAdded) {
|
||||||
if (isAdded) {
|
if (isAdded) {
|
||||||
// Attach the received media track to the video element. Cloning the
|
// Attach the received media track to the video element. Cloning the
|
||||||
// mediaStreamTrack creates a new object with a distinct, globally
|
// mediaStreamTrack creates a new object with a distinct, globally
|
||||||
// unique stream identifier.
|
// unique stream identifier.
|
||||||
const videoElement = document.getElementById("webrtc-output");
|
const videoElement = document.getElementById("webrtc-output");
|
||||||
const stream = new MediaStream();
|
if (videoElement.srcObject === null) {
|
||||||
stream.addTrack(mediaStreamTrack.clone());
|
videoElement.srcObject = new MediaStream();
|
||||||
videoElement.srcObject = stream;
|
}
|
||||||
|
videoElement.srcObject.addTrack(mediaStreamTrack.clone());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.\" Manpage for ustreamer-dump.
|
.\" Manpage for ustreamer-dump.
|
||||||
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
||||||
.TH USTREAMER-DUMP 1 "version 5.24" "January 2021"
|
.TH USTREAMER-DUMP 1 "version 5.25" "January 2021"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
ustreamer-dump \- Dump uStreamer's memory sink to file
|
ustreamer-dump \- Dump uStreamer's memory sink to file
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.\" Manpage for ustreamer.
|
.\" Manpage for ustreamer.
|
||||||
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
||||||
.TH USTREAMER 1 "version 5.24" "November 2020"
|
.TH USTREAMER 1 "version 5.25" "November 2020"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
ustreamer \- stream MJPEG video from any V4L2 device to the network
|
ustreamer \- stream MJPEG video from any V4L2 device to the network
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
|
|
||||||
pkgname=ustreamer
|
pkgname=ustreamer
|
||||||
pkgver=5.24
|
pkgver=5.25
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="Lightweight and fast MJPEG-HTTP streamer"
|
pkgdesc="Lightweight and fast MJPEG-HTTP streamer"
|
||||||
url="https://github.com/pikvm/ustreamer"
|
url="https://github.com/pikvm/ustreamer"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
[ -z "$NO_EDID" ] && {
|
[ -n "$EDID" ] && {
|
||||||
[ -n "$EDID_HEX" ] && echo "$EDID_HEX" > /edid.hex
|
[ -n "$EDID_HEX" ] && echo "$EDID_HEX" > /edid.hex
|
||||||
while true; do
|
while true; do
|
||||||
v4l2-ctl --device=/dev/video0 --set-edid=file=/edid.hex --fix-edid-checksums --info-edid && break
|
v4l2-ctl --device=/dev/video0 --set-edid=file=/edid.hex --fix-edid-checksums --info-edid && break
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=ustreamer
|
PKG_NAME:=ustreamer
|
||||||
PKG_VERSION:=5.24
|
PKG_VERSION:=5.25
|
||||||
PKG_RELEASE:=1
|
PKG_RELEASE:=1
|
||||||
PKG_MAINTAINER:=Maxim Devaev <mdevaev@gmail.com>
|
PKG_MAINTAINER:=Maxim Devaev <mdevaev@gmail.com>
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ def _find_sources(suffix: str) -> list[str]:
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
setup(
|
setup(
|
||||||
name="ustreamer",
|
name="ustreamer",
|
||||||
version="5.24",
|
version="5.25",
|
||||||
description="uStreamer tools",
|
description="uStreamer tools",
|
||||||
author="Maxim Devaev",
|
author="Maxim Devaev",
|
||||||
author_email="mdevaev@gmail.com",
|
author_email="mdevaev@gmail.com",
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define US_VERSION_MAJOR 5
|
#define US_VERSION_MAJOR 5
|
||||||
#define US_VERSION_MINOR 24
|
#define US_VERSION_MINOR 25
|
||||||
|
|
||||||
#define US_MAKE_VERSION2(_major, _minor) #_major "." #_minor
|
#define US_MAKE_VERSION2(_major, _minor) #_major "." #_minor
|
||||||
#define US_MAKE_VERSION1(_major, _minor) US_MAKE_VERSION2(_major, _minor)
|
#define US_MAKE_VERSION1(_major, _minor) US_MAKE_VERSION2(_major, _minor)
|
||||||
|
|||||||
@@ -220,7 +220,11 @@ static void _m2m_encoder_prepare(us_m2m_encoder_s *enc, const us_frame_s *frame)
|
|||||||
fmt.fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT;
|
fmt.fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT;
|
||||||
fmt.fmt.pix_mp.num_planes = 1;
|
fmt.fmt.pix_mp.num_planes = 1;
|
||||||
// fmt.fmt.pix_mp.plane_fmt[0].bytesperline = 0;
|
// fmt.fmt.pix_mp.plane_fmt[0].bytesperline = 0;
|
||||||
// fmt.fmt.pix_mp.plane_fmt[0].sizeimage = 512 << 10;
|
if (enc->output_format == V4L2_PIX_FMT_H264) {
|
||||||
|
// https://github.com/pikvm/ustreamer/issues/169
|
||||||
|
// https://github.com/raspberrypi/linux/pull/5232
|
||||||
|
fmt.fmt.pix_mp.plane_fmt[0].sizeimage = (1024 + 512) << 10; // 1.5Mb
|
||||||
|
}
|
||||||
_E_LOG_DEBUG("Configuring OUTPUT format ...");
|
_E_LOG_DEBUG("Configuring OUTPUT format ...");
|
||||||
_E_XIOCTL(VIDIOC_S_FMT, &fmt, "Can't set OUTPUT format");
|
_E_XIOCTL(VIDIOC_S_FMT, &fmt, "Can't set OUTPUT format");
|
||||||
if (fmt.fmt.pix_mp.pixelformat != enc->output_format) {
|
if (fmt.fmt.pix_mp.pixelformat != enc->output_format) {
|
||||||
|
|||||||
Reference in New Issue
Block a user