From bed388d6e7545d949d24e846e6841455a33b3a8e Mon Sep 17 00:00:00 2001 From: aler9 <46489434+aler9@users.noreply.github.com> Date: Sat, 18 Jul 2020 18:23:26 +0200 Subject: [PATCH] add gstreamer to tests and readme (#40) --- README.md | 5 ++ main_test.go | 97 +++++++++++++++++++++++----- test-images/ffmpeg/Dockerfile | 2 +- test-images/ffmpeg/start.sh | 2 +- test-images/gstreamer/Dockerfile | 16 +++++ test-images/gstreamer/emptyvideo.ts | Bin 0 -> 65048 bytes test-images/gstreamer/start.sh | 3 + test-images/vlc/start.sh | 19 ++++-- 8 files changed, 119 insertions(+), 25 deletions(-) create mode 100644 test-images/gstreamer/Dockerfile create mode 100644 test-images/gstreamer/emptyvideo.ts create mode 100644 test-images/gstreamer/start.sh diff --git a/README.md b/README.md index d86dd3e5..014c273b 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,11 @@ Features: ffmpeg -re -stream_loop -1 -i file.ts -c copy -f rtsp rtsp://localhost:8554/mystream ``` + or _GStreamer_: + ``` + gst-launch-1.0 filesrc location=file.mp4 ! qtdemux ! rtspclientsink location=rtsp://localhost:8554/mystream + ``` + 4. Open the stream. For instance, you can open the stream with _VLC_: ``` vlc rtsp://localhost:8554/mystream diff --git a/main_test.go b/main_test.go index 018b9f7a..6a56da37 100644 --- a/main_test.go +++ b/main_test.go @@ -6,7 +6,6 @@ import ( "os" "os/exec" "strconv" - "strings" "testing" "time" @@ -92,23 +91,86 @@ func (c *container) wait() int { return int(code) } -func TestPublishRead(t *testing.T) { - for _, conf := range [][3]string{ - {"udp", "udp", "ffmpeg"}, - {"udp", "tcp", "ffmpeg"}, - {"tcp", "udp", "ffmpeg"}, - {"tcp", "tcp", "ffmpeg"}, - {"tcp", "udp", "vlc"}, - {"tcp", "tcp", "vlc"}, +func TestPublish(t *testing.T) { + for _, conf := range []struct { + publishSoft string + publishProto string + }{ + {"ffmpeg", "udp"}, + {"ffmpeg", "tcp"}, + {"gstreamer", "udp"}, + {"gstreamer", "tcp"}, } { - t.Run(strings.Join(conf[:], "_"), func(t *testing.T) { + t.Run(conf.publishSoft+"_"+conf.publishProto, func(t *testing.T) { p, err := newProgram([]string{}, bytes.NewBuffer(nil)) require.NoError(t, err) defer p.close() time.Sleep(1 * time.Second) - cnt1, err := newContainer("ffmpeg", "source", []string{ + switch conf.publishSoft { + case "ffmpeg": + cnt1, err := newContainer("ffmpeg", "publish", []string{ + "-hide_banner", + "-loglevel", "panic", + "-re", + "-stream_loop", "-1", + "-i", "/emptyvideo.ts", + "-c", "copy", + "-f", "rtsp", + "-rtsp_transport", conf.publishProto, + "rtsp://" + ownDockerIp + ":8554/teststream", + }) + require.NoError(t, err) + defer cnt1.close() + + default: + cnt1, err := newContainer("gstreamer", "source", []string{ + "filesrc location=emptyvideo.ts ! tsdemux ! rtspclientsink " + + "location=rtsp://" + ownDockerIp + ":8554/teststream protocols=" + conf.publishProto, + }) + require.NoError(t, err) + defer cnt1.close() + } + + time.Sleep(1 * time.Second) + + cnt2, err := newContainer("ffmpeg", "read", []string{ + "-hide_banner", + "-loglevel", "panic", + "-rtsp_transport", "udp", + "-i", "rtsp://" + ownDockerIp + ":8554/teststream", + "-vframes", "1", + "-f", "image2", + "-y", "/dev/null", + }) + require.NoError(t, err) + defer cnt2.close() + + code := cnt2.wait() + require.Equal(t, 0, code) + }) + } +} + +func TestRead(t *testing.T) { + for _, conf := range []struct { + readSoft string + readProto string + }{ + {"ffmpeg", "udp"}, + {"ffmpeg", "tcp"}, + {"vlc", "udp"}, + {"vlc", "tcp"}, + } { + t.Run(conf.readSoft+"_"+conf.readProto, func(t *testing.T) { + p, err := newProgram([]string{}, bytes.NewBuffer(nil)) + require.NoError(t, err) + defer p.close() + + time.Sleep(1 * time.Second) + + cnt1, err := newContainer("ffmpeg", "publish", []string{ "-hide_banner", "-loglevel", "panic", "-re", @@ -116,7 +178,7 @@ func TestPublishRead(t *testing.T) { "-i", "/emptyvideo.ts", "-c", "copy", "-f", "rtsp", - "-rtsp_transport", conf[0], + "-rtsp_transport", "udp", "rtsp://" + ownDockerIp + ":8554/teststream", }) require.NoError(t, err) @@ -124,11 +186,12 @@ func TestPublishRead(t *testing.T) { time.Sleep(1 * time.Second) - if conf[2] == "ffmpeg" { - cnt2, err := newContainer("ffmpeg", "dest", []string{ + switch conf.readSoft { + case "ffmpeg": + cnt2, err := newContainer("ffmpeg", "read", []string{ "-hide_banner", "-loglevel", "panic", - "-rtsp_transport", conf[1], + "-rtsp_transport", conf.readProto, "-i", "rtsp://" + ownDockerIp + ":8554/teststream", "-vframes", "1", "-f", "image2", @@ -140,9 +203,9 @@ func TestPublishRead(t *testing.T) { code := cnt2.wait() require.Equal(t, 0, code) - } else { + default: args := []string{} - if conf[1] == "tcp" { + if conf.readProto == "tcp" { args = append(args, "--rtsp-tcp") } args = append(args, "rtsp://"+ownDockerIp+":8554/teststream") diff --git a/test-images/ffmpeg/Dockerfile b/test-images/ffmpeg/Dockerfile index 67312444..1f380e26 100644 --- a/test-images/ffmpeg/Dockerfile +++ b/test-images/ffmpeg/Dockerfile @@ -1,4 +1,4 @@ -FROM amd64/alpine:3.11 +FROM amd64/alpine:3.12 RUN apk add --no-cache \ ffmpeg diff --git a/test-images/ffmpeg/start.sh b/test-images/ffmpeg/start.sh index fe786544..673c643a 100644 --- a/test-images/ffmpeg/start.sh +++ b/test-images/ffmpeg/start.sh @@ -1,3 +1,3 @@ #!/bin/sh -e -ffmpeg $@ +exec ffmpeg $@ diff --git a/test-images/gstreamer/Dockerfile b/test-images/gstreamer/Dockerfile new file mode 100644 index 00000000..46a70444 --- /dev/null +++ b/test-images/gstreamer/Dockerfile @@ -0,0 +1,16 @@ +FROM amd64/alpine:3.12 + +RUN apk add --no-cache \ + gstreamer-tools \ + gst-plugins-good \ + gst-plugins-bad \ + && apk add --no-cache \ + -X http://dl-cdn.alpinelinux.org/alpine/edge/testing \ + gst-rtsp-server + +COPY emptyvideo.ts / + +COPY start.sh / +RUN chmod +x /start.sh + +ENTRYPOINT [ "/start.sh" ] diff --git a/test-images/gstreamer/emptyvideo.ts b/test-images/gstreamer/emptyvideo.ts new file mode 100644 index 0000000000000000000000000000000000000000..6693c037aa8cc233dd7a4f44803bef78b8cc53a5 GIT binary patch literal 65048 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 M2X2K-&1 & -sleep 10 +COUNTER=0 +while true; do + sleep 1 -if [ $(stat -c "%s" /out/stream.ts) -gt 0 ]; then - exit 0 -else - exit 1 -fi + if [ $(stat -c "%s" /out/stream.ts) -gt 0 ]; then + exit 0 + fi + + COUNTER=$(($COUNTER + 1)) + + if [ $COUNTER -ge 15 ]; then + exit 1 + fi +done