mirror of
https://github.com/langhuihui/monibuca.git
synced 2025-10-05 18:06:51 +08:00
117 lines
3.2 KiB
Go
117 lines
3.2 KiB
Go
package plugin_hdl
|
|
|
|
import (
|
|
"io"
|
|
"net"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"m7s.live/m7s/v5"
|
|
"m7s.live/m7s/v5/pkg/util"
|
|
. "m7s.live/m7s/v5/plugin/hdl/pkg"
|
|
rtmp "m7s.live/m7s/v5/plugin/rtmp/pkg"
|
|
)
|
|
|
|
type HDLPlugin struct {
|
|
m7s.Plugin
|
|
}
|
|
|
|
var _ = m7s.InstallPlugin[HDLPlugin]()
|
|
|
|
func (p *HDLPlugin) WriteFlvHeader(sub *m7s.Subscriber, w io.Writer) {
|
|
// at, vt := sub.Publisher, sub.Video
|
|
// hasAudio, hasVideo := at != nil, vt != nil
|
|
// var amf rtmp.AMF
|
|
// amf.Marshal("onMetaData")
|
|
// metaData := rtmp.EcmaArray{
|
|
// "MetaDataCreator": "m7s" + m7s.Version,
|
|
// "hasVideo": hasVideo,
|
|
// "hasAudio": hasAudio,
|
|
// "hasMatadata": true,
|
|
// "canSeekToEnd": false,
|
|
// "duration": 0,
|
|
// "hasKeyFrames": 0,
|
|
// "framerate": 0,
|
|
// "videodatarate": 0,
|
|
// "filesize": 0,
|
|
// }
|
|
var flags byte
|
|
// if hasAudio {
|
|
flags |= (1 << 2)
|
|
// metaData["audiocodecid"] = int(at.CodecID)
|
|
// metaData["audiosamplerate"] = at.SampleRate
|
|
// metaData["audiosamplesize"] = at.SampleSize
|
|
// metaData["stereo"] = at.Channels == 2
|
|
// }
|
|
// if hasVideo {
|
|
flags |= 1
|
|
// metaData["videocodecid"] = int(vt.CodecID)
|
|
// metaData["width"] = vt.SPSInfo.Width
|
|
// metaData["height"] = vt.SPSInfo.Height
|
|
// }
|
|
// amf.Marshal(metaData)
|
|
// 写入FLV头
|
|
w.Write([]byte{'F', 'L', 'V', 0x01, flags, 0, 0, 0, 9, 0, 0, 0, 0})
|
|
// codec.WriteFLVTag(w, codec.FLV_TAG_TYPE_SCRIPT, 0, amf.Buffer)
|
|
}
|
|
|
|
func (p *HDLPlugin) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
streamPath := strings.TrimSuffix(strings.TrimPrefix(r.URL.Path, "/"), ".flv")
|
|
if r.URL.RawQuery != "" {
|
|
streamPath += "?" + r.URL.RawQuery
|
|
}
|
|
|
|
sub, err := p.Subscribe(streamPath, w, r.Context())
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "video/x-flv")
|
|
w.Header().Set("Transfer-Encoding", "identity")
|
|
w.WriteHeader(http.StatusOK)
|
|
wto := p.GetCommonConf().WriteTimeout
|
|
var gotFlvTag func(tag *net.Buffers) error
|
|
if hijacker, ok := w.(http.Hijacker); ok && wto > 0 {
|
|
conn, _, _ := hijacker.Hijack()
|
|
conn.SetWriteDeadline(time.Now().Add(wto))
|
|
sub.Closer = conn
|
|
p.WriteFlvHeader(sub, conn)
|
|
gotFlvTag = func(tag *net.Buffers) (err error) {
|
|
conn.SetWriteDeadline(time.Now().Add(wto))
|
|
_, err = tag.WriteTo(conn)
|
|
return
|
|
}
|
|
} else {
|
|
w.(http.Flusher).Flush()
|
|
p.WriteFlvHeader(sub, w)
|
|
gotFlvTag = func(tag *net.Buffers) (err error) {
|
|
_, err = tag.WriteTo(w)
|
|
return
|
|
}
|
|
}
|
|
b := util.Buffer(make([]byte, 0, 15))
|
|
var flv net.Buffers
|
|
sub.Handle(func(audio *rtmp.RTMPAudio) error {
|
|
b.Reset()
|
|
b.WriteByte(FLV_TAG_TYPE_AUDIO)
|
|
dataSize := audio.Length
|
|
b.WriteUint24(uint32(dataSize))
|
|
b.WriteUint24(audio.Timestamp)
|
|
b.WriteByte(byte(audio.Timestamp >> 24))
|
|
b.WriteUint24(0)
|
|
flv = append(append(append(flv, b), audio.Buffers.Buffers...), util.PutBE(b.Malloc(4), dataSize+11))
|
|
return gotFlvTag(&flv)
|
|
}, func(video *rtmp.RTMPVideo) error {
|
|
b.Reset()
|
|
b.WriteByte(FLV_TAG_TYPE_VIDEO)
|
|
dataSize := video.Length
|
|
b.WriteUint24(uint32(dataSize))
|
|
b.WriteUint24(video.Timestamp)
|
|
b.WriteByte(byte(video.Timestamp >> 24))
|
|
b.WriteUint24(0)
|
|
flv = append(append(append(flv, b), video.Buffers.Buffers...), util.PutBE(b.Malloc(4), dataSize+11))
|
|
return gotFlvTag(&flv)
|
|
})
|
|
}
|