diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml index 7f253602d..e1e85431b 100644 --- a/.github/workflows/shellcheck.yml +++ b/.github/workflows/shellcheck.yml @@ -26,5 +26,5 @@ jobs: run: apt update && apt install -y shellcheck bash && shellcheck --version - name: Check shell scripts - run: shopt -s globstar && ls **/*.sh && shellcheck --severity=info **/*.sh + run: shopt -s globstar && ls **/*.sh && shellcheck -x -P "SCRIPTDIR" --severity=info **/*.sh shell: bash diff --git a/Earthfile b/Earthfile index 810779018..a2728115b 100644 --- a/Earthfile +++ b/Earthfile @@ -133,7 +133,7 @@ unit-tests: api-tests: FROM --platform=linux/amd64 bdwyertech/go-crosscompile - RUN apk add ffmpeg npm + RUN apk add npm font-noto && fc-cache -f COPY . /build WORKDIR /build/test/automated/api RUN npm install diff --git a/core/transcoder/transcoder.go b/core/transcoder/transcoder.go index fe162353b..57dbd4b9f 100644 --- a/core/transcoder/transcoder.go +++ b/core/transcoder/transcoder.go @@ -132,7 +132,7 @@ func (t *Transcoder) Start() { } if err := _commandExec.Start(); err != nil { - log.Errorln("Transcoder error. See ", logging.GetTranscoderLogFilePath(), " for full output to debug.") + log.Errorln("Transcoder error. See", logging.GetTranscoderLogFilePath(), "for full output to debug.") log.Panicln(err, command) } @@ -150,7 +150,7 @@ func (t *Transcoder) Start() { } if err != nil { - log.Errorln("transcoding error. look at ", logging.GetTranscoderLogFilePath(), " to help debug. your copy of ffmpeg may not support your selected codec of", t.codec.Name(), "https://owncast.online/docs/codecs/") + log.Errorln("transcoding error. look at", logging.GetTranscoderLogFilePath(), "to help debug. your copy of ffmpeg may not support your selected codec of", t.codec.Name(), "https://owncast.online/docs/codecs/") } } diff --git a/test/automated/api/configmanagement.test.js b/test/automated/api/configmanagement.test.js index 77ef73c06..c2481082c 100644 --- a/test/automated/api/configmanagement.test.js +++ b/test/automated/api/configmanagement.test.js @@ -374,10 +374,9 @@ test('verify updated config values', async (done) => { test('verify admin stream details', async (done) => { const res = await getAdminResponse('status'); - expect(res.body.broadcaster.streamDetails.width).toBe(320); - expect(res.body.broadcaster.streamDetails.height).toBe(180); - expect(res.body.broadcaster.streamDetails.framerate).toBe(24); - expect(res.body.broadcaster.streamDetails.videoBitrate).toBe(1269); + expect(res.body.broadcaster.streamDetails.width).toBe(1280); + expect(res.body.broadcaster.streamDetails.height).toBe(720); + expect(res.body.broadcaster.streamDetails.framerate).toBe(60); expect(res.body.broadcaster.streamDetails.videoCodec).toBe('H.264'); expect(res.body.broadcaster.streamDetails.audioCodec).toBe('AAC'); expect(res.body.online).toBe(true); diff --git a/test/automated/api/run.sh b/test/automated/api/run.sh index 59979ffab..716c9bdb5 100755 --- a/test/automated/api/run.sh +++ b/test/automated/api/run.sh @@ -1,19 +1,13 @@ #!/bin/bash +source ../tools.sh + TEMP_DB=$(mktemp) # Install the node test framework npm install --quiet --no-progress -# Download a specific version of ffmpeg -if [ ! -d "ffmpeg" ]; then - mkdir ffmpeg - pushd ffmpeg >/dev/null || exit - curl -sL https://github.com/vot/ffbinaries-prebuilt/releases/download/v4.2.1/ffmpeg-4.2.1-linux-64.zip --output ffmpeg.zip >/dev/null - unzip -o ffmpeg.zip >/dev/null - PATH=$PATH:$(pwd) - popd >/dev/null || exit -fi +ffmpegInstall pushd ../../.. >/dev/null || exit @@ -27,12 +21,12 @@ sleep 5 # Start streaming the test file over RTMP to # the local owncast instance. -ffmpeg -hide_banner -loglevel panic -stream_loop -1 -re -i ../test.mp4 -vcodec libx264 -profile:v main -sc_threshold 0 -b:v 1300k -acodec copy -f flv rtmp://127.0.0.1/live/abc123 & +../../ocTestStream.sh & FFMPEG_PID=$! function finish { - rm "$TEMP_DB" kill $SERVER_PID $FFMPEG_PID + rm -fr "$TEMP_DB" "$FFMPEG_PATH" } trap finish EXIT diff --git a/test/automated/browser/run.sh b/test/automated/browser/run.sh index 7c4a4eed1..249a3c628 100755 --- a/test/automated/browser/run.sh +++ b/test/automated/browser/run.sh @@ -3,6 +3,8 @@ set -o errexit set -o pipefail +source ../tools.sh + TEMP_DB=$(mktemp) BUILD_ID=$((RANDOM % 7200 + 600)) BROWSER="electron" # Default. Will try to use Google Chrome. @@ -38,16 +40,7 @@ fi set -o nounset -# Download a specific version of ffmpeg -if [ ! -d "ffmpeg" ]; then - echo "Downloading ffmpeg..." - mkdir -p /tmp/ffmpeg - pushd /tmp/ffmpeg >/dev/null - curl -sL --fail https://github.com/vot/ffbinaries-prebuilt/releases/download/v4.2.1/ffmpeg-4.2.1-linux-64.zip --output ffmpeg.zip - unzip -o ffmpeg.zip >/dev/null - PATH=$PATH:$(pwd) - popd >/dev/null -fi +ffmpegInstall # Build and run owncast from source echo "Building owncast..." @@ -67,13 +60,13 @@ npx cypress run --browser "$BROWSER" --group "mobile-offline" --ci-build-id $BUI # Start streaming the test file over RTMP to # the local owncast instance. echo "Waiting for stream to start..." -ffmpeg -hide_banner -loglevel panic -stream_loop -1 -re -i ../test.mp4 -vcodec libx264 -profile:v main -sc_threshold 0 -b:v 1300k -acodec copy -f flv rtmp://127.0.0.1/live/abc123 & +../../ocTestStream.sh & STREAMING_CLIENT=$! function finish { echo "Cleaning up..." - rm "$TEMP_DB" kill $SERVER_PID $STREAMING_CLIENT + rm -fr "$TEMP_DB" "$FFMPEG_PATH" } trap finish EXIT SIGHUP SIGINT SIGTERM SIGQUIT SIGABRT SIGTERM diff --git a/test/automated/hls/run.sh b/test/automated/hls/run.sh index 861b22284..ec4c48e83 100755 --- a/test/automated/hls/run.sh +++ b/test/automated/hls/run.sh @@ -2,12 +2,7 @@ set -e -function start_stream() { - # Start streaming the test file over RTMP to - # the local owncast instance. - ffmpeg -hide_banner -loglevel panic -stream_loop -1 -re -i ../test.mp4 -vcodec libx264 -profile:v main -sc_threshold 0 -b:v 1300k -acodec copy -f flv rtmp://127.0.0.1/live/abc123 & - STREAMING_CLIENT=$! -} +source ../tools.sh function update_storage_config() { echo "Configuring external storage to use ${S3_BUCKET}..." @@ -23,15 +18,7 @@ TEMP_DB=$(mktemp) # Install the node test framework npm install --silent >/dev/null -# Download a specific version of ffmpeg -if [ ! -d "ffmpeg" ]; then - mkdir ffmpeg - pushd ffmpeg >/dev/null - curl -sL https://github.com/vot/ffbinaries-prebuilt/releases/download/v4.2.1/ffmpeg-4.2.1-linux-64.zip --output ffmpeg.zip >/dev/null - unzip -o ffmpeg.zip >/dev/null - PATH=$PATH:$(pwd) - popd >/dev/null -fi +ffmpegInstall pushd ../../.. >/dev/null @@ -40,18 +27,19 @@ go build -o owncast main.go ./owncast -database "$TEMP_DB" & SERVER_PID=$! -function finish { - echo "Cleaning up..." - rm "$TEMP_DB" - kill $SERVER_PID $STREAMING_CLIENT -} -trap finish EXIT - popd >/dev/null sleep 5 # Start the stream. -start_stream +../../ocTestStream.sh & +STREAMING_CLIENT=$! + +function finish { + echo "Cleaning up..." + kill $SERVER_PID $STREAMING_CLIENT + rm -fr "$TEMP_DB" "$FFMPEG_PATH" +} +trap finish EXIT echo "Waiting..." sleep 13 @@ -73,7 +61,9 @@ sleep 5 update_storage_config # start the stream. -start_stream +../../ocTestStream.sh & +STREAMING_CLIENT=$! + echo "Waiting..." sleep 13 diff --git a/test/automated/test.mp4 b/test/automated/test.mp4 deleted file mode 100644 index b5b5e87ff..000000000 Binary files a/test/automated/test.mp4 and /dev/null differ diff --git a/test/automated/tools.sh b/test/automated/tools.sh new file mode 100755 index 000000000..da4ee26d2 --- /dev/null +++ b/test/automated/tools.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +ffmpegInstall(){ + # install a specific version of ffmpeg + + FFMPEG_VER="4.4.1" + FFMPEG_PATH="$(pwd)/ffmpeg-$FFMPEG_VER" + + if ! [[ -d "$FFMPEG_PATH" ]]; then + mkdir "$FFMPEG_PATH" + fi + + pushd "$FFMPEG_PATH" >/dev/null || exit + + if [[ -x "$FFMPEG_PATH/ffmpeg" ]]; then + + ffmpeg_version=$("$FFMPEG_PATH/ffmpeg" -version | awk -F 'ffmpeg version' '{print $2}' | awk 'NR==1{print $1}') + + if [[ "$ffmpeg_version" == "$FFMPEG_VER-static" ]]; then + return 0 + else + mv "$FFMPEG_PATH/ffmpeg" "$FFMPEG_PATH/ffmpeg.bk" || rm -f "$FFMPEG_PATH/ffmpeg" + fi + fi + + rm -f ffmpeg.zip + curl -sL --fail https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v${FFMPEG_VER}/ffmpeg-${FFMPEG_VER}-linux-64.zip --output ffmpeg.zip >/dev/null + unzip -o ffmpeg.zip >/dev/null && rm -f ffmpeg.zip + chmod +x ffmpeg + PATH=$FFMPEG_PATH:$PATH + + popd >/dev/null || exit +} \ No newline at end of file diff --git a/test/ocTestStream.sh b/test/ocTestStream.sh index 7cc22677b..9994b61bf 100755 --- a/test/ocTestStream.sh +++ b/test/ocTestStream.sh @@ -1,55 +1,116 @@ -#!/usr/bin/env bash +#!/bin/bash -# A recent version of ffmpeg is required for the loop of the provided videos -# to repeat indefinitely. -# Example: ./test/ocTestStream.sh ~/Downloads/*.mp4 rtmp://localhost/live/abc123 +# Requirements: +# ffmpeg (a recent version with loop video support) +# a Sans family font (for overlay text) +# awk +# readlink -if ! [[ $1 ]] -then - echo "ocTestStream is used for sending pre-recorded content to a RTMP server." - echo "Will default to localhost with the stream key of abc123 if one isn't provided." - echo "./ocTestStream.sh *.mp4 [RTMPDESINATION]" +# Example: ./test/ocTestStream.sh ~/Downloads/*.mp4 rtmp://127.0.0.1/live/abc123 + + +ffmpeg_execs=( 'ffmpeg' 'ffmpeg.exe' ) +ffmpeg_paths=( './' '../' '' ) + +for _ffmpeg_exec in "${ffmpeg_execs[@]}"; do + for _ffmpeg_path in "${ffmpeg_paths[@]}"; do + if [[ -x "$(command -v "${_ffmpeg_path}${_ffmpeg_exec}")" ]]; then + ffmpeg_exec="${_ffmpeg_path}${_ffmpeg_exec}" + break + fi + done +done + +if [[ ${*: -1} == "--help" ]]; then + echo "ocTestStream is used for sending pre-recorded or internal test content to an RTMP server." + echo "Usage: ./ocTestStream.sh [VIDEO_FILES] [RTMP_DESINATION]" + echo "VIDEO_FILES: path to one or multiple videos for sending to the RTMP server (optional)" + echo "RTMP_DESINATION: URL of RTMP server with key (optional; default: rtmp://127.0.0.1/live/abc123)" exit -fi - -# Make the destination optional and point to localhost with default key -if [[ ${*: -1} == *"rtmp://"* ]]; then +elif [[ ${*: -1} == *"rtmp://"* ]]; then echo "RTMP server is specified" DESTINATION_HOST=${*: -1} FILE_COUNT=$(( ${#} - 1 )) else echo "RTMP server is not specified" - DESTINATION_HOST="rtmp://localhost/live/abc123" + DESTINATION_HOST="rtmp://127.0.0.1/live/abc123" FILE_COUNT=${#} fi -if [[ FILE_COUNT -eq 0 ]]; then - echo "ERROR: ocTestStream needs a video file for sending to the RTMP server." - exit +if [[ -z "$ffmpeg_exec" ]]; then + echo "ERROR: ffmpeg was not found in path or in the current directory! Please install ffmpeg before using this script." + exit 1 +else + ffmpeg_version=$("$ffmpeg_exec" -version | awk -F 'ffmpeg version' '{print $2}' | awk 'NR==1{print $1}') + echo "ffmpeg executable: $ffmpeg_exec ($ffmpeg_version)" + echo "ffmpeg path: $(readlink -f "$(which "$ffmpeg_exec")")" fi -CONTENT=${*:1:${FILE_COUNT}} +if [[ ${FILE_COUNT} -eq 0 ]]; then + echo "Streaming internal test video loop to $DESTINATION_HOST" + echo "...press ctrl+c to exit" -# Delete the old list of files if it exists -if test -f list.txt; then - rm list.txt + command "${ffmpeg_exec}" -hide_banner -loglevel panic -nostdin -re -f lavfi \ + -i "testsrc=size=1280x720:rate=60[out0];sine=frequency=400:sample_rate=48000[out1]" \ + -vf "[in]drawtext=fontsize=96: box=1: boxcolor=black@0.75: boxborderw=5: fontcolor=white: x=(w-text_w)/2: y=((h-text_h)/2)+((h-text_h)/-2): text='Owncast Test Stream', drawtext=fontsize=96: box=1: boxcolor=black@0.75: boxborderw=5: fontcolor=white: x=(w-text_w)/2: y=((h-text_h)/2)+((h-text_h)/2): text='%{gmtime\:%H\\\\\:%M\\\\\:%S} UTC'[out]" \ + -nal-hrd cbr \ + -metadata:s:v encoder=test \ + -vcodec libx264 \ + -acodec aac \ + -preset veryfast \ + -profile:v baseline \ + -tune zerolatency \ + -bf 0 \ + -g 0 \ + -b:v 6320k \ + -b:a 160k \ + -ac 2 \ + -ar 48000 \ + -minrate 6320k \ + -maxrate 6320k \ + -bufsize 6320k \ + -muxrate 6320k \ + -r 60 \ + -pix_fmt yuv420p \ + -color_range 1 -colorspace 1 -color_primaries 1 -color_trc 1 \ + -flags:v +global_header \ + -bsf:v dump_extra \ + -x264-params "nal-hrd=cbr:min-keyint=2:keyint=2:scenecut=0:bframes=0" \ + -f flv "$DESTINATION_HOST" + +else + + CONTENT=${*:1:${FILE_COUNT}} + + rm -f list.txt + for file in $CONTENT + do + echo "file '$file'" >> list.txt + done + + function finish { + rm list.txt + } + trap finish EXIT + + echo "Streaming a loop of ${FILE_COUNT} video(s) to $DESTINATION_HOST" + if [[ ${FILE_COUNT} -gt 1 ]]; then + echo "Warning: If these files differ greatly in formats, transitioning from one to another may not always work correctly." + fi + echo "$CONTENT" + echo "...press ctrl+c to exit" + + command "${ffmpeg_exec}" -hide_banner -loglevel panic -nostdin -stream_loop -1 -re -f concat \ + -safe 0 \ + -i list.txt \ + -vcodec libx264 \ + -profile:v high \ + -g 48 \ + -r 24 \ + -sc_threshold 0 \ + -b:v 1300k \ + -preset veryfast \ + -acodec copy \ + -vf drawtext="fontsize=96: box=1: boxcolor=black@0.75: boxborderw=5: fontcolor=white: x=(w-text_w)/2: y=((h-text_h)/2)+((h-text_h)/4): text='%{gmtime\:%H\\\\\:%M\\\\\:%S}'" \ + -f flv "$DESTINATION_HOST" fi - -for file in $CONTENT -do - echo "file '$file'" >> list.txt -done - -function finish { - rm list.txt -} -trap finish EXIT - -echo "Streaming a loop of ${FILE_COUNT} videos to $DESTINATION_HOST." -if [[ FILE_COUNT -gt 1 ]]; then - echo "Warning: If these files differ greatly in formats transitioning from one to another may not always work correctly." -fi -echo "$CONTENT" -echo "...press ctl+c to exit" - -ffmpeg -hide_banner -loglevel panic -stream_loop -1 -re -f concat -safe 0 -i list.txt -vcodec libx264 -profile:v high -g 48 -r 24 -sc_threshold 0 -b:v 1300k -preset veryfast -acodec copy -vf drawtext="fontfile=monofonto.ttf: fontsize=96: box=1: boxcolor=black@0.75: boxborderw=5: fontcolor=white: x=(w-text_w)/2: y=((h-text_h)/2)+((h-text_h)/4): text='%{gmtime\:%H\\\\\:%M\\\\\:%S}'" -f flv "$DESTINATION_HOST" diff --git a/test/testContent.sh b/test/testContent.sh deleted file mode 100755 index ab4466dea..000000000 --- a/test/testContent.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/sh - -ffmpeg -hide_banner -loglevel panic -re -f lavfi \ - -i "testsrc=size=1280x720:rate=60[out0];sine=frequency=400:sample_rate=48000[out1]" \ - -vf "[in]drawtext=fontsize=96: box=1: boxcolor=black@0.75: boxborderw=5: fontcolor=white: x=(w-text_w)/2: y=((h-text_h)/2)+((h-text_h)/-2): text='Owncast Test Stream', drawtext=fontsize=96: box=1: boxcolor=black@0.75: boxborderw=5: fontcolor=white: x=(w-text_w)/2: y=((h-text_h)/2)+((h-text_h)/2): text='%{gmtime\:%H\\\\\:%M\\\\\:%S} UTC'[out]" \ - -nal-hrd cbr \ - -metadata:s:v encoder=test \ - -vcodec libx264 \ - -acodec aac \ - -preset veryfast \ - -profile:v baseline \ - -tune zerolatency \ - -bf 0 \ - -g 0 \ - -b:v 6320k \ - -b:a 160k \ - -ac 2 \ - -ar 48000 \ - -minrate 6320k \ - -maxrate 6320k \ - -bufsize 6320k \ - -muxrate 6320k \ - -r 60 \ - -pix_fmt yuv420p \ - -color_range 1 -colorspace 1 -color_primaries 1 -color_trc 1 \ - -flags:v +global_header \ - -bsf:v dump_extra \ - -x264-params "nal-hrd=cbr:min-keyint=2:keyint=2:scenecut=0:bframes=0" \ - -f flv "rtmp://127.0.0.1/live/abc123" >/dev/null diff --git a/web/docs/README.md b/web/docs/README.md index 97a777e78..290c7d822 100644 --- a/web/docs/README.md +++ b/web/docs/README.md @@ -11,7 +11,7 @@ ### Form fields -- Feel free to use the pre-styled `` text form field or the `` compnent, in a group of form fields together. These have been styled and laid out to match each other. +- Feel free to use the pre-styled `` text form field or the `` component, in a group of form fields together. These have been styled and laid out to match each other. - `Slider`'s - If your form uses an Ant Slider component, follow this recommended markup of CSS classes to maintain a consistent look and feel to other Sliders in the app. ```