Compare commits

...

105 Commits
v1.9.0 ... main

Author SHA1 Message Date
Ingo Oppermann
08b1dd0ba0
Fix chromecast support 2024-11-01 11:23:06 +01:00
Ingo Oppermann
5c2a3a1fa5
Merge pull request #73 from badincite/main
Fix chromecast
2024-11-01 11:09:13 +01:00
badincite
67cc21b1fa Fix chromecast
Chromecast needs to append the url origin for the source to properly pass to the cast device. And it appears to need the default receiver application ID.
2024-10-29 09:45:05 -04:00
Ingo Oppermann
c1a9c715a4
Update language files 2024-09-13 15:42:56 +02:00
Ingo Oppermann
ce2e4eb836
Bump version to 1.14.0, bundle version to 2.12.0 2024-09-13 15:39:28 +02:00
Ingo Oppermann
9e81f203cb
Add option to select which channels will be displayed on the playersite (#392, #800) 2024-09-13 15:33:47 +02:00
Ingo Oppermann
4a88f47af5
Fix docker build (#64) 2024-09-13 12:22:07 +02:00
Jan Stabenow
3f44579508 Mod updates changelog 2024-09-06 12:30:52 +02:00
Jan Stabenow
18490b0496 Add wettercom service 2024-09-06 12:28:06 +02:00
Ingo Oppermann
f0d1db9044
Merge branch 'dev' of github.com:datarhei/restreamer-ui into dev 2024-09-06 11:25:46 +02:00
Ingo Oppermann
eaacb94c54
Remove erroneous filter setting 2024-09-06 11:25:19 +02:00
Jan Stabenow
352138dfef Fix encoded address 2024-09-06 10:28:10 +02:00
Jan Stabenow
3f90be8598 Mod updates public videojs >v8 2024-09-06 09:51:00 +02:00
Ingo Oppermann
05649aa2fd
Fix double -filter parameter when encoder sets filter 2024-09-05 14:27:55 +02:00
Ingo Oppermann
f54adc6b94
Bump version to 1.13 2024-06-07 12:15:40 +02:00
Ingo Oppermann
625b080752
Add opt-in for extended list of channel layouts 2024-06-04 17:13:03 +02:00
Ingo Oppermann
1920eb583c
Add more audo channel layouts 2024-06-04 15:08:52 +02:00
Ingo Oppermann
8be8128d6e
Fix returning correct custom value in SelectCustom component 2024-06-04 14:55:46 +02:00
Jan Stabenow
88826db4fd Mod updates changelog 2024-06-02 10:01:15 +02:00
Jan Stabenow
6154b9b734 Mod enables ff-loglevel and prepares the logging component 2024-06-02 09:57:01 +02:00
Jan Stabenow
3d02d3a79b Mod updates dep. 2024-06-02 09:55:10 +02:00
Jan Stabenow
58d0292ef9 Mod reduces complexity 2024-05-24 17:10:19 +02:00
Jan Stabenow
1f04169aa5 Fix player position 2024-05-24 11:47:06 +02:00
Jan Stabenow
c128f1d3f2 Mod uses official RTMP target 2024-05-24 11:23:49 +02:00
Ingo Oppermann
fdfa0d8f6f
Update translations 2024-04-29 15:55:13 +02:00
Ingo Oppermann
9d666e0879
Fix missing stream URL, summarize streams in probe log, don't lock type for first stream 2024-04-29 15:54:17 +02:00
Ingo Oppermann
6f5ecf878c
Remove unused imports 2024-04-29 12:12:02 +02:00
Ingo Oppermann
486d64ff19
Add to allow stream hints in case probing fails 2024-04-26 21:41:09 +02:00
Ingo Oppermann
9277f04b4b
Bump version to 1.12.0 2024-04-23 14:26:13 +02:00
Ingo Oppermann
f4708c23f0
Fix comment 2024-04-23 11:38:25 +02:00
Ingo Oppermann
a87ad7d614
Fix always add probesize and analyzeduration options 2024-04-19 16:40:09 +02:00
Ingo Oppermann
8709d37738
Add option to select different SRT stream in wizard 2024-04-19 15:45:54 +02:00
Ingo Oppermann
9fad572ec0
Add option to select different RTMP stream in wizard 2024-04-19 15:45:24 +02:00
Ingo Oppermann
1ab3e39ba0
Fix datarhei/restreamer#710 2024-04-15 12:58:04 +02:00
Ingo Oppermann
ec7cc4bc47
Remove debug output 2024-04-15 12:38:38 +02:00
Ingo Oppermann
f53be95e70
Fix reset of previous audio settings when editing profile (datarhei/restreamer#730) 2024-04-15 12:12:08 +02:00
Ingo Oppermann
1e86878d75
Fix RTMP URL for receive mode 2024-04-12 15:21:59 +02:00
Ingo Oppermann
e7ace32c3c
Update languages 2024-04-04 10:06:25 +02:00
Ingo Oppermann
60d3e8f617
Rename buttons 2024-04-04 09:43:23 +02:00
Ingo Oppermann
ff2130138a
Rename decoder files 2024-04-03 21:17:54 +02:00
Ingo Oppermann
8e208789f0
Rename encoder files 2024-04-03 17:18:52 +02:00
Ingo Oppermann
7007ce71ed
Reorder encoders 2024-04-03 16:35:25 +02:00
Ingo Oppermann
06933e47d8
Enable other codecs in publication services 2024-04-03 16:34:50 +02:00
Ingo Oppermann
85a89b9b3a
Bump version to 1.11.0, update changelog 2024-04-03 14:29:42 +02:00
Ingo Oppermann
8ea3b71844
Merge branch 'main' into dev 2024-04-02 17:04:47 +02:00
Ingo Oppermann
6292e62858
Allow to stream HEVC and AV1 to Youtube via RTMP 2024-03-27 21:01:53 +01:00
Ingo Oppermann
82bd4f2d76
Add librav1e AV1 encoder 2024-03-27 21:01:20 +01:00
Ingo Oppermann
44657181a0
Rename AV1NVDEC to AV1CUVID 2024-03-27 21:00:52 +01:00
Ingo Oppermann
8f3c60a1a7
Remove console log 2024-03-27 20:58:11 +01:00
Ingo Oppermann
dc384ed554
Remove comments 2024-03-27 11:55:45 +01:00
Ingo Oppermann
12344c958f
Fix codec name, change to hevc 2024-03-27 10:46:51 +01:00
Ingo Oppermann
c73cc357b9
Add HEVC VideoToolbox encoder 2024-03-27 10:45:35 +01:00
Ingo Oppermann
a68a43ef48
Cleanup language files 2024-03-27 10:44:40 +01:00
Ingo Oppermann
b8c453bf48
Merge pull request #46 from patcarter883/dev
Update UI to support AV1 CUDA decoding.
2024-03-27 10:40:53 +01:00
patcarter883
3e4662b337 Revert unrequired change to NVDEC decoder. 2024-03-24 13:22:31 +00:00
patcarter883
a0c41bba87 AV1 decode 2024-03-24 13:18:14 +00:00
patcarter883
2226ce41c2 Merge branch 'dev' of https://github.com/patcarter883/restreamer-ui into dev 2024-03-24 10:26:08 +00:00
patcarter883
355f6a7967 Add AV1 to decoders 2024-03-24 10:25:14 +00:00
patcarter883
fa094782c7 Add AV1 to decoders 2024-03-22 12:35:45 +00:00
Ingo Oppermann
487899f934
Fix checking out correct branch 2024-02-27 11:24:00 +01:00
Ingo Oppermann
318a1e32f4
Add schedule for dev build 2024-02-26 10:14:52 +01:00
Ingo Oppermann
82796c3801
Anonymize error message (datarhei/restreamer#688) 2024-02-23 17:44:10 +01:00
Ingo Oppermann
cfb70e5325
Merge branch 'main' into dev 2024-02-23 13:07:05 +01:00
Ingo Oppermann
de6fa8d64f
Fix chromecast config (#37, datarhei/restreamer#689) 2024-02-23 13:03:21 +01:00
Ingo Oppermann
4de6e111cc
Fix version extraction 2024-02-22 21:32:31 +01:00
Ingo Oppermann
fa462d696d
Rename artifact 2024-02-22 21:09:17 +01:00
Ingo Oppermann
c2e95265ac
Remove layer cache 2024-02-22 21:07:09 +01:00
Ingo Oppermann
906adcd5c5
Update actions 2024-02-22 20:58:28 +01:00
Ingo Oppermann
9dfdc87983
Fix login action version 2024-02-22 20:50:03 +01:00
Ingo Oppermann
939635ed94
Make dev workflow manually triggered 2024-02-22 20:42:17 +01:00
Ingo Oppermann
3ef10bf093
Update workflows 2024-02-22 20:40:44 +01:00
Ingo Oppermann
78a6e68421
Add test workflow 2024-02-22 12:08:06 +01:00
Ingo Oppermann
2c88c4dbde
Add ffmpeg6 support 2024-02-05 11:08:06 +01:00
Jan Stabenow
d931bc6e05 Fix public url 2024-02-02 19:52:40 +01:00
Jan Stabenow
4e6725ae94 Fix typo 2024-02-02 18:03:26 +01:00
Jan Stabenow
92ce3b5ba7 Add PUBLIC_URL 2024-02-02 17:46:01 +01:00
Ingo Oppermann
af690c689c
Bump bundle to 2.8.0 2024-02-02 14:01:05 +01:00
Jan Stabenow
4ac941b128 Fix theme color 2024-01-26 18:03:16 +01:00
Jan Stabenow
50c325fcce Fix help 2024-01-26 17:29:04 +01:00
Jan Stabenow
adf1b0b3b9 Fix build env 2024-01-26 17:27:11 +01:00
Jan Stabenow
a1a79defd1 Mod removes comment (workflow failed) 2024-01-26 17:19:31 +01:00
Jan Stabenow
6b6efffe9f Mod parse ENV to GITHUB_ENV 2024-01-26 17:14:43 +01:00
Jan Stabenow
7bc922f1d5 Mod replaces env injection 2024-01-26 15:35:26 +01:00
Jan Stabenow
77dfcbe749 Merge branch 'dev' of https://github.com/datarhei/restreamer-ui into dev 2024-01-26 15:19:39 +01:00
Jan Stabenow
813252d0c0 Mod removes matrix build on workflow_dispatch 2024-01-26 15:19:33 +01:00
Jan Stabenow
7d7c09c870 Mod adds env 2024-01-26 15:19:00 +01:00
Ingo Oppermann
3270140555
Fix usage of initSettings in Network source 2024-01-26 15:12:12 +01:00
Jan Stabenow
febf34e8e4 Mod updates env 2024-01-26 15:00:58 +01:00
Jan Stabenow
ee2cc8eca7 Add CADDY_IMAGE env 2024-01-26 15:00:40 +01:00
Jan Stabenow
88e16f187d Mod updates npm 2024-01-26 14:10:35 +01:00
Jan Stabenow
ce1589ecde Mod uses :dev tag 2024-01-26 13:39:36 +01:00
Jan Stabenow
6d6028125c Merge branch 'dev' of https://github.com/datarhei/restreamer-ui into dev 2024-01-26 13:13:27 +01:00
Jan Stabenow
d98ff905b0 Mod removes matrix build 2024-01-26 13:13:21 +01:00
Ingo Oppermann
fda9f2adda
Bump to version v1.10.0 2024-01-26 13:04:36 +01:00
Jan Stabenow
80c01f93ad Merge branch 'dev' of https://github.com/datarhei/restreamer-ui into dev 2024-01-26 13:02:34 +01:00
Jan Stabenow
e92f87544e Fix docker tag 2024-01-26 13:02:22 +01:00
Ingo Oppermann
53e809685c
Merge branch 'dev' of github.com:datarhei/restreamer-ui into dev 2024-01-26 12:54:02 +01:00
Ingo Oppermann
ff79efca02
Set channelid as default push stream name 2024-01-26 12:53:32 +01:00
Jan Stabenow
12ab148f47 Fix multiarch build 2024-01-26 12:51:12 +01:00
Ingo Oppermann
d74438e300
Allow to select from publishing RTMP and SRT streams 2024-01-19 20:33:48 +01:00
Ingo Oppermann
42013ec2c1
Allow RTSPS protocol (datarhei/restreamer#677) 2024-01-19 12:41:02 +01:00
Ingo Oppermann
4854c63fb1
Add audio loop source 2023-12-15 14:41:37 +01:00
Ingo Oppermann
c1f9b95a08
Fix RTMPS address with custom ports (datarhei/restreamer#658) 2023-12-15 14:01:40 +01:00
Ingo Oppermann
bcd3b7ba52
Add resource usage and command to process details 2023-12-15 12:57:14 +01:00
Ingo Oppermann
f4c9fbe61a
Fix wrongly displayed SRT URL (datahrei/restreamer#635) 2023-12-04 12:30:52 +01:00
164 changed files with 45879 additions and 40073 deletions

View File

@ -10,3 +10,4 @@ node_modules/
.github .github
.github_build .github_build
.build .build
NONPUBLIC/

View File

@ -1,63 +1,88 @@
name: 'Build restreamer-ui' name: 'Build main restreamer-ui'
on: on:
#workflow_dispatch: workflow_dispatch:
#push:
# branches-ignore:
# - '**'
jobs: jobs:
docker: build-frontend:
runs-on: [self-hosted] runs-on: ubuntu-latest
steps: outputs:
- name: Checkout version: ${{ steps.latestversion.outputs.version }}
uses: actions/checkout@v2 steps:
- name: Checkout
uses: actions/checkout@v4
- uses: cardinalby/export-env-action@v1 - name: Get latest version from package.json
with: id: latestversion
envFile: '.github_build/Build.restreamer-ui.env' run: |
export: 'true' echo "version=$(cat ./package.json | jq '.version' | sed 's/\"//g')" >> "$GITHUB_OUTPUT"
expandWithJobEnv: 'true'
expand: 'true'
- name: Set up QEMU - name: Set up Node.js
uses: docker/setup-qemu-action@master uses: actions/setup-node@v4
with: with:
platforms: all node-version: '21'
- name: Set up Docker Buildx - name: Build React App
id: buildx run: |
uses: docker/setup-buildx-action@master yarn install
yarn build
env:
PUBLIC_URL: './'
- name: Cache Docker layers - name: Upload React build as artifact
uses: actions/cache@v2 uses: actions/upload-artifact@v4
with: with:
path: /tmp/.buildx-cache name: restreamerui-main-build
key: ${{ runner.os }}-buildx-${{ github.sha }} path: build/
restore-keys: |
${{ runner.os }}-buildx-
- name: Login to DockerHub build-docker:
if: github.event_name != 'pull_request' needs: build-frontend
uses: docker/login-action@v1 runs-on: [self-hosted]
with: steps:
username: ${{ secrets.DOCKER_USERNAME }} - name: Checkout
password: ${{ secrets.DOCKER_PASSWORD }} uses: actions/checkout@v4
- name: Build Multi-Arch - name: Download React build artifact
uses: docker/build-push-action@v2 uses: actions/download-artifact@v4
with: with:
builder: ${{ steps.buildx.outputs.name }} name: restreamerui-main-build
context: . path: build
file: ./Dockerfile
build-args: | - name: Docker meta
PUBLIC_URL=./ id: meta
NODE_IMAGE=${{ env.NODE_IMAGE }} uses: docker/metadata-action@v5
CADDY_IMAGE=${{ env.CADDY_IMAGE }} with:
platforms: linux/amd64,linux/arm64,linux/arm/v7 images: |
push: true datarhei/restreamer-ui
tags: | tags: |
datarhei/restreamer-ui:${{ env.RELEASE }} type=raw,value=latest
datarhei/restreamer-ui:latest type=raw,value=${{ needs.build-frontend.outputs.version }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new - name: Set up QEMU
uses: docker/setup-qemu-action@master
with:
platforms: all
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@master
- name: Login to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push Docker Image
uses: docker/build-push-action@v5
with:
builder: ${{ steps.buildx.outputs.name }}
context: .
file: ./Dockerfile.workflow
build-args: |
CADDY_IMAGE=caddy:2.7.6-alpine
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View File

@ -0,0 +1,88 @@
name: 'Build dev restreamer-ui'
on:
workflow_dispatch:
workflow_call:
schedule:
- cron: '37 4 * * *'
push:
branches:
- dev
jobs:
build-frontend:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: dev
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '21'
- name: Build React App
run: |
yarn install
yarn build
env:
PUBLIC_URL: './'
- name: Upload React build as artifact
uses: actions/upload-artifact@v4
with:
name: restreamerui-dev-build
path: build/
build-docker:
needs: build-frontend
runs-on: [self-hosted]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download React build artifact
uses: actions/download-artifact@v4
with:
name: restreamerui-dev-build
path: build
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: |
datarhei/restreamer-ui
tags: |
type=raw,value=dev
- name: Set up QEMU
uses: docker/setup-qemu-action@master
with:
platforms: all
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@master
- name: Login to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push Docker Image
uses: docker/build-push-action@v5
with:
builder: ${{ steps.buildx.outputs.name }}
context: .
file: ./Dockerfile.workflow
build-args: |
CADDY_IMAGE=caddy:2.7.6-alpine
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View File

@ -1,73 +0,0 @@
name: 'Build datarhei/restreamer-ui:dev'
on:
#workflow_dispatch:
#workflow_call:
#push:
# branches:
# - dev
jobs:
docker:
runs-on: [self-hosted]
strategy:
matrix:
branch:
- dev
steps:
- name: Checkout
uses: actions/checkout@v2
with:
ref: ${{ matrix.branch }}
- uses: actions-ecosystem/action-get-latest-tag@v1
id: get-latest-tag
with:
semver_only: true
- name: Docker meta
id: meta
uses: docker/metadata-action@v4
with:
images: |
datarhei/restreamer-ui
tags: |
type=raw,value=dev,enable=${{ matrix.branch == 'dev' }}
- name: Set up QEMU
uses: docker/setup-qemu-action@master
with:
platforms: all
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@master
- name: Cache Docker layers
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Login to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build Multi-Arch
uses: docker/build-push-action@v2
with:
builder: ${{ steps.buildx.outputs.name }}
context: .
file: ./Dockerfile
build-args: |
PUBLIC_URL=/ui
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new

View File

@ -1,4 +0,0 @@
# RESTREAMER UI
RELEASE=1.6.0
NODE_IMAGE=node:19.1-alpine3.16
CADDY_IMAGE=caddy:2.6.2-alpine

1
.gitignore vendored
View File

@ -13,6 +13,7 @@
/build /build
# misc # misc
NONPUBLIC
.DS_Store .DS_Store
.VSCodeCounter .VSCodeCounter
.env.local .env.local

View File

@ -22,7 +22,7 @@
"it", "it",
"ko", "ko",
"pl", "pl",
"pt", "pt-br",
"ru", "ru",
"sl", "sl",
"tr", "tr",

View File

@ -1,5 +1,53 @@
# Restreamer-UI # Restreamer-UI
## v1.13.0 > v1.14.0
- Add wettercom service
- Add option to select which channels will be displayed on the playersite ([#392](https://github.com/datarhei/restreamer/issues/392), [#800](https://github.com/datarhei/restreamer/issues/800))
- Mod updates public videojs >v8
- Fix erroneous filter setting
- Fix encoded address
- Fix double -filter parameter when encoder sets filter
- Fix Docker build ([#64](https://github.com/datarhei/restreamer-ui/issues/64))
## v1.12.0 > v1.13.0
- Add to allow stream hints in case probing fails
- Mod enables ff-loglevel and prepares the logging component
- Mod uses official Instagram-RTMP target
- Mod Remove unused imports
- Mod Update translations
- Mod updates dep.
- Fix player position
- Fix missing stream URL, summarize streams in probe log, don't lock type for first stream
## v1.11.0 > v1.12.0
- Add option to select different SRT stream in wizard
- Add option to select different RTMP stream in wizard
- Fix selecting other than first audio stream ([#710](https://github.com/datarhei/restreamer/issues/710))
- Fix reset of previous audio settings when editing profile ([#730](https://github.com/datarhei/restreamer/issues/730))
- Fix RTMP URL for receive mode
## v1.10.0 > v1.11.0
- Add allow to stream HEVC and AV1 to Youtube via RTMP
- Add librav1e AV1 encoder
- Add support for AV1 CUDA decoding ([PR 46](https://github.com/datarhei/restreamer-ui/pull/46))
- Add FFmpeg 6 support
- Add HEVC VideoToolbox encoder
- Fix anonymize error message ([#688](https://github.com/datarhei/restreamer/issues/688))
- Fix chromecast config ([#37](https://github.com/datarhei/restreamer-ui/issues/37))
## v1.9.0 > v1.10.0
- Add resource usage and ffmpeg command to process details
- Add audio loop source
- Add to allow to select from already publishing RTMP and SRT streams
- Fix wrongly displayed SRT URL ([#635](https://github.com/datarhei/restreamer/issues/635))
- Fix RTMPS address with custom ports ([#658](https://github.com/datarhei/restreamer/issues/658))
- Fix allow RTSPS protocol ([#677](https://github.com/datarhei/restreamer/issues/677))
## v1.8.0 > v1.9.0 ## v1.8.0 > v1.9.0
- Add enlarged channel overview - Add enlarged channel overview

View File

@ -1,22 +1,17 @@
ARG NODE_IMAGE=node:21-alpine3.17 ARG NODE_IMAGE=node:21-alpine3.20
ARG CADDY_IMAGE=caddy:2.7.5-alpine ARG CADDY_IMAGE=caddy:2.8.4-alpine
FROM $NODE_IMAGE as builder FROM $NODE_IMAGE AS builder
ARG NODE_SPACE_SIZE=10240 ENV PUBLIC_URL="./"
ENV NODE_OPTIONS="--openssl-legacy-provider --max-old-space-size=$NODE_SPACE_SIZE"
ENV PUBLIC_URL "./"
COPY . /ui COPY . /ui
WORKDIR /ui WORKDIR /ui
RUN cd /ui && \ RUN cd /ui && \
yarn set version berry && \ yarn install && \
yarn config set httpTimeout 600000 && \ yarn build
yarn install && \
yarn run build
FROM $CADDY_IMAGE FROM $CADDY_IMAGE

13
Dockerfile.workflow Normal file
View File

@ -0,0 +1,13 @@
ARG CADDY_IMAGE=caddy:2.7.5-alpine
FROM $CADDY_IMAGE
COPY build /ui/build
COPY Caddyfile /ui/Caddyfile
ENV PUBLIC_URL="./"
WORKDIR /ui
EXPOSE 3000
CMD [ "caddy", "run", "--config", "/ui/Caddyfile" ]

View File

@ -1,53 +1,52 @@
{ {
"name": "restreamer-ui", "name": "restreamer-ui",
"version": "1.9.0", "version": "1.14.0",
"bundle": "restreamer-v2.7.0", "bundle": "restreamer-v2.12.0",
"private": false, "private": false,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@auth0/auth0-spa-js": "^2.1.2", "@auth0/auth0-spa-js": "^2.1.3",
"@babel/plugin-proposal-private-property-in-object": "^7.21.11", "@babel/plugin-syntax-flow": "^7.24.7",
"@babel/plugin-syntax-flow": "^7.22.5", "@babel/plugin-transform-react-jsx": "^7.25.2",
"@babel/plugin-transform-react-jsx": "^7.22.15", "@emotion/react": "^11.13.3",
"@emotion/react": "^11.11.1", "@emotion/styled": "^11.13.0",
"@emotion/styled": "^11.11.0", "@fontsource/dosis": "^5.0.21",
"@fontsource/dosis": "^5.0.15", "@fontsource/roboto": "^5.0.14",
"@fontsource/roboto": "^5.0.8", "@fortawesome/fontawesome-svg-core": "^6.6.0",
"@fortawesome/fontawesome-svg-core": "^6.4.2", "@fortawesome/free-brands-svg-icons": "^6.6.0",
"@fortawesome/free-brands-svg-icons": "^6.4.2", "@fortawesome/free-solid-svg-icons": "^6.6.0",
"@fortawesome/free-solid-svg-icons": "^6.4.2", "@fortawesome/react-fontawesome": "^0.2.2",
"@fortawesome/react-fontawesome": "^0.2.0", "@lingui/core": "^4.11.4",
"@lingui/core": "^4.5.0", "@lingui/macro": "^4.11.4",
"@lingui/macro": "^4.5.0", "@lingui/react": "^4.11.4",
"@lingui/react": "^4.5.0", "@mui/icons-material": "^6.0.1",
"@mui/icons-material": "^5.14.13", "@mui/lab": "^6.0.0-beta.8",
"@mui/lab": "^5.0.0-alpha.148", "@mui/material": "^6.0.1",
"@mui/material": "^5.14.13", "@mui/styles": "^6.0.1",
"@mui/styles": "^5.14.13", "@testing-library/dom": "^10.4.0",
"@testing-library/dom": "^9.3.3", "@testing-library/jest-dom": "^6.5.0",
"@testing-library/jest-dom": "^6.1.4", "@testing-library/react": "^16.0.1",
"@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.5.2",
"@testing-library/user-event": "^14.5.1", "@types/react": "^18.3.5",
"@types/react": "^18.2.28",
"babel-plugin-macros": "^3.1.0", "babel-plugin-macros": "^3.1.0",
"eslint": "^8.51.0", "eslint": "^9.9.1",
"handlebars": "^4.7.8", "handlebars": "^4.7.8",
"jwt-decode": "^4.0.0", "jwt-decode": "^4.0.0",
"make-plural": "^7.3.0", "make-plural": "^7.4.0",
"react": "^18.2.0", "react": "^18.3.1",
"react-colorful": "^5.6.1", "react-colorful": "^5.6.1",
"react-device-detect": "^2.2.3", "react-device-detect": "^2.2.3",
"react-dom": "^18.2.0", "react-dom": "^18.3.1",
"react-markdown": "^9.0.0", "react-markdown": "^9.0.1",
"react-router-dom": "^6.16.0", "react-router-dom": "^6.26.1",
"react-scripts": "5.0.1", "react-scripts": "^5.0.1",
"semver": "^7.5.4", "semver": "^7.6.3",
"serve": "^14.2.1", "serve": "^14.2.3",
"typescript": "^5.2.2", "typescript": "^5.5.4",
"url-parse": "^1.5.10", "url-parse": "^1.5.10",
"util": "^0.12.5", "util": "^0.12.5",
"uuid": "^9.0.1", "uuid": "^10.0.0",
"video.js": "8.6.1", "video.js": "^8.17.3",
"videojs-overlay": "^3.1.0" "videojs-overlay": "^3.1.0"
}, },
"scripts": { "scripts": {
@ -87,11 +86,12 @@
] ]
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.23.2", "@babel/core": "^7.25.2",
"@lingui/cli": "^4.5.0", "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"babel-core": "^7.0.0-bridge.0", "@lingui/cli": "^4.11.4",
"babel-core": "^6.26.3",
"eslint-config-react-app": "^7.0.1", "eslint-config-react-app": "^7.0.1",
"prettier": "^3.0.3", "prettier": "^3.3.3",
"react-error-overlay": "^6.0.11" "react-error-overlay": "^6.0.11"
}, },
"resolutions": {} "resolutions": {}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
.vjs-airplay-button .vjs-icon-placeholder{background:url("ic_airplay_white_24px.svg") center center no-repeat;background-size:contain;display:inline-block;width:12px;height:12px}.vjs-airplay-button:hover{cursor:pointer}.vjs-airplay-button:hover .vjs-icon-placeholder{background-image:url("ic_airplay_white_24px.svg")}.vjs-airplay-button.vjs-airplay-button-lg:not(.vjs-hidden){display:flex;align-items:center;width:auto;padding:0 4px}.vjs-airplay-button.vjs-airplay-button-lg:not(.vjs-hidden) .vjs-airplay-button-label{flex-grow:1;margin-left:4px}.vjs-airplay-button.vjs-airplay-button-lg:not(.vjs-hidden) .vjs-icon-placeholder{flex-grow:1}

View File

@ -0,0 +1,308 @@
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
"use strict";
var hasAirPlayAPISupport = require('../lib/hasAirPlayAPISupport');
/**
* Registers the AirPlayButton Component with Video.js. Calls
* {@link http://docs.videojs.com/Component.html#.registerComponent}, which will add a
* component called `airPlayButton` to the list of globally registered Video.js
* components. The `airPlayButton` is added to the player's control bar UI automatically
* once {@link module:enableAirPlay} has been called. If you would like to specify the
* order of the buttons that appear in the control bar, including this button, you can do
* so in the options that you pass to the `videojs` function when creating a player:
*
* ```
* videojs('playerID', {
* controlBar: {
* children: [
* 'playToggle',
* 'progressControl',
* 'volumePanel',
* 'fullscreenToggle',
* 'airPlayButton',
* ],
* }
* });
* ```
*
* @param videojs {object} A reference to {@link http://docs.videojs.com/module-videojs.html|Video.js}
* @see http://docs.videojs.com/module-videojs.html#~registerPlugin
*/
module.exports = function (videojs) {
/**
* The AirPlayButton module contains both the AirPlayButton class definition and the
* function used to register the button as a Video.js Component.
*
* @module AirPlayButton
*/
const ButtonComponent = videojs.getComponent('Button');
/**
* The Video.js Button class is the base class for UI button components.
*
* @external Button
* @see {@link http://docs.videojs.com/Button.html|Button}
*/
/** @lends AirPlayButton.prototype */
class AirPlayButton extends ButtonComponent {
/**
* This class is a button component designed to be displayed in the
* player UI's control bar. It displays an Apple AirPlay selection
* list when clicked.
*
* @constructs
* @extends external:Button
*/
constructor(player, options) {
super(player, options);
if (!hasAirPlayAPISupport()) {
this.hide();
}
this._reactToAirPlayAvailableEvents();
if (options.addAirPlayLabelToButton) {
this.el().classList.add('vjs-airplay-button-lg');
this._labelEl = document.createElement('span');
this._labelEl.classList.add('vjs-airplay-button-label');
this._labelEl.textContent = this.localize('AirPlay');
this.el().appendChild(this._labelEl);
} else {
this.controlText('Start AirPlay');
}
}
/**
* Overrides Button#buildCSSClass to return the classes used on the button element.
*
* @param {DOMElement} el
* @see {@link http://docs.videojs.com/Button.html#buildCSSClass|Button#buildCSSClass}
*/
buildCSSClass() {
return 'vjs-airplay-button ' + super.buildCSSClass();
}
/**
* Overrides Button#handleClick to handle button click events. AirPlay
* functionality is handled outside of this class, which should be limited
* to UI related logic. This function simply triggers an event on the player.
*
* @fires AirPlayButton#airPlayRequested
* @param {DOMElement} el
* @see {@link http://docs.videojs.com/Button.html#handleClick|Button#handleClick}
*/
handleClick() {
this.player().trigger('airPlayRequested');
}
/**
* Gets the underlying DOMElement used by the player.
*
* @private
* @returns {DOMElement} either an <audio> or <video> tag, depending on the type of
* player
*/
_getMediaEl() {
var playerEl = this.player().el();
return playerEl.querySelector('video, audio');
}
/**
* Binds a listener to the `webkitplaybacktargetavailabilitychanged` event, if it is
* supported, that will show or hide this button Component based on the availability
* of the AirPlay function.
*
* @private
*/
_reactToAirPlayAvailableEvents() {
var mediaEl = this._getMediaEl(),
self = this;
if (!mediaEl || !hasAirPlayAPISupport()) {
return;
}
function onTargetAvailabilityChanged(event) {
if (event.availability === 'available') {
self.show();
} else {
self.hide();
}
}
mediaEl.addEventListener('webkitplaybacktargetavailabilitychanged', onTargetAvailabilityChanged);
this.on('dispose', function () {
mediaEl.removeEventListener('webkitplaybacktargetavailabilitychanged', onTargetAvailabilityChanged);
});
}
}
videojs.registerComponent('airPlayButton', AirPlayButton);
};
},{"../lib/hasAirPlayAPISupport":4}],2:[function(require,module,exports){
"use strict";
/**
* @module enableAirPlay
*/
var hasAirPlayAPISupport = require('./lib/hasAirPlayAPISupport');
/**
* @private
* @param {object} the Video.js Player instance
* @returns {AirPlayButton} or `undefined` if it does not exist
*/
function getExistingAirPlayButton(player) {
return player.controlBar.getChild('airPlayButton');
}
/**
* Adds the AirPlayButton Component to the player's ControlBar component, if the
* AirPlayButton does not already exist in the ControlBar.
* @private
* @param player {object} the Video.js Player instance
* @param options {object}
*/
function ensureAirPlayButtonExists(player, options) {
var existingAirPlayButton = getExistingAirPlayButton(player),
indexOpt;
if (options.addButtonToControlBar && !existingAirPlayButton) {
// Figure out AirPlay button's index
indexOpt = player.controlBar.children().length;
if (typeof options.buttonPositionIndex !== 'undefined') {
indexOpt = options.buttonPositionIndex >= 0 ? options.buttonPositionIndex : player.controlBar.children().length + options.buttonPositionIndex;
}
player.controlBar.addChild('airPlayButton', options, indexOpt);
}
}
/**
* Handles requests for AirPlay triggered by the AirPlayButton Component.
*
* @private
* @param player {object} the Video.js Player instance
*/
function onAirPlayRequested(player) {
var mediaEl = player.el().querySelector('video, audio');
if (mediaEl && mediaEl.webkitShowPlaybackTargetPicker) {
mediaEl.webkitShowPlaybackTargetPicker();
}
}
/**
* Adds an event listener for the `airPlayRequested` event triggered by the AirPlayButton
* Component.
*
* @private
* @param player {object} the Video.js Player instance
*/
function listenForAirPlayEvents(player) {
// Respond to requests for AirPlay. The AirPlayButton component triggers this event
// when the user clicks the AirPlay button.
player.on('airPlayRequested', onAirPlayRequested.bind(null, player));
}
/**
* Sets up the AirPlay plugin.
*
* @private
* @param player {object} the Video.js player
* @param options {object} the plugin options
*/
function enableAirPlay(player, options) {
if (!player.controlBar) {
return;
}
if (hasAirPlayAPISupport()) {
listenForAirPlayEvents(player);
ensureAirPlayButtonExists(player, options);
}
}
/**
* Registers the AirPlay plugin with Video.js. Calls
* {@link http://docs.videojs.com/module-videojs.html#~registerPlugin|videojs#registerPlugin},
* which will add a plugin function called `airPlay` to any instance of a Video.js player
* that is created after calling this function. Call `player.airPlay(options)`, passing in
* configuration options, to enable the AirPlay plugin on your Player instance.
*
* Currently, the only configuration option is:
*
* * **buttonText** - the text to display inside of the button component. By default,
* this text is hidden and is used for accessibility purposes.
*
* @param {object} videojs
* @see http://docs.videojs.com/module-videojs.html#~registerPlugin
*/
module.exports = function (videojs) {
videojs.registerPlugin('airPlay', function (options) {
var pluginOptions = Object.assign({
addButtonToControlBar: true
}, options || {});
// `this` is an instance of a Video.js Player.
// Wait until the player is "ready" so that the player's control bar component has
// been created.
this.ready(enableAirPlay.bind(this, this, pluginOptions));
});
};
},{"./lib/hasAirPlayAPISupport":4}],3:[function(require,module,exports){
"use strict";
var createAirPlayButton = require('./components/AirPlayButton'),
createAirPlayPlugin = require('./enableAirPlay');
/**
* @module index
*/
/**
* Registers the AirPlay plugin and AirPlayButton Component with Video.js. See
* {@link module:AirPlayButton} and {@link module:enableAirPlay} for more details about
* how the plugin and button are registered and configured.
*
* @param {object} videojs
* @see module:enableAirPlay
* @see module:AirPlayButton
*/
module.exports = function (videojs) {
videojs = videojs || window.videojs;
createAirPlayButton(videojs);
createAirPlayPlugin(videojs);
};
},{"./components/AirPlayButton":1,"./enableAirPlay":2}],4:[function(require,module,exports){
"use strict";
/**
* @module hasAirPlayAPISupport
*/
/**
* Returns whether or not the current browser environment supports AirPlay.
*
* @private
* @returns {boolean} true if AirPlay support is available
*/
module.exports = function () {
return !!window.WebKitPlaybackTargetAvailabilityEvent;
};
},{}],5:[function(require,module,exports){
"use strict";
/**
* This module is used as an entry point for the build system to bundle this plugin into a
* single javascript file that can be loaded by a script tag on a web page. The javascript
* file that is built assumes that `videojs` is available globally at `window.videojs`, so
* Video.js must be loaded **before** this plugin is loaded.
*
* Run `npm install` and then `grunt build` to build the plugin's bundled javascript
* file, as well as the CSS and image assets into the project's `./dist/` folder.
*
* @module standalone
*/
require('./index')();
},{"./index":3}]},{},[5]);

View File

@ -1 +1 @@
.vjs-airplay-button .vjs-icon-placeholder{background:url("ic_airplay_white_24px.svg") center center no-repeat;background-size:contain;display:inline-block;width:20px;height:20px}.vjs-airplay-button:hover{cursor:pointer}.vjs-airplay-button:hover .vjs-icon-placeholder{background-image:url("ic_airplay_white_24px.svg")} .vjs-airplay-button .vjs-icon-placeholder{background:url("ic_airplay_white_24px.svg") center center no-repeat;background-size:contain;display:inline-block;width:12px;height:12px}.vjs-airplay-button:hover{cursor:pointer}.vjs-airplay-button:hover .vjs-icon-placeholder{background-image:url("ic_airplay_white_24px.svg")}.vjs-airplay-button.vjs-airplay-button-lg:not(.vjs-hidden){display:flex;align-items:center;width:auto;padding:0 4px}.vjs-airplay-button.vjs-airplay-button-lg:not(.vjs-hidden) .vjs-airplay-button-label{flex-grow:1;margin-left:4px}.vjs-airplay-button.vjs-airplay-button-lg:not(.vjs-hidden) .vjs-icon-placeholder{flex-grow:1}

File diff suppressed because it is too large Load Diff

View File

@ -1,65 +1 @@
/** Silvermine Chromecast **/ .vjs-chromecast-button .vjs-icon-placeholder{background:url("ic_cast_white_24dp.png") center center no-repeat;background-size:contain;display:inline-block;width:12px;height:12px}.vjs-chromecast-button:hover{cursor:pointer}.vjs-chromecast-button:hover .vjs-icon-placeholder{background-image:url("ic_cast_white_24dp.png")}.vjs-chromecast-button.vjs-chromecast-casting-state .vjs-icon-placeholder{background-image:url("ic_cast_connected_white_24dp.png")}.vjs-chromecast-button.vjs-chromecast-casting-state:hover .vjs-icon-placeholder{background-image:url("ic_cast_connected_white_24dp.png")}.vjs-chromecast-button.vjs-chromecast-button-lg:not(.vjs-hidden){display:flex;align-items:center;width:auto;padding:0 4px}.vjs-chromecast-button.vjs-chromecast-button-lg:not(.vjs-hidden) .vjs-chromecast-button-label{flex-grow:1;margin-left:4px}.vjs-chromecast-button.vjs-chromecast-button-lg:not(.vjs-hidden) .vjs-icon-placeholder{flex-grow:1}.vjs-tech-chromecast{display:flex;flex-direction:column;justify-content:center;align-items:center;overflow:hidden}.vjs-tech-chromecast .vjs-tech-chromecast-poster::after{content:" ";display:block;height:2px;width:100px;background-color:#ccc;position:absolute;left:calc(50% - 50px)}.vjs-tech-chromecast .vjs-tech-chromecast-poster-img{max-height:180px;width:auto;border:2px solid #ccc}.vjs-tech-chromecast .vjs-tech-chromecast-poster-img.vjs-tech-chromecast-poster-img-empty{width:160px;height:90px}.vjs-tech-chromecast .vjs-tech-chromecast-title-container{position:absolute;bottom:50%;margin-bottom:100px;color:#ccc;text-align:center}.vjs-tech-chromecast .vjs-tech-chromecast-title{font-size:22px}.vjs-tech-chromecast .vjs-tech-chromecast-title.vjs-tech-chromecast-title-empty{display:none}.vjs-tech-chromecast .vjs-tech-chromecast-subtitle{font-size:18px;padding-top:.5em}.vjs-tech-chromecast .vjs-tech-chromecast-subtitle.vjs-tech-chromecast-subtitle-empty{display:none}
.vjs-chromecast-button .vjs-icon-placeholder {
background: url('ic_cast_white_24dp.png') center center no-repeat;
background-size: contain;
display: inline-block;
width: 20px;
height: 20px;
}
.vjs-chromecast-button:hover {
cursor: pointer;
}
.vjs-chromecast-button:hover .vjs-icon-placeholder {
background-image: url('ic_cast_white_24dp.png');
}
.vjs-chromecast-button.vjs-chromecast-casting-state .vjs-icon-placeholder {
background-image: url('ic_cast_connected_white_24dp.png');
}
.vjs-chromecast-button.vjs-chromecast-casting-state:hover .vjs-icon-placeholder {
background-image: url('ic_cast_connected_white_24dp.png');
}
.vjs-tech-chromecast {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
overflow: hidden;
}
.vjs-tech-chromecast .vjs-tech-chromecast-poster::after {
content: ' ';
display: block;
height: 2px;
width: 100px;
background-color: #cccccc;
position: absolute;
left: calc(50% - 50px);
}
.vjs-tech-chromecast .vjs-tech-chromecast-poster-img {
max-height: 180px;
width: auto;
border: 2px solid #cccccc;
}
.vjs-tech-chromecast .vjs-tech-chromecast-poster-img.vjs-tech-chromecast-poster-img-empty {
width: 160px;
height: 90px;
}
.vjs-tech-chromecast .vjs-tech-chromecast-title-container {
position: absolute;
bottom: 50%;
margin-bottom: 100px;
color: #cccccc;
text-align: center;
}
.vjs-tech-chromecast .vjs-tech-chromecast-title {
font-size: 22px;
}
.vjs-tech-chromecast .vjs-tech-chromecast-title.vjs-tech-chromecast-title-empty {
display: none;
}
.vjs-tech-chromecast .vjs-tech-chromecast-subtitle {
font-size: 18px;
padding-top: 0.5em;
}
.vjs-tech-chromecast .vjs-tech-chromecast-subtitle.vjs-tech-chromecast-subtitle-empty {
display: none;
}

File diff suppressed because it is too large Load Diff

View File

@ -1 +1 @@
.vjs-chromecast-button .vjs-icon-placeholder{background:url(ic_cast_white_24dp.png) center center no-repeat;background-size:contain;display:inline-block;width:20px;height:20px}.vjs-chromecast-button:hover{cursor:pointer}.vjs-chromecast-button:hover .vjs-icon-placeholder{background-image:url(ic_cast_white_24dp.png)}.vjs-chromecast-button.vjs-chromecast-casting-state .vjs-icon-placeholder{background-image:url(ic_cast_connected_white_24dp.png)}.vjs-chromecast-button.vjs-chromecast-casting-state:hover .vjs-icon-placeholder{background-image:url(ic_cast_connected_white_24dp.png)}.vjs-tech-chromecast{display:flex;flex-direction:column;justify-content:center;align-items:center;overflow:hidden}.vjs-tech-chromecast .vjs-tech-chromecast-poster::after{content:' ';display:block;height:2px;width:100px;background-color:#ccc;position:absolute;left:calc(50% - 50px)}.vjs-tech-chromecast .vjs-tech-chromecast-poster-img{max-height:180px;width:auto;border:2px solid #ccc}.vjs-tech-chromecast .vjs-tech-chromecast-poster-img.vjs-tech-chromecast-poster-img-empty{width:160px;height:90px}.vjs-tech-chromecast .vjs-tech-chromecast-title-container{position:absolute;bottom:50%;margin-bottom:100px;color:#ccc;text-align:center}.vjs-tech-chromecast .vjs-tech-chromecast-title{font-size:22px}.vjs-tech-chromecast .vjs-tech-chromecast-title.vjs-tech-chromecast-title-empty{display:none}.vjs-tech-chromecast .vjs-tech-chromecast-subtitle{font-size:18px;padding-top:.5em}.vjs-tech-chromecast .vjs-tech-chromecast-subtitle.vjs-tech-chromecast-subtitle-empty{display:none} .vjs-chromecast-button .vjs-icon-placeholder{background:url("ic_cast_white_24dp.png") center center no-repeat;background-size:contain;display:inline-block;width:12px;height:12px}.vjs-chromecast-button:hover{cursor:pointer}.vjs-chromecast-button:hover .vjs-icon-placeholder{background-image:url("ic_cast_white_24dp.png")}.vjs-chromecast-button.vjs-chromecast-casting-state .vjs-icon-placeholder{background-image:url("ic_cast_connected_white_24dp.png")}.vjs-chromecast-button.vjs-chromecast-casting-state:hover .vjs-icon-placeholder{background-image:url("ic_cast_connected_white_24dp.png")}.vjs-chromecast-button.vjs-chromecast-button-lg:not(.vjs-hidden){display:flex;align-items:center;width:auto;padding:0 4px}.vjs-chromecast-button.vjs-chromecast-button-lg:not(.vjs-hidden) .vjs-chromecast-button-label{flex-grow:1;margin-left:4px}.vjs-chromecast-button.vjs-chromecast-button-lg:not(.vjs-hidden) .vjs-icon-placeholder{flex-grow:1}.vjs-tech-chromecast{display:flex;flex-direction:column;justify-content:center;align-items:center;overflow:hidden}.vjs-tech-chromecast .vjs-tech-chromecast-poster::after{content:" ";display:block;height:2px;width:100px;background-color:#ccc;position:absolute;left:calc(50% - 50px)}.vjs-tech-chromecast .vjs-tech-chromecast-poster-img{max-height:180px;width:auto;border:2px solid #ccc}.vjs-tech-chromecast .vjs-tech-chromecast-poster-img.vjs-tech-chromecast-poster-img-empty{width:160px;height:90px}.vjs-tech-chromecast .vjs-tech-chromecast-title-container{position:absolute;bottom:50%;margin-bottom:100px;color:#ccc;text-align:center}.vjs-tech-chromecast .vjs-tech-chromecast-title{font-size:22px}.vjs-tech-chromecast .vjs-tech-chromecast-title.vjs-tech-chromecast-title-empty{display:none}.vjs-tech-chromecast .vjs-tech-chromecast-subtitle{font-size:18px;padding-top:.5em}.vjs-tech-chromecast .vjs-tech-chromecast-subtitle.vjs-tech-chromecast-subtitle-empty{display:none}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -82,15 +82,14 @@
liveui: true, liveui: true,
responsive: true, responsive: true,
fluid: true, fluid: true,
sources: [{ src: playerConfig.source, type: 'application/x-mpegURL' }], sources: [{ src: window.location.origin + '/' + playerConfig.source, type: 'application/x-mpegURL' }],
plugins: {
license: playerConfig.license
}
}; };
if (playerConfig.chromecast) { if (playerConfig.chromecast) {
config.techOrder = ["chromecast", "html5"]; config.techOrder = ["chromecast", "html5"];
config.plugins.chromecast = {}; config.plugins.chromecast = {
receiverApplicationId: 'CC1AD845'
};
} }
if (playerConfig.airplay) { if (playerConfig.airplay) {
@ -130,6 +129,8 @@
}, },
], ],
}); });
player.license(playerConfig.license);
} }
if (autoplay === true) { if (autoplay === true) {

View File

@ -6,25 +6,32 @@ var config = {
liveui: true, liveui: true,
responsive: true, responsive: true,
fluid: true, fluid: true,
// Needed to append the url orgin in order for the source to properly pass to the cast device // Needed to append the url origin in order for the source to properly pass to the cast device
sources: [{ src: playerConfig.source, type: 'application/x-mpegURL' }], sources: [{ src: window.location.origin + '/' + playerConfig.source, type: 'application/x-mpegURL' }],
plugins: { plugins: {},
license: playerConfig.license,
},
}; };
if (chromecast) { if (chromecast) {
config.techOrder = ['chromecast', 'html5']; config.techOrder = ['chromecast', 'html5'];
config.plugins.chromecast = {}; // Provide a default reciever application ID
} config.plugins.chromecast = {
receiverApplicationId: 'CC1AD845',
if (airplay) { };
config.plugins.airPlay = {};
} }
var player = videojs('player', config); var player = videojs('player', config);
player.ready(function () { player.ready(function () {
if (chromecast) {
player.chromecast();
}
if (airplay) {
player.airPlay();
}
player.license(playerConfig.license);
if (playerConfig.logo.image.length != 0) { if (playerConfig.logo.image.length != 0) {
var overlay = null; var overlay = null;

View File

@ -4,7 +4,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" href="favicon.ico" /> <link rel="icon" href="favicon.ico" />
<meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width" /> <meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#282728" />
<meta name="description" content="Restreamer Video-Streaming" /> <meta name="description" content="Restreamer Video-Streaming" />
<link rel="apple-touch-icon" href="logo192.png" /> <link rel="apple-touch-icon" href="logo192.png" />
<link rel="manifest" href="manifest.json" /> <link rel="manifest" href="manifest.json" />

View File

@ -20,6 +20,6 @@
], ],
"start_url": ".", "start_url": ".",
"display": "standalone", "display": "standalone",
"theme_color": "#000000", "theme_color": "#282728",
"background_color": "#ffffff" "background_color": "#282728"
} }

View File

@ -2,7 +2,6 @@ import React from 'react';
import { I18nProvider } from '@lingui/react'; import { I18nProvider } from '@lingui/react';
import { i18n } from '@lingui/core'; import { i18n } from '@lingui/core';
import * as plurals from 'make-plural/plurals';
import { messages as EN } from './locales/en/messages.js'; import { messages as EN } from './locales/en/messages.js';
import { messages as DA } from './locales/da/messages.js'; import { messages as DA } from './locales/da/messages.js';
@ -13,7 +12,7 @@ import { messages as FR } from './locales/fr/messages.js';
import { messages as IT } from './locales/it/messages.js'; import { messages as IT } from './locales/it/messages.js';
import { messages as KO } from './locales/ko/messages.js'; import { messages as KO } from './locales/ko/messages.js';
import { messages as PL } from './locales/pl/messages.js'; import { messages as PL } from './locales/pl/messages.js';
import { messages as PT } from './locales/pt/messages.js'; import { messages as PT } from './locales/pt-br/messages.js';
import { messages as RU } from './locales/ru/messages.js'; import { messages as RU } from './locales/ru/messages.js';
import { messages as SL } from './locales/sl/messages.js'; import { messages as SL } from './locales/sl/messages.js';
import { messages as TR } from './locales/tr/messages.js'; import { messages as TR } from './locales/tr/messages.js';
@ -21,21 +20,6 @@ import { messages as UK } from './locales/uk/messages.js';
import { messages as ZH } from './locales/zh-hans/messages.js'; import { messages as ZH } from './locales/zh-hans/messages.js';
import * as Storage from './utils/storage'; import * as Storage from './utils/storage';
i18n.loadLocaleData('en', { plurals: plurals.en });
i18n.loadLocaleData('da', { plurals: plurals.da });
i18n.loadLocaleData('de', { plurals: plurals.de });
i18n.loadLocaleData('el', { plurals: plurals.el });
i18n.loadLocaleData('es', { plurals: plurals.es });
i18n.loadLocaleData('fr', { plurals: plurals.fr });
i18n.loadLocaleData('it', { plurals: plurals.it });
i18n.loadLocaleData('ko', { plurals: plurals.ko });
i18n.loadLocaleData('pl', { plurals: plurals.pl });
i18n.loadLocaleData('pt', { plurals: plurals.pt });
i18n.loadLocaleData('ru', { plurals: plurals.ru });
i18n.loadLocaleData('sl', { plurals: plurals.sl });
i18n.loadLocaleData('tr', { plurals: plurals.tr });
i18n.loadLocaleData('uk', { plurals: plurals.tr });
i18n.loadLocaleData('zh-hans', { plurals: plurals.zh });
i18n.load({ i18n.load({
en: EN, en: EN,
da: DA, da: DA,
@ -46,7 +30,7 @@ i18n.load({
it: IT, it: IT,
ko: KO, ko: KO,
pl: PL, pl: PL,
pt: PT, 'pt-br': PT,
ru: RU, ru: RU,
sl: SL, sl: SL,
tr: TR, tr: TR,
@ -55,7 +39,7 @@ i18n.load({
}); });
const aliases = { const aliases = {
'pt-br': 'pt', pt: 'pt-br',
'zh-cn': 'zh-hans', 'zh-cn': 'zh-hans',
}; };
@ -93,7 +77,7 @@ const getBrowserLanguage = (defaultLanguage) => {
return match[0].toLowerCase(); return match[0].toLowerCase();
}; };
i18n.activate(getLanguage('en', ['en', 'da', 'de', 'el', 'es', 'fr', 'it', 'ko', 'pl', 'pt', 'ru', 'sl', 'tr', 'uk', 'zh-hans'])); i18n.activate(getLanguage('en', ['en', 'da', 'de', 'el', 'es', 'fr', 'it', 'ko', 'pl', 'pt-br', 'ru', 'sl', 'tr', 'uk', 'zh-hans']));
export default function Provider(props) { export default function Provider(props) {
return <I18nProvider i18n={i18n}>{props.children}</I18nProvider>; return <I18nProvider i18n={i18n}>{props.children}</I18nProvider>;

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -155,14 +155,14 @@ export default function EncodingSelect(props) {
encoderList.push( encoderList.push(
<MenuItem value={c.coder} key={c.coder}> <MenuItem value={c.coder} key={c.coder}>
{c.name} {c.name}
</MenuItem> </MenuItem>,
); );
} }
} else { } else {
encoderList.push( encoderList.push(
<MenuItem value={c.coder} key={c.coder}> <MenuItem value={c.coder} key={c.coder}>
{c.name} {c.name}
</MenuItem> </MenuItem>,
); );
} }
} }
@ -195,7 +195,7 @@ export default function EncodingSelect(props) {
decoderList.push( decoderList.push(
<MenuItem value={c.coder} key={c.coder}> <MenuItem value={c.coder} key={c.coder}>
{c.name} {c.name}
</MenuItem> </MenuItem>,
); );
} }
} }

View File

@ -91,7 +91,7 @@ export default function FilterSelect(props) {
} }
filterSettings.push( filterSettings.push(
<Settings key={c.filter} settings={profile.filter.settings[c.filter].settings} onChange={handleFilterSettingsChange(c.filter)} /> <Settings key={c.filter} settings={profile.filter.settings[c.filter].settings} onChange={handleFilterSettingsChange(c.filter)} />,
); );
} }
} }

View File

@ -15,16 +15,9 @@ const MenuProps = {
export default function Component(props) { export default function Component(props) {
return ( return (
<FormControl variant="outlined" fullWidth> <FormControl variant={props.variant} disabled={props.disabled} fullWidth>
<InputLabel>{props.label}</InputLabel> <InputLabel>{props.label}</InputLabel>
<Select <Select multiple value={props.value} onChange={props.onChange} input={<OutlinedInput />} renderValue={props.renderValue} MenuProps={MenuProps}>
multiple
value={props.value}
onChange={props.onChange}
input={<OutlinedInput />}
renderValue={(selected) => selected.join(', ')}
MenuProps={MenuProps}
>
{props.children} {props.children}
</Select> </Select>
</FormControl> </FormControl>
@ -32,7 +25,10 @@ export default function Component(props) {
} }
Component.defaultProps = { Component.defaultProps = {
variant: 'outlined',
label: '', label: '',
value: [], value: [],
disabled: false,
renderValue: (selected) => selected.join(', '),
onChange: function (event) {}, onChange: function (event) {},
}; };

View File

@ -28,6 +28,8 @@ function init(props) {
drop: 0, drop: 0,
dup: 0, dup: 0,
frames: 0, frames: 0,
cpu: 0,
memory: 0,
...props, ...props,
}; };
@ -54,6 +56,32 @@ export default function Progress(props) {
<Grid item xs={12}> <Grid item xs={12}>
<Divider /> <Divider />
</Grid> </Grid>
<Grid item xs={12}>
<Typography variant="h4">
<strong>
<Number value={progress.cpu} digits={2} minDigits={2} />%
</strong>
</Typography>
<Typography variant="body2" gutterBottom>
<Trans>CPU</Trans>
</Typography>
</Grid>
<Grid item xs={12}>
<Divider />
</Grid>
<Grid item xs={12}>
<Typography variant="h4">
<strong>
<Number value={progress.memory / 1024 / 1024} digits={0} minDigits={0} /> MB
</strong>
</Typography>
<Typography variant="body2" gutterBottom>
<Trans>Memory</Trans>
</Typography>
</Grid>
<Grid item xs={12}>
<Divider />
</Grid>
<Grid item xs={12}> <Grid item xs={12}>
<Typography variant="h4"> <Typography variant="h4">
<strong> <strong>

View File

@ -41,7 +41,11 @@ export default function Component(props) {
isCustom: v === props.customKey ? true : false, isCustom: v === props.customKey ? true : false,
}); });
props.onChange(event); props.onChange({
target: {
value: v === props.customKey ? value.custom : value.value,
},
});
}; };
const handleCustomChange = (event) => { const handleCustomChange = (event) => {
@ -59,7 +63,7 @@ export default function Component(props) {
options.push( options.push(
<MenuItem key={o.value} value={o.value} disabled={o.disabled === true}> <MenuItem key={o.value} value={o.value} disabled={o.disabled === true}>
{o.label} {o.label}
</MenuItem> </MenuItem>,
); );
} }

View File

@ -17,6 +17,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [], global: [],
local: [], local: [],
filter: [],
}; };
return mapping; return mapping;

View File

@ -1,21 +1,22 @@
import * as AudioDefault from './audio/Default'; import * as AudioDefault from './audio/default';
import * as NVDEC from './video/NVDEC'; import * as NVDEC from './video/nvdec';
import * as H264MMAL from './video/H264MMAL'; import * as H264MMAL from './video/h264_mmal';
import * as H264CUVID from './video/H264CUVID'; import * as H264CUVID from './video/h264_cuvid';
import * as HEVCCUVID from './video/HEVCCUVID'; import * as HEVCCUVID from './video/hevc_cuvid';
import * as MJPEGCUVID from './video/MJPEGCUVID'; import * as MJPEGCUVID from './video/mjpeg_cuvid';
import * as MPEG1CUVID from './video/MPEG1CUVID'; import * as MPEG1CUVID from './video/mpeg1_cuvid';
import * as MPEG2CUVID from './video/MPEG2CUVID'; import * as MPEG2CUVID from './video/mpeg2_cuvid';
import * as MPEG2MMAL from './video/MPEG2MMAL'; import * as MPEG2MMAL from './video/mpeg2_mmal';
import * as MPEG4CUVID from './video/MPEG4CUVID'; import * as MPEG4CUVID from './video/mpeg4_cuvid';
import * as MPEG4MMAL from './video/MPEG4MMAL'; import * as MPEG4MMAL from './video/mpeg4_mmal';
import * as VC1CUVID from './video/VC1CUVID'; import * as VC1CUVID from './video/vc1_cuvid';
import * as VC1MMAL from './video/VC1MMAL'; import * as VC1MMAL from './video/vc1_mmal';
import * as VideoDefault from './video/Default'; import * as VideoDefault from './video/default';
import * as VideoToolbox from './video/VideoToolbox'; import * as VideoToolbox from './video/videotoolbox';
import * as VP8CUVID from './video/VP8CUVID'; import * as VP8CUVID from './video/vp8_cuvid';
import * as VP9CUVID from './video/VP9CUVID'; import * as VP9CUVID from './video/vp9_cuvid';
import * as AV1CUVID from './video/av1_cuvid';
class Registry { class Registry {
constructor(type) { constructor(type) {
@ -112,6 +113,7 @@ const videoRegistry = new Registry('video');
videoRegistry.Register(VideoDefault); videoRegistry.Register(VideoDefault);
videoRegistry.Register(VideoToolbox); videoRegistry.Register(VideoToolbox);
videoRegistry.Register(AV1CUVID);
videoRegistry.Register(NVDEC); videoRegistry.Register(NVDEC);
videoRegistry.Register(H264MMAL); videoRegistry.Register(H264MMAL);
videoRegistry.Register(H264CUVID); videoRegistry.Register(H264CUVID);

View File

@ -0,0 +1,73 @@
import React from 'react';
import Helper from '../../helper';
function init(initialState) {
const state = {
...initialState,
};
return state;
}
function createMapping(settings, stream, skills) {
stream = Helper.InitStream(stream);
skills = Helper.InitSkills(skills);
const mapping = {
global: [],
local: ['-hwaccel', 'cuda', '-c:v', 'av1_cuvid'],
filter: [],
};
return mapping;
}
function Coder(props) {
const settings = init(props.settings);
const stream = Helper.InitStream(props.stream);
const skills = Helper.InitSkills(props.skills);
const handleChange = (newSettings) => {
let automatic = false;
if (!newSettings) {
newSettings = settings;
automatic = true;
}
props.onChange(newSettings, createMapping(newSettings, stream, skills), automatic);
};
React.useEffect(() => {
handleChange(null);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return null;
}
Coder.defaultProps = {
stream: {},
settings: {},
skills: {},
onChange: function (settings, mapping) {},
};
// -hwaccel nvdec
const coder = 'av1_cuvid';
const name = 'AV1 (CUVID)';
const codecs = ['av1'];
const type = 'video';
const hwaccel = true;
function defaults(stream, skills) {
const settings = init({});
return {
settings: settings,
mapping: createMapping(settings, stream, skills),
};
}
export { coder, name, codecs, type, hwaccel, defaults, Coder as component };

View File

@ -17,6 +17,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [], global: [],
local: [], local: [],
filter: [],
}; };
return mapping; return mapping;

View File

@ -17,6 +17,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [], global: [],
local: ['-c:v', 'h264_cuvid'], local: ['-c:v', 'h264_cuvid'],
filter: [],
}; };
return mapping; return mapping;

View File

@ -17,6 +17,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [], global: [],
local: ['-c:v', 'h264_mmal'], local: ['-c:v', 'h264_mmal'],
filter: [],
}; };
return mapping; return mapping;

View File

@ -17,6 +17,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [], global: [],
local: ['-c:v', 'hevc_cuvid'], local: ['-c:v', 'hevc_cuvid'],
filter: [],
}; };
return mapping; return mapping;

View File

@ -17,6 +17,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [], global: [],
local: ['-c:v', 'mjpeg_cuvid'], local: ['-c:v', 'mjpeg_cuvid'],
filter: [],
}; };
return mapping; return mapping;

View File

@ -17,6 +17,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [], global: [],
local: ['-c:v', 'mpeg1_cuvid'], local: ['-c:v', 'mpeg1_cuvid'],
filter: [],
}; };
return mapping; return mapping;

View File

@ -17,6 +17,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [], global: [],
local: ['-c:v', 'mpeg2_cuvid'], local: ['-c:v', 'mpeg2_cuvid'],
filter: [],
}; };
return mapping; return mapping;

