forked from External/mediamtx
support unix timestamp in filenames of recorded segments (#2774)
* added support for %s to use unix timestamp in filenames * fix lint errors * add tests * update documentation --------- Co-authored-by: aler9 <46489434+aler9@users.noreply.github.com>
This commit is contained in:
parent
3e12f83732
commit
47bd7352f0
4 changed files with 66 additions and 3 deletions
|
|
@ -1153,7 +1153,7 @@ pathDefaults:
|
||||||
record: yes
|
record: yes
|
||||||
# Path of recording segments.
|
# Path of recording segments.
|
||||||
# Extension is added automatically.
|
# Extension is added automatically.
|
||||||
# Available variables are %path (path name), %Y %m %d %H %M %S %f (time in strftime format)
|
# Available variables are %path (path name), %Y %m %d %H %M %S %f %s (time in strftime format)
|
||||||
recordPath: ./recordings/%path/%Y-%m-%d_%H-%M-%S-%f
|
recordPath: ./recordings/%path/%Y-%m-%d_%H-%M-%S-%f
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ func decodeRecordPath(format string, v string) *recordPathParams {
|
||||||
re = strings.ReplaceAll(re, "%M", "([0-9]{2})")
|
re = strings.ReplaceAll(re, "%M", "([0-9]{2})")
|
||||||
re = strings.ReplaceAll(re, "%S", "([0-9]{2})")
|
re = strings.ReplaceAll(re, "%S", "([0-9]{2})")
|
||||||
re = strings.ReplaceAll(re, "%f", "([0-9]{6})")
|
re = strings.ReplaceAll(re, "%f", "([0-9]{6})")
|
||||||
|
re = strings.ReplaceAll(re, "%s", "([0-9]{10})")
|
||||||
r := regexp.MustCompile(re)
|
r := regexp.MustCompile(re)
|
||||||
|
|
||||||
var groupMapping []string
|
var groupMapping []string
|
||||||
|
|
@ -77,6 +78,7 @@ func decodeRecordPath(format string, v string) *recordPathParams {
|
||||||
"%M",
|
"%M",
|
||||||
"%S",
|
"%S",
|
||||||
"%f",
|
"%f",
|
||||||
|
"%s",
|
||||||
} {
|
} {
|
||||||
if strings.HasPrefix(cur, va) {
|
if strings.HasPrefix(cur, va) {
|
||||||
groupMapping = append(groupMapping, va)
|
groupMapping = append(groupMapping, va)
|
||||||
|
|
@ -104,6 +106,7 @@ func decodeRecordPath(format string, v string) *recordPathParams {
|
||||||
var minute int
|
var minute int
|
||||||
var second int
|
var second int
|
||||||
var micros int
|
var micros int
|
||||||
|
var unixSec int64 = -1
|
||||||
|
|
||||||
for k, v := range values {
|
for k, v := range values {
|
||||||
switch k {
|
switch k {
|
||||||
|
|
@ -134,10 +137,18 @@ func decodeRecordPath(format string, v string) *recordPathParams {
|
||||||
case "%f":
|
case "%f":
|
||||||
tmp, _ := strconv.ParseInt(v, 10, 64)
|
tmp, _ := strconv.ParseInt(v, 10, 64)
|
||||||
micros = int(tmp)
|
micros = int(tmp)
|
||||||
|
|
||||||
|
case "%s":
|
||||||
|
unixSec, _ = strconv.ParseInt(v, 10, 64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
t := time.Date(year, month, day, hour, minute, second, micros*1000, time.Local)
|
var t time.Time
|
||||||
|
if unixSec > 0 {
|
||||||
|
t = time.Unix(unixSec, 0)
|
||||||
|
} else {
|
||||||
|
t = time.Date(year, month, day, hour, minute, second, micros*1000, time.Local)
|
||||||
|
}
|
||||||
|
|
||||||
return &recordPathParams{
|
return &recordPathParams{
|
||||||
path: values["%path"],
|
path: values["%path"],
|
||||||
|
|
@ -153,5 +164,6 @@ func encodeRecordPath(params *recordPathParams, v string) string {
|
||||||
v = strings.ReplaceAll(v, "%M", leadingZeros(params.time.Minute(), 2))
|
v = strings.ReplaceAll(v, "%M", leadingZeros(params.time.Minute(), 2))
|
||||||
v = strings.ReplaceAll(v, "%S", leadingZeros(params.time.Second(), 2))
|
v = strings.ReplaceAll(v, "%S", leadingZeros(params.time.Second(), 2))
|
||||||
v = strings.ReplaceAll(v, "%f", leadingZeros(params.time.Nanosecond()/1000, 6))
|
v = strings.ReplaceAll(v, "%f", leadingZeros(params.time.Nanosecond()/1000, 6))
|
||||||
|
v = strings.ReplaceAll(v, "%s", strconv.FormatInt(params.time.Unix(), 10))
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
|
||||||
51
internal/record/record_path_test.go
Normal file
51
internal/record/record_path_test.go
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
package record
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
var recordPathCases = []struct {
|
||||||
|
name string
|
||||||
|
format string
|
||||||
|
dec *recordPathParams
|
||||||
|
enc string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"standard",
|
||||||
|
"%path/%Y-%m-%d_%H-%M-%S-%f.mp4",
|
||||||
|
&recordPathParams{
|
||||||
|
path: "mypath",
|
||||||
|
time: time.Date(2008, 11, 0o7, 11, 22, 4, 123456000, time.Local),
|
||||||
|
},
|
||||||
|
"mypath/2008-11-07_11-22-04-123456.mp4",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"unix seconds",
|
||||||
|
"%path/%s.mp4",
|
||||||
|
&recordPathParams{
|
||||||
|
path: "mypath",
|
||||||
|
time: time.Date(2021, 12, 2, 12, 15, 23, 0, time.UTC).Local(),
|
||||||
|
},
|
||||||
|
"mypath/1638447323.mp4",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRecordPathDecode(t *testing.T) {
|
||||||
|
for _, ca := range recordPathCases {
|
||||||
|
t.Run(ca.name, func(t *testing.T) {
|
||||||
|
require.Equal(t, ca.dec, decodeRecordPath(ca.format, ca.enc))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRecordPathEncode(t *testing.T) {
|
||||||
|
for _, ca := range recordPathCases {
|
||||||
|
t.Run(ca.name, func(t *testing.T) {
|
||||||
|
require.Equal(t, ca.enc, strings.ReplaceAll(encodeRecordPath(ca.dec, ca.format), "%path", "mypath"))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -296,7 +296,7 @@ pathDefaults:
|
||||||
record: no
|
record: no
|
||||||
# Path of recording segments.
|
# Path of recording segments.
|
||||||
# Extension is added automatically.
|
# Extension is added automatically.
|
||||||
# Available variables are %path (path name), %Y %m %d %H %M %S %f (time in strftime format)
|
# Available variables are %path (path name), %Y %m %d %H %M %S %f %s (time in strftime format)
|
||||||
recordPath: ./recordings/%path/%Y-%m-%d_%H-%M-%S-%f
|
recordPath: ./recordings/%path/%Y-%m-%d_%H-%M-%S-%f
|
||||||
# Format of recorded segments.
|
# Format of recorded segments.
|
||||||
# Available formats are "fmp4" (fragmented MP4) and "mpegts" (MPEG-TS).
|
# Available formats are "fmp4" (fragmented MP4) and "mpegts" (MPEG-TS).
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue