Skip to content

Commit 0f7d4ba

Browse files
committed
Added support for Single NAL and kinda Non-interleaved mode
1 parent 26b61df commit 0f7d4ba

File tree

6 files changed

+174
-52
lines changed

6 files changed

+174
-52
lines changed

README.md

Lines changed: 56 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,56 @@
1-
# rtpdump
2-
3-
Extract media files from RTP streams in pcap format
4-
5-
## codec support
6-
7-
This program is intended to support usual audio/video codecs used on IMS networks (VoLTE/VoWiFi).
8-
Therefore, some codecs might be limited to usual scenarios on these networks.
9-
10-
+ AMR - [RFC 4867](https://tools.ietf.org/html/rfc4867)
11-
Supports bandwidth-efficient and octet-aligned modes.
12-
Single-channel, single-frame per packet only.
13-
+ EVS - [3GPP TS 26.445](http://www.3gpp.org/DynaReport/26445.htm)
14-
*Not yet supported.*
15-
+ H263 - [RFC 2190](https://tools.ietf.org/html/rfc2190)
16-
*Not yet supported.*
17-
+ H264 - [RFC 6184](https://tools.ietf.org/html/rfc6184)
18-
*Not yet supported.*
19-
20-
## usage
21-
22-
+ rtpdump streams [pcap]
23-
displays RTP streams
24-
+ rtpdump dump -i [pcap]
25-
dumps a media stream.
26-
`-i` options is for interactive dump. Codecs and modes are choosen via prompt.
27-
**Currently only mode available**
28-
29-
## compiling
30-
31-
Checkout [gopacket](https://github.com/google/gopacket).
32-
Linux should be straightforward.
33-
For Windows, make sure mingw(32/64) toolchain is on PATH for gopacket WinPcap dependency. Install WinPcap on standard location `C:\WpdPack`
34-
35-
## planned features
36-
37-
1. Support for H264
38-
2. Include stream analisys, packets lost, jitter, etc
39-
3. Media player directly from pcap. ffmpeg support.
40-
4. Jitter buffer to simulate original condition, i.e. packet loss due to jitter
41-
42-
## contributions
43-
44-
Are always appreciated.
1+
# rtpdump
2+
3+
Extract media files from RTP streams in pcap format
4+
5+
## codec support
6+
7+
This program is intended to support usual audio/video codecs used on IMS networks (VoLTE/VoWiFi).
8+
Therefore, some codecs might be limited to usual scenarios on these networks.
9+
10+
+ AMR - [RFC 4867](https://tools.ietf.org/html/rfc4867)
11+
Supports bandwidth-efficient and octet-aligned modes.
12+
Single-channel, single-frame per packet only.
13+
+ H264 - [RFC 6184](https://tools.ietf.org/html/rfc6184)
14+
Supports Single NAL Mode and some Non-Interleaved Mode streams, due to current lack of STAP-A support
15+
16+
| Payload Type | Support |
17+
|--------------- |-------------- |
18+
| 1-23 NAL Unit | Yes |
19+
| 24 STAP-A | No - planned |
20+
| 25 STAP-B | No |
21+
| 26 MTAP16 | No |
22+
| 27 MTAP24 | Yes |
23+
| 28 FU-A | Yes |
24+
| 29 FU-B | No |
25+
26+
+ EVS - [3GPP TS 26.445](http://www.3gpp.org/DynaReport/26445.htm)
27+
*Not yet supported.*
28+
+ H263 - [RFC 2190](https://tools.ietf.org/html/rfc2190)
29+
*Not yet supported.*
30+
31+
32+
## usage
33+
34+
+ rtpdump streams [pcap]
35+
displays RTP streams
36+
+ rtpdump dump -i [pcap]
37+
dumps a media stream.
38+
`-i` options is for interactive dump. Codecs and modes are choosen via prompt.
39+
**Currently only mode available**
40+
41+
## compiling
42+
43+
Checkout [gopacket](https://github.com/google/gopacket).
44+
Linux should be straightforward.
45+
For Windows, make sure mingw(32/64) toolchain is on PATH for gopacket WinPcap dependency. Install WinPcap on standard location `C:\WpdPack`
46+
47+
## planned features
48+
49+
1. Support for H264
50+
2. Include stream analisys, packets lost, jitter, etc
51+
3. Media player directly from pcap. ffmpeg support.
52+
4. Jitter buffer to simulate original condition, i.e. packet loss due to jitter
53+
54+
## contributions
55+
56+
Are always appreciated.

codecs/codecs.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ package codecs
22

33
var CodecList = []CodecMetadata{
44
AmrMetadata,
5+
H264Metadata,
56
}

codecs/h264.go

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package codecs
2+
import (
3+
"errors"
4+
"github.com/hdiniz/rtpdump/log"
5+
"github.com/hdiniz/rtpdump/rtp"
6+
)
7+
8+
9+
var SINGLE_NAL_MODE = 0
10+
var NON_INTERLEAVED_MODE = 1
11+
var INTERLEAVED_MODE = 2
12+
13+
type H264 struct {
14+
packetizationMode string
15+
started bool
16+
configured bool
17+
timestamp uint32
18+
}
19+
20+
func NewH264() Codec {
21+
return &H264{started: false, configured: false, timestamp: 0}
22+
}
23+
24+
func (c *H264) Init() {
25+
}
26+
27+
func (c *H264) SetOptions(options map[string]string) error {
28+
29+
v,ok := options["packetization-mode"]
30+
if !ok {
31+
return errors.New("required codec option not present")
32+
}
33+
34+
c.packetizationMode = v
35+
return nil
36+
}
37+
38+
func (c H264) GetFormatMagic() []byte {
39+
return []byte{}
40+
}
41+
42+
func (c *H264) HandleRtpPacket(packet *rtp.RtpPacket) (result []byte, err error) {
43+
payload := packet.Payload
44+
forbidden := (payload[0] & 0x80) == 0x80
45+
if forbidden {
46+
log.Warn("forbidden bit set in this payload")
47+
return nil, errors.New("forbidden bit set in this payload")
48+
}
49+
50+
nri := (payload[0] & 0x60) >> 5
51+
nalType := payload[0] & 0x1F
52+
53+
log.Sdebug("h264, seq:%d nri:%d, nalType:%d",
54+
packet.SequenceNumber, nri, nalType)
55+
56+
switch {
57+
case nalType >= 1 && nalType <= 23:
58+
return c.handleNalUnit(payload[:])
59+
case nalType >= 24 && nalType <= 27:
60+
//aggregation packet
61+
log.Debug("h264, aggregation not supported")
62+
return nil, errors.New("h264, aggregation not supported")
63+
case nalType == 28:
64+
return c.handleFuA(payload[:])
65+
default:
66+
log.Sdebug("h264, nal type not supported")
67+
return nil, errors.New("h264, nal type not supported")
68+
}
69+
}
70+
71+
func (c *H264) handleNalUnit(payload []byte) (result []byte, err error) {
72+
result = append(result, []byte{0x00, 0x00, 0x00, 0x01}...)
73+
result = append(result, payload[:]...)
74+
return result, nil
75+
}
76+
func (c *H264) handleFuA(payload []byte) (result []byte, err error) {
77+
isStart := payload[1] & 0x80 == 0x80
78+
//isEnd := payload[0] & 0x40 == 0x40
79+
80+
log.Sdebug("h264, FU-A isStart:%t", isStart)
81+
if isStart {
82+
result = append(result, []byte{0x00, 0x00, 0x00, 0x01}...)
83+
nalUnitHeader := payload[0] & 0xE0
84+
nalUnitHeader = nalUnitHeader | (payload[1] & 0x1F)
85+
result = append(result, nalUnitHeader)
86+
result = append(result, payload[2:]...)
87+
} else {
88+
result = append(result, payload[2:]...)
89+
}
90+
log.Sdebug("FU-A: %#v", result)
91+
92+
return
93+
}
94+
95+
96+
var H264Metadata = CodecMetadata{
97+
Name: "h264",
98+
LongName: "H.264",
99+
Options: []CodecOption {
100+
h264PacketizationModeOption,
101+
},
102+
Init: NewH264,
103+
}
104+
105+
var h264PacketizationModeOption = CodecOption{
106+
Required: true,
107+
Name: "packetization-mode",
108+
Description: "whether this payload is octet-aligned or bandwidth-efficient",
109+
ValidValues: []string {"0", "1", "2"},
110+
ValueDescription: []string {"Single NAL Unit Mode", "Non-Interleaved Mode", "Interleaved Mode"},
111+
RestrictValues: true,
112+
}

dist/x32/rtpdump_x32_0.6.0.exe

4.3 MB
Binary file not shown.

dist/x64/rtpdump_x64_0.6.0.exe

5.39 MB
Binary file not shown.

rtp/rtpreader.go

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package rtp
33
import (
44
"errors"
55
"time"
6-
log "github.com/Sirupsen/logrus"
6+
"github.com/hdiniz/rtpdump/log"
77
"github.com/google/gopacket"
88
"github.com/google/gopacket/layers"
99
"github.com/google/gopacket/pcap"
@@ -26,18 +26,13 @@ func NewRtpReader(path string) (reader *RtpReader, err error) {
2626
func (r *RtpReader) openPcapFile(path string) (err error) {
2727
r.handle, err = pcap.OpenOffline(path)
2828
if err != nil {
29-
log.WithFields(log.Fields{
30-
"path": path,
31-
"error": err,
32-
}).Error("Failed to open pcap file")
29+
log.Error("Failed to open pcap file")
3330
return err
3431
}
3532
err = r.handle.SetBPFFilter(RtpCapureFilter)
3633
if err != nil {
3734
r.handle.Close()
38-
log.WithFields(log.Fields{
39-
"capture-filter": RtpCapureFilter,
40-
}).Error("Failed to set bpf file")
35+
log.Error("Failed to set bpf file")
4136
return err
4237
}
4338
return nil
@@ -81,9 +76,11 @@ func (r *RtpReader) parsePacket(packet gopacket.Packet) error {
8176
rtp, _ := rtpLayer.(*RtpLayer)
8277
r.processRtpPacket(receivedAt, ip, udp, rtp)
8378
} else {
79+
log.Debug("Not able to decode RTP layer")
8480
return errors.New("Not able to decode RTP layer")
8581
}
8682
} else {
83+
log.Debug("Not able to decode Network/Transport layer")
8784
return errors.New("Not able to decode Network/Transport layers")
8885
}
8986
return nil

0 commit comments

Comments
 (0)