Skip to content

luci-app-ustreamer: complete rewrite#8324

Open
httpstorm wants to merge 1 commit intoopenwrt:masterfrom
httpstorm:luci-app-ustreamer_2026-02-14
Open

luci-app-ustreamer: complete rewrite#8324
httpstorm wants to merge 1 commit intoopenwrt:masterfrom
httpstorm:luci-app-ustreamer_2026-02-14

Conversation

@httpstorm
Copy link

@httpstorm httpstorm commented Feb 14, 2026

New features:

  • Implement all supported ustreamer features
  • Detailed UI text and description based on the program help
  • Input validation for all parameters
  • Stream preview with link to the stream page
  • Dark theme colours for the stream preview
  • Bulgarian translation (complete)

Bug fixes:

  • Use of poll.add inside the render function results in a fork bomb
  • Repeated use if setTimeout results in a fork bomb when the stream is not available (old bug from luci-app-mjpg-streamer)

Merge:

  • I tried to keep existing translations as much as possible
  • All existing features, except [video_devs]

Removed:

  • [video_devs] parameters, this or a similar feature will be implemented once I fully test it, and choose an optimal strategy, with support for multiple video input devices. In order to comlpete work on this feature, I need programatic access to the configuration name for each instance:
config ustreamer 'configuration_name'

Formatting:

  • Format code for readability and to fit 80 column where possible

TODO:
Ask the ustreamer author whether we should use 0-255 limits for some of the image control parameters. Note: My camera expects 0-255, while the source code internally accepts int range, but warns when a value is outside the range I have defined. These limits could be standard, in which case we should keep them or dependent on the camera used, in which case we should remove the limits and accept any int value.

Edit: The values for image control varies between camera models, therefore the range is unrestricted.

Note:
Due to a race condition, two instances of the package got created. I put a lot of effort and testing in every single detail, and the other implementation got merged first. All features and translations are merged here, except for [video_devs], which will be reworked later.

  • This PR is not from my main or master branch 💩, but a separate branch ✅
  • Each commit has a valid ✒️ Signed-off-by: <my@email.address> row (via git commit --signoff)
  • Each commit and PR title has a valid 📝 <package name>: title first line subject for packages
  • Incremented 🆙 any PKG_VERSION in the Makefile
  • Tested on: (mvebu/cortexa9 WRT3200ACM, openwrt main r32847+5-bc8424ab89, Safari 26.2) ✅
  • ( Preferred ) Mention: @ the original code author for feedback
  • ( Preferred ) Screenshot or mp4 of changes:

@systemcrash @hnyman @GeorgeSapkin @mdevaev

01-Preview
02-General
03-Capture
04-HTTP-server
05-JPEG-sink
06-RAW-sink
07-H264-sink
08-Logging
09-Image-control

@mdevaev
Copy link

mdevaev commented Feb 14, 2026

Image values depends on the camera itself. Generally they should be taken from v4l2-ctl --list-ctrls --device=/dev/videoX, the ranges could be very wide. See my camera for example:


                     brightness 0x00980900 (int)    : min=-64 max=64 step=1 default=0 value=0
                       contrast 0x00980901 (int)    : min=0 max=95 step=1 default=0 value=0
                     saturation 0x00980902 (int)    : min=0 max=100 step=1 default=64 value=64
                            hue 0x00980903 (int)    : min=-2000 max=2000 step=1 default=0 value=0
        white_balance_automatic 0x0098090c (bool)   : default=1 value=1
                          gamma 0x00980910 (int)    : min=100 max=300 step=1 default=100 value=100
           power_line_frequency 0x00980918 (menu)   : min=0 max=2 default=2 value=1 (50 Hz)
      white_balance_temperature 0x0098091a (int)    : min=2800 max=6500 step=10 default=4600 value=4600 flags=inactive
                      sharpness 0x0098091b (int)    : min=1 max=7 step=1 default=2 value=2
         backlight_compensation 0x0098091c (int)    : min=0 max=3 step=1 default=3 value=3

@httpstorm httpstorm force-pushed the luci-app-ustreamer_2026-02-14 branch from 889146e to 2d1e7fa Compare February 14, 2026 16:36
New features:
- Implement all supported ustreamer features
- Detailed UI text and description based on the program help
- Input validation for all parameters
- Stream preview with link to the stream page
- Dark theme colours for the stream preview
- Bulgarian translation (complete)

Bug fixes:
- Use of poll.add inside the render function results in a fork bomb
- Repeated use if setTimeout results in a fork bomb when the stream
is not available (old bug from luci-app-mjpg-streamer)

Merge:
- I tried to keep existing translations as much as possible
- All existing features, except [video_devs]

Removed:
- [video_devs] parameters, this or a similar feature will be implemented
once I fully test it, and choose an optimal strategy, with support
for multiple video input devices. In order to comlpete work on this
feature, I need programatic access to the configuration name for
each instance:

config ustreamer 'configuration_name'

Formatting:
- Format code for readability and to fit 80 column where possible

Notes:
The values for image control varies between camera models, therefore
the range is unrestricted.

Due to a race condition, two instances of the package got created.
I put a lot of effort and testing in every single detail, and the
other implementation got merged first. All features and translations
are merged here, except for [video_devs], which will be reworked
later.

Signed-off-by: Georgi Valkov <gvalkov@gmail.com>
@httpstorm httpstorm force-pushed the luci-app-ustreamer_2026-02-14 branch from 2d1e7fa to e74454c Compare February 14, 2026 16:40
@httpstorm
Copy link
Author

