mirror of
https://github.com/aler9/gortsplib
synced 2025-10-02 05:52:09 +08:00
133 lines
2.8 KiB
Go
133 lines
2.8 KiB
Go
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)
|
|
}
|
|
}
|
|
}
|