From bb139dbd4a22c5e55c5bbbb61340f266ff4cd2ab Mon Sep 17 00:00:00 2001 From: Alessandro Ros Date: Sat, 27 Jan 2024 19:34:25 +0100 Subject: [PATCH] add example client-record-format-mjpeg-from-image (#489) (#512) --- README.md | 1 + examples/client-record-format-g711/main.go | 2 +- examples/client-record-format-g722/main.go | 2 +- examples/client-record-format-h264/main.go | 2 +- examples/client-record-format-h265/main.go | 2 +- examples/client-record-format-lpcm/main.go | 2 +- .../main.go | 104 ++++++++++++++++++ examples/client-record-format-mjpeg/main.go | 2 +- .../client-record-format-mpeg4audio/main.go | 2 +- examples/client-record-format-opus/main.go | 2 +- examples/client-record-format-vp8/main.go | 2 +- examples/client-record-format-vp9/main.go | 2 +- examples/client-record-options/main.go | 2 +- examples/client-record-pause/main.go | 2 +- 14 files changed, 117 insertions(+), 12 deletions(-) create mode 100644 examples/client-record-format-mjpeg-from-image/main.go diff --git a/README.md b/README.md index 5dd75c5d..c1a6f6f7 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,7 @@ Features: * [client-record-format-h265](examples/client-record-format-h265/main.go) * [client-record-format-lpcm](examples/client-record-format-lpcm/main.go) * [client-record-format-mjpeg](examples/client-record-format-mjpeg/main.go) +* [client-record-format-mjpeg-from-image](examples/client-record-format-mjpeg-from-image/main.go) * [client-record-format-mpeg4audio](examples/client-record-format-mpeg4audio/main.go) * [client-record-format-opus](examples/client-record-format-opus/main.go) * [client-record-format-vp8](examples/client-record-format-vp8/main.go) diff --git a/examples/client-record-format-g711/main.go b/examples/client-record-format-g711/main.go index 7c9fcbf4..4f98bdbb 100644 --- a/examples/client-record-format-g711/main.go +++ b/examples/client-record-format-g711/main.go @@ -12,7 +12,7 @@ import ( // This example shows how to // 1. generate RTP/G711 packets with GStreamer -// 2. connect to a RTSP server, announce a G711 media +// 2. connect to a RTSP server, announce a G711 format // 3. route the packets from GStreamer to the server func main() { diff --git a/examples/client-record-format-g722/main.go b/examples/client-record-format-g722/main.go index da8a05c8..a98397f7 100644 --- a/examples/client-record-format-g722/main.go +++ b/examples/client-record-format-g722/main.go @@ -12,7 +12,7 @@ import ( // This example shows how to // 1. generate RTP/G722 packets with GStreamer -// 2. connect to a RTSP server, announce a G722 media +// 2. connect to a RTSP server, announce a G722 format // 3. route the packets from GStreamer to the server func main() { diff --git a/examples/client-record-format-h264/main.go b/examples/client-record-format-h264/main.go index 0ed4bcdd..35a52aa9 100644 --- a/examples/client-record-format-h264/main.go +++ b/examples/client-record-format-h264/main.go @@ -12,7 +12,7 @@ import ( // This example shows how to // 1. generate RTP/H264 packets with GStreamer -// 2. connect to a RTSP server, announce an H264 media +// 2. connect to a RTSP server, announce an H264 format // 3. route the packets from GStreamer to the server func main() { diff --git a/examples/client-record-format-h265/main.go b/examples/client-record-format-h265/main.go index 73b9f51d..319d6dfa 100644 --- a/examples/client-record-format-h265/main.go +++ b/examples/client-record-format-h265/main.go @@ -12,7 +12,7 @@ import ( // This example shows how to // 1. generate RTP/H265 packets with GStreamer -// 2. connect to a RTSP server, announce an H265 media +// 2. connect to a RTSP server, announce an H265 format // 3. route the packets from GStreamer to the server func main() { diff --git a/examples/client-record-format-lpcm/main.go b/examples/client-record-format-lpcm/main.go index 4ac0c8d9..f451acc8 100644 --- a/examples/client-record-format-lpcm/main.go +++ b/examples/client-record-format-lpcm/main.go @@ -12,7 +12,7 @@ import ( // This example shows how to // 1. generate RTP/LPCM packets with GStreamer -// 2. connect to a RTSP server, announce an LPCM media +// 2. connect to a RTSP server, announce an LPCM format // 3. route the packets from GStreamer to the server func main() { diff --git a/examples/client-record-format-mjpeg-from-image/main.go b/examples/client-record-format-mjpeg-from-image/main.go new file mode 100644 index 00000000..eb11fa79 --- /dev/null +++ b/examples/client-record-format-mjpeg-from-image/main.go @@ -0,0 +1,104 @@ +package main + +import ( + "bytes" + "image" + "image/color" + "image/jpeg" + "time" + + "github.com/bluenviron/gortsplib/v4" + "github.com/bluenviron/gortsplib/v4/pkg/description" + "github.com/bluenviron/gortsplib/v4/pkg/format" + "github.com/bluenviron/gortsplib/v4/pkg/rtptime" +) + +// This example shows how to +// 1. connect to a RTSP server, announce a M-JPEG format +// 2. generate an image +// 3. encode the image with JPEG +// 4. generate RTP/M-JPEG packets from the JPEG image +// 5. write packets to the server + +func main() { + // create a description that contains a M-JPEG format + forma := &format.MJPEG{} + desc := &description.Session{ + Medias: []*description.Media{{ + Type: description.MediaTypeVideo, + Formats: []format.Format{forma}, + }}, + } + + // connect to the server, announce the format and start recording + c := gortsplib.Client{} + err := c.StartRecording("rtsp://localhost:8554/mystream", desc) + if err != nil { + panic(err) + } + defer c.Close() + + // setup JPEG -> RTP/M-JPEG encoder + rtpEnc, err := forma.CreateEncoder() + if err != nil { + panic(err) + } + + // setup timestamp generator + rtpTime := rtptime.NewEncoder(forma.ClockRate(), 0) + start := time.Now() + + // setup a ticker to sleep between frames + ticker := time.NewTicker(200 * time.Millisecond) + defer ticker.Stop() + + i := 0 + + for range ticker.C { + // create a RGBA image + image := image.NewRGBA(image.Rect(0, 0, 640, 480)) + + // fill the image + var cl color.RGBA + switch i { + case 0: + cl = color.RGBA{255, 0, 0, 0} + case 1: + cl = color.RGBA{0, 255, 0, 0} + case 2: + cl = color.RGBA{0, 0, 255, 0} + } + for y := 0; y < image.Rect.Dy(); y++ { + for x := 0; x < image.Rect.Dx(); x++ { + image.SetRGBA(x, y, cl) + } + } + i = (i + 1) % 3 + + // encode the image with JPEG + var buf bytes.Buffer + err := jpeg.Encode(&buf, image, &jpeg.Options{Quality: 80}) + if err != nil { + panic(err) + } + + // generate RTP/M-JPEG packets from the JPEG image + pkts, err := rtpEnc.Encode(buf.Bytes()) + if err != nil { + panic(err) + } + + // get current timestamp + ts := rtpTime.Encode(time.Now().Sub(start)) + + // write packets to the server + for _, pkt := range pkts { + pkt.Timestamp = ts + + err = c.WritePacketRTP(desc.Medias[0], pkt) + if err != nil { + panic(err) + } + } + } +} diff --git a/examples/client-record-format-mjpeg/main.go b/examples/client-record-format-mjpeg/main.go index 843cf9e3..80140b2e 100644 --- a/examples/client-record-format-mjpeg/main.go +++ b/examples/client-record-format-mjpeg/main.go @@ -12,7 +12,7 @@ import ( // This example shows how to // 1. generate RTP/M-JPEG packets with GStreamer -// 2. connect to a RTSP server, announce a M-JPEG media +// 2. connect to a RTSP server, announce a M-JPEG format // 3. route the packets from GStreamer to the server func main() { diff --git a/examples/client-record-format-mpeg4audio/main.go b/examples/client-record-format-mpeg4audio/main.go index 91d0f60d..467396f2 100644 --- a/examples/client-record-format-mpeg4audio/main.go +++ b/examples/client-record-format-mpeg4audio/main.go @@ -13,7 +13,7 @@ import ( // This example shows how to // 1. generate RTP/MPEG-4 audio packets with GStreamer -// 2. connect to a RTSP server, announce an MPEG-4 audio media +// 2. connect to a RTSP server, announce an MPEG-4 audio format // 3. route the packets from GStreamer to the server func main() { diff --git a/examples/client-record-format-opus/main.go b/examples/client-record-format-opus/main.go index 8f88f346..6b30ccb8 100644 --- a/examples/client-record-format-opus/main.go +++ b/examples/client-record-format-opus/main.go @@ -12,7 +12,7 @@ import ( // This example shows how to // 1. generate RTP/Opus packets with GStreamer -// 2. connect to a RTSP server, announce an Opus media +// 2. connect to a RTSP server, announce an Opus format // 3. route the packets from GStreamer to the server func main() { diff --git a/examples/client-record-format-vp8/main.go b/examples/client-record-format-vp8/main.go index d2e647e6..35f47a53 100644 --- a/examples/client-record-format-vp8/main.go +++ b/examples/client-record-format-vp8/main.go @@ -12,7 +12,7 @@ import ( // This example shows how to // 1. generate RTP/VP8 packets with GStreamer -// 2. connect to a RTSP server, announce a VP8 media +// 2. connect to a RTSP server, announce a VP8 format // 3. route the packets from GStreamer to the server func main() { diff --git a/examples/client-record-format-vp9/main.go b/examples/client-record-format-vp9/main.go index 496238a5..1666c850 100644 --- a/examples/client-record-format-vp9/main.go +++ b/examples/client-record-format-vp9/main.go @@ -12,7 +12,7 @@ import ( // This example shows how to // 1. generate RTP/VP9 packets with GStreamer -// 2. connect to a RTSP server, announce a VP9 media +// 2. connect to a RTSP server, announce a VP9 format // 3. route the packets from GStreamer to the server func main() { diff --git a/examples/client-record-options/main.go b/examples/client-record-options/main.go index 78a16697..6ec18403 100644 --- a/examples/client-record-options/main.go +++ b/examples/client-record-options/main.go @@ -14,7 +14,7 @@ import ( // This example shows how to // 1. set additional client options // 2. generate RTP/H264 frames from a file with GStreamer -// 3. connect to a RTSP server, announce an H264 media +// 3. connect to a RTSP server, announce an H264 format // 4. write the frames to the server func main() { diff --git a/examples/client-record-pause/main.go b/examples/client-record-pause/main.go index ec631db5..9d16584b 100644 --- a/examples/client-record-pause/main.go +++ b/examples/client-record-pause/main.go @@ -13,7 +13,7 @@ import ( // This example shows how to // 1. generate RTP/H264 frames from a file with GStreamer -// 2. connect to a RTSP server, announce an H264 media +// 2. connect to a RTSP server, announce an H264 format // 3. write the frames to the server for 5 seconds // 4. pause for 5 seconds // 5. repeat