View File

@ -17,6 +17,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [], global: [],
local: ['-c:v', 'mpeg2_mmal'], local: ['-c:v', 'mpeg2_mmal'],
filter: [],
}; };
return mapping; return mapping;

View File

@ -17,6 +17,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [], global: [],
local: ['-c:v', 'mpeg4_cuvid'], local: ['-c:v', 'mpeg4_cuvid'],
filter: [],
}; };
return mapping; return mapping;

View File

@ -17,6 +17,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [], global: [],
local: ['-c:v', 'mpeg4_mmal'], local: ['-c:v', 'mpeg4_mmal'],
filter: [],
}; };
return mapping; return mapping;

View File

@ -17,6 +17,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [], global: [],
local: ['-hwaccel', 'cuda', '-hwaccel_output_format', 'cuda'], local: ['-hwaccel', 'cuda', '-hwaccel_output_format', 'cuda'],
filter: [],
}; };
return mapping; return mapping;

View File

@ -17,6 +17,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [], global: [],
local: ['-c:v', 'vc1_cuvid'], local: ['-c:v', 'vc1_cuvid'],
filter: [],
}; };
return mapping; return mapping;

View File

@ -17,6 +17,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [], global: [],
local: ['-c:v', 'vc1_mmal'], local: ['-c:v', 'vc1_mmal'],
filter: [],
}; };
return mapping; return mapping;

