136 lines
2.7 KiB
Go
136 lines
2.7 KiB
Go
|
|
package m3u8d
|
||
|
|
|
||
|
|
import (
|
||
|
|
"crypto/sha256"
|
||
|
|
"encoding/hex"
|
||
|
|
"errors"
|
||
|
|
"io"
|
||
|
|
"os"
|
||
|
|
"os/exec"
|
||
|
|
"path/filepath"
|
||
|
|
"sync"
|
||
|
|
)
|
||
|
|
|
||
|
|
type SetupFfmpeg_Resp struct {
|
||
|
|
ErrMsg string
|
||
|
|
FfmpegPath string
|
||
|
|
}
|
||
|
|
|
||
|
|
var gFfmpegExePath string
|
||
|
|
var gFfmpegExePathLocker sync.Mutex
|
||
|
|
|
||
|
|
func SetupFfmpeg() (p string, err error) {
|
||
|
|
gFfmpegExePathLocker.Lock()
|
||
|
|
defer gFfmpegExePathLocker.Unlock()
|
||
|
|
|
||
|
|
if gFfmpegExePath != "" {
|
||
|
|
return gFfmpegExePath, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
ffmpegPath, err := exec.LookPath("ffmpeg")
|
||
|
|
if err != nil {
|
||
|
|
ffmpegPath, err = UnzipFfmpegToLocal(getTempDir())
|
||
|
|
if err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
gFfmpegExePath = ffmpegPath
|
||
|
|
return ffmpegPath, nil
|
||
|
|
}
|
||
|
|
gFfmpegExePath = ffmpegPath
|
||
|
|
return ffmpegPath, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func getTempDir() string {
|
||
|
|
dir := filepath.Join(os.TempDir(), "m3u8d")
|
||
|
|
if !isDirExists(dir) {
|
||
|
|
_ = os.MkdirAll(dir, 0777)
|
||
|
|
}
|
||
|
|
return dir
|
||
|
|
}
|
||
|
|
|
||
|
|
func mergeTsFileList_Ffmpeg(ffmpegPath string, tsFileList []string, outputMp4 string) (contentHash string, err error) {
|
||
|
|
outputMp4Temp := outputMp4 + ".tmp"
|
||
|
|
cmd := exec.Command(ffmpegPath, "-i", "-", "-acodec", "copy", "-vcodec", "copy", "-f", "mp4", outputMp4Temp)
|
||
|
|
ip, err := cmd.StdinPipe()
|
||
|
|
if err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
if isFileExists(outputMp4Temp) {
|
||
|
|
err = os.Remove(outputMp4Temp)
|
||
|
|
if err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//cmd.Stderr = os.Stderr
|
||
|
|
cmd.Stdout = os.Stdout
|
||
|
|
setupCmd(cmd)
|
||
|
|
err = cmd.Start()
|
||
|
|
if err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
for _, name := range tsFileList {
|
||
|
|
fin, err := os.Open(name)
|
||
|
|
if err != nil {
|
||
|
|
cmd.Process.Kill()
|
||
|
|
cmd.Wait()
|
||
|
|
return "", errors.New("read error: " + err.Error())
|
||
|
|
}
|
||
|
|
_, err = io.Copy(ip, fin)
|
||
|
|
if err != nil {
|
||
|
|
cmd.Process.Kill()
|
||
|
|
cmd.Wait()
|
||
|
|
fin.Close()
|
||
|
|
return "", errors.New("write error: " + err.Error())
|
||
|
|
}
|
||
|
|
fin.Close()
|
||
|
|
}
|
||
|
|
err = ip.Close()
|
||
|
|
if err != nil {
|
||
|
|
cmd.Process.Kill()
|
||
|
|
cmd.Wait()
|
||
|
|
return "", errors.New("ip.Close error: " + err.Error())
|
||
|
|
}
|
||
|
|
err = cmd.Wait()
|
||
|
|
if err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
err = os.Rename(outputMp4Temp, outputMp4)
|
||
|
|
if err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
return getFileSha256(outputMp4), nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func mergeTsFileList_Raw(tsFileList []string, outputTs string) (hash string, err error) {
|
||
|
|
fout, err := os.Create(outputTs)
|
||
|
|
if err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
hashWriter := sha256.New()
|
||
|
|
multiW := io.MultiWriter(fout, hashWriter)
|
||
|
|
|
||
|
|
for _, tsName := range tsFileList {
|
||
|
|
var fin *os.File
|
||
|
|
fin, err = os.Open(tsName)
|
||
|
|
if err != nil {
|
||
|
|
fout.Close()
|
||
|
|
_ = os.Remove(outputTs)
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
_, err = io.Copy(multiW, fin)
|
||
|
|
if err != nil {
|
||
|
|
fin.Close()
|
||
|
|
fout.Close()
|
||
|
|
_ = os.Remove(outputTs)
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
fin.Close()
|
||
|
|
}
|
||
|
|
err = fout.Close()
|
||
|
|
if err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
tmp := hashWriter.Sum(nil)
|
||
|
|
return hex.EncodeToString(tmp[:]), nil
|
||
|
|
}
|