forked from q191201771/lal
-
Notifications
You must be signed in to change notification settings - Fork 0
/
t_rtmp.go
145 lines (123 loc) · 4.73 KB
/
t_rtmp.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
145
// Copyright 2020, Chef. All rights reserved.
// https://github.com/forkiss/lal
//
// Use of this source code is governed by a MIT-style license
// that can be found in the License file.
//
// Author: Chef (191201771@qq.com)
package base
import "github.com/forkiss/naza/pkg/bele"
const (
// RtmpTypeIdAudio spec-rtmp_specification_1.0.pdf
// 7.1. Types of Messages
RtmpTypeIdAudio uint8 = 8
RtmpTypeIdVideo uint8 = 9
RtmpTypeIdMetadata uint8 = 18 // RtmpTypeIdDataMessageAmf0
RtmpTypeIdSetChunkSize uint8 = 1
RtmpTypeIdAck uint8 = 3
RtmpTypeIdUserControl uint8 = 4
RtmpTypeIdWinAckSize uint8 = 5
RtmpTypeIdBandwidth uint8 = 6
RtmpTypeIdCommandMessageAmf3 uint8 = 17
RtmpTypeIdCommandMessageAmf0 uint8 = 20
RtmpTypeIdAggregateMessage uint8 = 22
// RtmpUserControlStreamBegin RtmpUserControlXxx...
//
// user control message type
//
RtmpUserControlStreamBegin uint8 = 0
RtmpUserControlRecorded uint8 = 4
RtmpUserControlPingRequest uint8 = 6
RtmpUserControlPingResponse uint8 = 7
// RtmpFrameTypeKey spec-video_file_format_spec_v10.pdf
// Video tags
// VIDEODATA
// FrameType UB[4]
// CodecId UB[4]
// AVCVIDEOPACKET
// AVCPacketType UI8
// CompositionTime SI24
// Data UI8[n]
RtmpFrameTypeKey uint8 = 1
RtmpFrameTypeInter uint8 = 2
RtmpCodecIdAvc uint8 = 7
RtmpCodecIdHevc uint8 = 12
// RtmpAvcPacketTypeSeqHeader RtmpAvcPacketTypeNalu RtmpHevcPacketTypeSeqHeader RtmpHevcPacketTypeNalu
// 注意,按照标准文档上描述,PacketType还有可能为2:
// 2: AVC end of sequence (lower level NALU sequence ender is not required or supported)
//
// 我自己遇到过在流结尾时,对端发送 27 02 00 00 00的情况(比如我们的使用wontcry.flv的单元测试,最后一个包)
//
RtmpAvcPacketTypeSeqHeader uint8 = 0
RtmpAvcPacketTypeNalu uint8 = 1
RtmpHevcPacketTypeSeqHeader = RtmpAvcPacketTypeSeqHeader
RtmpHevcPacketTypeNalu = RtmpAvcPacketTypeNalu
RtmpAvcKeyFrame = RtmpFrameTypeKey<<4 | RtmpCodecIdAvc
RtmpHevcKeyFrame = RtmpFrameTypeKey<<4 | RtmpCodecIdHevc
RtmpAvcInterFrame = RtmpFrameTypeInter<<4 | RtmpCodecIdAvc
RtmpHevcInterFrame = RtmpFrameTypeInter<<4 | RtmpCodecIdHevc
// RtmpSoundFormatAac spec-video_file_format_spec_v10.pdf
// Audio tags
// AUDIODATA
// SoundFormat UB[4]
// SoundRate UB[2]
// SoundSize UB[1]
// SoundType UB[1]
// AACAUDIODATA
// AACPacketType UI8
// Data UI8[n]
RtmpSoundFormatAac uint8 = 10 // 注意,视频的CodecId是后4位,音频是前4位
RtmpAacPacketTypeSeqHeader = 0
RtmpAacPacketTypeRaw = 1
)
type RtmpHeader struct {
Csid int
MsgLen uint32 // 不包含header的大小
MsgTypeId uint8 // 8 audio 9 video 18 metadata
MsgStreamId int
TimestampAbs uint32 // dts, 经过计算得到的流上的绝对时间戳,单位毫秒
}
type RtmpMsg struct {
Header RtmpHeader
Payload []byte // Payload不包含Header内容。如果需要将RtmpMsg序列化成RTMP chunk,可调用rtmp.ChunkDivider相关的函数
}
func (msg RtmpMsg) IsAvcKeySeqHeader() bool {
return msg.Header.MsgTypeId == RtmpTypeIdVideo && msg.Payload[0] == RtmpAvcKeyFrame && msg.Payload[1] == RtmpAvcPacketTypeSeqHeader
}
func (msg RtmpMsg) IsHevcKeySeqHeader() bool {
return msg.Header.MsgTypeId == RtmpTypeIdVideo && msg.Payload[0] == RtmpHevcKeyFrame && msg.Payload[1] == RtmpHevcPacketTypeSeqHeader
}
func (msg RtmpMsg) IsVideoKeySeqHeader() bool {
return msg.IsAvcKeySeqHeader() || msg.IsHevcKeySeqHeader()
}
func (msg RtmpMsg) IsAvcKeyNalu() bool {
return msg.Header.MsgTypeId == RtmpTypeIdVideo && msg.Payload[0] == RtmpAvcKeyFrame && msg.Payload[1] == RtmpAvcPacketTypeNalu
}
func (msg RtmpMsg) IsHevcKeyNalu() bool {
return msg.Header.MsgTypeId == RtmpTypeIdVideo && msg.Payload[0] == RtmpHevcKeyFrame && msg.Payload[1] == RtmpHevcPacketTypeNalu
}
func (msg RtmpMsg) IsVideoKeyNalu() bool {
return msg.IsAvcKeyNalu() || msg.IsHevcKeyNalu()
}
func (msg RtmpMsg) IsAacSeqHeader() bool {
return msg.Header.MsgTypeId == RtmpTypeIdAudio && (msg.Payload[0]>>4) == RtmpSoundFormatAac && msg.Payload[1] == RtmpAacPacketTypeSeqHeader
}
func (msg RtmpMsg) VideoCodecId() uint8 {
return msg.Payload[0] & 0xF
}
func (msg RtmpMsg) Clone() (ret RtmpMsg) {
ret.Header = msg.Header
ret.Payload = make([]byte, len(msg.Payload))
copy(ret.Payload, msg.Payload)
return
}
func (msg RtmpMsg) Dts() uint32 {
return msg.Header.TimestampAbs
}
// Pts
//
// 注意,只有视频才能调用该函数获取pts,音频的dts和pts都直接使用 RtmpMsg.Header.TimestampAbs
//
func (msg RtmpMsg) Pts() uint32 {
return msg.Header.TimestampAbs + bele.BeUint24(msg.Payload[2:])
}