mirror of
https://github.com/aler9/gortsplib
synced 2025-11-03 03:03:31 +08:00
add client-record-format-h264-from-disk (#578)
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
132
examples/client-record-format-h264-from-disk/main.go
Normal file
132
examples/client-record-format-h264-from-disk/main.go
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user