From f916c002f50b9e1d7c47d08000d0e1113c7f7f98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbjo=CC=88rn=20Einarsson?= Date: Thu, 3 Apr 2025 13:26:37 +0200 Subject: [PATCH 1/4] feat: add RTP 12 byte removal in pcap-unpack --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c41f569..6690a24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -- Nothing yet +### Added + +- New -rtp flag to remove (12-byte) RTP headers in pcap-unpack ## [0.2.0] - 2024-12-18 From da56fa02300d912a3adf08055e092feb93889724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbjo=CC=88rn=20Einarsson?= Date: Wed, 19 Nov 2025 10:40:20 +0100 Subject: [PATCH 2/4] feat: Improved output names --- CHANGELOG.md | 4 ++++ cmd/pcap-unpack/pcap.go | 13 +++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6690a24..ec7c803 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- Output file names are now capture_192_168_1_1_5000.ts instead of capture.pcap_192.168.1.1_5000.ts + ### Added - New -rtp flag to remove (12-byte) RTP headers in pcap-unpack diff --git a/cmd/pcap-unpack/pcap.go b/cmd/pcap-unpack/pcap.go index cf807fc..81b7957 100644 --- a/cmd/pcap-unpack/pcap.go +++ b/cmd/pcap-unpack/pcap.go @@ -5,6 +5,7 @@ import ( "io" "os" "path/filepath" + "strings" "github.com/google/gopacket" "github.com/google/gopacket/layers" @@ -47,15 +48,19 @@ func processPcapHandle(handle *pcap.Handle, fileName, dstDir string, rtpHdr bool continue } dstPort := int(udp.DstPort) - dst := fmt.Sprintf("%s_%d.ts", ip.DstIP, dstPort) + // Replace dots in IP address with underscores + ipStr := strings.ReplaceAll(ip.DstIP.String(), ".", "_") + dst := fmt.Sprintf("%s_%d.ts", ipStr, dstPort) if _, ok := udpDsts[dst]; !ok { var dstPath string + // Remove file extension from input filename (e.g., .pcap) + baseName := filepath.Base(fileName) + baseNameWithoutExt := strings.TrimSuffix(baseName, filepath.Ext(baseName)) switch { case dstDir == "": - dstPath = fmt.Sprintf("%s_%s", fileName, dst) + dstPath = fmt.Sprintf("%s_%s", baseNameWithoutExt, dst) default: - base := filepath.Base(fileName) - dstPath = filepath.Join(dstDir, fmt.Sprintf("%s_%s", base, dst)) + dstPath = filepath.Join(dstDir, fmt.Sprintf("%s_%s", baseNameWithoutExt, dst)) } fh, err := os.Create(dstPath) if err != nil { From 6a34b1db01f2a579602da283606cce50c64b1ea0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbjo=CC=88rn=20Einarsson?= Date: Wed, 19 Nov 2025 10:59:02 +0100 Subject: [PATCH 3/4] change: make RTP header removal automatic --- CHANGELOG.md | 5 +---- cmd/pcap-unpack/main.go | 9 +++++---- cmd/pcap-unpack/pcap.go | 20 +++++++++++++++----- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec7c803..5767ed1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,10 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Output file names are now capture_192_168_1_1_5000.ts instead of capture.pcap_192.168.1.1_5000.ts - -### Added - -- New -rtp flag to remove (12-byte) RTP headers in pcap-unpack +- RTP headers are automatically removed if 12-byte length and 13'th byte is sync byte ## [0.2.0] - 2024-12-18 diff --git a/cmd/pcap-unpack/main.go b/cmd/pcap-unpack/main.go index 922cd34..e10f1db 100644 --- a/cmd/pcap-unpack/main.go +++ b/cmd/pcap-unpack/main.go @@ -15,15 +15,17 @@ const ( var usg = `Usage of %s: -%s unpacks UDP streams from from a Wireshark/tcpdump capture. +%s unpacks UDP TS streams from from a Wireshark/tcpdump capture. The output is saved as files with names input_destAddress_port.ts (assuming that the streams are MPEG-2 TS streams). + +RTP headers are automatically removed if the UDP length modulo +188 is 12 and the 13th byte is sync byte 0x47. ` type options struct { dst string - rtpHdr bool version bool } @@ -36,7 +38,6 @@ func parseOptions(fs *flag.FlagSet, args []string) (*options, error) { opts := options{} fs.StringVar(&opts.dst, "dst", "", "Destination directory for output files") - fs.BoolVar(&opts.rtpHdr, "rtp", false, "Remove RTP headers UDP") fs.BoolVar(&opts.version, "version", false, "Get mp4ff version") err := fs.Parse(args[1:]) @@ -72,7 +73,7 @@ func run(args []string) error { } for _, pcapFile := range pcapFiles { - err := processPCAP(pcapFile, opts.dst, opts.rtpHdr) + err := processPCAP(pcapFile, opts.dst) if err != nil { return err } diff --git a/cmd/pcap-unpack/pcap.go b/cmd/pcap-unpack/pcap.go index 81b7957..9044a81 100644 --- a/cmd/pcap-unpack/pcap.go +++ b/cmd/pcap-unpack/pcap.go @@ -12,7 +12,7 @@ import ( "github.com/google/gopacket/pcap" ) -func processPCAP(pcapFile string, dst string, rtpHdr bool) error { +func processPCAP(pcapFile string, dst string) error { if pcapFile == "" { return fmt.Errorf("pcapFile is required") } @@ -22,10 +22,10 @@ func processPCAP(pcapFile string, dst string, rtpHdr bool) error { } defer handle.Close() - return processPcapHandle(handle, pcapFile, dst, rtpHdr) + return processPcapHandle(handle, pcapFile, dst) } -func processPcapHandle(handle *pcap.Handle, fileName, dstDir string, rtpHdr bool) error { +func processPcapHandle(handle *pcap.Handle, fileName, dstDir string) error { // Loop through packets from source packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) packetChannel := packetSource.Packets() @@ -72,8 +72,18 @@ func processPcapHandle(handle *pcap.Handle, fileName, dstDir string, rtpHdr bool } fh := udpDsts[dst] payload := udp.Payload - if rtpHdr { - payload = payload[12:] + hdrLen := len(payload) % 188 + + switch hdrLen { + case 0: + // Pure TS, do nothing + case 12: + // Assume RTP header of length 12 and remove it if sync byte found + if payload[12] == 0x47 { + payload = payload[12:] + } + default: + // Unknown header length, write anyway } _, err := fh.Write(payload) if err != nil { From 22aaaa8875e0625ff5961b783926992f28df0b53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbjo=CC=88rn=20Einarsson?= Date: Wed, 19 Nov 2025 10:42:23 +0100 Subject: [PATCH 4/4] docs: v0.3.0 --- CHANGELOG.md | 7 ++++++- internal/version.go | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5767ed1..0a147f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- Nothing yet + +## [0.3.0] - 2025-11-19 + ### Changed - Output file names are now capture_192_168_1_1_5000.ts instead of capture.pcap_192.168.1.1_5000.ts @@ -25,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - New tool pcap-replay that resends all UDP packets carrying UDP/TS or UDP/RTP/TS streams - initial version of the repo -[Unreleased]: https://github.com/Eyevinn/mp2ts-tools/releases/tag/v0.2.0...HEAD +[Unreleased]: https://github.com/Eyevinn/mp2ts-tools/releases/tag/v0.3.0...HEAD +[0.3.0]: https://github.com/Eyevinn/mp2ts-tools/releases/tag/v0.3.0...v0.3.0 [0.2.0]: https://github.com/Eyevinn/mp2ts-tools/releases/tag/v0.1.0...v0.2.0 [0.1.0]: https://github.com/Eyevinn/mp2ts-tools/releases/tag/v0.1.0 diff --git a/internal/version.go b/internal/version.go index 6835ba2..090e244 100644 --- a/internal/version.go +++ b/internal/version.go @@ -7,8 +7,8 @@ import ( ) var ( - commitVersion string = "v0.2" // May be updated using build flags - commitDate string = "1734534139" // commitDate in Epoch seconds (may be overridden using build flags) + commitVersion string = "v0.3" // May be updated using build flags + commitDate string = "1763545288" // commitDate in Epoch seconds (may be overridden using build flags) ) // GetVersion - get version and also commitHash and commitDate if inserted via Makefile