使用udpxy和msd_lite都有一些小问题,参考多方用golang写了个简单rtp多播转http单播,无缓存,cpu占用有点小高,效果不错。
package main
import (
"flag"
"fmt"
"github.com/pion/rtp"
"io"
"net"
"net/http"
//"strings"
"time"
)
var timeout = 2000 * time.Millisecond
var readbuffer = 2 * 1024 * 1024
var buffer = 1500
const (
RTP_Payload_MP2T = 33
ContentType_MP2T = "video/MP2T"
ContentType_DEFAULT = "application/octet-stream"
)
var McastIface = flag.String("m", "eth1.23", "mcast iface (IP addr or name)")
var ListenAddr = flag.String("a", "0.0.0.0", "http listen addr (default 0.0.0.0)")
var ListenPort = flag.Int("p", 8080, "http listen port (default 8080)")
func main() {
flag.Parse()
http.HandleFunc("/", handler)
fmt.Printf("http listen: %s:%d\n", *ListenAddr, *ListenPort)
err := http.ListenAndServe(fmt.Sprintf("%s:%d", *ListenAddr, *ListenPort), nil)
if err != nil {
panic(err)
}
}
var tag = "/udp/"
var tagLen = len(tag)
func handler(w http.ResponseWriter, r *http.Request) {
var err error
defer func(w http.ResponseWriter, r *http.Request) {
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
io.WriteString(w, err.Error()+"\n")
}
fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "close http: "+r.RemoteAddr)
}(w, r)
path := r.URL.Path
if len(path) < tagLen {
w.WriteHeader(http.StatusBadRequest)
io.WriteString(w, "No address specified\n")
return
}
addr := path[tagLen:]
fmt.Println(time.Now().Format("2006-01-02 15:04:05"), addr, r.RemoteAddr)
conn, err := newMulticastReader(addr)
if err != nil {
return
}
defer func() {
_ = conn.Close()
fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "close udp: "+addr)
}()
w.Header().Set("X-Content-Type-Options", "nosniff")
conn.SetReadBuffer(readbuffer)
headerSent := false
p := &rtp.Packet{}
var buf = make([]byte, buffer)
for {
conn.SetReadDeadline(time.Now().Add(timeout))
n, err := conn.Read(buf)
if err != nil {
fmt.Println("read err:", err)
w.WriteHeader(http.StatusInternalServerError)
io.WriteString(w, err.Error())
return
}
//fmt.Println(time.Now(), n, "buf len:", len(buf))
if err = p.Unmarshal(buf[:n]); err != nil {
fmt.Println("unpack err:", err)
return
}
if !headerSent {
headerSent = true
if p.PayloadType == RTP_Payload_MP2T {
w.Header().Set("Content-Type", ContentType_MP2T)
} else {
w.Header().Set("Content-Type", ContentType_DEFAULT)
}
w.WriteHeader(http.StatusOK)
}
if _, err = w.Write(p.Payload); err != nil {
return
}
}
}
func newMulticastReader(address string) (conn *net.UDPConn, err error) {
addr, err := net.ResolveUDPAddr("udp", address)
if err != nil {
return
}
//fmt.Printf(time.Now().Format("2006-01-02 15:04:05")+" multicast: listen addr %s\n", address)
iface, err := net.InterfaceByName(*McastIface)
conn, err = net.ListenMulticastUDP("udp", iface, addr)
if err != nil {
panic(err)
}
return
}
参考:
https://github.com/hello-xnew/gdpxy
https://github.com/darren/retv