View File

@ -17,6 +17,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [], global: [],
local: ['-hwaccel', 'videotoolbox'], local: ['-hwaccel', 'videotoolbox'],
filter: [],
}; };
return mapping; return mapping;
@ -53,8 +54,8 @@ Coder.defaultProps = {
}; };
const coder = 'videotoolbox'; const coder = 'videotoolbox';
const name = 'H264 (VideoToolbox)'; const name = 'VideoToolbox';
const codecs = ['h264']; const codecs = ['h264', 'hevc', 'vp9', 'mpeg1', 'mpeg2', 'mpeg4'];
const type = 'video'; const type = 'video';
const hwaccel = true; const hwaccel = true;

View File

@ -17,6 +17,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [], global: [],
local: ['-c:v', 'vp8_cuvid'], local: ['-c:v', 'vp8_cuvid'],
filter: [],
}; };
return mapping; return mapping;

View File

@ -17,6 +17,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [], global: [],
local: ['-c:v', 'vp9_cuvid'], local: ['-c:v', 'vp9_cuvid'],
filter: [],
}; };
return mapping; return mapping;

View File

@ -27,6 +27,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [], global: [],
local: local, local: local,
filter: [],
}; };
return mapping; return mapping;

View File

@ -27,6 +27,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [['-vsync', 'drop']], global: [['-vsync', 'drop']],
local: local, local: local,
filter: [],
}; };
return mapping; return mapping;