Changes:
The values for image control varies between camera models, therefore the range is now unrestricted.
The downside is that I had to remove the comments for range and default value, but they would be confusing anyway, since different cameras expect different values.

@systemcrash
Copy link
Contributor

I suppose I forgot to add a variable to check for existing polls. :/

'require uci';
'require ui';
'require view';
'require poll';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keep alphabetic order

Comment on lines -21 to -24
return Promise.all([
L.resolveDefault(fs.list('/dev/'), []).then(entries => entries.filter(e => /^video.*$/.test(e.name)) ),
uci.load('ustreamer'),
]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use this to find available devices.

Comment on lines -26 to +31
render([video_devs]) {
render: function () {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keep

'<li><kbd>HW ───────── </kbd>Use pre-encoded MJPEG frames directly from camera hardware</li>' +
'<li><kbd>M2M-VIDEO ── </kbd>GPU-accelerated MJPEG encoding using V4L2 M2M video interface</li>' +
'<li><kbd>M2M-IMAGE ── </kbd>GPU-accelerated JPEG encoding using V4L2 M2M image interface</li>'
));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use strings here, and put any html outside of i18n strings. See elsewhere in apps and the repo for examples.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I should replace all strings containing <br /> like this, and update all translations? I'll try to do it tomorrow.

- _('line_1<br />line_2')
+ _('line_1') + '<br />' + _('line_2')

I'm doing this for the first time. What are the i18n strings? This? _('text')

How easy or hard is it to use Weblate? I spent the past few days editing 37 translations at the same time, to keep them in perfect sync with the code. It was painful, even though I learned some tricks and my efficiency improved greatly.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This repo uses GNU message tools. Anything you change in js, just run build/i18n-sync.sh applications/luci-app-ustreamer/ and it refreshes for you.

this_tab, form.Flag, 'allow_truncated_frames',
_('Allow truncated frames'), _(
'Allows to handle truncated frames. Default: disabled<br />' +
'Useful if the device produces incorrect but still acceptable frames'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same - use br outside of _()

const dv_timings = s.taboption(
this_tab, form.Flag, 'dv_timings', _('DV-timings'), _(
'Enable DV-timings querying and events processing to automatic ' +
'resolution change<br />Default: disable'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same. If we keep Default: disable as a separate string, it only needs i18n once.

@systemcrash
Copy link
Contributor

Image values depends on the camera itself. Generally they should be taken from v4l2-ctl --list-ctrls --device=/dev/videoX, the ranges could be very wide. See my camera for example:


                     brightness 0x00980900 (int)    : min=-64 max=64 step=1 default=0 value=0
                       contrast 0x00980901 (int)    : min=0 max=95 step=1 default=0 value=0
                     saturation 0x00980902 (int)    : min=0 max=100 step=1 default=64 value=64
                            hue 0x00980903 (int)    : min=-2000 max=2000 step=1 default=0 value=0
        white_balance_automatic 0x0098090c (bool)   : default=1 value=1
                          gamma 0x00980910 (int)    : min=100 max=300 step=1 default=100 value=100
           power_line_frequency 0x00980918 (menu)   : min=0 max=2 default=2 value=1 (50 Hz)
      white_balance_temperature 0x0098091a (int)    : min=2800 max=6500 step=10 default=4600 value=4600 flags=inactive
                      sharpness 0x0098091b (int)    : min=1 max=7 step=1 default=2 value=2
         backlight_compensation 0x0098091c (int)    : min=0 max=3 step=1 default=3 value=3

@httpstorm

It's not difficult to run this command during page init (after fs.list) and poll the camera for acceptable values. But the tricky part I suppose is telling the sectionentry that uses that device to know which of these to apply. I could help you figure it out after we get the baby steps going here.

@httpstorm
Copy link
Author

@systemcrash @mdevaev
I've done a lot of parsing, so that should be the easy part. Then there is dependency. If I'm not mistaken v4l2-ctl is from v4l-utils, and depends on libiconv-full, libintl-full, libv4l. OpenWRT should have as little dependencies as possible, so this command is unlikely to be present. Now if ustreamer can provide this info as JSON output, that would make the parsing pretty simple and dependency free. Do we show all controls or only those that are supported? What happens if a device is not currently present? Do we cache the values or show default. What if the device is in use by ustreamer will we still be able to query supported image control parameters?

{
"brightness": { "min":-64, "max":64, "step":1, "default":0, "auto":1, "value":0 },
"contrast": { "min":0, "max":95, "step":1, "default":0, "auto":0, "value":0 },
// auto can also be hardcoded, since we know which parameters support it
}

@systemcrash
Copy link
Contributor

If a device is not present - no keys to the kingdom. But I figure ustreamer could provide some sane defaults in that case. Or the UI falls back to some default.

@systemcrash
Copy link
Contributor

Any update on this?

@httpstorm
Copy link
Author

I had to switch to an urgent task for work, and I'll resume this soon. Sorry for the delay.

@mdevaev
Copy link

mdevaev commented Feb 23, 2026

@httpstorm Unfortunately, ustreamer does not provide an option for dumping existing image parameters. I could do that, but I'm too overwhelmed right now. Sorry about this.

@httpstorm
Copy link
Author

No worries. Once implemented in ustreamer the web interface can be extended to support this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants