av/packets/packets_test.go

349 lines
9.3 KiB
Go
Raw Normal View History

/*
NAME
MpegTs.go - provides a data structure intended to encapsulate the properties
of an MpegTs packet.
DESCRIPTION
See Readme.md
AUTHOR
Saxon Nelson-Milton <saxon.milton@gmail.com>
LICENSE
MpegTs.go is Copyright (C) 2017 the Australian Ocean Lab (AusOcean)
It is free software: you can redistribute it and/or modify them
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
It is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with revid in gpl.txt. If not, see [GNU licenses](http://www.gnu.org/licenses).
*/
package packets
import (
//"bytes"
"fmt"
"io"
"log"
"net"
"reflect"
"testing"
"time"
"github.com/beatgammit/rtsp"
)
/*******************************************************
Testing stuff related to connection i.e. rtsp, rtp, rtcp
********************************************************/
const (
rtpPort = 17300
rtcpPort = 17319
rtspUrl = "rtsp://192.168.0.50:8554/CH002.sdp"
rtpUrl = "rtsp://192.168.0.50:8554/CH002.sdp/track1"
)
/* Let's see if we can connect to an rtsp device then read an rtp stream,
and then convert the rtp packets to mpegts packets and output. */
func TestRTSP(t *testing.T) {
sess := rtsp.NewSession()
res, err := sess.Options(rtspUrl)
if err != nil {
t.Errorf("Shouldn't have got error: %v\n", err)
}
res, err = sess.Describe(rtspUrl)
if err != nil {
log.Fatalln(err)
t.Errorf("Shouldn't have got error: %v\n", err)
}
p, err := rtsp.ParseSdp(&io.LimitedReader{R: res.Body, N: res.ContentLength})
if err != nil {
t.Errorf("Shouldn't have got error: %v\n", err)
}
log.Printf("%+v", p)
res, err = sess.Setup(rtpUrl, fmt.Sprintf("RTP/AVP;unicast;client_port=%d-%d", rtpPort, rtcpPort))
if err != nil {
t.Errorf("Shouldn't have got error: %v\n", err)
}
log.Println(res)
res, err = sess.Play(rtspUrl, res.Header.Get("Session"))
if err != nil {
t.Errorf("Shouldn't have got error: %v\n", err)
}
log.Println(res)
}
func TestRTP(t *testing.T) {
sess := rtsp.NewSession()
res, err := sess.Options(rtspUrl)
if err != nil {
t.Errorf("Shouldn't have got error: %v\n", err)
}
res, err = sess.Describe(rtspUrl)
if err != nil {
log.Fatalln(err)
t.Errorf("Shouldn't have got error: %v\n", err)
}
p, err := rtsp.ParseSdp(&io.LimitedReader{R: res.Body, N: res.ContentLength})
if err != nil {
t.Errorf("Shouldn't have got error: %v\n", err)
}
log.Printf("%+v", p)
res, err = sess.Setup(rtpUrl, fmt.Sprintf("RTP/AVP;unicast;client_port=%d-%d", rtpPort, rtcpPort))
if err != nil {
t.Errorf("Shouldn't have got error: %v\n", err)
}
log.Println(res)
res, err = sess.Play(rtspUrl, res.Header.Get("Session"))
if err != nil {
t.Errorf("Shouldn't have got error: %v\n", err)
}
log.Println(res)
// create udp connection for rtp stuff
rtpLaddr, err := net.ResolveUDPAddr("udp", "192.168.0.109:17300")
if err != nil {
t.Errorf("Local rtp addr not set! %v\n", err)
}
rtpAddr, err := net.ResolveUDPAddr("udp", "192.168.0.50:17300")
if err != nil {
t.Errorf("Resolving rtp address didn't work! %v\n", err)
}
rtpConn, err := net.DialUDP("udp", rtpLaddr, rtpAddr)
if err != nil {
t.Errorf("Conncection not established! %v\n", err)
}
// Create udp connection for rtcp stuff
rtcpLaddr, err := net.ResolveUDPAddr("udp", "192.168.0.109:17319")
if err != nil {
t.Errorf("Local RTCP address not resolved! %v\n", err)
}
rtcpAddr, err := net.ResolveUDPAddr("udp", "192.168.0.50:17301")
if err != nil {
t.Errorf("Remote RTCP address not resolved! %v\n", err)
}
rtcpConn, err := net.DialUDP("udp", rtcpLaddr, rtcpAddr)
if err != nil {
t.Errorf("Connection not established! %v\n", err)
}
// let's create a session that will store useful stuff from the connections
rtpSession := NewSession(rtpConn, rtcpConn)
time.Sleep(2 * time.Second)
select {
default:
t.Errorf("Should have got rtpPacket!")
case rtpPacket := <-rtpSession.RtpChan:
fmt.Printf("RTP packet: %v\n", rtpPacket)
}
}
/*******************************************************
Testing stuff related to the Nal.go file
********************************************************/
var parseInput = []byte{
0x6C, // 3NalUnitBits = 101(5), Fragment type = 1100 (type = 12 )
0x94, // starbit = 1, endbit = 0, Reservedbit = 0, 5NalUnitBits = 10100 (20)
0x8E, // 10001110 random frame byte
0x26, // 00100110 random frame byte
0xD0, // 11010000 random frame byte
}
var expectedParsing = []interface{}{
byte(3),
byte(12),
bool(true),
bool(false),
bool(false),
byte(20),
[]byte{0x8E, 0x26, 0xD0},
}
const (
nalTestType = 12
)
func TestNalFragmentParsing(t *testing.T) {
nalUnit := ParseNALFragment(parseInput)
value := reflect.ValueOf(*nalUnit)
length := value.NumField()
fields := make([]interface{}, length)
for ii := 0; ii < length; ii++ {
fields[ii] = value.Field(ii).Interface()
}
for ii := range fields {
if !reflect.DeepEqual(fields[ii], expectedParsing[ii]) {
t.Errorf("Bad Parsing! Field: %v wanted: %v got: %v\n", ii, expectedParsing[ii],
2017-12-21 05:57:36 +03:00
fields[ii])
}
}
}
func TestNalFragmentToByteSlice(t *testing.T) {
nalUnit := ParseNALFragment(parseInput)
output := nalUnit.ToByteSlice()
for ii := range output {
if output[ii] != parseInput[ii] {
t.Errorf("Bad conversion to byte slice at %vth byte! wanted: %v got: %v",
parseInput[ii], output[ii])
}
}
}
func TestNalFragmentType(t *testing.T) {
nalUnit := ParseNALFragment(parseInput)
nalType := nalUnit.GetType()
if nalType != nalTestType {
t.Errorf("Returned wrong type!")
}
}
func TestNalSpsPpsParsing(t *testing.T) {
2017-12-21 05:57:36 +03:00
nalSpsPps := ParseNALSpsPps(parseInput)
for ii := range parseInput {
if nalSpsPps.Data[ii] != parseInput[ii] {
t.Errorf("Bad Parsing! Byte: %v wanted: %v got: %v\n", ii, parseInput[ii],
2017-12-21 05:57:36 +03:00
nalSpsPps.Data[ii])
}
}
}
func TestNalSpsPpsToByteSlice(t *testing.T) {
2017-12-21 05:57:36 +03:00
nalSpsPps := ParseNALSpsPps(parseInput)
nalSpsPpsByteSlice := nalSpsPps.ToByteSlice()
for ii := range parseInput {
if nalSpsPpsByteSlice[ii] != parseInput[ii] {
t.Errorf("Bad conversion to byte slice! Byte: %v wanted: %v got: %v\n", ii,
parseInput[ii], nalSpsPpsByteSlice[ii])
2017-12-21 05:57:36 +03:00
}
}
}
func TestNalSpsPpsType(t *testing.T) {
2017-12-21 05:57:36 +03:00
nalSpsPps := ParseNALSpsPps(parseInput)
if nalSpsPps.GetType() != nalTestType {
t.Errorf("Returned wrong type!")
}
}
/*******************************************************
Pes Packet testing!
********************************************************/
const (
dataLength = 3 // bytes
)
2017-12-21 05:57:36 +03:00
func TestPesToByteSlice(t *testing.T) {
pesPkt := PESPacket{
byte(0xE0), // StreamID
uint16(6), // Length
byte(0), // ScramblingControl
bool(true), // Priority
bool(false), // DAI
bool(false), // copyright
bool(true), // Original
byte(0), // PDI
bool(false), // Escr
bool(false), // ESRate
bool(false), // DSMTrickMode
bool(false), // ACI
bool(false), // CRC
bool(false), // Ext
byte(0), // header length
[]byte{},
[]byte{},
[]byte{ // data
0xEA,
0x4B,
0x12,
},
}
pesExpectedOutput := []byte{
0x00, // packet start code prefix byte 1
0x00, // packet start code prefix byte 2
0x01, // packet start code prefix byte 3
0xE0, // stream ID
0x00, // PES Packet length byte 1
0x06, // PES packet length byte 2
0x89, // Marker bits,ScramblingControl, Priority, DAI, Copyright, Original
0x00, // PDI, ESCR, ESRate, DSMTrickMode, ACI, CRC, Ext
0x00, // header length
0xEA, // data byte 1
0x4B, // data byte 2
0x12, // data byte 3
}
pesPktAsByteSlice := pesPkt.ToByteSlice()
for ii := range pesPktAsByteSlice {
if pesPktAsByteSlice[ii] != pesExpectedOutput[ii] {
t.Errorf("Conversion to byte slice bad! Byte: %v Wanted: %v Got: %v",
ii, pesExpectedOutput[ii], pesPktAsByteSlice[ii])
}
}
2017-12-21 05:57:36 +03:00
}
/*******************************************************
Mpegts testing
********************************************************/
func TestMpegTsToByteSlice(t *testing.T){
tsPkt := MpegTsPacket{
byte(0x47), // sync byte
bool(false), // TEI
bool(false), // PUSI
bool(false), // Priority
uint16(256), // PID
byte(0), // TSC
byte(3), // AFC
byte(6), // CC
[]byte{
byte(3), // AF length after this byte 1 + 2*stuffing byte
byte(0), // AF flags for optional fields
0xFF, // stuffing byte 1
0xFF, // stuffing byte 2
},
[]byte{ // data
0x67,
0xB2,
0xE3,
},
}
expectedOutput := []byte{
0x47,
0x01,
0x00,
0x36,
0x03,
0x00,
// this is where stuffing is, expect that to be 0xFF
0x67,
0xB2,
0xE3,
}
tsPktAsByteSlice := tsPkt.ToByteSlice()
for ii := 0; ii < 6; ii++ {
if tsPktAsByteSlice[ii] != expectedOutput[ii] {
t.Errorf("Conversion to byte slice bad! Byte: %v Wanted: %v Got: %v",
ii, expectedOutput[ii], tsPktAsByteSlice[ii])
}
}
// Check that the stuffing is all there
for ii := 6; ii < 179; ii++ {
if tsPktAsByteSlice[ii] != 0xFF {
t.Errorf("Conversion to byte slice bad! Byte: %v Wanted: %v Got: %v",
ii, expectedOutput[ii], tsPktAsByteSlice[ii])
}
}
for ii := 6; ii < 179; ii++ {
if tsPktAsByteSlice[ii] != 0xFF {
t.Errorf("Conversion to byte slice bad! Byte: %v Wanted: %v Got: %v",
ii, expectedOutput[ii], tsPktAsByteSlice[ii])
}
}
}