Feat: ts to png

pull/31/head
zijiren233 1 year ago
parent ff34f8209c
commit e4eeddde79

@ -26,7 +26,7 @@ require (
github.com/ulule/limiter/v3 v3.11.2
github.com/zijiren233/gencontainer v0.0.0-20230930135658-e410015e13cc
github.com/zijiren233/go-colorable v0.0.0-20230930131441-997304c961cb
github.com/zijiren233/livelib v0.2.2-0.20231021080243-c5097432686c
github.com/zijiren233/livelib v0.2.3-0.20231103145812-58de2ae7f423
github.com/zijiren233/stream v0.5.1
github.com/zijiren233/yaml-comment v0.2.1
golang.org/x/crypto v0.14.0
@ -46,7 +46,7 @@ require (
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/bytedance/sonic v1.10.2 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.0 // indirect
github.com/chenzhuoyu/iasm v0.9.1 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fatih/color v1.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect

@ -21,6 +21,8 @@ github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo=
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0=
github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -204,6 +206,10 @@ github.com/zijiren233/go-colorable v0.0.0-20230930131441-997304c961cb h1:0DyOxf/
github.com/zijiren233/go-colorable v0.0.0-20230930131441-997304c961cb/go.mod h1:6TCzjDiQ8+5gWZiwsC3pnA5M0vUy2jV2Y7ciHJh729g=
github.com/zijiren233/livelib v0.2.2-0.20231021080243-c5097432686c h1:sQtkWQi+QWdmx4Jx2MA/Ib9pYPmnVw5Qd/xOB8K5zs0=
github.com/zijiren233/livelib v0.2.2-0.20231021080243-c5097432686c/go.mod h1:2wrAAqNIdMZjQrdbO7ERQfqK4VS5fzgUj2xXwrJ8/uo=
github.com/zijiren233/livelib v0.2.2 h1:2VeJSg9tmmQ7KfeeVQwVZhmzj/FkXRErdwdvZVxUyN0=
github.com/zijiren233/livelib v0.2.2/go.mod h1:2wrAAqNIdMZjQrdbO7ERQfqK4VS5fzgUj2xXwrJ8/uo=
github.com/zijiren233/livelib v0.2.3-0.20231103145812-58de2ae7f423 h1:6febr/evRs52lo2lHSpcc6e7+yVPI04ba9eEl26tl+Y=
github.com/zijiren233/livelib v0.2.3-0.20231103145812-58de2ae7f423/go.mod h1:2wrAAqNIdMZjQrdbO7ERQfqK4VS5fzgUj2xXwrJ8/uo=
github.com/zijiren233/stream v0.5.1 h1:9SUwM/fpET6frtBRT5WZBHnan0Hyzkezk/P8N78cgZQ=
github.com/zijiren233/stream v0.5.1/go.mod h1:iIrOm3qgIepQFmptD/HDY+YzamSSzQOtPjpVcK7FCOw=
github.com/zijiren233/yaml-comment v0.2.1 h1:/ymMfauuR6zPme+c59FvGNmvxmjOS+BRZSU9YEM82g4=

@ -6,6 +6,7 @@ type RtmpConfig struct {
CustomPublishHost string `yaml:"custom_publish_host" lc:"default use http header host" env:"RTMP_CUSTOM_PUBLISH_HOST"`
RtmpPlayer bool `yaml:"rtmp_player" hc:"can watch live streams through the RTMP protocol (without authentication, insecure)." env:"RTMP_PLAYER"`
TsDisguisedAsPng bool `yaml:"ts_disguised_as_png" hc:"disguise the .ts file as a .png file" env:"RTMP_TS_DISGUISED_AS_PNG"`
}
func DefaultRtmpConfig() RtmpConfig {
@ -14,5 +15,6 @@ func DefaultRtmpConfig() RtmpConfig {
Port: 0,
CustomPublishHost: "",
RtmpPlayer: false,
TsDisguisedAsPng: true,
}
}

@ -8,8 +8,10 @@ import (
"github.com/go-resty/resty/v2"
"github.com/synctv-org/synctv/internal/model"
"github.com/synctv-org/synctv/utils"
"github.com/zijiren233/livelib/av"
"github.com/zijiren233/livelib/container/flv"
"github.com/zijiren233/livelib/protocol/hls"
rtmpProto "github.com/zijiren233/livelib/protocol/rtmp"
"github.com/zijiren233/livelib/protocol/rtmp/core"
rtmps "github.com/zijiren233/livelib/server"
@ -27,6 +29,10 @@ func (m *movie) Channel() (*rtmps.Channel, error) {
return m.channel, m.init()
}
func genTsName() string {
return utils.SortUUID()
}
func (m *movie) init() (err error) {
if err = m.Movie.Validate(); err != nil {
return
@ -35,7 +41,7 @@ func (m *movie) init() (err error) {
case m.Base.Live && m.Base.RtmpSource:
if m.channel == nil {
m.channel = rtmps.NewChannel()
m.channel.InitHlsPlayer()
m.channel.InitHlsPlayer(hls.WithGenTsNameFunc(genTsName))
}
case m.Base.Live && m.Base.Proxy:
u, err := url.Parse(m.Base.Url)
@ -46,7 +52,7 @@ func (m *movie) init() (err error) {
case "rtmp":
if m.channel == nil {
m.channel = rtmps.NewChannel()
m.channel.InitHlsPlayer()
m.channel.InitHlsPlayer(hls.WithGenTsNameFunc(genTsName))
go func() {
for {
if m.channel.Closed() {
@ -68,7 +74,7 @@ func (m *movie) init() (err error) {
case "http", "https":
if m.channel == nil {
m.channel = rtmps.NewChannel()
m.channel.InitHlsPlayer()
m.channel.InitHlsPlayer(hls.WithGenTsNameFunc(genTsName))
go func() {
for {
if m.channel.Closed() {

@ -3,6 +3,10 @@ package handlers
import (
"errors"
"fmt"
"image"
"image/color"
"image/png"
"math/rand"
"net/http"
"path"
"strconv"
@ -528,13 +532,23 @@ func JoinLive(ctx *gin.Context) {
w.SendPacket()
case ".m3u8":
ctx.Header("Cache-Control", "no-store")
b, err := channel.GenM3U8PlayList(fmt.Sprintf("/api/movie/live/%s", channelName))
b, err := channel.GenM3U8File(func(tsName string) (tsPath string) {
ext := "ts"
if conf.Conf.Rtmp.TsDisguisedAsPng {
ext = "png"
}
return fmt.Sprintf("/api/movie/live/%s.%s", channelName, ext)
})
if err != nil {
ctx.AbortWithStatusJSON(http.StatusNotFound, model.NewApiErrorResp(err))
return
}
ctx.Data(http.StatusOK, hls.M3U8ContentType, b.Bytes())
ctx.Data(http.StatusOK, hls.M3U8ContentType, b)
case ".ts":
if conf.Conf.Rtmp.TsDisguisedAsPng {
ctx.AbortWithStatusJSON(http.StatusNotFound, model.NewApiErrorResp(FormatErrNotSupportFileType(fileExt)))
return
}
b, err := channel.GetTsFile(movieIdSplitd[1])
if err != nil {
ctx.AbortWithStatusJSON(http.StatusNotFound, model.NewApiErrorResp(err))
@ -542,6 +556,22 @@ func JoinLive(ctx *gin.Context) {
}
ctx.Header("Cache-Control", "public, max-age=90")
ctx.Data(http.StatusOK, hls.TSContentType, b)
case ".png":
if !conf.Conf.Rtmp.TsDisguisedAsPng {
ctx.AbortWithStatusJSON(http.StatusNotFound, model.NewApiErrorResp(FormatErrNotSupportFileType(fileExt)))
return
}
b, err := channel.GetTsFile(movieIdSplitd[1])
if err != nil {
ctx.AbortWithStatusJSON(http.StatusNotFound, model.NewApiErrorResp(err))
return
}
ctx.Header("Cache-Control", "public, max-age=90")
ctx.Header("Content-Type", "image/png")
img := image.NewGray(image.Rect(0, 0, 1, 1))
img.Set(1, 1, color.Gray{uint8(rand.Intn(255))})
png.Encode(ctx.Writer, img)
ctx.Writer.Write(b)
default:
ctx.Header("Cache-Control", "no-store")
ctx.AbortWithStatusJSON(http.StatusBadRequest, model.NewApiErrorResp(FormatErrNotSupportFileType(fileExt)))

Loading…
Cancel
Save