Skip to content

Commit 3bca02f

Browse files
committed
Add support for FLV over HTTP streaming
1 parent 64dfd1c commit 3bca02f

14 files changed

Lines changed: 459 additions & 75 deletions

File tree

app/api/api.go

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1488,14 +1488,15 @@ func (a *api) start(ctx context.Context) error {
14881488
Cors: http.CorsConfig{
14891489
Origins: cfg.Storage.CORS.Origins,
14901490
},
1491-
RTMP: a.rtmpserver,
1492-
SRT: a.srtserver,
1493-
Config: a.config.store,
1494-
Sessions: a.sessions,
1495-
Router: router,
1496-
ReadOnly: cfg.API.ReadOnly,
1497-
Cluster: a.cluster,
1498-
IAM: a.iam,
1491+
RTMP: a.rtmpserver,
1492+
RTMPHTTPFLVMount: "",
1493+
SRT: a.srtserver,
1494+
Config: a.config.store,
1495+
Sessions: a.sessions,
1496+
Router: router,
1497+
ReadOnly: cfg.API.ReadOnly,
1498+
Cluster: a.cluster,
1499+
IAM: a.iam,
14991500
IAMSkipper: func(ip string) bool {
15001501
if !cfg.API.Auth.Enable {
15011502
return true
@@ -1520,6 +1521,10 @@ func (a *api) start(ctx context.Context) error {
15201521
},
15211522
}
15221523

1524+
if cfg.RTMP.HTTPFLV.Enable {
1525+
serverConfig.RTMPHTTPFLVMount = cfg.RTMP.HTTPFLV.Mount
1526+
}
1527+
15231528
mainserverhandler, err := http.NewServer(serverConfig)
15241529

15251530
if err != nil {

cluster/docs/ClusterAPI_docs.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2092,6 +2092,17 @@ const docTemplateClusterAPI = `{
20922092
"enable_tls": {
20932093
"type": "boolean"
20942094
},
2095+
"httpflv": {
2096+
"type": "object",
2097+
"properties": {
2098+
"enable": {
2099+
"type": "boolean"
2100+
},
2101+
"mount": {
2102+
"type": "string"
2103+
}
2104+
}
2105+
},
20952106
"token": {
20962107
"description": "Deprecated, use IAM",
20972108
"type": "string"

cluster/docs/ClusterAPI_swagger.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2085,6 +2085,17 @@
20852085
"enable_tls": {
20862086
"type": "boolean"
20872087
},
2088+
"httpflv": {
2089+
"type": "object",
2090+
"properties": {
2091+
"enable": {
2092+
"type": "boolean"
2093+
},
2094+
"mount": {
2095+
"type": "string"
2096+
}
2097+
}
2098+
},
20882099
"token": {
20892100
"description": "Deprecated, use IAM",
20902101
"type": "string"

cluster/docs/ClusterAPI_swagger.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,13 @@ definitions:
546546
type: boolean
547547
enable_tls:
548548
type: boolean
549+
httpflv:
550+
properties:
551+
enable:
552+
type: boolean
553+
mount:
554+
type: string
555+
type: object
549556
token:
550557
description: Deprecated, use IAM
551558
type: string

config/config.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,8 @@ func (d *Config) init() {
271271
d.vars.Register(value.NewMustAddress(&d.RTMP.AddressTLS, ":1936"), "rtmp.address_tls", "CORE_RTMP_ADDRESS_TLS", nil, "RTMPS server listen address", false, false)
272272
d.vars.Register(value.NewAbsolutePath(&d.RTMP.App, "/"), "rtmp.app", "CORE_RTMP_APP", nil, "RTMP app for publishing", false, false)
273273
d.vars.Register(value.NewString(&d.RTMP.Token, ""), "rtmp.token", "CORE_RTMP_TOKEN", nil, "RTMP token for publishing and playing", false, true)
274+
d.vars.Register(value.NewBool(&d.RTMP.HTTPFLV.Enable, false), "rtmp.httpflv_enable", "CORE_RTMP_HTTPFLV_ENABLE", nil, "Enable FLV over HTTP for RTMP streams", false, false)
275+
d.vars.Register(value.NewAbsolutePath(&d.RTMP.HTTPFLV.Mount, "/rtmp"), "rtmp.httpflv_mount", "CORE_RTMP_HTTPFLV_MOUNT", nil, "Mountpoint for FLV over HTTP", false, true)
274276

275277
// SRT
276278
d.vars.Register(value.NewBool(&d.SRT.Enable, false), "srt.enable", "CORE_SRT_ENABLE", nil, "Enable SRT server", false, false)
@@ -449,6 +451,14 @@ func (d *Config) Validate(resetLogs bool) {
449451
}
450452
}
451453

454+
if d.RTMP.Enable {
455+
if d.RTMP.HTTPFLV.Enable {
456+
if d.RTMP.HTTPFLV.Mount == "/" {
457+
d.vars.Log("error", "rtmp.httpflv.mount", "The FLV over HTTP mount point cannot be root")
458+
}
459+
}
460+
}
461+
452462
// If CORE_MEMFS_USERNAME and CORE_MEMFS_PASSWORD are set, automatically active/deactivate Basic-Auth for memfs
453463
if d.vars.IsMerged("storage.memory.auth.username") && d.vars.IsMerged("storage.memory.auth.password") {
454464
d.Storage.Memory.Auth.Enable = true

config/data.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ type Data struct {
115115
AddressTLS string `json:"address_tls"`
116116
App string `json:"app"`
117117
Token string `json:"token"` // Deprecated, use IAM
118+
HTTPFLV struct {
119+
Enable bool `json:"enable"`
120+
Mount string `json:"mount"`
121+
} `json:"httpflv"`
118122
} `json:"rtmp"`
119123
SRT struct {
120124
Enable bool `json:"enable"`
@@ -227,7 +231,6 @@ func MergeV2toV3(data *Data, d *v2.Data) (*Data, error) {
227231
data.DB = d.DB
228232
data.Host = d.Host
229233
data.API = d.API
230-
data.RTMP = d.RTMP
231234
data.SRT = d.SRT
232235
data.Playout = d.Playout
233236
data.Metrics = d.Metrics
@@ -264,6 +267,15 @@ func MergeV2toV3(data *Data, d *v2.Data) (*Data, error) {
264267
data.Sessions.MaxBitrate = d.Sessions.MaxBitrate
265268
data.Sessions.MaxSessions = d.Sessions.MaxSessions
266269

270+
data.RTMP.Enable = d.RTMP.Enable
271+
data.RTMP.EnableTLS = d.RTMP.EnableTLS
272+
data.RTMP.Address = d.RTMP.Address
273+
data.RTMP.AddressTLS = d.RTMP.AddressTLS
274+
data.RTMP.App = d.RTMP.App
275+
data.RTMP.Token = d.RTMP.Token
276+
data.RTMP.HTTPFLV.Enable = false
277+
data.RTMP.HTTPFLV.Mount = "/rtmp"
278+
267279
data.SRT.Log.Topics = slices.Copy(d.SRT.Log.Topics)
268280

269281
data.Router.BlockedPrefixes = slices.Copy(d.Router.BlockedPrefixes)
@@ -325,7 +337,6 @@ func DowngradeV3toV2(d *Data) (*v2.Data, error) {
325337
data.DB = d.DB
326338
data.Host = d.Host
327339
data.API = d.API
328-
data.RTMP = d.RTMP
329340
data.SRT = d.SRT
330341
data.Playout = d.Playout
331342
data.Metrics = d.Metrics
@@ -362,6 +373,13 @@ func DowngradeV3toV2(d *Data) (*v2.Data, error) {
362373
data.Sessions.MaxBitrate = d.Sessions.MaxBitrate
363374
data.Sessions.MaxSessions = d.Sessions.MaxSessions
364375

376+
data.RTMP.Enable = d.RTMP.Enable
377+
data.RTMP.EnableTLS = d.RTMP.EnableTLS
378+
data.RTMP.Address = d.RTMP.Address
379+
data.RTMP.AddressTLS = d.RTMP.AddressTLS
380+
data.RTMP.App = d.RTMP.App
381+
data.RTMP.Token = d.RTMP.Token
382+
365383
data.SRT.Log.Topics = slices.Copy(d.SRT.Log.Topics)
366384

367385
data.Router.BlockedPrefixes = slices.Copy(d.Router.BlockedPrefixes)

docs/docs.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5509,6 +5509,46 @@ const docTemplate = `{
55095509
}
55105510
}
55115511
}
5512+
},
5513+
"/rtmp/{path}": {
5514+
"get": {
5515+
"description": "Plays a RTMP stream over HTTP",
5516+
"produces": [
5517+
"video/x-flv",
5518+
"application/json"
5519+
],
5520+
"tags": [
5521+
"v16.?.?"
5522+
],
5523+
"summary": "Plays a RTMP stream over HTTP",
5524+
"operationId": "rtmp-3-play",
5525+
"responses": {
5526+
"200": {
5527+
"description": "OK",
5528+
"schema": {
5529+
"type": "file"
5530+
}
5531+
},
5532+
"403": {
5533+
"description": "Forbidden",
5534+
"schema": {
5535+
"$ref": "#/definitions/api.Error"
5536+
}
5537+
},
5538+
"404": {
5539+
"description": "Not Found",
5540+
"schema": {
5541+
"$ref": "#/definitions/api.Error"
5542+
}
5543+
},
5544+
"500": {
5545+
"description": "Internal Server Error",
5546+
"schema": {
5547+
"$ref": "#/definitions/api.Error"
5548+
}
5549+
}
5550+
}
5551+
}
55125552
}
55135553
},
55145554
"definitions": {
@@ -6572,6 +6612,17 @@ const docTemplate = `{
65726612
"enable_tls": {
65736613
"type": "boolean"
65746614
},
6615+
"httpflv": {
6616+
"type": "object",
6617+
"properties": {
6618+
"enable": {
6619+
"type": "boolean"
6620+
},
6621+
"mount": {
6622+
"type": "string"
6623+
}
6624+
}
6625+
},
65756626
"token": {
65766627
"description": "Deprecated, use IAM",
65776628
"type": "string"
@@ -9321,6 +9372,17 @@ const docTemplate = `{
93219372
"enable_tls": {
93229373
"type": "boolean"
93239374
},
9375+
"httpflv": {
9376+
"type": "object",
9377+
"properties": {
9378+
"enable": {
9379+
"type": "boolean"
9380+
},
9381+
"mount": {
9382+
"type": "string"
9383+
}
9384+
}
9385+
},
93249386
"token": {
93259387
"description": "Deprecated, use IAM",
93269388
"type": "string"

docs/swagger.json

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5502,6 +5502,46 @@
55025502
}
55035503
}
55045504
}
5505+
},
5506+
"/rtmp/{path}": {
5507+
"get": {
5508+
"description": "Plays a RTMP stream over HTTP",
5509+
"produces": [
5510+
"video/x-flv",
5511+
"application/json"
5512+
],
5513+
"tags": [
5514+
"v16.?.?"
5515+
],
5516+
"summary": "Plays a RTMP stream over HTTP",
5517+
"operationId": "rtmp-3-play",
5518+
"responses": {
5519+
"200": {
5520+
"description": "OK",
5521+
"schema": {
5522+
"type": "file"
5523+
}
5524+
},
5525+
"403": {
5526+
"description": "Forbidden",
5527+
"schema": {
5528+
"$ref": "#/definitions/api.Error"
5529+
}
5530+
},
5531+
"404": {
5532+
"description": "Not Found",
5533+
"schema": {
5534+
"$ref": "#/definitions/api.Error"
5535+
}
5536+
},
5537+
"500": {
5538+
"description": "Internal Server Error",
5539+
"schema": {
5540+
"$ref": "#/definitions/api.Error"
5541+
}
5542+
}
5543+
}
5544+
}
55055545
}
55065546
},
55075547
"definitions": {
@@ -6565,6 +6605,17 @@
65656605
"enable_tls": {
65666606
"type": "boolean"
65676607
},
6608+
"httpflv": {
6609+
"type": "object",
6610+
"properties": {
6611+
"enable": {
6612+
"type": "boolean"
6613+
},
6614+
"mount": {
6615+
"type": "string"
6616+
}
6617+
}
6618+
},
65686619
"token": {
65696620
"description": "Deprecated, use IAM",
65706621
"type": "string"
@@ -9314,6 +9365,17 @@
93149365
"enable_tls": {
93159366
"type": "boolean"
93169367
},
9368+
"httpflv": {
9369+
"type": "object",
9370+
"properties": {
9371+
"enable": {
9372+
"type": "boolean"
9373+
},
9374+
"mount": {
9375+
"type": "string"
9376+
}
9377+
}
9378+
},
93179379
"token": {
93189380
"description": "Deprecated, use IAM",
93199381
"type": "string"

docs/swagger.yaml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,13 @@ definitions:
723723
type: boolean
724724
enable_tls:
725725
type: boolean
726+
httpflv:
727+
properties:
728+
enable:
729+
type: boolean
730+
mount:
731+
type: string
732+
type: object
726733
token:
727734
description: Deprecated, use IAM
728735
type: string
@@ -2643,6 +2650,13 @@ definitions:
26432650
type: boolean
26442651
enable_tls:
26452652
type: boolean
2653+
httpflv:
2654+
properties:
2655+
enable:
2656+
type: boolean
2657+
mount:
2658+
type: string
2659+
type: object
26462660
token:
26472661
description: Deprecated, use IAM
26482662
type: string
@@ -6635,6 +6649,33 @@ paths:
66356649
schema:
66366650
type: string
66376651
summary: Retrieve profiling data from the application
6652+
/rtmp/{path}:
6653+
get:
6654+
description: Plays a RTMP stream over HTTP
6655+
operationId: rtmp-3-play
6656+
produces:
6657+
- video/x-flv
6658+
- application/json
6659+
responses:
6660+
"200":
6661+
description: OK
6662+
schema:
6663+
type: file
6664+
"403":
6665+
description: Forbidden
6666+
schema:
6667+
$ref: '#/definitions/api.Error'
6668+
"404":
6669+
description: Not Found
6670+
schema:
6671+
$ref: '#/definitions/api.Error'
6672+
"500":
6673+
description: Internal Server Error
6674+
schema:
6675+
$ref: '#/definitions/api.Error'
6676+
summary: Plays a RTMP stream over HTTP
6677+
tags:
6678+
- v16.?.?
66386679
securityDefinitions:
66396680
ApiKeyAuth:
66406681
in: header

0 commit comments

Comments
 (0)