/
ffcm.go
144 lines (130 loc) · 3.39 KB
/
ffcm.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package ffcm
import (
"fmt"
"regexp"
"strings"
"math"
"github.com/Centny/gwf/log"
"github.com/Centny/gwf/netw/dtm"
"github.com/Centny/gwf/util"
)
func init() {
dtm.AddCreator("Video", dtm.FuncCreator(NewAbsV))
}
var FFPROBE_C = "ffprobe"
type Video struct {
Filename string `bson:"filename" json:"filename"`
Duration float64 `bson:"duration" json:"duration"`
Size int64 `bson:"size" json:"size"`
Width int64 `bson:"width" json:"width"`
Height int64 `bson:"height" json:"height"`
Alias string `bson:"alias" json:"alias"`
Kvs util.Map `bson:"-" json:"-"`
Info interface{} `bson:"info" json:"info"`
}
func ParseData(data, reg string) ([]*util.Fcfg, error) {
dataes := regexp.MustCompile(reg).Split(data, -1)
var cfgs []*util.Fcfg
for _, data = range dataes {
data = strings.Trim(data, " \t\n")
if len(data) < 1 {
continue
}
var stream = util.NewFcfg3()
err := stream.InitWithData(data)
if err == nil {
cfgs = append(cfgs, stream)
}
}
return cfgs, nil
}
func ParseFormat(path string) (*util.Fcfg, error) {
data, err := util.Exec(FFPROBE_C, "-show_format", path)
if err != nil {
return nil, util.Err("exec(%v -show_format %v) error->%v", FFPROBE_C, path, err)
}
cfgs, err := ParseData(data, "\\[[/]*FORMAT\\]")
var cfg *util.Fcfg
if len(cfgs) > 0 {
cfg = cfgs[0]
}
return cfg, err
}
func ParseStreams(path string) ([]*util.Fcfg, error) {
data, err := util.Exec(FFPROBE_C, "-show_streams", path)
if err != nil {
return nil, util.Err("exec(%v) error->%v", FFPROBE_C, err)
}
return ParseData(data, "\\[[/]*STREAM\\]")
}
func ParseVideo(path string) (*Video, error) {
var video = &Video{}
var cfg = util.NewFcfg3()
//parse format
format, err := ParseFormat(path)
if err != nil {
return nil, err
}
video.Filename = format.Val("filename")
video.Duration = format.FloatValV("duration", 0)
video.Size = format.Int64ValV("size", 0)
cfg.Merge2("format", format)
//parse streams
streams, err := ParseStreams(path)
for _, stream := range streams {
if stream.Val("codec_type") == "video" {
video.Width = stream.Int64ValV("width", 0)
video.Height = stream.Int64ValV("height", 0)
}
cfg.Merge2("s"+stream.Val("index"), stream)
}
video.Kvs = cfg.Map
return video, err
}
func Dim(whs []string) ([]string, error) {
if len(whs) < 4 {
return nil, util.Err("arguments less 4")
}
ivs, err := util.ParseInts(whs)
if err != nil {
return nil, err
}
var tw, th int = ivs[0], ivs[1]
if tw > ivs[2] {
tw = ivs[2]
th = int(float64(ivs[1]) / float64(ivs[0]) * float64(tw))
}
if th > ivs[3] {
th = ivs[3]
tw = int(float64(ivs[0]) / float64(ivs[1]) * float64(th))
}
if (tw % 2) > 0 {
tw += 1
}
if (th % 2) > 0 {
th += 1
}
return []string{fmt.Sprintf("%v", tw), fmt.Sprintf("%v", th)}, nil
}
func Dim2(whs []string) (string, error) {
vals, err := Dim(whs)
return strings.Join(vals, "x"), err
}
func VerifyVideo(va, vb string) (int, error) {
videoa, err := ParseVideo(va)
if err != nil {
return 0, err
}
if videoa.Duration == 0 {
return 1, fmt.Errorf("zero source(%v)", va)
}
videob, err := ParseVideo(vb)
if err != nil {
return 0, err
}
if math.Abs(videoa.Duration-videob.Duration) > 2 {
return -1, fmt.Errorf("the duration verify fail to %v(%v),%v(%v)", va, videoa.Duration, vb, videob.Duration)
}
log.D("Verify duration ok by %v(%v),%v(%v)", va, videoa.Duration, vb, videob.Duration)
return 0, nil
}