mirror of
https://github.com/xfrr/goffmpeg.git
synced 2025-10-17 05:20:45 +08:00
Added input path to mediafile and seek using TS option for input
This commit is contained in:
323
models/media.go
323
models/media.go
@@ -1,10 +1,10 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
"strconv"
|
"strconv"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Mediafile struct {
|
type Mediafile struct {
|
||||||
@@ -24,341 +24,380 @@ type Mediafile struct {
|
|||||||
audioChannels int
|
audioChannels int
|
||||||
bufferSize int
|
bufferSize int
|
||||||
threads int
|
threads int
|
||||||
preset string
|
preset string
|
||||||
target string
|
target string
|
||||||
duration string
|
duration string
|
||||||
seekTime string
|
seekTime string
|
||||||
quality int
|
quality int
|
||||||
metadata Metadata
|
metadata Metadata
|
||||||
|
muxDelay int
|
||||||
|
seekUsingTsInput bool
|
||||||
|
inputPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** SETTERS ***/
|
/*** SETTERS ***/
|
||||||
|
|
||||||
func (m *Mediafile) SetAspect(v string) {
|
func (m *Mediafile) SetAspect(v string) {
|
||||||
m.aspect = v
|
m.aspect = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) SetResolution(v string) {
|
func (m *Mediafile) SetResolution(v string) {
|
||||||
m.resolution = v
|
m.resolution = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) SetVideoBitRate(v int) {
|
func (m *Mediafile) SetVideoBitRate(v int) {
|
||||||
m.videoBitRate = v
|
m.videoBitRate = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) SetVideoBitRateTolerance(v int) {
|
func (m *Mediafile) SetVideoBitRateTolerance(v int) {
|
||||||
m.videoBitRateTolerance = v
|
m.videoBitRateTolerance = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) SetVideoMaxBitrate(v int) {
|
func (m *Mediafile) SetVideoMaxBitrate(v int) {
|
||||||
m.videoMaxBitRate = v
|
m.videoMaxBitRate = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) SetVideoMinBitRate(v int) {
|
func (m *Mediafile) SetVideoMinBitRate(v int) {
|
||||||
m.videoMinBitrate = v
|
m.videoMinBitrate = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) SetVideoCodec(v string) {
|
func (m *Mediafile) SetVideoCodec(v string) {
|
||||||
m.videoCodec = v
|
m.videoCodec = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) SetFrameRate(v int) {
|
func (m *Mediafile) SetFrameRate(v int) {
|
||||||
m.frameRate = v
|
m.frameRate = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) SetMaxKeyFrame(v int) {
|
func (m *Mediafile) SetMaxKeyFrame(v int) {
|
||||||
m.maxKeyframe = v
|
m.maxKeyframe = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) SetMinKeyFrame(v int) {
|
func (m *Mediafile) SetMinKeyFrame(v int) {
|
||||||
m.minKeyframe = v
|
m.minKeyframe = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) SetKeyframeInterval(v int) {
|
func (m *Mediafile) SetKeyframeInterval(v int) {
|
||||||
m.keyframeInterval = v
|
m.keyframeInterval = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) SetAudioCodec(v string) {
|
func (m *Mediafile) SetAudioCodec(v string) {
|
||||||
m.audioCodec = v
|
m.audioCodec = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) SetAudioBitRate(v int) {
|
func (m *Mediafile) SetAudioBitRate(v int) {
|
||||||
m.audioBitrate = v
|
m.audioBitrate = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) SetAudioChannels(v int) {
|
func (m *Mediafile) SetAudioChannels(v int) {
|
||||||
m.audioChannels = v
|
m.audioChannels = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) SetBufferSize(v int) {
|
func (m *Mediafile) SetBufferSize(v int) {
|
||||||
m.bufferSize = v
|
m.bufferSize = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) SetThreads(v int) {
|
func (m *Mediafile) SetThreads(v int) {
|
||||||
m.threads = v
|
m.threads = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) SetPreset(v string) {
|
func (m *Mediafile) SetPreset(v string) {
|
||||||
m.preset = v
|
m.preset = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) SetDuration(v string) {
|
func (m *Mediafile) SetDuration(v string) {
|
||||||
m.duration = v
|
m.duration = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) SetSeekTime(v string) {
|
func (m *Mediafile) SetSeekTime(v string) {
|
||||||
m.seekTime = v
|
m.seekTime = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) SetQuality(v int) {
|
func (m *Mediafile) SetQuality(v int) {
|
||||||
m.quality = v
|
m.quality = v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mediafile) SetSeekUsingTsInput(val bool) {
|
||||||
|
m.seekUsingTsInput = val
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mediafile) SetInputPath(val string) {
|
||||||
|
m.inputPath = val
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) SetMetadata(v Metadata) {
|
func (m *Mediafile) SetMetadata(v Metadata) {
|
||||||
m.metadata = v
|
m.metadata = v
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** GETTERS ***/
|
/*** GETTERS ***/
|
||||||
|
|
||||||
func (m Mediafile) Aspect() string {
|
func (m Mediafile) Aspect() string {
|
||||||
return m.aspect
|
return m.aspect
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Mediafile) Resolution() string {
|
func (m Mediafile) Resolution() string {
|
||||||
return m.resolution
|
return m.resolution
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Mediafile) VideoBitrate() int {
|
func (m Mediafile) VideoBitrate() int {
|
||||||
return m.videoBitRate
|
return m.videoBitRate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Mediafile) VideoBitRateTolerance() int {
|
func (m Mediafile) VideoBitRateTolerance() int {
|
||||||
return m.videoBitRateTolerance
|
return m.videoBitRateTolerance
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Mediafile) VideoMaxBitRate() int {
|
func (m Mediafile) VideoMaxBitRate() int {
|
||||||
return m.videoMaxBitRate
|
return m.videoMaxBitRate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Mediafile) VideoMinBitRate() int {
|
func (m Mediafile) VideoMinBitRate() int {
|
||||||
return m.videoMinBitrate
|
return m.videoMinBitrate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Mediafile) VideoCodec() string {
|
func (m Mediafile) VideoCodec() string {
|
||||||
return m.videoCodec
|
return m.videoCodec
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Mediafile) FrameRate() int {
|
func (m Mediafile) FrameRate() int {
|
||||||
return m.frameRate
|
return m.frameRate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Mediafile) MaxKeyFrame() int {
|
func (m Mediafile) MaxKeyFrame() int {
|
||||||
return m.maxKeyframe
|
return m.maxKeyframe
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Mediafile) MinKeyFrame() int {
|
func (m Mediafile) MinKeyFrame() int {
|
||||||
return m.minKeyframe
|
return m.minKeyframe
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Mediafile) KeyFrameInterval() int {
|
func (m Mediafile) KeyFrameInterval() int {
|
||||||
return m.keyframeInterval
|
return m.keyframeInterval
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Mediafile) AudioCodec() string {
|
func (m Mediafile) AudioCodec() string {
|
||||||
return m.audioCodec
|
return m.audioCodec
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Mediafile) AudioBitrate() int {
|
func (m Mediafile) AudioBitrate() int {
|
||||||
return m.audioBitrate
|
return m.audioBitrate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Mediafile) AudioChannels() int {
|
func (m Mediafile) AudioChannels() int {
|
||||||
return m.audioChannels
|
return m.audioChannels
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Mediafile) BufferSize() int {
|
func (m Mediafile) BufferSize() int {
|
||||||
return m.bufferSize
|
return m.bufferSize
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Mediafile) Threads() int {
|
func (m Mediafile) Threads() int {
|
||||||
return m.threads
|
return m.threads
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Mediafile) Target() string {
|
func (m Mediafile) Target() string {
|
||||||
return m.target
|
return m.target
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Mediafile) Duration() string {
|
func (m Mediafile) Duration() string {
|
||||||
return m.duration
|
return m.duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Mediafile) SeekTime() string {
|
func (m Mediafile) SeekTime() string {
|
||||||
return m.seekTime
|
return m.seekTime
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Mediafile) Quality() int {
|
func (m Mediafile) Quality() int {
|
||||||
return m.quality
|
return m.quality
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Mediafile) MuxDelay() int {
|
||||||
|
return m.muxDelay
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Mediafile) SeekUsingTsInput() bool {
|
||||||
|
return m.seekUsingTsInput
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Mediafile) InputPath() string {
|
||||||
|
return m.inputPath
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Mediafile) Metadata() Metadata {
|
func (m Mediafile) Metadata() Metadata {
|
||||||
return m.metadata
|
return m.metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
/** OPTS **/
|
/** OPTS **/
|
||||||
func (m Mediafile) ToStrCommand() string {
|
func (m Mediafile) ToStrCommand() string {
|
||||||
var strCommand string
|
var strCommand string
|
||||||
|
|
||||||
opts := []string{"Aspect", "VideoCodec", "FrameRate", "Resolution", "VideoBitRate", "VideoBitRateTolerance", "AudioCodec", "AudioBitRate", "AudioChannels", "VideoMaxBitRate", "VideoMinBitRate", "BufferSize", "Threads", "Preset", "Target", "Duration", "KeyframeInterval", "SeekTime", "Quality"}
|
opts := []string{"SeekUsingTsInput", "InputPath", "Aspect", "VideoCodec", "FrameRate", "Resolution", "VideoBitRate", "VideoBitRateTolerance", "AudioCodec", "AudioBitRate", "AudioChannels", "VideoMaxBitRate", "VideoMinBitRate", "BufferSize", "Threads", "Preset", "Target", "Duration", "KeyframeInterval", "SeekTime", "Quality", "ObtainMuxDelay"}
|
||||||
for _, name := range opts {
|
for _, name := range opts {
|
||||||
opt := reflect.ValueOf(&m).MethodByName(fmt.Sprintf("Obtain%s", name))
|
opt := reflect.ValueOf(&m).MethodByName(fmt.Sprintf("Obtain%s", name))
|
||||||
if (opt != reflect.Value{}) {
|
if (opt != reflect.Value{}) {
|
||||||
result := opt.Call([]reflect.Value{})
|
result := opt.Call([]reflect.Value{})
|
||||||
|
|
||||||
if result[0].String() != "" {
|
if result[0].String() != "" {
|
||||||
strCommand += " "
|
strCommand += " "
|
||||||
strCommand += result[0].String()
|
strCommand += result[0].String()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return strCommand
|
return strCommand
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (m *Mediafile) ObtainAspect() string {
|
func (m *Mediafile) ObtainAspect() string {
|
||||||
// Set aspect
|
// Set aspect
|
||||||
if m.resolution != "" {
|
if m.resolution != "" {
|
||||||
resolution := strings.Split(m.resolution, "x")
|
resolution := strings.Split(m.resolution, "x")
|
||||||
if len(resolution) != 0 {
|
if len(resolution) != 0 {
|
||||||
width, _ := strconv.ParseFloat(resolution[0], 64)
|
width, _ := strconv.ParseFloat(resolution[0], 64)
|
||||||
height, _ := strconv.ParseFloat(resolution[1], 64)
|
height, _ := strconv.ParseFloat(resolution[1], 64)
|
||||||
return fmt.Sprintf("-aspect %f", width/height)
|
return fmt.Sprintf("-aspect %f", width/height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.aspect != "" {
|
if m.aspect != "" {
|
||||||
return fmt.Sprintf("-aspect %s", m.aspect)
|
return fmt.Sprintf("-aspect %s", m.aspect)
|
||||||
} else {
|
} else {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mediafile) ObtainInputPath() string {
|
||||||
|
return fmt.Sprintf("-i \"%s\"", m.inputPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) ObtainVideoCodec() string {
|
func (m *Mediafile) ObtainVideoCodec() string {
|
||||||
if m.videoCodec != "" {
|
if m.videoCodec != "" {
|
||||||
return fmt.Sprintf("-vcodec %s", m.videoCodec)
|
return fmt.Sprintf("-vcodec %s", m.videoCodec)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
func (m *Mediafile) ObtainFrameRate() string {
|
func (m *Mediafile) ObtainFrameRate() string {
|
||||||
if m.frameRate != 0 {
|
if m.frameRate != 0 {
|
||||||
return fmt.Sprintf("-r %d", m.frameRate)
|
return fmt.Sprintf("-r %d", m.frameRate)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) ObtainResolution() string {
|
func (m *Mediafile) ObtainResolution() string {
|
||||||
if m.resolution != "" {
|
if m.resolution != "" {
|
||||||
return fmt.Sprintf("-s %s", m.resolution)
|
return fmt.Sprintf("-s %s", m.resolution)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) ObtainVideoBitRate() string {
|
func (m *Mediafile) ObtainVideoBitRate() string {
|
||||||
if m.videoBitRate != 0 {
|
if m.videoBitRate != 0 {
|
||||||
return fmt.Sprintf("-b:v %d", m.videoBitRate)
|
return fmt.Sprintf("-b:v %d", m.videoBitRate)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) ObtainAudioCodec() string {
|
func (m *Mediafile) ObtainAudioCodec() string {
|
||||||
if m.audioCodec != "" {
|
if m.audioCodec != "" {
|
||||||
return fmt.Sprintf("-acodec %s", m.audioCodec)
|
return fmt.Sprintf("-acodec %s", m.audioCodec)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) ObtainAudioBitRate() string {
|
func (m *Mediafile) ObtainAudioBitRate() string {
|
||||||
if m.audioBitrate != 0 {
|
if m.audioBitrate != 0 {
|
||||||
return fmt.Sprintf("-b:a %d", m.audioBitrate)
|
return fmt.Sprintf("-b:a %d", m.audioBitrate)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) ObtainAudioChannels() string {
|
func (m *Mediafile) ObtainAudioChannels() string {
|
||||||
if m.audioChannels != 0 {
|
if m.audioChannels != 0 {
|
||||||
return fmt.Sprintf("-ac %d", m.audioChannels)
|
return fmt.Sprintf("-ac %d", m.audioChannels)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) ObtainVideoMaxBitRate() string {
|
func (m *Mediafile) ObtainVideoMaxBitRate() string {
|
||||||
if m.videoMaxBitRate != 0 {
|
if m.videoMaxBitRate != 0 {
|
||||||
return fmt.Sprintf("-maxrate %dk", m.videoMaxBitRate)
|
return fmt.Sprintf("-maxrate %dk", m.videoMaxBitRate)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) ObtainVideoMinBitRate() string {
|
func (m *Mediafile) ObtainVideoMinBitRate() string {
|
||||||
if m.videoMinBitrate != 0 {
|
if m.videoMinBitrate != 0 {
|
||||||
return fmt.Sprintf("-minrate %dk", m.videoMinBitrate)
|
return fmt.Sprintf("-minrate %dk", m.videoMinBitrate)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) ObtainBufferSize() string {
|
func (m *Mediafile) ObtainBufferSize() string {
|
||||||
if m.bufferSize != 0 {
|
if m.bufferSize != 0 {
|
||||||
return fmt.Sprintf("-bufsize %dk", m.bufferSize)
|
return fmt.Sprintf("-bufsize %dk", m.bufferSize)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) ObtainVideoBitRateTolerance() string {
|
func (m *Mediafile) ObtainVideoBitRateTolerance() string {
|
||||||
if m.videoBitRateTolerance != 0 {
|
if m.videoBitRateTolerance != 0 {
|
||||||
return fmt.Sprintf("-bt %dk", m.videoBitRateTolerance)
|
return fmt.Sprintf("-bt %dk", m.videoBitRateTolerance)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) ObtainThreads() string {
|
func (m *Mediafile) ObtainThreads() string {
|
||||||
if m.threads != 0 {
|
if m.threads != 0 {
|
||||||
return fmt.Sprintf("-threads %d", m.threads)
|
return fmt.Sprintf("-threads %d", m.threads)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) ObtainTarget() string {
|
func (m *Mediafile) ObtainTarget() string {
|
||||||
if m.target != "" {
|
if m.target != "" {
|
||||||
return fmt.Sprintf("-target %s", m.target)
|
return fmt.Sprintf("-target %s", m.target)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) ObtainDuration() string {
|
func (m *Mediafile) ObtainDuration() string {
|
||||||
if m.duration != "" {
|
if m.duration != "" {
|
||||||
return fmt.Sprintf("-t %s", m.duration)
|
return fmt.Sprintf("-t %s", m.duration)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) ObtainKeyframeInterval() string {
|
func (m *Mediafile) ObtainKeyframeInterval() string {
|
||||||
if m.keyframeInterval != 0 {
|
if m.keyframeInterval != 0 {
|
||||||
return fmt.Sprintf("-g %d", m.keyframeInterval)
|
return fmt.Sprintf("-g %d", m.keyframeInterval)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) ObtainSeekTime() string {
|
func (m *Mediafile) ObtainSeekTime() string {
|
||||||
if m.seekTime != "" {
|
if m.seekTime != "" {
|
||||||
return fmt.Sprintf("-ss %s", m.seekTime)
|
return fmt.Sprintf("-ss %s", m.seekTime)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mediafile) ObtainPreset() string {
|
func (m *Mediafile) ObtainPreset() string {
|
||||||
if m.preset != "" {
|
if m.preset != "" {
|
||||||
return fmt.Sprintf("-preset %s", m.preset)
|
return fmt.Sprintf("-preset %s", m.preset)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mediafile) ObtainMuxDelay() string {
|
||||||
|
return fmt.Sprintf("-muxdelay %d", m.muxDelay)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Mediafile) ObtainSeekUsingTsInput() string {
|
||||||
|
if m.seekUsingTsInput {
|
||||||
|
return "-seek_timestamp 1"
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
114
models/models.go
114
models/models.go
@@ -1,79 +1,79 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
type Ffmpeg struct {
|
type Ffmpeg struct {
|
||||||
FfmpegBinPath string
|
FfmpegBinPath string
|
||||||
FfprobeBinPath string
|
FfprobeBinPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Metadata struct {
|
type Metadata struct {
|
||||||
Streams []Streams `json:"streams"`
|
Streams []Streams `json:"streams"`
|
||||||
Format Format `json:"format"`
|
Format Format `json:"format"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Streams struct {
|
type Streams struct {
|
||||||
Index int
|
Index int
|
||||||
CodecName string `json:"codec_name"`
|
CodecName string `json:"codec_name"`
|
||||||
CodecLongName string `json:"codec_long_name"`
|
CodecLongName string `json:"codec_long_name"`
|
||||||
Profile string `json:"profile"`
|
Profile string `json:"profile"`
|
||||||
CodecType string `json:"codec_type"`
|
CodecType string `json:"codec_type"`
|
||||||
CodecTimeBase string `json:"codec_time_base"`
|
CodecTimeBase string `json:"codec_time_base"`
|
||||||
CodecTagString string `json:"codec_tag_string"`
|
CodecTagString string `json:"codec_tag_string"`
|
||||||
CodecTag string `json:"codec_tag"`
|
CodecTag string `json:"codec_tag"`
|
||||||
Width int `json:"width"`
|
Width int `json:"width"`
|
||||||
Height int `json:"height"`
|
Height int `json:"height"`
|
||||||
CodedWidth int `json:"coded_width"`
|
CodedWidth int `json:"coded_width"`
|
||||||
CodedHeight int `json:"coded_height"`
|
CodedHeight int `json:"coded_height"`
|
||||||
HasBFrames int `json:"has_b_frames"`
|
HasBFrames int `json:"has_b_frames"`
|
||||||
SampleAspectRatio string `json:"sample_aspect_ratio"`
|
SampleAspectRatio string `json:"sample_aspect_ratio"`
|
||||||
DisplayAspectRatio string `json:"display_aspect_ratio"`
|
DisplayAspectRatio string `json:"display_aspect_ratio"`
|
||||||
PixFmt string `json:"pix_fmt"`
|
PixFmt string `json:"pix_fmt"`
|
||||||
Level int `json:"level"`
|
Level int `json:"level"`
|
||||||
ChromaLocation string `json:"chroma_location"`
|
ChromaLocation string `json:"chroma_location"`
|
||||||
Refs int `json:"refs"`
|
Refs int `json:"refs"`
|
||||||
QuarterSample string `json:"quarter_sample"`
|
QuarterSample string `json:"quarter_sample"`
|
||||||
DivxPacked string `json:"divx_packed"`
|
DivxPacked string `json:"divx_packed"`
|
||||||
RFrameRrate string `json:"r_frame_rate"`
|
RFrameRrate string `json:"r_frame_rate"`
|
||||||
AvgFrameRate string `json:"avg_frame_rate"`
|
AvgFrameRate string `json:"avg_frame_rate"`
|
||||||
TimeBase string `json:"time_base"`
|
TimeBase string `json:"time_base"`
|
||||||
DurationTs int `json:"duration_ts"`
|
DurationTs int `json:"duration_ts"`
|
||||||
Duration string `json:"duration"`
|
Duration string `json:"duration"`
|
||||||
Disposition Disposition `json:"disposition"`
|
Disposition Disposition `json:"disposition"`
|
||||||
BitRate string `json:"bit_rate"`
|
BitRate string `json:"bit_rate"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Disposition struct {
|
type Disposition struct {
|
||||||
Default int `json:"default"`
|
Default int `json:"default"`
|
||||||
Dub int `json:"dub"`
|
Dub int `json:"dub"`
|
||||||
Original int `json:"original"`
|
Original int `json:"original"`
|
||||||
Comment int `json:"comment"`
|
Comment int `json:"comment"`
|
||||||
Lyrics int `json:"lyrics"`
|
Lyrics int `json:"lyrics"`
|
||||||
Karaoke int `json:"karaoke"`
|
Karaoke int `json:"karaoke"`
|
||||||
Forced int `json:"forced"`
|
Forced int `json:"forced"`
|
||||||
HearingImpaired int `json:"hearing_impaired"`
|
HearingImpaired int `json:"hearing_impaired"`
|
||||||
VisualImpaired int `json:"visual_impaired"`
|
VisualImpaired int `json:"visual_impaired"`
|
||||||
CleanEffects int `json:"clean_effects"`
|
CleanEffects int `json:"clean_effects"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Format struct {
|
type Format struct {
|
||||||
Filename string
|
Filename string
|
||||||
NbStreams int `json:"nb_streams"`
|
NbStreams int `json:"nb_streams"`
|
||||||
NbPrograms int `json:"nb_programs"`
|
NbPrograms int `json:"nb_programs"`
|
||||||
FormatName string `json:"format_name"`
|
FormatName string `json:"format_name"`
|
||||||
FormatLongName string `json:"format_long_name"`
|
FormatLongName string `json:"format_long_name"`
|
||||||
Duration string `json:"duration"`
|
Duration string `json:"duration"`
|
||||||
Size string `json:"size"`
|
Size string `json:"size"`
|
||||||
BitRate string `json:"bit_rate"`
|
BitRate string `json:"bit_rate"`
|
||||||
ProbeScore int `json:"probe_score"`
|
ProbeScore int `json:"probe_score"`
|
||||||
Tags Tags `json:"tags"`
|
Tags Tags `json:"tags"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Progress struct {
|
type Progress struct {
|
||||||
FramesProcessed string
|
FramesProcessed string
|
||||||
CurrentTime string
|
CurrentTime string
|
||||||
CurrentBitrate string
|
CurrentBitrate string
|
||||||
Progress float64
|
Progress float64
|
||||||
}
|
}
|
||||||
|
|
||||||
type Tags struct {
|
type Tags struct {
|
||||||
Encoder string `json:"ENCODER"`
|
Encoder string `json:"ENCODER"`
|
||||||
}
|
}
|
||||||
|
@@ -1,87 +1,78 @@
|
|||||||
package transcoder
|
package transcoder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
"goffmpeg/models"
|
"goffmpeg/models"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"fmt"
|
"fmt"
|
||||||
"goffmpeg/ffmpeg"
|
"goffmpeg/ffmpeg"
|
||||||
"goffmpeg/utils"
|
"goffmpeg/utils"
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"bufio"
|
"bufio"
|
||||||
"strings"
|
"strings"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Transcoder struct {
|
type Transcoder struct {
|
||||||
process *exec.Cmd
|
process *exec.Cmd
|
||||||
inputPath string
|
outputPath string
|
||||||
outputPath string
|
mediafile *models.Mediafile
|
||||||
mediafile *models.Mediafile
|
configuration ffmpeg.Configuration
|
||||||
configuration ffmpeg.Configuration
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Transcoder) SetProccess(v *exec.Cmd) {
|
func (t *Transcoder) SetProccess(v *exec.Cmd) {
|
||||||
t.process = v
|
t.process = v
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Transcoder) SetInputPath(v string) {
|
|
||||||
t.inputPath = v
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Transcoder) SetOutputPath(v string) {
|
func (t *Transcoder) SetOutputPath(v string) {
|
||||||
t.outputPath = v
|
t.outputPath = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Transcoder) SetMediaFile(v *models.Mediafile) {
|
func (t *Transcoder) SetMediaFile(v *models.Mediafile) {
|
||||||
t.mediafile = v
|
t.mediafile = v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Transcoder) SetConfiguration(v ffmpeg.Configuration) {
|
func (t *Transcoder) SetConfiguration(v ffmpeg.Configuration) {
|
||||||
t.configuration = v
|
t.configuration = v
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** GETTERS ***/
|
/*** GETTERS ***/
|
||||||
|
|
||||||
func (t Transcoder) Process() *exec.Cmd {
|
func (t Transcoder) Process() *exec.Cmd {
|
||||||
return t.process
|
return t.process
|
||||||
}
|
|
||||||
|
|
||||||
func (t Transcoder) InputPath() string {
|
|
||||||
return t.inputPath
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Transcoder) OutputPath() string {
|
func (t Transcoder) OutputPath() string {
|
||||||
return t.outputPath
|
return t.outputPath
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Transcoder) MediaFile() *models.Mediafile {
|
func (t Transcoder) MediaFile() *models.Mediafile {
|
||||||
return t.mediafile
|
return t.mediafile
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Transcoder) FFmpegExec() string {
|
func (t Transcoder) FFmpegExec() string {
|
||||||
return t.configuration.FfmpegBin
|
return t.configuration.FfmpegBin
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Transcoder) FFprobeExec() string {
|
func (t Transcoder) FFprobeExec() string {
|
||||||
return t.configuration.FfprobeBin
|
return t.configuration.FfprobeBin
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Transcoder) GetCommand() string {
|
func (t Transcoder) GetCommand() string {
|
||||||
var rcommand string
|
var rcommand string
|
||||||
|
|
||||||
rcommand = fmt.Sprintf("%s -y -i \"%s\" ", t.configuration.FfmpegBin, t.inputPath)
|
rcommand = fmt.Sprintf("%s -y ", t.configuration.FfmpegBin)
|
||||||
|
|
||||||
media := t.mediafile
|
media := t.mediafile
|
||||||
|
|
||||||
rcommand += media.ToStrCommand()
|
rcommand += media.ToStrCommand()
|
||||||
|
|
||||||
rcommand += " \"" + t.outputPath + "\""
|
rcommand += " \"" + t.outputPath + "\""
|
||||||
|
|
||||||
return rcommand
|
return rcommand
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,194 +80,194 @@ func (t Transcoder) GetCommand() string {
|
|||||||
|
|
||||||
func (t *Transcoder) Initialize(inputPath string, outputPath string) (error) {
|
func (t *Transcoder) Initialize(inputPath string, outputPath string) (error) {
|
||||||
|
|
||||||
configuration, err := ffmpeg.Configure()
|
configuration, err := ffmpeg.Configure()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if inputPath == "" {
|
if inputPath == "" {
|
||||||
return errors.New("error: transcoder.Initialize -> inputPath missing")
|
return errors.New("error: transcoder.Initialize -> inputPath missing")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = os.Stat(inputPath)
|
_, err = os.Stat(inputPath)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return errors.New("error: transcoder.Initialize -> input file not found")
|
return errors.New("error: transcoder.Initialize -> input file not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
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(configuration.ExecCmd, configuration.ExecArgs, command)
|
cmd := exec.Command(configuration.ExecCmd, configuration.ExecArgs, command)
|
||||||
|
|
||||||
fmt.Println("FFprobe command: " + command)
|
fmt.Println("FFprobe command: " + command)
|
||||||
|
|
||||||
var out bytes.Buffer
|
var out bytes.Buffer
|
||||||
|
|
||||||
cmd.Stdout = &out
|
cmd.Stdout = &out
|
||||||
|
|
||||||
err = cmd.Start()
|
err = cmd.Start()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = cmd.Process.Wait()
|
_, err = cmd.Process.Wait()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var Metadata models.Metadata
|
var Metadata models.Metadata
|
||||||
|
|
||||||
if err = json.Unmarshal([]byte(out.String()), &Metadata); err != nil {
|
if err = json.Unmarshal([]byte(out.String()), &Metadata); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set new Mediafile
|
// Set new Mediafile
|
||||||
MediaFile := new(models.Mediafile)
|
MediaFile := new(models.Mediafile)
|
||||||
MediaFile.SetMetadata(Metadata)
|
MediaFile.SetMetadata(Metadata)
|
||||||
|
MediaFile.SetInputPath(inputPath)
|
||||||
// Set transcoder configuration
|
// Set transcoder configuration
|
||||||
t.SetInputPath(inputPath)
|
|
||||||
t.SetOutputPath(outputPath)
|
t.SetOutputPath(outputPath)
|
||||||
t.SetMediaFile(MediaFile)
|
t.SetMediaFile(MediaFile)
|
||||||
t.SetConfiguration(configuration)
|
t.SetConfiguration(configuration)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Transcoder) Run() (<-chan bool, error) {
|
func (t *Transcoder) Run() (<-chan bool, error) {
|
||||||
done := make(chan bool)
|
done := make(chan bool)
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
command := t.GetCommand()
|
command := t.GetCommand()
|
||||||
|
|
||||||
fmt.Println("FFmpeg command: " + command)
|
fmt.Println("FFmpeg command: " + command)
|
||||||
|
|
||||||
proc := exec.Command(t.configuration.ExecCmd, t.configuration.ExecArgs, command)
|
proc := exec.Command(t.configuration.ExecCmd, t.configuration.ExecArgs, command)
|
||||||
|
|
||||||
t.SetProccess(proc)
|
t.SetProccess(proc)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
err := proc.Start()
|
err := proc.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
proc.Wait()
|
proc.Wait()
|
||||||
|
|
||||||
done <- true
|
done <- true
|
||||||
close(done)
|
close(done)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return done, err
|
return done, err
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Transcoder) Output() (<-chan models.Progress, error) {
|
func (t Transcoder) Output() (<-chan models.Progress, error) {
|
||||||
out := make(chan models.Progress)
|
out := make(chan models.Progress)
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer close(out)
|
defer close(out)
|
||||||
|
|
||||||
stderr, stderror := t.Process().StderrPipe()
|
stderr, stderror := t.Process().StderrPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = stderror
|
err = stderror
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
scanner := bufio.NewScanner(stderr)
|
scanner := bufio.NewScanner(stderr)
|
||||||
filetype := utils.CheckFileType(t.MediaFile().Metadata().Streams)
|
filetype := utils.CheckFileType(t.MediaFile().Metadata().Streams)
|
||||||
|
|
||||||
split := func(data []byte, atEOF bool) (advance int, token []byte, spliterror error) {
|
split := func(data []byte, atEOF bool) (advance int, token []byte, spliterror error) {
|
||||||
|
|
||||||
if atEOF && len(data) == 0 {
|
if atEOF && len(data) == 0 {
|
||||||
return 0, nil, nil
|
return 0, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
Iframe := strings.Index(string(data), "frame=")
|
Iframe := strings.Index(string(data), "frame=")
|
||||||
|
|
||||||
if filetype == "video" {
|
if filetype == "video" {
|
||||||
if Iframe > 0 {
|
if Iframe > 0 {
|
||||||
return Iframe + 1, data[Iframe:], nil
|
return Iframe + 1, data[Iframe:], nil
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if i := bytes.IndexByte(data, '\n'); i >= 0 {
|
if i := bytes.IndexByte(data, '\n'); i >= 0 {
|
||||||
// We have a full newline-terminated line.
|
// We have a full newline-terminated line.
|
||||||
return i + 1, data[0:i], nil
|
return i + 1, data[0:i], nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if atEOF {
|
if atEOF {
|
||||||
return len(data), data, nil
|
return len(data), data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0, nil, nil
|
return 0, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
scanner.Split(split)
|
scanner.Split(split)
|
||||||
buf := make([]byte, 2)
|
buf := make([]byte, 2)
|
||||||
scanner.Buffer(buf, bufio.MaxScanTokenSize)
|
scanner.Buffer(buf, bufio.MaxScanTokenSize)
|
||||||
|
|
||||||
var lastProgress float64
|
var lastProgress float64
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
Progress := new(models.Progress)
|
Progress := new(models.Progress)
|
||||||
line := scanner.Text()
|
line := scanner.Text()
|
||||||
|
|
||||||
if strings.Contains(line, "time=") && strings.Contains(line, "bitrate=") {
|
if strings.Contains(line, "time=") && strings.Contains(line, "bitrate=") {
|
||||||
var re= regexp.MustCompile(`=\s+`)
|
var re= regexp.MustCompile(`=\s+`)
|
||||||
st := re.ReplaceAllString(line, `=`)
|
st := re.ReplaceAllString(line, `=`)
|
||||||
|
|
||||||
f := strings.Fields(st)
|
f := strings.Fields(st)
|
||||||
|
|
||||||
var framesProcessed string
|
var framesProcessed string
|
||||||
var currentTime string
|
var currentTime string
|
||||||
var currentBitrate string
|
var currentBitrate string
|
||||||
|
|
||||||
for j := 0; j < len(f); j++ {
|
for j := 0; j < len(f); j++ {
|
||||||
field := f[j]
|
field := f[j]
|
||||||
fieldSplit := strings.Split(field, "=")
|
fieldSplit := strings.Split(field, "=")
|
||||||
|
|
||||||
if len(fieldSplit) > 1 {
|
if len(fieldSplit) > 1 {
|
||||||
fieldname := strings.Split(field, "=")[0]
|
fieldname := strings.Split(field, "=")[0]
|
||||||
fieldvalue := strings.Split(field, "=")[1]
|
fieldvalue := strings.Split(field, "=")[1]
|
||||||
|
|
||||||
if fieldname == "frame" {
|
if fieldname == "frame" {
|
||||||
framesProcessed = fieldvalue
|
framesProcessed = fieldvalue
|
||||||
}
|
}
|
||||||
|
|
||||||
if fieldname == "time" {
|
if fieldname == "time" {
|
||||||
currentTime = fieldvalue
|
currentTime = fieldvalue
|
||||||
}
|
}
|
||||||
|
|
||||||
if fieldname == "bitrate" {
|
if fieldname == "bitrate" {
|
||||||
currentBitrate = fieldvalue
|
currentBitrate = fieldvalue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
timesec := utils.DurToSec(currentTime)
|
timesec := utils.DurToSec(currentTime)
|
||||||
dursec, _ := strconv.ParseFloat(t.MediaFile().Metadata().Format.Duration, 64)
|
dursec, _ := strconv.ParseFloat(t.MediaFile().Metadata().Format.Duration, 64)
|
||||||
// Progress calculation
|
// Progress calculation
|
||||||
progress := (timesec * 100) / dursec
|
progress := (timesec * 100) / dursec
|
||||||
|
|
||||||
Progress.Progress = progress
|
Progress.Progress = progress
|
||||||
Progress.CurrentBitrate = currentBitrate
|
Progress.CurrentBitrate = currentBitrate
|
||||||
Progress.FramesProcessed = framesProcessed
|
Progress.FramesProcessed = framesProcessed
|
||||||
Progress.CurrentTime = currentTime
|
Progress.CurrentTime = currentTime
|
||||||
|
|
||||||
if progress != lastProgress {
|
if progress != lastProgress {
|
||||||
lastProgress = progress
|
lastProgress = progress
|
||||||
out <- *Progress
|
out <- *Progress
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if scerror := scanner.Err(); err != nil {
|
if scerror := scanner.Err(); err != nil {
|
||||||
err = scerror
|
err = scerror
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return out, err
|
return out, err
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user