mirror of
https://github.com/aler9/rtsp-simple-server
synced 2025-10-16 12:40:56 +08:00
hls source: support proxying H265 and Opus tracks
This commit is contained in:
@@ -13,7 +13,7 @@ Live streams can be published to the server with:
|
|||||||
|RTSP servers and cameras|UDP, UDP-Multicast, TCP, RTSPS|H264, H265, VP8, VP9, AV1, MPEG2, M-JPEG, MP3, MPEG4 Audio (AAC), Opus, G711, G722, LPCM and any RTP-compatible codec|
|
|RTSP servers and cameras|UDP, UDP-Multicast, TCP, RTSPS|H264, H265, VP8, VP9, AV1, MPEG2, M-JPEG, MP3, MPEG4 Audio (AAC), Opus, G711, G722, LPCM and any RTP-compatible codec|
|
||||||
|RTMP clients (OBS Studio)|RTMP, RTMPS|H264, H265, MPEG4 Audio (AAC)|
|
|RTMP clients (OBS Studio)|RTMP, RTMPS|H264, H265, MPEG4 Audio (AAC)|
|
||||||
|RTMP servers and cameras|RTMP, RTMPS|H264, MPEG4 Audio (AAC)|
|
|RTMP servers and cameras|RTMP, RTMPS|H264, MPEG4 Audio (AAC)|
|
||||||
|HLS servers and cameras|Low-Latency HLS, MP4-based HLS, legacy HLS|H264, MPEG4 Audio (AAC)|
|
|HLS servers and cameras|Low-Latency HLS, MP4-based HLS, legacy HLS|H264, H265, MPEG4 Audio (AAC), Opus|
|
||||||
|Raspberry Pi Cameras||H264|
|
|Raspberry Pi Cameras||H264|
|
||||||
|
|
||||||
And can be read from the server with:
|
And can be read from the server with:
|
||||||
|
@@ -83,6 +83,18 @@ func (s *hlsSource) run(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
case *format.H265:
|
||||||
|
c.OnData(track, func(pts time.Duration, dat interface{}) {
|
||||||
|
err := stream.writeData(medi, ctrack, &formatprocessor.DataH265{
|
||||||
|
PTS: pts,
|
||||||
|
AU: dat.([][]byte),
|
||||||
|
NTP: time.Now(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
s.Log(logger.Warn, "%v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
case *format.MPEG4Audio:
|
case *format.MPEG4Audio:
|
||||||
c.OnData(track, func(pts time.Duration, dat interface{}) {
|
c.OnData(track, func(pts time.Duration, dat interface{}) {
|
||||||
err := stream.writeData(medi, ctrack, &formatprocessor.DataMPEG4Audio{
|
err := stream.writeData(medi, ctrack, &formatprocessor.DataMPEG4Audio{
|
||||||
@@ -94,6 +106,18 @@ func (s *hlsSource) run(ctx context.Context) error {
|
|||||||
s.Log(logger.Warn, "%v", err)
|
s.Log(logger.Warn, "%v", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
case *format.Opus:
|
||||||
|
c.OnData(track, func(pts time.Duration, dat interface{}) {
|
||||||
|
err := stream.writeData(medi, ctrack, &formatprocessor.DataOpus{
|
||||||
|
PTS: pts,
|
||||||
|
Frame: dat.([]byte),
|
||||||
|
NTP: time.Now(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
s.Log(logger.Warn, "%v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -39,7 +39,9 @@ func codecParametersGenerate(track format.Format) string {
|
|||||||
func codecParametersAreSupported(codecs string) bool {
|
func codecParametersAreSupported(codecs string) bool {
|
||||||
for _, codec := range strings.Split(codecs, ",") {
|
for _, codec := range strings.Split(codecs, ",") {
|
||||||
if !strings.HasPrefix(codec, "avc1.") &&
|
if !strings.HasPrefix(codec, "avc1.") &&
|
||||||
!strings.HasPrefix(codec, "mp4a.") {
|
!strings.HasPrefix(codec, "hvc1.") &&
|
||||||
|
!strings.HasPrefix(codec, "mp4a.") &&
|
||||||
|
codec != "opus" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
internal/hls/fmp4/boxes_h265.go
Normal file
12
internal/hls/fmp4/boxes_h265.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
//nolint:gochecknoinits,revive,gocritic
|
||||||
|
package fmp4
|
||||||
|
|
||||||
|
import (
|
||||||
|
gomp4 "github.com/abema/go-mp4"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BoxTypeHvc1() gomp4.BoxType { return gomp4.StrToBoxType("hvc1") }
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
gomp4.AddAnyTypeBoxDef(&gomp4.VisualSampleEntry{}, BoxTypeHvc1())
|
||||||
|
}
|
@@ -76,7 +76,6 @@ func (i *Init) Unmarshal(byts []byte) error {
|
|||||||
if state != waitingCodec {
|
if state != waitingCodec {
|
||||||
return nil, fmt.Errorf("unexpected box 'avc1'")
|
return nil, fmt.Errorf("unexpected box 'avc1'")
|
||||||
}
|
}
|
||||||
|
|
||||||
state = waitingAvcC
|
state = waitingAvcC
|
||||||
|
|
||||||
case "avcC":
|
case "avcC":
|
||||||
@@ -116,7 +115,7 @@ func (i *Init) Unmarshal(byts []byte) error {
|
|||||||
}
|
}
|
||||||
state = waitingTrak
|
state = waitingTrak
|
||||||
|
|
||||||
case "hev1":
|
case "hev1", "hvc1":
|
||||||
if state != waitingCodec {
|
if state != waitingCodec {
|
||||||
return nil, fmt.Errorf("unexpected box 'hev1'")
|
return nil, fmt.Errorf("unexpected box 'hev1'")
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user