mirror of
https://github.com/xfrr/goffmpeg.git
synced 2025-10-05 16:06:50 +08:00
Transcoding files
Added getters & setters Get file's metada using ffprobe Getting ffmpeg proccess info: frames processed, bitrate, current time and progress percentage through channel
This commit is contained in:
360
models/media.go
Normal file
360
models/media.go
Normal file
@@ -0,0 +1,360 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"strconv"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type Mediafile struct {
|
||||
aspect string
|
||||
resolution string
|
||||
videoBitRate int
|
||||
videoBitRateTolerance int
|
||||
videoMaxBitRate int
|
||||
videoMinBitrate int
|
||||
videoCodec string
|
||||
frameRate int
|
||||
maxKeyframe int
|
||||
minKeyframe int
|
||||
keyframeInterval int
|
||||
audioCodec string
|
||||
audioBitrate int
|
||||
audioChannels int
|
||||
bufferSize int
|
||||
threads int
|
||||
target string
|
||||
duration string
|
||||
seekTime string
|
||||
quality int
|
||||
metadata Metadata
|
||||
}
|
||||
|
||||
/*** SETTERS ***/
|
||||
|
||||
func (m *Mediafile) SetAspect(v string) {
|
||||
m.aspect = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetResolution(v string) {
|
||||
m.resolution = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetVideoBitRate(v int) {
|
||||
m.videoBitRate = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetVideoBitRateTolerance(v int) {
|
||||
m.videoBitRateTolerance = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetVideoMaxBitrate(v int) {
|
||||
m.videoMaxBitRate = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetVideoMinBitRate(v int) {
|
||||
m.videoMinBitrate = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetVideoCodec(v string) {
|
||||
m.videoCodec = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetFrameRate(v int) {
|
||||
m.frameRate = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetMaxKeyFrame(v int) {
|
||||
m.maxKeyframe = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetMinKeyFrame(v int) {
|
||||
m.minKeyframe = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetKeyframeInterval(v int) {
|
||||
m.keyframeInterval = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetAudioCodec(v string) {
|
||||
m.audioCodec = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetAudioBitRate(v int) {
|
||||
m.audioBitrate = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetAudioChannels(v int) {
|
||||
m.audioChannels = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetBufferSize(v int) {
|
||||
m.bufferSize = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetThreads(v int) {
|
||||
m.threads = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetDuration(v string) {
|
||||
m.duration = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetSeekTime(v string) {
|
||||
m.seekTime = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetQuality(v int) {
|
||||
m.quality = v
|
||||
}
|
||||
|
||||
func (m *Mediafile) SetMetadata(v Metadata) {
|
||||
m.metadata = v
|
||||
}
|
||||
|
||||
/*** GETTERS ***/
|
||||
|
||||
func (m Mediafile) Aspect() string {
|
||||
return m.aspect
|
||||
}
|
||||
|
||||
func (m Mediafile) Resolution() string {
|
||||
return m.resolution
|
||||
}
|
||||
|
||||
func (m Mediafile) VideoBitrate() int {
|
||||
return m.videoBitRate
|
||||
}
|
||||
|
||||
func (m Mediafile) VideoBitRateTolerance() int {
|
||||
return m.videoBitRateTolerance
|
||||
}
|
||||
|
||||
func (m Mediafile) VideoMaxBitRate() int {
|
||||
return m.videoMaxBitRate
|
||||
}
|
||||
|
||||
func (m Mediafile) VideoMinBitRate() int {
|
||||
return m.videoMinBitrate
|
||||
}
|
||||
|
||||
func (m Mediafile) VideoCodec() string {
|
||||
return m.videoCodec
|
||||
}
|
||||
|
||||
func (m Mediafile) FrameRate() int {
|
||||
return m.frameRate
|
||||
}
|
||||
|
||||
func (m Mediafile) MaxKeyFrame() int {
|
||||
return m.maxKeyframe
|
||||
}
|
||||
|
||||
func (m Mediafile) MinKeyFrame() int {
|
||||
return m.minKeyframe
|
||||
}
|
||||
|
||||
func (m Mediafile) KeyFrameInterval() int {
|
||||
return m.keyframeInterval
|
||||
}
|
||||
|
||||
func (m Mediafile) AudioCodec() string {
|
||||
return m.audioCodec
|
||||
}
|
||||
|
||||
func (m Mediafile) AudioBitrate() int {
|
||||
return m.audioBitrate
|
||||
}
|
||||
|
||||
func (m Mediafile) AudioChannels() int {
|
||||
return m.audioChannels
|
||||
}
|
||||
|
||||
func (m Mediafile) BufferSize() int {
|
||||
return m.bufferSize
|
||||
}
|
||||
|
||||
func (m Mediafile) Threads() int {
|
||||
return m.threads
|
||||
}
|
||||
|
||||
func (m Mediafile) Target() string {
|
||||
return m.target
|
||||
}
|
||||
|
||||
func (m Mediafile) Duration() string {
|
||||
return m.duration
|
||||
}
|
||||
|
||||
func (m Mediafile) SeekTime() string {
|
||||
return m.seekTime
|
||||
}
|
||||
|
||||
func (m Mediafile) Quality() int {
|
||||
return m.quality
|
||||
}
|
||||
|
||||
func (m Mediafile) Metadata() Metadata {
|
||||
return m.metadata
|
||||
}
|
||||
|
||||
/** OPTS **/
|
||||
func (m Mediafile) ToStrCommand() string {
|
||||
var strCommand string
|
||||
|
||||
opts := []string{"Aspect", "VideoCodec", "FrameRate", "Resolution", "VideoBitRate", "VideoBitRateTolerance", "AudioCodec", "AudioBitRate", "AudioChannels", "VideoMaxBitRate", "VideoMinBitRate", "BufferSize", "Threads", "Target", "Duration", "KeyframeInterval", "SeekTime", "Quality"}
|
||||
for _, name := range opts {
|
||||
opt := reflect.ValueOf(&m).MethodByName(fmt.Sprintf("Obtain%s", name))
|
||||
if (opt != reflect.Value{}) {
|
||||
result := opt.Call([]reflect.Value{})
|
||||
|
||||
if result[0].String() != "" {
|
||||
strCommand += " "
|
||||
strCommand += result[0].String()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return strCommand
|
||||
|
||||
}
|
||||
|
||||
|
||||
func (m *Mediafile) ObtainAspect() string {
|
||||
// Set aspect
|
||||
if m.resolution != "" {
|
||||
resolution := strings.Split(m.resolution, "x")
|
||||
if len(resolution) != 0 {
|
||||
width, _ := strconv.ParseFloat(resolution[0], 64)
|
||||
height, _ := strconv.ParseFloat(resolution[1], 64)
|
||||
return fmt.Sprintf("-aspect %f", width/height)
|
||||
}
|
||||
}
|
||||
|
||||
if m.aspect != "" {
|
||||
return fmt.Sprintf("-aspect %s", m.aspect)
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainVideoCodec() string {
|
||||
if m.videoCodec != "" {
|
||||
return fmt.Sprintf("-vcodec %s", m.videoCodec)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
func (m *Mediafile) ObtainFrameRate() string {
|
||||
if m.frameRate != 0 {
|
||||
return fmt.Sprintf("-r %d", m.frameRate)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainResolution() string {
|
||||
if m.resolution != "" {
|
||||
return fmt.Sprintf("-s %s", m.resolution)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainVideoBitRate() string {
|
||||
if m.videoBitRate != 0 {
|
||||
return fmt.Sprintf("-b:v %d", m.videoBitRate)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainAudioCodec() string {
|
||||
if m.audioCodec != "" {
|
||||
return fmt.Sprintf("-acodec %s", m.audioCodec)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainAudioBitRate() string {
|
||||
if m.audioBitrate != 0 {
|
||||
return fmt.Sprintf("-b:a %d", m.audioBitrate)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainAudioChannels() string {
|
||||
if m.audioChannels != 0 {
|
||||
return fmt.Sprintf("-ac %d", m.audioChannels)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainVideoMaxBitRate() string {
|
||||
if m.videoMaxBitRate != 0 {
|
||||
return fmt.Sprintf("-maxrate %dk", m.videoMaxBitRate)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainVideoMinBitRate() string {
|
||||
if m.videoMinBitrate != 0 {
|
||||
return fmt.Sprintf("-minrate %dk", m.videoMinBitrate)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainBufferSize() string {
|
||||
if m.bufferSize != 0 {
|
||||
return fmt.Sprintf("-bufsize %dk", m.bufferSize)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainVideoBitRateTolerance() string {
|
||||
if m.videoBitRateTolerance != 0 {
|
||||
return fmt.Sprintf("-bt %dk", m.videoBitRateTolerance)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainThreads() string {
|
||||
if m.threads != 0 {
|
||||
return fmt.Sprintf("-threads %d", m.threads)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainTarget() string {
|
||||
if m.target != "" {
|
||||
return fmt.Sprintf("-target %s", m.target)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainDuration() string {
|
||||
if m.duration != "" {
|
||||
return fmt.Sprintf("-t %s", m.duration)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainKeyframeInterval() string {
|
||||
if m.keyframeInterval != 0 {
|
||||
return fmt.Sprintf("-g %d", m.keyframeInterval)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Mediafile) ObtainSeekTime() string {
|
||||
if m.seekTime != "" {
|
||||
return fmt.Sprintf("-ss %s", m.seekTime)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
func (m *Mediafile) ObtainQuality() string {
|
||||
if m.quality != 0 {
|
||||
return fmt.Sprintf("-q:v %d", m.quality)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
@@ -1,28 +1,78 @@
|
||||
package models
|
||||
|
||||
type Ffmpeg struct {
|
||||
FfmpegBinPath string
|
||||
FfprobeBinPath string
|
||||
FfmpegBinPath string
|
||||
FfprobeBinPath string
|
||||
}
|
||||
|
||||
type Mediafile struct {
|
||||
Aspect string
|
||||
Resolution string
|
||||
VideoBitRate string
|
||||
VideoMaxBitrate string
|
||||
VideoMinBitrate string
|
||||
VideoCodec string
|
||||
FrameRate string
|
||||
MaxKeyframe string
|
||||
MinKeyframe string
|
||||
AudioCodec string
|
||||
AudioBitrate string
|
||||
AudioSampleRate string
|
||||
AudioChannels string
|
||||
BufferSize string
|
||||
Threads string
|
||||
Target string
|
||||
Duration string
|
||||
SeekTime string
|
||||
Quality string
|
||||
type Metadata struct {
|
||||
Streams []Streams `json:"streams"`
|
||||
Format Format `json:"format"`
|
||||
}
|
||||
|
||||
type Streams struct {
|
||||
Index int
|
||||
CodecName string `json:"codec_name"`
|
||||
CodecLongName string `json:"codec_long_name"`
|
||||
Profile string `json:"profile"`
|
||||
CodecType string `json:"codec_type"`
|
||||
CodecTimeBase string `json:"codec_time_base"`
|
||||
CodecTagString string `json:"codec_tag_string"`
|
||||
CodecTag string `json:"codec_tag"`
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
CodedWidth int `json:"coded_width"`
|
||||
CodedHeight int `json:"coded_height"`
|
||||
HasBFrames int `json:"has_b_frames"`
|
||||
SampleAspectRatio string `json:"sample_aspect_ratio"`
|
||||
DisplayAspectRatio string `json:"display_aspect_ratio"`
|
||||
PixFmt string `json:"pix_fmt"`
|
||||
Level int `json:"level"`
|
||||
ChromaLocation string `json:"chroma_location"`
|
||||
Refs int `json:"refs"`
|
||||
QuarterSample string `json:"quarter_sample"`
|
||||
DivxPacked string `json:"divx_packed"`
|
||||
RFrameRrate string `json:"r_frame_rate"`
|
||||
AvgFrameRate string `json:"avg_frame_rate"`
|
||||
TimeBase string `json:"time_base"`
|
||||
DurationTs int `json:"duration_ts"`
|
||||
Duration string `json:"duration"`
|
||||
Disposition Disposition `json:"disposition"`
|
||||
}
|
||||
|
||||
type Disposition struct {
|
||||
Default int `json:"default"`
|
||||
Dub int `json:"dub"`
|
||||
Original int `json:"original"`
|
||||
Comment int `json:"comment"`
|
||||
Lyrics int `json:"lyrics"`
|
||||
Karaoke int `json:"karaoke"`
|
||||
Forced int `json:"forced"`
|
||||
HearingImpaired int `json:"hearing_impaired"`
|
||||
VisualImpaired int `json:"visual_impaired"`
|
||||
CleanEffects int `json:"clean_effects"`
|
||||
}
|
||||
|
||||
type Format struct {
|
||||
Filename string
|
||||
NbStreams int `json:"nb_streams"`
|
||||
NbPrograms int `json:"nb_programs"`
|
||||
FormatName string `json:"format_name"`
|
||||
FormatLongName string `json:"format_long_name"`
|
||||
Duration string `json:"duration"`
|
||||
Size string `json:"size"`
|
||||
BitRate string `json:"bit_rate"`
|
||||
ProbeScore int `json:"probe_score"`
|
||||
Tags Tags `json:"tags"`
|
||||
}
|
||||
|
||||
type Progress struct {
|
||||
FramesProcessed string
|
||||
CurrentTime string
|
||||
CurrentBitrate string
|
||||
Progress float64
|
||||
}
|
||||
|
||||
type Tags struct {
|
||||
Encoder string `json:"ENCODER"`
|
||||
}
|
||||
|
@@ -1,41 +1,107 @@
|
||||
package transcoder
|
||||
|
||||
import (
|
||||
//"fmt"
|
||||
//"os"
|
||||
"errors"
|
||||
"os"
|
||||
"goffmpeg/models"
|
||||
"os/exec"
|
||||
"fmt"
|
||||
"goffmpeg/ffmpeg"
|
||||
"goffmpeg/utils"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"bufio"
|
||||
"strings"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"log"
|
||||
)
|
||||
|
||||
type Transcoder struct {
|
||||
Process *os.Process
|
||||
InputPath string
|
||||
OutputPath string
|
||||
MediaFile *models.Mediafile
|
||||
process *exec.Cmd
|
||||
inputPath string
|
||||
outputPath string
|
||||
mediafile *models.Mediafile
|
||||
configuration ffmpeg.Configuration
|
||||
}
|
||||
|
||||
func New(inputPath *string, configuration *ffmpeg.Configuration) (*Transcoder, error) {
|
||||
transcoding := new(Transcoder)
|
||||
func (t *Transcoder) SetProccess(v *exec.Cmd) {
|
||||
t.process = v
|
||||
}
|
||||
|
||||
if inputPath == nil {
|
||||
return nil, errors.New("error: transcoder.Initialize -> inputPath missing")
|
||||
func (t *Transcoder) SetInputPath(v string) {
|
||||
t.inputPath = v
|
||||
}
|
||||
|
||||
func (t *Transcoder) SetOutputPath(v string) {
|
||||
t.outputPath = v
|
||||
}
|
||||
|
||||
func (t *Transcoder) SetMediaFile(v *models.Mediafile) {
|
||||
t.mediafile = v
|
||||
}
|
||||
|
||||
func (t *Transcoder) SetConfiguration(v ffmpeg.Configuration) {
|
||||
t.configuration = v
|
||||
}
|
||||
|
||||
/*** GETTERS ***/
|
||||
|
||||
func (t Transcoder) Process() *exec.Cmd {
|
||||
return t.process
|
||||
}
|
||||
|
||||
func (t Transcoder) InputPath() string {
|
||||
return t.inputPath
|
||||
}
|
||||
|
||||
func (t Transcoder) OutputPath() string {
|
||||
return t.outputPath
|
||||
}
|
||||
|
||||
func (t Transcoder) MediaFile() *models.Mediafile {
|
||||
return t.mediafile
|
||||
}
|
||||
|
||||
func (t Transcoder) FFmpegExec() string {
|
||||
return t.configuration.FfmpegBin
|
||||
}
|
||||
|
||||
func (t Transcoder) FFprobeExec() string {
|
||||
return t.configuration.FfprobeBin
|
||||
}
|
||||
|
||||
func (t Transcoder) GetCommand() string {
|
||||
var rcommand string
|
||||
|
||||
rcommand = fmt.Sprintf("%s -y -i %s ", t.configuration.FfmpegBin, t.inputPath)
|
||||
|
||||
media := t.mediafile
|
||||
|
||||
rcommand += media.ToStrCommand()
|
||||
|
||||
rcommand += " " + t.outputPath
|
||||
|
||||
fmt.Println(rcommand)
|
||||
|
||||
return rcommand
|
||||
|
||||
}
|
||||
|
||||
/*** FUNCTIONS ***/
|
||||
|
||||
func (t *Transcoder) Initialize(inputPath string, outputPath string, configuration *ffmpeg.Configuration) (error) {
|
||||
|
||||
if inputPath == "" {
|
||||
return errors.New("error: transcoder.Initialize -> inputPath missing")
|
||||
}
|
||||
|
||||
_, err := os.Stat(*inputPath)
|
||||
_, err := os.Stat(inputPath)
|
||||
if os.IsNotExist(err) {
|
||||
return nil, errors.New("error: transcoder.Initialize -> input file not found")
|
||||
return errors.New("error: transcoder.Initialize -> input file not found")
|
||||
}
|
||||
|
||||
// Set input path
|
||||
transcoding.InputPath = *inputPath
|
||||
|
||||
// TODO: Get file metadata from ffprobe and set MediaFile
|
||||
command := fmt.Sprintf("%s -i %s -print_format json -show_format -show_streams -show_error", configuration.FfprobeBin, *inputPath)
|
||||
command := fmt.Sprintf("%s -i %s -print_format json -show_format -show_streams -show_error", configuration.FfprobeBin, inputPath)
|
||||
|
||||
cmd := exec.Command("/bin/sh", "-c", command)
|
||||
|
||||
@@ -46,25 +112,144 @@ func New(inputPath *string, configuration *ffmpeg.Configuration) (*Transcoder, e
|
||||
cmdErr := cmd.Start()
|
||||
|
||||
if cmdErr != nil {
|
||||
return nil, cmdErr
|
||||
return cmdErr
|
||||
}
|
||||
|
||||
_, errProc := cmd.Process.Wait()
|
||||
if errProc != nil {
|
||||
return nil, errProc
|
||||
return errProc
|
||||
}
|
||||
|
||||
stdout := out.String()
|
||||
var Metadata models.Metadata
|
||||
|
||||
fmt.Println(stdout)
|
||||
if err := json.Unmarshal([]byte(out.String()), &Metadata); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
transcoding.MediaFile = new(models.Mediafile)
|
||||
// Set new Mediafile
|
||||
MediaFile := new(models.Mediafile)
|
||||
MediaFile.SetMetadata(Metadata)
|
||||
|
||||
return transcoding, nil
|
||||
// Set transcoder configuration
|
||||
t.SetInputPath(inputPath)
|
||||
t.SetOutputPath(outputPath)
|
||||
t.SetMediaFile(MediaFile)
|
||||
t.SetConfiguration(*configuration)
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (t *Transcoder) SetBitRate(v *string) string {
|
||||
t.MediaFile.VideoBitRate = *v
|
||||
return t.MediaFile.VideoBitRate
|
||||
func (t *Transcoder) Run() (<-chan bool) {
|
||||
done := make(chan bool)
|
||||
command := t.GetCommand()
|
||||
|
||||
proc := exec.Command("/bin/sh", "-c", command)
|
||||
|
||||
t.SetProccess(proc)
|
||||
|
||||
go func() {
|
||||
perror := proc.Start()
|
||||
if perror != nil {
|
||||
log.Fatal(perror)
|
||||
return
|
||||
}
|
||||
|
||||
proc.Wait()
|
||||
|
||||
done <- true
|
||||
}()
|
||||
|
||||
return done
|
||||
|
||||
}
|
||||
|
||||
// TODO: ONLY WORKS FOR VIDEO FILES
|
||||
func (t Transcoder) Output() (chan models.Progress) {
|
||||
out := make(chan models.Progress)
|
||||
|
||||
go func() {
|
||||
|
||||
stderr, serr := t.Process().StderrPipe()
|
||||
if serr != nil {
|
||||
log.Fatal(serr)
|
||||
return
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(stderr)
|
||||
|
||||
split := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
||||
if atEOF && len(data) == 0 {
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
||||
fr := strings.Index(string(data), "frame=")
|
||||
|
||||
if fr > 0 {
|
||||
return fr + 1, data[fr:], nil
|
||||
}
|
||||
|
||||
if atEOF {
|
||||
return len(data), data, nil
|
||||
}
|
||||
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
||||
scanner.Split(split)
|
||||
buf := make([]byte, 2)
|
||||
scanner.Buffer(buf, bufio.MaxScanTokenSize)
|
||||
|
||||
var lastProgress float64
|
||||
var lastFrames string
|
||||
for scanner.Scan() {
|
||||
Progress := new(models.Progress)
|
||||
line := scanner.Text()
|
||||
|
||||
if strings.Contains(line, "time=") && strings.Contains(line, "bitrate=") {
|
||||
var re= regexp.MustCompile(`=\s+`)
|
||||
st := re.ReplaceAllString(line, `=`)
|
||||
|
||||
f := strings.Fields(st)
|
||||
|
||||
// Frames processed
|
||||
framesProcessed := strings.Split(f[0], "=")[1]
|
||||
|
||||
// Current time processed
|
||||
time := strings.Split(f[4], "=")[1]
|
||||
timesec := utils.DurToSec(time)
|
||||
dursec, _ := strconv.ParseFloat(t.MediaFile().Metadata().Format.Duration, 64)
|
||||
// Progress calculation
|
||||
progress := (timesec * 100) / dursec
|
||||
|
||||
// Current bitrate
|
||||
currentBitrate := strings.Split(f[5], "=")[1]
|
||||
|
||||
Progress.Progress = progress
|
||||
Progress.CurrentBitrate = currentBitrate
|
||||
Progress.FramesProcessed = framesProcessed
|
||||
Progress.CurrentTime = time
|
||||
|
||||
if progress != lastProgress && framesProcessed != lastFrames{
|
||||
lastProgress = progress
|
||||
lastFrames = framesProcessed
|
||||
out <- *Progress
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defer close(out)
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
return out
|
||||
}
|
||||
|
24
utils/utils.go
Normal file
24
utils/utils.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func DurToSec(dur string) (sec float64) {
|
||||
durAry := strings.Split(dur, ":")
|
||||
var secs float64
|
||||
if len(durAry) != 3 {
|
||||
return
|
||||
}
|
||||
hr, _ := strconv.ParseFloat(durAry[0], 64)
|
||||
secs = hr * (60 * 60)
|
||||
min, _ := strconv.ParseFloat(durAry[1], 64)
|
||||
secs += min * (60)
|
||||
second, _ := strconv.ParseFloat(durAry[2], 64)
|
||||
secs += second
|
||||
return secs
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user