client: turn ReadFrames into OnPacketRTP, OnPacketRTCP

This commit is contained in:
aler9
2021-11-04 11:05:51 +01:00
committed by Alessandro Ros
parent b4aadd8e4c
commit a22116e66e
12 changed files with 353 additions and 318 deletions

View File

@@ -25,31 +25,6 @@ const (
)
func main() {
c := gortsplib.Client{}
// connect to the server and start reading all tracks
err := c.DialRead(inputStream)
if err != nil {
panic(err)
}
defer c.Close()
// find the H264 track
var h264TrackID int = -1
var h264Conf *gortsplib.TrackConfigH264
for i, track := range c.Tracks() {
if track.IsH264() {
h264TrackID = i
h264Conf, err = track.ExtractConfigH264()
if err != nil {
panic(err)
}
}
}
if h264TrackID < 0 {
panic(fmt.Errorf("H264 track not found"))
}
// open output file
f, err := os.Create(outputFile)
if err != nil {
@@ -73,100 +48,128 @@ func main() {
})
mux.SetPCRPID(256)
// read packets
err = c.ReadFrames(func(trackID int, streamType gortsplib.StreamType, payload []byte) {
if trackID != h264TrackID {
return
}
var h264TrackID int = -1
var h264Conf *gortsplib.TrackConfigH264
if streamType != gortsplib.StreamTypeRTP {
return
}
// parse RTP packets
var pkt rtp.Packet
err := pkt.Unmarshal(payload)
if err != nil {
return
}
// decode H264 NALUs from RTP packets
nalus, pts, err := dec.DecodeUntilMarker(&pkt)
if err != nil {
return
}
if !firstPacketWritten {
firstPacketWritten = true
startPTS = pts
}
// check whether there's an IDR
idrPresent := func() bool {
for _, nalu := range nalus {
typ := h264.NALUType(nalu[0] & 0x1F)
if typ == h264.NALUTypeIDR {
return true
c := gortsplib.Client{
// called before sending a PLAY request
OnPlay: func(c *gortsplib.Client) {
// find the H264 track
for i, track := range c.Tracks() {
if track.IsH264() {
h264TrackID = i
var err error
h264Conf, err = track.ExtractConfigH264()
if err != nil {
panic(err)
}
}
}
return false
}()
// prepend an AUD. This is required by some players
filteredNALUs := [][]byte{
{byte(h264.NALUTypeAccessUnitDelimiter), 240},
}
for _, nalu := range nalus {
// remove existing SPS, PPS, AUD
typ := h264.NALUType(nalu[0] & 0x1F)
switch typ {
case h264.NALUTypeSPS, h264.NALUTypePPS, h264.NALUTypeAccessUnitDelimiter:
continue
if h264TrackID < 0 {
panic(fmt.Errorf("H264 track not found"))
}
},
// called when a RTP packet arrives
OnPacketRTP: func(c *gortsplib.Client, trackID int, payload []byte) {
if trackID != h264TrackID {
return
}
// add SPS and PPS before every IDR
if typ == h264.NALUTypeIDR {
filteredNALUs = append(filteredNALUs, h264Conf.SPS)
filteredNALUs = append(filteredNALUs, h264Conf.PPS)
// parse RTP packets
var pkt rtp.Packet
err := pkt.Unmarshal(payload)
if err != nil {
return
}
filteredNALUs = append(filteredNALUs, nalu)
}
// decode H264 NALUs from RTP packets
nalus, pts, err := dec.DecodeUntilMarker(&pkt)
if err != nil {
return
}
// encode into Annex-B
enc, err := h264.EncodeAnnexB(filteredNALUs)
if err != nil {
panic(err)
}
if !firstPacketWritten {
firstPacketWritten = true
startPTS = pts
}
dts := dtsEst.Feed(pts - startPTS)
pts = pts - startPTS
// check whether there's an IDR
idrPresent := func() bool {
for _, nalu := range nalus {
typ := h264.NALUType(nalu[0] & 0x1F)
if typ == h264.NALUTypeIDR {
return true
}
}
return false
}()
// write TS packet
_, err = mux.WriteData(&astits.MuxerData{
PID: 256,
AdaptationField: &astits.PacketAdaptationField{
RandomAccessIndicator: idrPresent,
},
PES: &astits.PESData{
Header: &astits.PESHeader{
OptionalHeader: &astits.PESOptionalHeader{
MarkerBits: 2,
PTSDTSIndicator: astits.PTSDTSIndicatorBothPresent,
DTS: &astits.ClockReference{Base: int64(dts.Seconds() * 90000)},
PTS: &astits.ClockReference{Base: int64(pts.Seconds() * 90000)},
},
StreamID: 224, // video
// prepend an AUD. This is required by some players
filteredNALUs := [][]byte{
{byte(h264.NALUTypeAccessUnitDelimiter), 240},
}
for _, nalu := range nalus {
// remove existing SPS, PPS, AUD
typ := h264.NALUType(nalu[0] & 0x1F)
switch typ {
case h264.NALUTypeSPS, h264.NALUTypePPS, h264.NALUTypeAccessUnitDelimiter:
continue
}
// add SPS and PPS before every IDR
if typ == h264.NALUTypeIDR {
filteredNALUs = append(filteredNALUs, h264Conf.SPS)
filteredNALUs = append(filteredNALUs, h264Conf.PPS)
}
filteredNALUs = append(filteredNALUs, nalu)
}
// encode into Annex-B
enc, err := h264.EncodeAnnexB(filteredNALUs)
if err != nil {
panic(err)
}
dts := dtsEst.Feed(pts - startPTS)
pts = pts - startPTS
// write TS packet
_, err = mux.WriteData(&astits.MuxerData{
PID: 256,
AdaptationField: &astits.PacketAdaptationField{
RandomAccessIndicator: idrPresent,
},
Data: enc,
},
})
if err != nil {
panic(err)
}
PES: &astits.PESData{
Header: &astits.PESHeader{
OptionalHeader: &astits.PESOptionalHeader{
MarkerBits: 2,
PTSDTSIndicator: astits.PTSDTSIndicatorBothPresent,
DTS: &astits.ClockReference{Base: int64(dts.Seconds() * 90000)},
PTS: &astits.ClockReference{Base: int64(pts.Seconds() * 90000)},
},
StreamID: 224, // video
},
Data: enc,
},
})
if err != nil {
panic(err)
}
fmt.Println("wrote ts packet")
})
fmt.Println("wrote ts packet")
},
}
// connect to the server and start reading all tracks
err = c.DialRead(inputStream)
if err != nil {
panic(err)
}
defer c.Close()
// read packets
err = c.ReadFrames()
panic(err)
}