Sample code
import (
"crypto/md5"
"encoding/json"
"fmt"
"io"
"os"
"os/exec"
"runtime"
"smartcloud/common"
"smartcloud/log"
"smartcloud/models"
"strconv"
"strings"
//"time"
"net/url"
)
type TranscodeServiceController struct {
TranscodeBaseController
}
type Element struct {
PlayList string
Sn string
ChannelName string
OssType int
Country string
Ptstr string
}
const (
QueueNum = 100
TransCodingNum = 10
)
排队数目
var Queue = make(chan Element, QueueNum)
var md5key string = "videotranscode_1232017321"
func init() {
go Transcoding()
}
func (this *TranscodeServiceController) TransCode() {
playList := this.GetString("play_list")
signature := this.GetString("cylansignature")
sn := this.GetString("sn")
channel_name := this.GetString("channel_name")
ossType := this.GetString("oss_type")
country := this.GetString("country")
//三个平台都使用一个转码服务器,需要知道是哪个平台调用的,转完码后才知道往哪个Bucket上传
ptstr := this.GetString("ptstr")
if playList == "" || signature == "" || sn == "" ||
channel_name == "" || ossType == "" || country == "" || ptstr == "" {
this.jsonStandardResult(-1, "参数错误,有参数为空", "")
return
}
ossType_i, _ := strconv.Atoi(ossType)
var t Element
t.ChannelName = channel_name
t.Country = country
t.OssType = ossType_i
t.PlayList = playList
t.Ptstr = ptstr
t.Sn = sn
js, _ := json.Marshal(t)
if md5Sign(string(js), md5key) != signature {
this.jsonStandardResult(-2, "签名错误", "")
return
}
if len(Queue) < QueueNum {
Queue <- t
} else {
//队列满
this.jsonStandardResult(-3, "系统忙,请稍后再试!", "")
return
}
this.jsonStandardResult(0, "ok", "")
return
}
云存储转码服务器数据:
CPU 四核开启 10 个转码服务 每个视频长度 22 分 18 秒(720*1152) 转码后文件每个大小 344M 耗时 2 分 11 秒
var TransChan = make(chan int, TransCodingNum) //同时转码个数
func Transcoding() {
for {
TransChan <- 1
t := <-Queue
go func() {
var where int
if strings.EqualFold(runtime.GOOS, "windows") {
where = 0
} else { //linux
where = 1
}
_, _, _, OssApiBucket := common.GetOssApiUploadPara2(t.Ptstr, t.Country, t.OssType, where)
loclPath := "/mnt/" + OssApiBucket + "/" + t.ChannelName + "/"
loclPath = strings.Replace(loclPath, "//", "/", -1)
u, err := url.ParseRequestURI(t.PlayList)
name := ""
localFile := ""
if u != nil {
name = u.Path[strings.LastIndex(u.Path, "/")+1 : strings.LastIndex(u.Path, ".m3u8")]
localFile = loclPath + u.Path[strings.LastIndex(u.Path, "/")+1:]
} else {
writelog.WriteError("解析播放列表错误,err:%s", err.Error())
<-TransChan
return
}
localFile = strings.Replace(localFile, "//", "/", -1)
name = name + ".mp4"
outPutFile := common.GetCurrentDirectory() + "/" + t.Sn + "_" + name
outPutFile = strings.Replace(outPutFile, "//", "/", -1)
_, err = os.Stat(localFile)
//判断文件是否已经挂载在本地了
if !os.IsExist(err) { //文件不存在
//writelog.WriteDebug("文件不在本地")
_, err = exec.Command("ffmpeg", "-i", t.PlayList, "-vcodec", "copy", "-strict", "-2", "-f", "mp4", outPutFile).Output()
if err != nil {
writelog.WriteError("视屏转码失败,playList:%s,err:%s", t.PlayList, err.Error())
//os.Remove(outPutFile)
<-TransChan
return
}
contentDisposition := fmt.Sprintf(`attachment; filename="%s"`, t.Sn+"_"+name)
err = models.OssApiUploadFileFromLocal(t.OssType, where, t.ChannelName, t.Country, name, outPutFile, t.Ptstr, contentDisposition)
if err != nil {
writelog.WriteError("将转码后的视频上传到OSS出错,err:%s", err.Error())
os.Remove(outPutFile)
<-TransChan
return
}
} else { //文件存在
//writelog.WriteDebug("文件在本地")
_, err = exec.Command("ffmpeg", "-i", localFile, "-vcodec", "copy", "-strict", "-2", "-f", "mp4", outPutFile).Output()
if err != nil {
writelog.WriteError("视屏转码失败,localFile:%s,err:%s", localFile, err.Error())
//os.Remove(outPutFile)
<-TransChan
return
}
dstfile := loclPath + "/" + name
dstfile = strings.Replace(dstfile, "//", "/", -1)
_, err = exec.Command("cp", "-f", outPutFile, dstfile).Output()
if err != nil {
writelog.WriteError("将转码后的视频上传到OSS出错,localFile:%s,dstfile:%s,err:%s", localFile, dstfile, err.Error())
os.Remove(outPutFile)
<-TransChan
return
}
}
<-TransChan
os.Remove(outPutFile) //上传完了,将本地的文件删除
}()
}
}
func md5Sign(str, key string) string {
h := md5.New()
io.WriteString(h, str)
io.WriteString(h, key)
return fmt.Sprintf("%x", h.Sum(nil))
}