Ready-to-use SRT / WebRTC / RTSP / RTMP / LL-HLS media server and media proxy that allows to read, publish, proxy, record and playback video and audio streams.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

206 lines
4.0 KiB

package record
import (
"regexp"
"strconv"
"strings"
"time"
"github.com/bluenviron/mediamtx/internal/conf"
)
func leadingZeros(v int, size int) string {
out := strconv.FormatInt(int64(v), 10)
if len(out) >= size {
return out
}
out2 := ""
for i := 0; i < (size - len(out)); i++ {
out2 += "0"
}
return out2 + out
}
// PathAddExtension adds the file extension to path.
func PathAddExtension(path string, format conf.RecordFormat) string {
switch format {
case conf.RecordFormatMPEGTS:
return path + ".ts"
default:
return path + ".mp4"
}
}
// CommonPath returns the common path between all segments with given recording path.
func CommonPath(v string) string {
common := ""
remaining := v
for {
i := strings.IndexAny(remaining, "\\/")
if i < 0 {
break
}
var part string
part, remaining = remaining[:i+1], remaining[i+1:]
if strings.Contains(part, "%") {
break
}
common += part
}
if len(common) > 0 {
common = common[:len(common)-1]
}
return common
}
// Path is a record path.
type Path time.Time
// Decode decodes a Path.
func (p *Path) Decode(format string, v string) bool {
re := format
for _, ch := range []uint8{
'\\',
'.',
'+',
'*',
'?',
'^',
'$',
'(',
')',
'[',
']',
'{',
'}',
'|',
} {
re = strings.ReplaceAll(re, string(ch), "\\"+string(ch))
}
re = strings.ReplaceAll(re, "%path", "(.*?)")
re = strings.ReplaceAll(re, "%Y", "([0-9]{4})")
re = strings.ReplaceAll(re, "%m", "([0-9]{2})")
re = strings.ReplaceAll(re, "%d", "([0-9]{2})")
re = strings.ReplaceAll(re, "%H", "([0-9]{2})")
re = strings.ReplaceAll(re, "%M", "([0-9]{2})")
re = strings.ReplaceAll(re, "%S", "([0-9]{2})")
re = strings.ReplaceAll(re, "%f", "([0-9]{6})")
re = strings.ReplaceAll(re, "%s", "([0-9]{10})")
r := regexp.MustCompile(re)
var groupMapping []string
cur := format
for {
i := strings.Index(cur, "%")
if i < 0 {
break
}
cur = cur[i:]
for _, va := range []string{
"%path",
"%Y",
"%m",
"%d",
"%H",
"%M",
"%S",
"%f",
"%s",
} {
if strings.HasPrefix(cur, va) {
groupMapping = append(groupMapping, va)
}
}
cur = cur[1:]
}
matches := r.FindStringSubmatch(v)
if matches == nil {
return false
}
values := make(map[string]string)
for i, match := range matches[1:] {
values[groupMapping[i]] = match
}
var year int
var month time.Month = 1
day := 1
var hour int
var minute int
var second int
var micros int
var unixSec int64 = -1
for k, v := range values {
switch k {
case "%Y":
tmp, _ := strconv.ParseInt(v, 10, 64)
year = int(tmp)
case "%m":
tmp, _ := strconv.ParseInt(v, 10, 64)
month = time.Month(int(tmp))
case "%d":
tmp, _ := strconv.ParseInt(v, 10, 64)
day = int(tmp)
case "%H":
tmp, _ := strconv.ParseInt(v, 10, 64)
hour = int(tmp)
case "%M":
tmp, _ := strconv.ParseInt(v, 10, 64)
minute = int(tmp)
case "%S":
tmp, _ := strconv.ParseInt(v, 10, 64)
second = int(tmp)
case "%f":
tmp, _ := strconv.ParseInt(v, 10, 64)
micros = int(tmp)
case "%s":
unixSec, _ = strconv.ParseInt(v, 10, 64)
}
}
if unixSec > 0 {
*p = Path(time.Unix(unixSec, 0))
} else {
*p = Path(time.Date(year, month, day, hour, minute, second, micros*1000, time.Local))
}
return true
}
// Encode encodes a path.
func (p Path) Encode(format string) string {
format = strings.ReplaceAll(format, "%Y", strconv.FormatInt(int64(time.Time(p).Year()), 10))
format = strings.ReplaceAll(format, "%m", leadingZeros(int(time.Time(p).Month()), 2))
format = strings.ReplaceAll(format, "%d", leadingZeros(time.Time(p).Day(), 2))
format = strings.ReplaceAll(format, "%H", leadingZeros(time.Time(p).Hour(), 2))
format = strings.ReplaceAll(format, "%M", leadingZeros(time.Time(p).Minute(), 2))
format = strings.ReplaceAll(format, "%S", leadingZeros(time.Time(p).Second(), 2))
format = strings.ReplaceAll(format, "%f", leadingZeros(time.Time(p).Nanosecond()/1000, 6))
format = strings.ReplaceAll(format, "%s", strconv.FormatInt(time.Time(p).Unix(), 10))
return format
}