View File

@ -15,6 +15,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [], global: [],
local: local, local: local,
filter: [],
}; };
return mapping; return mapping;

View File

@ -24,6 +24,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [['-vsync', 'drop']], global: [['-vsync', 'drop']],
local: local, local: local,
filter: [],
}; };
return mapping; return mapping;

View File

@ -11,6 +11,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [], global: [],
local: local, local: local,
filter: [],
}; };
return mapping; return mapping;

View File

@ -7,7 +7,7 @@ import { useLingui } from '@lingui/react';
import { Trans, t } from '@lingui/macro'; import { Trans, t } from '@lingui/macro';
import Audio from '../../settings/Audio'; import Audio from '../../settings/Audio';
import SelectCustom from '../../../../misc/SelectCustom'; import SelectCustom from '../../../SelectCustom';
import Helper from '../../helper'; import Helper from '../../helper';
function init(initialState) { function init(initialState) {
@ -44,6 +44,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [['-vsync', 'drop']], global: [['-vsync', 'drop']],
local: local, local: local,
filter: [],
}; };
return mapping; return mapping;

View File

@ -23,6 +23,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [], global: [],
local: local, local: local,
filter: [],
}; };
return mapping; return mapping;

View File

@ -23,6 +23,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [['-vsync', 'drop']], global: [['-vsync', 'drop']],
local: local, local: local,
filter: [],
}; };
return mapping; return mapping;

View File

@ -23,6 +23,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [['-vsync', 'drop']], global: [['-vsync', 'drop']],
local: local, local: local,
filter: [],
}; };
return mapping; return mapping;

View File

@ -1,26 +1,28 @@
import * as AudioCopy from './audio/Copy'; import * as AudioCopy from './audio/copy';
import * as AudioNone from './audio/None'; import * as AudioNone from './audio/none';
import * as AAC from './audio/AAC'; import * as AAC from './audio/aac';
import * as AACAudioToolbox from './audio/AACAudioToolbox'; import * as AACAudioToolbox from './audio/aac_audiotoolbox';
import * as Libopus from './audio/Libopus'; import * as Libopus from './audio/opus_libopus';
import * as Libvorbis from './audio/Libvorbis'; import * as Libvorbis from './audio/vorbis_libvorbis';
import * as MP3 from './audio/MP3'; import * as MP3 from './audio/mp3_libmp3lame';
import * as Opus from './audio/Opus'; import * as Opus from './audio/opus';
import * as Vorbis from './audio/Vorbis'; import * as Vorbis from './audio/vorbis';
import * as X264 from './video/X264'; import * as X264 from './video/h264_libx264';
import * as X265 from './video/X265'; import * as X265 from './video/hevc_libx265';
import * as H264VideoToolbox from './video/H264VideoToolbox'; import * as H264VideoToolbox from './video/h264_videotoolbox';
import * as H264NVENC from './video/H264NVENC'; import * as H264NVENC from './video/h264_nvenc';
import * as H264OMX from './video/H264OMX'; import * as H264OMX from './video/h264_omx';
import * as H264V4L2M2M from './video/H264V4L2M2M'; import * as H264V4L2M2M from './video/h264_v4l2m2m';
import * as H264VAAPI from './video/H264VAAPI'; import * as H264VAAPI from './video/h264_vaapi';
import * as HEVCVAAPI from './video/HEVCVAAPI'; import * as HEVCVAAPI from './video/hevc_vaapi';
import * as VP9VAAPI from './video/VP9VAAPI'; import * as HEVCVideoToolbox from './video/hevc_videotoolbox';
import * as VideoCopy from './video/Copy'; import * as VP9VAAPI from './video/vp9_vaapi';
import * as VideoNone from './video/None'; import * as VideoCopy from './video/copy';
import * as VideoRaw from './video/Raw'; import * as VideoNone from './video/none';
import * as VP9 from './video/VP9'; import * as VideoRaw from './video/rawvideo';
import * as VP9 from './video/vp9_libvpx';
import * as AV1Rav1e from './video/av1_librav1e';
class Registry { class Registry {
constructor(type) { constructor(type) {
@ -123,15 +125,17 @@ const videoRegistry = new Registry('video');
videoRegistry.Register(VideoCopy); videoRegistry.Register(VideoCopy);
videoRegistry.Register(VideoNone); videoRegistry.Register(VideoNone);
videoRegistry.Register(X264); videoRegistry.Register(X264);
videoRegistry.Register(X265);
videoRegistry.Register(H264VideoToolbox); videoRegistry.Register(H264VideoToolbox);
videoRegistry.Register(H264NVENC); videoRegistry.Register(H264NVENC);
videoRegistry.Register(H264OMX); videoRegistry.Register(H264OMX);
videoRegistry.Register(H264V4L2M2M); videoRegistry.Register(H264V4L2M2M);
videoRegistry.Register(H264VAAPI); videoRegistry.Register(H264VAAPI);
videoRegistry.Register(X265);
videoRegistry.Register(HEVCVAAPI); videoRegistry.Register(HEVCVAAPI);
videoRegistry.Register(HEVCVideoToolbox);
videoRegistry.Register(VP9VAAPI); videoRegistry.Register(VP9VAAPI);
videoRegistry.Register(VP9); videoRegistry.Register(VP9);
videoRegistry.Register(AV1Rav1e);
videoRegistry.Register(VideoRaw); videoRegistry.Register(VideoRaw);
export { audioRegistry as Audio, videoRegistry as Video }; export { audioRegistry as Audio, videoRegistry as Video };

View File

@ -0,0 +1,256 @@
import React from 'react';
import Grid from '@mui/material/Grid';
import MenuItem from '@mui/material/MenuItem';
import TextField from '@mui/material/TextField';
import Typography from '@mui/material/Typography';
import { Trans } from '@lingui/macro';
import Select from '../../../Select';
import Video from '../../settings/Video';
import Helper from '../../helper';
function init(initialState) {
const state = {
bitrate: '4096',
fps: '25',
fps_mode: 'auto',
gop: '2',
qp: '-1',
speed: '-1',
tiles: '0',
tile_rows: '0',
tile_columns: '0',
params: '',
...initialState,
};
return state;
}
function createMapping(settings, stream, skills) {
stream = Helper.InitStream(stream);
skills = Helper.InitSkills(skills);
const local = [
'-codec:v',
'librav1e',
'-b:v',
`${settings.bitrate}k`,
'-maxrate:v',
`${settings.bitrate}k`,
'-bufsize:v',
`${settings.bitrate}k`,
'-r',
`${settings.fps}`,
'-pix_fmt',
'yuv420p',
'-qp',
`${settings.qp}`,
'-speed',
`${settings.speed}`,
'-tiles',
`${settings.tiles}`,
'-tile-rows',
`${settings.tile_rows}`,
'-tile-columns',
`${settings.tile_columns}`,
];
if (settings.params.length !== 0) {
local.push('-rav1e-params', `${settings.params}`);
}
if (settings.gop !== 'auto') {
local.push(
'-g',
`${Math.round(parseInt(settings.fps) * parseInt(settings.gop)).toFixed(0)}`,
'-keyint_min',
`${Math.round(parseInt(settings.fps) * parseInt(settings.gop)).toFixed(0)}`,
);
}
if (skills.ffmpeg.version_major >= 5) {
local.push('-fps_mode', `${settings.fps_mode}`);
}
const mapping = {
global: [],
local: local,
filter: [],
};
return mapping;
}
function Speed(props) {
return (
<React.Fragment>
<Select label={<Trans>Speed Preset</Trans>} value={props.value} onChange={props.onChange}>
<MenuItem value="-1">auto (-1)</MenuItem>
<MenuItem value="0">slowest (0)</MenuItem>
<MenuItem value="1">1</MenuItem>
<MenuItem value="2">2</MenuItem>
<MenuItem value="3">3</MenuItem>
<MenuItem value="4">4</MenuItem>
<MenuItem value="5">5</MenuItem>
<MenuItem value="6">6</MenuItem>
<MenuItem value="7">7</MenuItem>
<MenuItem value="8">8</MenuItem>
<MenuItem value="9">9</MenuItem>
<MenuItem value="10">fastest (10)</MenuItem>
</Select>
<Typography variant="caption">
<Trans>What speed preset to use.</Trans>
</Typography>
</React.Fragment>
);
}
Speed.defaultProps = {
value: '-1',
onChange: function (event) {},
};
function Coder(props) {
const settings = init(props.settings);
const stream = Helper.InitStream(props.stream);
const skills = Helper.InitSkills(props.skills);
const handleChange = (newSettings) => {
let automatic = false;
if (!newSettings) {
newSettings = settings;
automatic = true;
}
props.onChange(newSettings, createMapping(newSettings, stream, skills), automatic);
};
const update = (what) => (event) => {
const newSettings = {
...settings,
[what]: event.target.value,
};
handleChange(newSettings);
};
React.useEffect(() => {
handleChange(null);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<Grid container spacing={2}>
<Grid item xs={12}>
<Video.Bitrate value={settings.bitrate} onChange={update('bitrate')} allowCustom />
</Grid>
<Grid item xs={12} md={6}>
<Video.Framerate value={settings.fps} onChange={update('fps')} allowCustom />
</Grid>
<Grid item xs={12} md={6}>
<Video.GOP value={settings.gop} onChange={update('gop')} allowAuto allowCustom />
</Grid>
{skills.ffmpeg.version_major >= 5 && (
<Grid item xs={12}>
<Video.FpsMode value={settings.fps_mode} onChange={update('fps_mode')} />
</Grid>
)}
<Grid item xs={6}>
<Speed value={settings.speed} onChange={update('speed')} />
</Grid>
<Grid item xs={6}>
<TextField
variant="outlined"
fullWidth
type="number"
inputProps={{ min: -1, max: 255 }}
label={<Trans>QP</Trans>}
value={settings.qp}
onChange={update('qp')}
/>
<Typography variant="caption">
<Trans>Constant Quantizer Mode (-1 to 255).</Trans>
</Typography>
</Grid>
<Grid item xs={4}>
<TextField
variant="outlined"
fullWidth
type="number"
inputProps={{ min: -1 }}
label={<Trans>Tiles</Trans>}
value={settings.tiles}
onChange={update('tiles')}
/>
<Typography variant="caption">
<Trans>Number of tiles encode with.</Trans>
</Typography>
</Grid>
<Grid item xs={4}>
<TextField
variant="outlined"
fullWidth
type="number"
inputProps={{ min: -1 }}
label={<Trans>Tile Rows</Trans>}
value={settings.tile_rows}
onChange={update('tile_rows')}
/>
<Typography variant="caption">
<Trans>Number of tiles rows to encode with.</Trans>
</Typography>
</Grid>
<Grid item xs={4}>
<TextField
variant="outlined"
fullWidth
type="number"
inputProps={{ min: -1 }}
label={<Trans>Tile Columns</Trans>}
value={settings.tile_columns}
onChange={update('tile_columns')}
/>
<Typography variant="caption">
<Trans>Number of tiles columns to encode with.</Trans>
</Typography>
</Grid>
<Grid item xs={12}>
<TextField variant="outlined" fullWidth label={<Trans>rav1e Parameters</Trans>} value={settings.params} onChange={update('params')} />
<Typography variant="caption">
<Trans>Set the rav1e configuration using a :-separated list of key=value parameters.</Trans>
</Typography>
</Grid>
</Grid>
);
}
Coder.defaultProps = {
stream: {},
settings: {},
skills: {},
onChange: function (settings, mapping) {},
};
const coder = 'librav1e';
const name = 'AV1 (librav1e)';
const codec = 'av1';
const type = 'video';
const hwaccel = false;
function summarize(settings) {
return `${name}, ${settings.bitrate} kbit/s, ${settings.fps} FPS, Speed: ${settings.speed}, QP: ${settings.qp}`;
}
function defaults(stream, skills) {
const settings = init({});
return {
settings: settings,
mapping: createMapping(settings, stream, skills),
};
}
export { coder, name, codec, type, hwaccel, summarize, defaults, Coder as component };

View File

@ -11,6 +11,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [], global: [],
local: local, local: local,
filter: [],
}; };
return mapping; return mapping;

View File

@ -1,5 +1,4 @@
import React from 'react'; import React from 'react';
import SemverSatisfies from 'semver/functions/satisfies';
import Grid from '@mui/material/Grid'; import Grid from '@mui/material/Grid';
import MenuItem from '@mui/material/MenuItem'; import MenuItem from '@mui/material/MenuItem';
@ -29,11 +28,6 @@ function createMapping(settings, stream, skills) {
stream = Helper.InitStream(stream); stream = Helper.InitStream(stream);
skills = Helper.InitSkills(skills); skills = Helper.InitSkills(skills);
let ffversion = 4;
if (SemverSatisfies(skills.ffmpeg.version, '^5.0.0')) {
ffversion = 5;
}
const local = [ const local = [
'-codec:v', '-codec:v',
'libx264', 'libx264',
@ -58,11 +52,11 @@ function createMapping(settings, stream, skills) {
'-g', '-g',
`${Math.round(parseInt(settings.fps) * parseInt(settings.gop)).toFixed(0)}`, `${Math.round(parseInt(settings.fps) * parseInt(settings.gop)).toFixed(0)}`,
'-keyint_min', '-keyint_min',
`${Math.round(parseInt(settings.fps) * parseInt(settings.gop)).toFixed(0)}` `${Math.round(parseInt(settings.fps) * parseInt(settings.gop)).toFixed(0)}`,
); );
} }
if (ffversion === 5) { if (skills.ffmpeg.version_major >= 5) {
local.push('-fps_mode', `${settings.fps_mode}`); local.push('-fps_mode', `${settings.fps_mode}`);
} }
@ -77,6 +71,7 @@ function createMapping(settings, stream, skills) {
const mapping = { const mapping = {
global: [], global: [],
local: local, local: local,
filter: [],
}; };
return mapping; return mapping;
@ -127,11 +122,6 @@ function Coder(props) {
const stream = Helper.InitStream(props.stream); const stream = Helper.InitStream(props.stream);
const skills = Helper.InitSkills(props.skills); const skills = Helper.InitSkills(props.skills);
let ffversion = 4;
if (SemverSatisfies(skills.ffmpeg.version, '^5.0.0')) {
ffversion = 5;
}
const handleChange = (newSettings) => { const handleChange = (newSettings) => {
let automatic = false; let automatic = false;
if (!newSettings) { if (!newSettings) {
@ -167,7 +157,7 @@ function Coder(props) {
<Grid item xs={12} md={6}> <Grid item xs={12} md={6}>
<Video.GOP value={settings.gop} onChange={update('gop')} allowAuto allowCustom /> <Video.GOP value={settings.gop} onChange={update('gop')} allowAuto allowCustom />
</Grid> </Grid>
{ffversion === 5 && ( {skills.ffmpeg.version_major >= 5 && (
<Grid item xs={12}> <Grid item xs={12}>
<Video.FpsMode value={settings.fps_mode} onChange={update('fps_mode')} /> <Video.FpsMode value={settings.fps_mode} onChange={update('fps_mode')} />
</Grid> </Grid>

Some files were not shown because too many files have changed in this diff Show More