From 615db9c5fa5c64cf09b99ec8f5e3e8c6e2069817 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Tue, 22 Sep 2026 21:13:06 -0700 Subject: [PATCH 1/3] Unify the test workflow and pin action digests --- .github/renovate.json | 14 +++-- .github/workflows/codetests.yml | 33 ++++++------ encode.go | 4 +- encode_test.go | 92 ++++++++++++++++----------------- 4 files changed, 77 insertions(+), 66 deletions(-) diff --git a/.github/renovate.json b/.github/renovate.json index 0fc55f7..3b65103 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -2,14 +2,22 @@ "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ "config:base", - "default:automergeDigest" + "default:automergeDigest", + "helpers:pinGitHubActionDigestsToSemver" ], + "minimumReleaseAge": "7 days", + "internalChecksFilter": "strict", "packageRules": [ { - "matchDatasources": ["go", "github-releases", "github-tags"], + "description": "Automerge non-major Go module updates when checks pass", + "matchManagers": ["gomod"], "matchUpdateTypes": ["minor", "patch", "pin", "digest"], "automerge": true + }, + { + "description": "Automerge GitHub Actions updates, including majors, when checks pass", + "matchManagers": ["github-actions"], + "automerge": true } ] } - diff --git a/.github/workflows/codetests.yml b/.github/workflows/codetests.yml index 2c5201c..942eaa9 100644 --- a/.github/workflows/codetests.yml +++ b/.github/workflows/codetests.yml @@ -1,14 +1,18 @@ name: test-and-lint on: - push: - branches: - - main pull_request: branches: - main permissions: contents: read jobs: + codespell: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: codespell-project/actions-codespell@e3258cca84ce02b0bb36a3d41f2c18f719a0cc1a # v2.4.3 + with: + skip: .git,go.sum # Runs `go test` against 3 operating systems. gotest: strategy: @@ -16,13 +20,12 @@ jobs: os: [macos, windows, ubuntu] runs-on: ${{ matrix.os }}-latest steps: - - uses: actions/checkout@v6 - - uses: actions/setup-go@v6 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: stable - name: go-test - run: go test -race -covermode=atomic -coverprofile=coverage ./... && go tool cover -func=coverage - + run: go test -race -covermode=atomic '-test.v' ./... # Runs golangci-lint on macos against freebsd and macos. golangci-darwin: strategy: @@ -33,14 +36,14 @@ jobs: env: GOOS: ${{ matrix.os }} steps: - - uses: actions/setup-go@v6 + - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: stable - - uses: actions/checkout@v6 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: golangci-lint - uses: golangci/golangci-lint-action@v9 + uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9.3.0 with: - version: v2.11.4 + version: v2.13 # Runs golangci-lint on linux against linux and windows. golangci-linux: strategy: @@ -51,11 +54,11 @@ jobs: env: GOOS: ${{ matrix.os }} steps: - - uses: actions/setup-go@v6 + - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: stable - - uses: actions/checkout@v6 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: golangci-lint - uses: golangci/golangci-lint-action@v9 + uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9.3.0 with: - version: v2.11.4 + version: v2.13 diff --git a/encode.go b/encode.go index 27de15f..9f8c88f 100644 --- a/encode.go +++ b/encode.go @@ -190,7 +190,7 @@ func (e *Encoder) SetSize(size string) int64 { return e.config.Size } -// GetVideo retreives video from an input and returns an io.ReadCloser to consume the output. +// GetVideo retrieves video from an input and returns an io.ReadCloser to consume the output. // Input must be an RTSP URL. Title is encoded into the video as the "movie title." // Returns command used for diagnostics, io.ReadCloser and error or nil. // This will automatically create a context timeout based on the requested capture length. @@ -221,7 +221,7 @@ func (e *Encoder) GetVideo(input, title string) (string, io.ReadCloser, error) { return cmdStr, &cancelReadCloser{ReadCloser: stream, cancel: cancel}, nil } -// GetVideoContext retreives video from an input and returns an io.ReadCloser to consume the output. +// GetVideoContext retrieves video from an input and returns an io.ReadCloser to consume the output. // Input must be an RTSP URL. Title is encoded into the video as the "movie title." // Returns command used for diagnostics, io.ReadCloser and error or nil. // Use the context to add a timeout value (max run duration) to the ffmpeg command. diff --git a/encode_test.go b/encode_test.go index 3fed599..1486fc5 100644 --- a/encode_test.go +++ b/encode_test.go @@ -15,37 +15,37 @@ import ( func TestFixValues(t *testing.T) { t.Parallel() - asert := assert.New(t) + check := assert.New(t) encode := Get(&Config{}) // Test default values. - asert.False(encode.SetAudio(""), "Wrong default 'audio' value!") - asert.Equal(DefaultProfile, encode.SetProfile(""), "Wrong default 'profile' value!") - asert.Equal(DefaultLevel, encode.SetLevel(""), "Wrong default 'level' value!") - asert.Equal(DefaultFrameHeight, encode.SetHeight(""), "Wrong default 'height' value!") - asert.Equal(DefaultFrameWidth, encode.SetWidth(""), "Wrong default 'width' value!") - asert.Equal(DefaultEncodeCRF, encode.SetCRF(""), "Wrong default 'crf' value!") - asert.Equal(DefaultCaptureTime, encode.SetTime(""), "Wrong default 'time' value!") - asert.Equal(DefaultFrameRate, encode.SetRate(""), "Wrong default 'rate' value!") - asert.Equal(DefaultCaptureSize, encode.SetSize(""), "Wrong default 'size' value!") + check.False(encode.SetAudio(""), "Wrong default 'audio' value!") + check.Equal(DefaultProfile, encode.SetProfile(""), "Wrong default 'profile' value!") + check.Equal(DefaultLevel, encode.SetLevel(""), "Wrong default 'level' value!") + check.Equal(DefaultFrameHeight, encode.SetHeight(""), "Wrong default 'height' value!") + check.Equal(DefaultFrameWidth, encode.SetWidth(""), "Wrong default 'width' value!") + check.Equal(DefaultEncodeCRF, encode.SetCRF(""), "Wrong default 'crf' value!") + check.Equal(DefaultCaptureTime, encode.SetTime(""), "Wrong default 'time' value!") + check.Equal(DefaultFrameRate, encode.SetRate(""), "Wrong default 'rate' value!") + check.Equal(DefaultCaptureSize, encode.SetSize(""), "Wrong default 'size' value!") // Text max values. - asert.Equal(MaximumFrameSize, encode.SetHeight("9000"), "Wrong maximum 'height' value!") - asert.Equal(MaximumFrameSize, encode.SetWidth("9000"), "Wrong maximum 'width' value!") - asert.Equal(MaximumEncodeCRF, encode.SetCRF("9000"), "Wrong maximum 'crf' value!") - asert.Equal(MaximumCaptureTime, encode.SetTime("9000"), "Wrong maximum 'time' value!") - asert.Equal(MaximumFrameRate, encode.SetRate("9000"), "Wrong maximum 'rate' value!") - asert.Equal(MaximumCaptureSize, encode.SetSize("999999999"), "Wrong maximum 'size' value!") + check.Equal(MaximumFrameSize, encode.SetHeight("9000"), "Wrong maximum 'height' value!") + check.Equal(MaximumFrameSize, encode.SetWidth("9000"), "Wrong maximum 'width' value!") + check.Equal(MaximumEncodeCRF, encode.SetCRF("9000"), "Wrong maximum 'crf' value!") + check.Equal(MaximumCaptureTime, encode.SetTime("9000"), "Wrong maximum 'time' value!") + check.Equal(MaximumFrameRate, encode.SetRate("9000"), "Wrong maximum 'rate' value!") + check.Equal(MaximumCaptureSize, encode.SetSize("999999999"), "Wrong maximum 'size' value!") // Text min values. - asert.Equal(MinimumFrameSize, encode.SetHeight("1"), "Wrong minimum 'height' value!") - asert.Equal(MinimumFrameSize, encode.SetWidth("1"), "Wrong minimum 'width' value!") - asert.Equal(MinimumEncodeCRF, encode.SetCRF("1"), "Wrong minimum 'CRF' value!") - asert.Equal(MinimumFrameRate, encode.SetRate("-1"), "Wrong minimum 'rate' value!") + check.Equal(MinimumFrameSize, encode.SetHeight("1"), "Wrong minimum 'height' value!") + check.Equal(MinimumFrameSize, encode.SetWidth("1"), "Wrong minimum 'width' value!") + check.Equal(MinimumEncodeCRF, encode.SetCRF("1"), "Wrong minimum 'CRF' value!") + check.Equal(MinimumFrameRate, encode.SetRate("-1"), "Wrong minimum 'rate' value!") } func TestSaveVideo(t *testing.T) { t.Parallel() - asert := assert.New(t) + check := assert.New(t) encode := Get(&Config{FFMPEG: "echo"}) fileTemp := "/tmp/go-securityspy-encode-test-12345.txt" @@ -53,31 +53,31 @@ func TestSaveVideo(t *testing.T) { require.NoError(t, err, "echo returned an error. Something may be wrong with your environment.") // Make sure the produced command has all the expected values. - asert.Contains(cmd, "-an", "Audio may not be correctly disabled.") - asert.Contains(cmd, "-i INPUT", "INPUT value appears to be missing") - asert.Contains(cmd, "-metadata title=TITLE", "TITLE value appears to be missing.") - asert.Contains(cmd, fmt.Sprintf("-vcodec libx264 -profile:v %v -level %v", DefaultProfile, DefaultLevel), + check.Contains(cmd, "-an", "Audio may not be correctly disabled.") + check.Contains(cmd, "-i INPUT", "INPUT value appears to be missing") + check.Contains(cmd, "-metadata title=TITLE", "TITLE value appears to be missing.") + check.Contains(cmd, fmt.Sprintf("-vcodec libx264 -profile:v %v -level %v", DefaultProfile, DefaultLevel), "Level or Profile are missing or out of order.") - asert.Contains(cmd, "-f mov", "File output should use mov container.") - asert.Contains(cmd, "-movflags faststart", "File output should set faststart for mov.") - asert.Contains(cmd, fmt.Sprintf("-crf %d", DefaultEncodeCRF), "CRF value is missing or malformed.") - asert.Contains(cmd, fmt.Sprintf("-t %d", DefaultCaptureTime), + check.Contains(cmd, "-f mov", "File output should use mov container.") + check.Contains(cmd, "-movflags faststart", "File output should set faststart for mov.") + check.Contains(cmd, fmt.Sprintf("-crf %d", DefaultEncodeCRF), "CRF value is missing or malformed.") + check.Contains(cmd, fmt.Sprintf("-t %d", DefaultCaptureTime), "Capture Time value is missing or malformed.") - asert.Contains(cmd, fmt.Sprintf("-s %dx%d", DefaultFrameWidth, DefaultFrameHeight), + check.Contains(cmd, fmt.Sprintf("-s %dx%d", DefaultFrameWidth, DefaultFrameHeight), "Framesize is missing or malformed.") - asert.Contains(cmd, fmt.Sprintf("-r %d", DefaultFrameRate), "Frame Rate value is missing or malformed.") - asert.Contains(cmd, fmt.Sprintf("-fs %d", DefaultCaptureSize), "Size value is missing or malformed.") - asert.True(strings.HasPrefix(cmd, "echo"), "The command does not - but should - begin with the Encoder value.") - asert.True(strings.HasSuffix(cmd, fileTemp), + check.Contains(cmd, fmt.Sprintf("-r %d", DefaultFrameRate), "Frame Rate value is missing or malformed.") + check.Contains(cmd, fmt.Sprintf("-fs %d", DefaultCaptureSize), "Size value is missing or malformed.") + check.True(strings.HasPrefix(cmd, "echo"), "The command does not - but should - begin with the Encoder value.") + check.True(strings.HasSuffix(cmd, fileTemp), "The command does not - but should - end with a dash to indicate output to stdout.") - asert.Equal(cmd, "echo "+strings.TrimSpace(out), "Somehow the wrong value was written") + check.Equal(cmd, "echo "+strings.TrimSpace(out), "Somehow the wrong value was written") // Make sure audio can be turned on. encode = Get(&Config{FFMPEG: "echo", Audio: true}) cmd, _, err = encode.GetVideo("INPUT", "TITLE") require.NoError(t, err, "echo returned an error. Something may be wrong with your environment.") - asert.Contains(cmd, "-c:a copy", "Audio may not be correctly enabled.") + check.Contains(cmd, "-c:a copy", "Audio may not be correctly enabled.") } func TestRTSPTransportOption(t *testing.T) { @@ -171,18 +171,18 @@ func TestGetNilConfig(t *testing.T) { func TestValues(t *testing.T) { t.Parallel() - asert := assert.New(t) + check := assert.New(t) config := Get(&Config{}).Config() - asert.Equal(DefaultFFmpegPath, config.FFMPEG) - asert.Equal(DefaultFrameRate, config.Rate) - asert.Equal(DefaultFrameHeight, config.Height) - asert.Equal(DefaultFrameWidth, config.Width) - asert.Equal(DefaultEncodeCRF, config.CRF) - asert.Equal(DefaultCaptureTime, config.Time) - asert.Equal(DefaultCaptureSize, config.Size) - asert.Equal(DefaultProfile, config.Prof) - asert.Equal(DefaultLevel, config.Level) + check.Equal(DefaultFFmpegPath, config.FFMPEG) + check.Equal(DefaultFrameRate, config.Rate) + check.Equal(DefaultFrameHeight, config.Height) + check.Equal(DefaultFrameWidth, config.Width) + check.Equal(DefaultEncodeCRF, config.CRF) + check.Equal(DefaultCaptureTime, config.Time) + check.Equal(DefaultCaptureSize, config.Size) + check.Equal(DefaultProfile, config.Prof) + check.Equal(DefaultLevel, config.Level) } /* GoDoc Code Examples */ From 336fb86439ad59c62ae4ef76fff1a5c423d50c6a Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Tue, 22 Sep 2026 21:26:30 -0700 Subject: [PATCH 2/3] Use the config:recommended Renovate preset. --- .github/renovate.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/renovate.json b/.github/renovate.json index 3b65103..aee303c 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -1,7 +1,7 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ - "config:base", + "config:recommended", "default:automergeDigest", "helpers:pinGitHubActionDigestsToSemver" ], From 45a43aa9d2de1ef61e4f27406c86d33b5c2e45fe Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Wed, 23 Sep 2026 00:41:12 -0700 Subject: [PATCH 3/3] Tighten the ffmpeg lint config. Drop the unused Close exclusions, keep wsl_v5 on, and move the tests outside the package. Co-authored-by: Cursor --- .golangci.yml | 19 +++----- encode_test.go | 119 +++++++++++++++++++++++++------------------------ 2 files changed, 67 insertions(+), 71 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index cb78de7..5ddb615 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,11 +1,12 @@ -version: '2' +version: "2" linters: default: all disable: - - exhaustruct - - depguard - - wsl - - testpackage + - wsl # deprecated. + - exhaustruct # deprecated. + - exhaustruct_v5 # Config and the stream types leave sync and buffer fields at zero. + - gomodguard # deprecated. + - depguard # flags testify. settings: gocritic: enable-all: true @@ -14,14 +15,6 @@ linters: settings: unnamedResult: checkExported: true - errcheck: - check-type-assertions: true - check-blank: false - disable-default-exclusions: false - exclude-functions: - - (*os.File).Close - - (io.Closer).Close - issues: max-issues-per-linter: 0 max-same-issues: 0 diff --git a/encode_test.go b/encode_test.go index 1486fc5..638e66b 100644 --- a/encode_test.go +++ b/encode_test.go @@ -1,4 +1,4 @@ -package ffmpeg +package ffmpeg_test import ( "context" @@ -10,43 +10,46 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "golift.io/ffmpeg" ) +const echoCommand = "echo" + func TestFixValues(t *testing.T) { t.Parallel() check := assert.New(t) - encode := Get(&Config{}) + encode := ffmpeg.Get(&ffmpeg.Config{}) // Test default values. check.False(encode.SetAudio(""), "Wrong default 'audio' value!") - check.Equal(DefaultProfile, encode.SetProfile(""), "Wrong default 'profile' value!") - check.Equal(DefaultLevel, encode.SetLevel(""), "Wrong default 'level' value!") - check.Equal(DefaultFrameHeight, encode.SetHeight(""), "Wrong default 'height' value!") - check.Equal(DefaultFrameWidth, encode.SetWidth(""), "Wrong default 'width' value!") - check.Equal(DefaultEncodeCRF, encode.SetCRF(""), "Wrong default 'crf' value!") - check.Equal(DefaultCaptureTime, encode.SetTime(""), "Wrong default 'time' value!") - check.Equal(DefaultFrameRate, encode.SetRate(""), "Wrong default 'rate' value!") - check.Equal(DefaultCaptureSize, encode.SetSize(""), "Wrong default 'size' value!") + check.Equal(ffmpeg.DefaultProfile, encode.SetProfile(""), "Wrong default 'profile' value!") + check.Equal(ffmpeg.DefaultLevel, encode.SetLevel(""), "Wrong default 'level' value!") + check.Equal(ffmpeg.DefaultFrameHeight, encode.SetHeight(""), "Wrong default 'height' value!") + check.Equal(ffmpeg.DefaultFrameWidth, encode.SetWidth(""), "Wrong default 'width' value!") + check.Equal(ffmpeg.DefaultEncodeCRF, encode.SetCRF(""), "Wrong default 'crf' value!") + check.Equal(ffmpeg.DefaultCaptureTime, encode.SetTime(""), "Wrong default 'time' value!") + check.Equal(ffmpeg.DefaultFrameRate, encode.SetRate(""), "Wrong default 'rate' value!") + check.Equal(ffmpeg.DefaultCaptureSize, encode.SetSize(""), "Wrong default 'size' value!") // Text max values. - check.Equal(MaximumFrameSize, encode.SetHeight("9000"), "Wrong maximum 'height' value!") - check.Equal(MaximumFrameSize, encode.SetWidth("9000"), "Wrong maximum 'width' value!") - check.Equal(MaximumEncodeCRF, encode.SetCRF("9000"), "Wrong maximum 'crf' value!") - check.Equal(MaximumCaptureTime, encode.SetTime("9000"), "Wrong maximum 'time' value!") - check.Equal(MaximumFrameRate, encode.SetRate("9000"), "Wrong maximum 'rate' value!") - check.Equal(MaximumCaptureSize, encode.SetSize("999999999"), "Wrong maximum 'size' value!") + check.Equal(ffmpeg.MaximumFrameSize, encode.SetHeight("9000"), "Wrong maximum 'height' value!") + check.Equal(ffmpeg.MaximumFrameSize, encode.SetWidth("9000"), "Wrong maximum 'width' value!") + check.Equal(ffmpeg.MaximumEncodeCRF, encode.SetCRF("9000"), "Wrong maximum 'crf' value!") + check.Equal(ffmpeg.MaximumCaptureTime, encode.SetTime("9000"), "Wrong maximum 'time' value!") + check.Equal(ffmpeg.MaximumFrameRate, encode.SetRate("9000"), "Wrong maximum 'rate' value!") + check.Equal(ffmpeg.MaximumCaptureSize, encode.SetSize("999999999"), "Wrong maximum 'size' value!") // Text min values. - check.Equal(MinimumFrameSize, encode.SetHeight("1"), "Wrong minimum 'height' value!") - check.Equal(MinimumFrameSize, encode.SetWidth("1"), "Wrong minimum 'width' value!") - check.Equal(MinimumEncodeCRF, encode.SetCRF("1"), "Wrong minimum 'CRF' value!") - check.Equal(MinimumFrameRate, encode.SetRate("-1"), "Wrong minimum 'rate' value!") + check.Equal(ffmpeg.MinimumFrameSize, encode.SetHeight("1"), "Wrong minimum 'height' value!") + check.Equal(ffmpeg.MinimumFrameSize, encode.SetWidth("1"), "Wrong minimum 'width' value!") + check.Equal(ffmpeg.MinimumEncodeCRF, encode.SetCRF("1"), "Wrong minimum 'CRF' value!") + check.Equal(ffmpeg.MinimumFrameRate, encode.SetRate("-1"), "Wrong minimum 'rate' value!") } func TestSaveVideo(t *testing.T) { t.Parallel() check := assert.New(t) - encode := Get(&Config{FFMPEG: "echo"}) + encode := ffmpeg.Get(&ffmpeg.Config{FFMPEG: echoCommand}) fileTemp := "/tmp/go-securityspy-encode-test-12345.txt" cmd, out, err := encode.SaveVideo("INPUT", fileTemp, "TITLE") @@ -56,24 +59,24 @@ func TestSaveVideo(t *testing.T) { check.Contains(cmd, "-an", "Audio may not be correctly disabled.") check.Contains(cmd, "-i INPUT", "INPUT value appears to be missing") check.Contains(cmd, "-metadata title=TITLE", "TITLE value appears to be missing.") - check.Contains(cmd, fmt.Sprintf("-vcodec libx264 -profile:v %v -level %v", DefaultProfile, DefaultLevel), + check.Contains(cmd, fmt.Sprintf("-vcodec libx264 -profile:v %v -level %v", ffmpeg.DefaultProfile, ffmpeg.DefaultLevel), "Level or Profile are missing or out of order.") check.Contains(cmd, "-f mov", "File output should use mov container.") check.Contains(cmd, "-movflags faststart", "File output should set faststart for mov.") - check.Contains(cmd, fmt.Sprintf("-crf %d", DefaultEncodeCRF), "CRF value is missing or malformed.") - check.Contains(cmd, fmt.Sprintf("-t %d", DefaultCaptureTime), + check.Contains(cmd, fmt.Sprintf("-crf %d", ffmpeg.DefaultEncodeCRF), "CRF value is missing or malformed.") + check.Contains(cmd, fmt.Sprintf("-t %d", ffmpeg.DefaultCaptureTime), "Capture Time value is missing or malformed.") - check.Contains(cmd, fmt.Sprintf("-s %dx%d", DefaultFrameWidth, DefaultFrameHeight), + check.Contains(cmd, fmt.Sprintf("-s %dx%d", ffmpeg.DefaultFrameWidth, ffmpeg.DefaultFrameHeight), "Framesize is missing or malformed.") - check.Contains(cmd, fmt.Sprintf("-r %d", DefaultFrameRate), "Frame Rate value is missing or malformed.") - check.Contains(cmd, fmt.Sprintf("-fs %d", DefaultCaptureSize), "Size value is missing or malformed.") - check.True(strings.HasPrefix(cmd, "echo"), "The command does not - but should - begin with the Encoder value.") + check.Contains(cmd, fmt.Sprintf("-r %d", ffmpeg.DefaultFrameRate), "Frame Rate value is missing or malformed.") + check.Contains(cmd, fmt.Sprintf("-fs %d", ffmpeg.DefaultCaptureSize), "Size value is missing or malformed.") + check.True(strings.HasPrefix(cmd, echoCommand), "The command does not - but should - begin with the Encoder value.") check.True(strings.HasSuffix(cmd, fileTemp), "The command does not - but should - end with a dash to indicate output to stdout.") - check.Equal(cmd, "echo "+strings.TrimSpace(out), "Somehow the wrong value was written") + check.Equal(cmd, echoCommand+" "+strings.TrimSpace(out), "Somehow the wrong value was written") // Make sure audio can be turned on. - encode = Get(&Config{FFMPEG: "echo", Audio: true}) + encode = ffmpeg.Get(&ffmpeg.Config{FFMPEG: echoCommand, Audio: true}) cmd, _, err = encode.GetVideo("INPUT", "TITLE") require.NoError(t, err, "echo returned an error. Something may be wrong with your environment.") @@ -83,7 +86,7 @@ func TestSaveVideo(t *testing.T) { func TestRTSPTransportOption(t *testing.T) { t.Parallel() - encode := Get(&Config{FFMPEG: "echo"}) + encode := ffmpeg.Get(&ffmpeg.Config{FFMPEG: echoCommand}) rtspCmd, _, err := encode.SaveVideo("rtsp://example.local/stream", "/tmp/out.mov", "TITLE") require.NoError(t, err) @@ -97,25 +100,25 @@ func TestRTSPTransportOption(t *testing.T) { func TestSaveVideoErrors(t *testing.T) { t.Parallel() - encode := Get(&Config{FFMPEG: "echo"}) + encode := ffmpeg.Get(&ffmpeg.Config{FFMPEG: echoCommand}) _, _, err := encode.SaveVideoContext(context.Background(), "", "/tmp/nope", "title") - require.ErrorIs(t, err, ErrInvalidInput) + require.ErrorIs(t, err, ffmpeg.ErrInvalidInput) _, _, err = encode.SaveVideoContext(context.Background(), "INPUT", "", "title") - require.ErrorIs(t, err, ErrInvalidOutput) + require.ErrorIs(t, err, ffmpeg.ErrInvalidOutput) _, _, err = encode.SaveVideoContext(context.Background(), "INPUT", "-", "title") - require.ErrorIs(t, err, ErrInvalidOutput) + require.ErrorIs(t, err, ffmpeg.ErrInvalidOutput) } func TestGetVideoContextErrors(t *testing.T) { t.Parallel() - encode := Get(&Config{FFMPEG: "echo"}) + encode := ffmpeg.Get(&ffmpeg.Config{FFMPEG: echoCommand}) _, _, err := encode.GetVideoContext(context.Background(), "", "title") - require.ErrorIs(t, err, ErrInvalidInput) + require.ErrorIs(t, err, ffmpeg.ErrInvalidInput) - encode = Get(&Config{FFMPEG: "/path/that/does/not/exist/ffmpeg"}) + encode = ffmpeg.Get(&ffmpeg.Config{FFMPEG: "/path/that/does/not/exist/ffmpeg"}) _, stream, err := encode.GetVideoContext(context.Background(), "INPUT", "title") require.Error(t, err) require.Nil(t, stream) @@ -125,7 +128,7 @@ func TestGetVideoContextErrors(t *testing.T) { func TestGetVideoStreamLifecycle(t *testing.T) { t.Parallel() - encode := Get(&Config{FFMPEG: "echo"}) + encode := ffmpeg.Get(&ffmpeg.Config{FFMPEG: echoCommand}) cmd, stream, err := encode.GetVideoContext(context.Background(), "INPUT", "TITLE") require.NoError(t, err) require.NotNil(t, stream) @@ -144,8 +147,8 @@ func TestGetVideoStreamLifecycle(t *testing.T) { func TestGetVideoTitleFallbackAndCopy(t *testing.T) { t.Parallel() - encode := Get(&Config{ - FFMPEG: "echo", + encode := ffmpeg.Get(&ffmpeg.Config{ + FFMPEG: echoCommand, Copy: true, Audio: true, }) @@ -163,26 +166,26 @@ func TestGetVideoTitleFallbackAndCopy(t *testing.T) { func TestGetNilConfig(t *testing.T) { t.Parallel() - config := Get(nil).Config() - require.Equal(t, DefaultFFmpegPath, config.FFMPEG) - require.Equal(t, DefaultFrameRate, config.Rate) + config := ffmpeg.Get(nil).Config() + require.Equal(t, ffmpeg.DefaultFFmpegPath, config.FFMPEG) + require.Equal(t, ffmpeg.DefaultFrameRate, config.Rate) } func TestValues(t *testing.T) { t.Parallel() check := assert.New(t) - config := Get(&Config{}).Config() - - check.Equal(DefaultFFmpegPath, config.FFMPEG) - check.Equal(DefaultFrameRate, config.Rate) - check.Equal(DefaultFrameHeight, config.Height) - check.Equal(DefaultFrameWidth, config.Width) - check.Equal(DefaultEncodeCRF, config.CRF) - check.Equal(DefaultCaptureTime, config.Time) - check.Equal(DefaultCaptureSize, config.Size) - check.Equal(DefaultProfile, config.Prof) - check.Equal(DefaultLevel, config.Level) + config := ffmpeg.Get(&ffmpeg.Config{}).Config() + + check.Equal(ffmpeg.DefaultFFmpegPath, config.FFMPEG) + check.Equal(ffmpeg.DefaultFrameRate, config.Rate) + check.Equal(ffmpeg.DefaultFrameHeight, config.Height) + check.Equal(ffmpeg.DefaultFrameWidth, config.Width) + check.Equal(ffmpeg.DefaultEncodeCRF, config.CRF) + check.Equal(ffmpeg.DefaultCaptureTime, config.Time) + check.Equal(ffmpeg.DefaultCaptureSize, config.Size) + check.Equal(ffmpeg.DefaultProfile, config.Prof) + check.Equal(ffmpeg.DefaultLevel, config.Level) } /* GoDoc Code Examples */ @@ -191,13 +194,13 @@ func TestValues(t *testing.T) { func Example_securitySpy() { //nolint:testableexamples // it's an example. securitypsy := "rtsp://user:pass@127.0.0.1:8000/++stream?cameraNum=1" //nolint:gosec // it's an example. output := "/tmp/securitypsy_captured_file.mov" - config := &Config{ + config := &ffmpeg.Config{ FFMPEG: "/usr/local/bin/ffmpeg", Copy: true, // do not transcode Audio: true, // retain audio stream Time: 10, // 10 seconds } - encode := Get(config) + encode := ffmpeg.Get(config) cmd, out, err := encode.SaveVideo(securitypsy, output, "SecuritySpyVideoTitle") log.Println("Command Used:", cmd) @@ -214,7 +217,7 @@ func Example_securitySpy() { //nolint:testableexamples // it's an example. func Example_dahua() { //nolint:testableexamples // it's an example. dahua := "rtsp://admin:password@192.168.1.12/live" //nolint:gosec // it's an example. output := "/tmp/dahua_captured_file.m4v" - encode := Get(&Config{ + encode := ffmpeg.Get(&ffmpeg.Config{ Audio: true, // retain audio stream Time: 10, // 10 seconds Width: 1920,