mirror of
https://github.com/aler9/gortsplib
synced 2025-10-04 23:02:45 +08:00
add client-record-format-h264-from-disk (#578)
This commit is contained in:
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)
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user