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 00000000..6693c037 Binary files /dev/null and b/test-images/gstreamer/emptyvideo.ts differ diff --git a/test-images/gstreamer/start.sh b/test-images/gstreamer/start.sh new file mode 100644 index 00000000..c66f6f0d --- /dev/null +++ b/test-images/gstreamer/start.sh @@ -0,0 +1,3 @@ +#!/bin/sh -e + +exec gst-launch-1.0 $@ diff --git a/test-images/vlc/start.sh b/test-images/vlc/start.sh index 2c72b2b3..612c343a 100644 --- a/test-images/vlc/start.sh +++ b/test-images/vlc/start.sh @@ -6,10 +6,17 @@ chown user:user /out CMD="cvlc --play-and-exit --no-audio --no-video --sout file/ts:/out/stream.ts -vvv $@" su - user -c "$CMD" 2>&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