-
Notifications
You must be signed in to change notification settings - Fork 103
/
Copy pathmerge.go
125 lines (117 loc) · 2.79 KB
/
merge.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
package m3u8d
import (
"bytes"
"context"
"errors"
"github.com/yapingcat/gomedia/go-codec"
"github.com/yapingcat/gomedia/go-mp4"
"github.com/yapingcat/gomedia/go-mpeg2"
"io/ioutil"
"os"
"strconv"
"time"
)
type MergeTsFileListToSingleMp4_Req struct {
TsFileList []string
OutputMp4 string
Status *SpeedStatus
Ctx context.Context
}
func MergeTsFileListToSingleMp4(req MergeTsFileListToSingleMp4_Req) (err error) {
mp4file, err := os.OpenFile(req.OutputMp4, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0666)
if err != nil {
return err
}
defer mp4file.Close()
if req.Status != nil {
req.Status.SpeedResetBytes()
}
muxer, err := mp4.CreateMp4Muxer(mp4file)
if err != nil {
return err
}
var vtid uint32 // video track id
atid := muxer.AddAudioTrack(mp4.MP4_CODEC_AAC)
demuxer := mpeg2.NewTSDemuxer()
var OnFrameErr error
var audioTimestamp uint64 = 0
aacSampleRate := -1
demuxer.OnFrame = func(cid mpeg2.TS_STREAM_TYPE, frame []byte, pts uint64, dts uint64) {
if OnFrameErr != nil {
return
}
if cid == mpeg2.TS_STREAM_AAC {
audioTimestamp = pts
codec.SplitAACFrame(frame, func(aac []byte) {
if aacSampleRate == -1 {
adts := codec.NewAdtsFrameHeader()
adts.Decode(aac)
aacSampleRate = codec.AACSampleIdxToSample(int(adts.Fix_Header.Sampling_frequency_index))
}
err = muxer.Write(atid, aac, audioTimestamp, audioTimestamp)
audioTimestamp += uint64(1024 * 1000 / aacSampleRate) //每帧aac采样固定为1024。aac_sampleRate 为采样率
if err != nil {
OnFrameErr = err
return
}
})
} else if cid == mpeg2.TS_STREAM_H264 || cid == mpeg2.TS_STREAM_H265 {
if vtid == 0 {
switch cid {
case mpeg2.TS_STREAM_H264:
vtid = muxer.AddVideoTrack(mp4.MP4_CODEC_H264)
case mpeg2.TS_STREAM_H265:
vtid = muxer.AddVideoTrack(mp4.MP4_CODEC_H265)
default:
OnFrameErr = errors.New("unknown cid2 " + strconv.Itoa(int(cid)))
return
}
}
err = muxer.Write(vtid, frame, pts, dts)
if err != nil {
OnFrameErr = err
return
}
} else {
OnFrameErr = errors.New("unknown cid " + strconv.Itoa(int(cid)))
return
}
}
if req.Status != nil {
req.Status.SpeedResetTotalBlockCount(len(req.TsFileList))
}
for _, tsFile := range req.TsFileList {
select {
case <-req.Ctx.Done():
return req.Ctx.Err()
default:
}
var buf []byte
buf, err = ioutil.ReadFile(tsFile)
if err != nil {
return err
}
err = demuxer.Input(bytes.NewReader(buf))
if err != nil {
return err
}
if OnFrameErr != nil {
return OnFrameErr
}
if req.Status != nil {
req.Status.SpeedAdd1Block(time.Now(), len(buf))
}
}
err = muxer.WriteTrailer()
if err != nil {
return err
}
err = mp4file.Sync()
if err != nil {
return err
}
if req.Status != nil {
req.Status.DrawProgressBar(1, 1)
}
return nil
}