add client-record-format-h264-from-disk (#578)

This commit is contained in:
Alessandro Ros
2024-05-25 19:04:41 +02:00
committed by GitHub
parent b3204e7cda
commit 29c6e18e89
25 changed files with 184 additions and 45 deletions

View File

@@ -12,7 +12,7 @@ import (
)
// This example shows how to
// 1. generate RTP/G711 packets with GStreamer
// 1. generate a G711 stream and RTP packets with GStreamer
// 2. connect to a RTSP server, find a back channel that supports G711
// 3. route the packets from GStreamer to the channel

View File

@@ -71,7 +71,7 @@ func main() {
panic("media not found")
}
// setup RTP/H264 -> H264 decoder
// setup RTP -> H264 decoder
rtpDec, err := forma.CreateDecoder()
if err != nil {
panic(err)

View File

@@ -44,7 +44,7 @@ func main() {
panic("media not found")
}
// setup RTP/H264 -> H264 decoder
// setup RTP -> H264 decoder
rtpDec, err := forma.CreateDecoder()
if err != nil {
panic(err)

View File

@@ -47,7 +47,7 @@ func main() {
panic("media not found")
}
// setup RTP/H264 -> H264 decoder
// setup RTP -> H264 decoder
rtpDec, err := forma.CreateDecoder()
if err != nil {
panic(err)

View File

@@ -71,7 +71,7 @@ func main() {
panic("media not found")
}
// setup RTP/H265 -> H265 decoder
// setup RTP -> H265 decoder
rtpDec, err := forma.CreateDecoder()
if err != nil {
panic(err)

View File

@@ -44,7 +44,7 @@ func main() {
panic("media not found")
}
// setup RTP/H265 -> H265 decoder
// setup RTP -> H265 decoder
rtpDec, err := forma.CreateDecoder()
if err != nil {
panic(err)

View File

@@ -47,7 +47,7 @@ func main() {
panic("media not found")
}
// setup RTP/H265 -> H265 decoder
// setup RTP -> H265 decoder
rtpDec, err := forma.CreateDecoder()
if err != nil {
panic(err)

View File

@@ -44,7 +44,7 @@ func main() {
panic("media not found")
}
// setup RTP/MPEG-4 audio -> MPEG-4 audio decoder
// setup RTP -> MPEG-4 audio decoder
rtpDec, err := forma.CreateDecoder()
if err != nil {
panic(err)

View File

@@ -44,7 +44,7 @@ func main() {
panic("media not found")
}
// setup RTP/Opus -> Opus decoder
// setup RTP -> Opus decoder
rtpDec, err := forma.CreateDecoder()
if err != nil {
panic(err)

View File

@@ -11,7 +11,7 @@ import (
)
// This example shows how to
// 1. generate RTP/G711 packets with GStreamer
// 1. generate a G711 and RTP packets with GStreamer
// 2. connect to a RTSP server, announce a G711 format
// 3. route the packets from GStreamer to the server

View File

@@ -11,7 +11,7 @@ import (
)
// This example shows how to
// 1. generate RTP/G722 packets with GStreamer
// 1. generate a G722 stream and RTP packets with GStreamer
// 2. connect to a RTSP server, announce a G722 format
// 3. route the packets from GStreamer to the server

View File

@@ -0,0 +1,132 @@
package main
import (
"fmt"
"log"
"os"
"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"
"github.com/bluenviron/mediacommon/pkg/formats/mpegts"
)
// This example shows how to
// 1. read H264 frames from a video file in MPEG-TS format
// 2. connect to a RTSP server, announce a H264 format
// 3. wrap frames into RTP packets
// 4. write packets to the server
func findTrack(r *mpegts.Reader) (*mpegts.Track, error) {
for _, track := range r.Tracks() {
if _, ok := track.Codec.(*mpegts.CodecH264); ok {
return track, nil
}
}
return nil, fmt.Errorf("H264 track not found")
}
func main() {
// open a file in MPEG-TS format
f, err := os.Open("myvideo.ts")
if err != nil {
panic(err)
}
defer f.Close()
// setup MPEG-TS parser
r, err := mpegts.NewReader(f)
if err != nil {
panic(err)
}
// find the H264 track inside the file
track, err := findTrack(r)
if err != nil {
panic(err)
}
// create a RTSP description that contains a H264 format
forma := &format.H264{
PayloadTyp: 96,
PacketizationMode: 1,
}
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 H264 -> RTP encoder
rtpEnc, err := forma.CreateEncoder()
if err != nil {
panic(err)
}
// setup RTP timestamp generator
rtpTime := &rtptime.Encoder{ClockRate: forma.ClockRate()}
err = rtpTime.Initialize()
if err != nil {
panic(err)
}
var firstDTS *int64
var startTime time.Time
// setup a callback that is called whenever a H264 access unit is read from the file
r.OnDataH264(track, func(pts, dts int64, au [][]byte) error {
// sleep between access units
if firstDTS != nil {
timeDrift := time.Duration(dts-*firstDTS)*time.Second/90000 - time.Since(startTime)
if timeDrift > 0 {
time.Sleep(timeDrift)
}
} else {
startTime = time.Now()
firstDTS = &dts
}
log.Printf("writing access unit with pts=%d dts=%d", pts, dts)
// wrap the access unit into RTP packets
packets, err := rtpEnc.Encode(au)
if err != nil {
return err
}
// set timestamp
rtpTime := rtpTime.Encode(time.Duration(pts) * time.Second / 90000)
for _, packet := range packets {
packet.Timestamp = rtpTime
}
// write packets to the server
for _, packet := range packets {
err := c.WritePacketRTP(desc.Medias[0], packet)
if err != nil {
return err
}
}
return nil
})
// start reading the MPEG-TS file
for {
err := r.Read()
if err != nil {
panic(err)
}
}
}

View File

@@ -11,7 +11,7 @@ import (
)
// This example shows how to
// 1. generate RTP/H264 packets with GStreamer
// 1. generate a H264 stream and RTP packets with GStreamer
// 2. connect to a RTSP server, announce an H264 format
// 3. route the packets from GStreamer to the server

View File

@@ -11,7 +11,7 @@ import (
)
// This example shows how to
// 1. generate RTP/H265 packets with GStreamer
// 1. generate a H265 stream and RTP packets with GStreamer
// 2. connect to a RTSP server, announce an H265 format
// 3. route the packets from GStreamer to the server

View File

@@ -11,7 +11,7 @@ import (
)
// This example shows how to
// 1. generate RTP/LPCM packets with GStreamer
// 1. generate a LPCM stream and RTP packets with GStreamer
// 2. connect to a RTSP server, announce an LPCM format
// 3. route the packets from GStreamer to the server

View File

@@ -17,9 +17,31 @@ import (
// 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
// 4. generate RTP packets from the JPEG image
// 5. write packets to the server
func createRandomImage(i int) *image.RGBA {
img := image.NewRGBA(image.Rect(0, 0, 640, 480))
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 < img.Rect.Dy(); y++ {
for x := 0; x < img.Rect.Dx(); x++ {
img.SetRGBA(x, y, cl)
}
}
return img
}
func main() {
// create a description that contains a M-JPEG format
forma := &format.MJPEG{}
@@ -38,13 +60,13 @@ func main() {
}
defer c.Close()
// setup JPEG -> RTP/M-JPEG encoder
// setup JPEG -> RTP encoder
rtpEnc, err := forma.CreateEncoder()
if err != nil {
panic(err)
}
// setup timestamp generator
// setup RTP timestamp generator
rtpTime := &rtptime.Encoder{ClockRate: forma.ClockRate()}
err = rtpTime.Initialize()
if err != nil {
@@ -59,34 +81,18 @@ func main() {
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)
}
}
// create a random image
img := createRandomImage(i)
i = (i + 1) % 3
// encode the image with JPEG
var buf bytes.Buffer
err := jpeg.Encode(&buf, image, &jpeg.Options{Quality: 80})
err := jpeg.Encode(&buf, img, &jpeg.Options{Quality: 80})
if err != nil {
panic(err)
}
// generate RTP/M-JPEG packets from the JPEG image
// generate RTP packets from the JPEG image
pkts, err := rtpEnc.Encode(buf.Bytes())
if err != nil {
panic(err)

View File

@@ -11,7 +11,7 @@ import (
)
// This example shows how to
// 1. generate RTP/M-JPEG packets with GStreamer
// 1. generate a M-JPEG stream and RTP packets with GStreamer
// 2. connect to a RTSP server, announce a M-JPEG format
// 3. route the packets from GStreamer to the server

View File

@@ -12,7 +12,7 @@ import (
)
// This example shows how to
// 1. generate RTP/MPEG-4 audio packets with GStreamer
// 1. generate a MPEG-4 audio stream and RTP packets with GStreamer
// 2. connect to a RTSP server, announce an MPEG-4 audio format
// 3. route the packets from GStreamer to the server

View File

@@ -11,7 +11,7 @@ import (
)
// This example shows how to
// 1. generate RTP/Opus packets with GStreamer
// 1. generate a Opus stream and RTP packets with GStreamer
// 2. connect to a RTSP server, announce an Opus format
// 3. route the packets from GStreamer to the server

View File

@@ -11,7 +11,7 @@ import (
)
// This example shows how to
// 1. generate RTP/VP8 packets with GStreamer
// 1. generate a VP8 stream and RTP packets with GStreamer
// 2. connect to a RTSP server, announce a VP8 format
// 3. route the packets from GStreamer to the server

View File

@@ -11,7 +11,7 @@ import (
)
// This example shows how to
// 1. generate RTP/VP9 packets with GStreamer
// 1. generate a VP9 stream and RTP packets with GStreamer
// 2. connect to a RTSP server, announce a VP9 format
// 3. route the packets from GStreamer to the server

View File

@@ -13,7 +13,7 @@ import (
// This example shows how to
// 1. set additional client options
// 2. generate RTP/H264 frames from a file with GStreamer
// 2. read H264 frames from a file and generate RTP packets with GStreamer
// 3. connect to a RTSP server, announce an H264 format
// 4. write the frames to the server

View File

@@ -12,7 +12,7 @@ import (
)
// This example shows how to
// 1. generate RTP/H264 frames from a file with GStreamer
// 1. read H264 frames from a file and generate RTP packets with GStreamer
// 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

View File

@@ -76,7 +76,7 @@ func (sh *serverHandler) OnAnnounce(ctx *gortsplib.ServerHandlerOnAnnounceCtx) (
}, fmt.Errorf("H264 media not found")
}
// setup RTP/H264 -> H264 decoder
// setup RTP -> H264 decoder
rtpDec, err := forma.CreateDecoder()
if err != nil {
panic(err)