mirror of
https://github.com/datarhei/core.git
synced 2025-10-06 08:27:08 +08:00
Unify FFmpeg prelude parser, add pid awareness
The progress and probe parser had both their own prelude parsing implementation in case the json variant is not available. Now there's a new package for this implementation that both use. If a program has an ID (in case of srt+mpegts) then this was no recognized by the parser and these inputs/outputs were not detected.
This commit is contained in:
191
ffmpeg/prelude/prelude.go
Normal file
191
ffmpeg/prelude/prelude.go
Normal file
@@ -0,0 +1,191 @@
|
||||
package prelude
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type IO struct {
|
||||
// common
|
||||
Address string
|
||||
Format string
|
||||
Index uint64
|
||||
Stream uint64
|
||||
Language string
|
||||
Type string
|
||||
Codec string
|
||||
Coder string
|
||||
Bitrate float64 // kbps
|
||||
Duration float64 // sec
|
||||
|
||||
// video
|
||||
FPS float64
|
||||
Pixfmt string
|
||||
Width uint64
|
||||
Height uint64
|
||||
|
||||
// audio
|
||||
Sampling uint64 // Hz
|
||||
Layout string
|
||||
Channels uint64
|
||||
}
|
||||
|
||||
// Parse parses the inputs and outputs from the default FFmpeg output. It returns a list of
|
||||
// detected inputs and outputs as well as the number of outputs according to the stream mapping.
|
||||
func Parse(lines []string) (inputs, outputs []IO, noutputs int) {
|
||||
// Input #0, lavfi, from 'testsrc=size=1280x720:rate=25':
|
||||
// Input #1, lavfi, from 'anullsrc=r=44100:cl=stereo':
|
||||
// Output #0, hls, to './data/testsrc.m3u8':
|
||||
reFormat := regexp.MustCompile(`^(Input|Output) #([0-9]+), (.*?), (from|to) '([^']+)`)
|
||||
|
||||
// Duration: 00:01:02.28, start: 0.000000, bitrate: 5895 kb/s
|
||||
// Duration: N/A, start: 0.000000, bitrate: 5895 kb/s
|
||||
reDuration := regexp.MustCompile(`Duration: ([0-9]+):([0-9]+):([0-9]+)\.([0-9]+)`)
|
||||
|
||||
// Stream #0:0: Video: rawvideo (RGB[24] / 0x18424752), rgb24, 1280x720 [SAR 1:1 DAR 16:9], 25 tbr, 25 tbn, 25 tbc
|
||||
// Stream #1:0: Audio: pcm_u8, 44100 Hz, stereo, u8, 705 kb/s
|
||||
// Stream #0:0: Video: h264 (libx264), yuv420p(progressive), 1280x720 [SAR 1:1 DAR 16:9], q=-1--1, 25 fps, 90k tbn, 25 tbc
|
||||
// Stream #0:1: Audio: aac (LC), 44100 Hz, stereo, fltp, 64 kb/s
|
||||
// Stream #4:0[0x100]: Video: h264 (Main) ([27][0][0][0] / 0x001B), yuv420p(tv, smpte170m/bt709/bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 25 tbr, 90k tbn
|
||||
// Stream #4:1[0x101]: Audio: aac (LC) ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp, 162 kb/s
|
||||
reStream := regexp.MustCompile(`Stream #([0-9]+):([0-9]+)(?:\[[0-9a-fx]+\])?(?:\(([a-z]+)\))?: (Video|Audio|Subtitle): (.*)`)
|
||||
reStreamCodec := regexp.MustCompile(`^([^\s,]+)`)
|
||||
reStreamVideoPixfmtSize := regexp.MustCompile(`, ([0-9A-Za-z]+)(\([^\)]+\))?, ([0-9]+)x([0-9]+)`)
|
||||
reStreamVideoFPS := regexp.MustCompile(`, ([0-9]+(\.[0-9]+)?) fps`)
|
||||
reStreamAudio := regexp.MustCompile(`, ([0-9]+) Hz, ([^,]+)`)
|
||||
reStreamBitrate := regexp.MustCompile(`, ([0-9]+) kb/s`)
|
||||
|
||||
reStreamMapping := regexp.MustCompile(`^Stream mapping:`)
|
||||
reStreamMap := regexp.MustCompile(`^[\s]+Stream #[0-9]+:[0-9]+`)
|
||||
|
||||
iotype := ""
|
||||
format := ""
|
||||
address := ""
|
||||
var duration float64 = 0.0
|
||||
|
||||
streamMapping := false
|
||||
|
||||
for _, line := range lines {
|
||||
if reStreamMapping.MatchString(line) {
|
||||
streamMapping = true
|
||||
continue
|
||||
}
|
||||
|
||||
if streamMapping {
|
||||
if reStreamMap.MatchString(line) {
|
||||
noutputs++
|
||||
} else {
|
||||
streamMapping = false
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if matches := reFormat.FindStringSubmatch(line); matches != nil {
|
||||
iotype = matches[1]
|
||||
format = matches[3]
|
||||
address = matches[5]
|
||||
duration = 0
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if matches := reDuration.FindStringSubmatch(line); matches != nil {
|
||||
duration = 0.0
|
||||
|
||||
// hours
|
||||
if x, err := strconv.ParseFloat(matches[1], 64); err == nil {
|
||||
duration += x * 60 * 60
|
||||
}
|
||||
|
||||
// minutes
|
||||
if x, err := strconv.ParseFloat(matches[2], 64); err == nil {
|
||||
duration += x * 60
|
||||
}
|
||||
|
||||
// seconds
|
||||
if x, err := strconv.ParseFloat(matches[3], 64); err == nil {
|
||||
duration += x
|
||||
}
|
||||
|
||||
// fractions
|
||||
if x, err := strconv.ParseFloat(matches[4], 64); err == nil {
|
||||
duration += x / 100
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if matches := reStream.FindStringSubmatch(line); matches != nil {
|
||||
io := IO{}
|
||||
|
||||
io.Address = address
|
||||
io.Format = format
|
||||
io.Duration = duration
|
||||
|
||||
if x, err := strconv.ParseUint(matches[1], 10, 64); err == nil {
|
||||
io.Index = x
|
||||
}
|
||||
|
||||
if x, err := strconv.ParseUint(matches[2], 10, 64); err == nil {
|
||||
io.Stream = x
|
||||
}
|
||||
|
||||
io.Language = "und"
|
||||
if len(matches[3]) == 3 {
|
||||
io.Language = matches[3]
|
||||
}
|
||||
|
||||
io.Type = strings.ToLower(matches[4])
|
||||
|
||||
streamDetail := matches[5]
|
||||
|
||||
if matches = reStreamCodec.FindStringSubmatch(streamDetail); matches != nil {
|
||||
io.Codec = matches[1]
|
||||
}
|
||||
|
||||
if matches = reStreamBitrate.FindStringSubmatch(streamDetail); matches != nil {
|
||||
if x, err := strconv.ParseFloat(matches[1], 64); err == nil {
|
||||
io.Bitrate = x
|
||||
}
|
||||
}
|
||||
|
||||
if io.Type == "video" {
|
||||
if matches = reStreamVideoPixfmtSize.FindStringSubmatch(streamDetail); matches != nil {
|
||||
io.Pixfmt = matches[1]
|
||||
|
||||
if x, err := strconv.ParseUint(matches[3], 10, 64); err == nil {
|
||||
io.Width = x
|
||||
}
|
||||
if x, err := strconv.ParseUint(matches[4], 10, 64); err == nil {
|
||||
io.Height = x
|
||||
}
|
||||
}
|
||||
|
||||
if matches = reStreamVideoFPS.FindStringSubmatch(streamDetail); matches != nil {
|
||||
if x, err := strconv.ParseFloat(matches[1], 64); err == nil {
|
||||
io.FPS = x
|
||||
}
|
||||
}
|
||||
|
||||
} else if io.Type == "audio" {
|
||||
if matches = reStreamAudio.FindStringSubmatch(streamDetail); matches != nil {
|
||||
if x, err := strconv.ParseUint(matches[1], 10, 64); err == nil {
|
||||
io.Sampling = x
|
||||
}
|
||||
|
||||
io.Layout = matches[2]
|
||||
}
|
||||
}
|
||||
|
||||
if iotype == "Input" {
|
||||
inputs = append(inputs, io)
|
||||
} else if iotype == "Output" {
|
||||
outputs = append(outputs, io)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
Reference in New Issue
Block a user