Last active
June 27, 2022 14:33
-
-
Save kala13x/0995fa8c8a020b3f7ed50d218b74fc5e to your computer and use it in GitHub Desktop.
Extract MPEGTS payload from PCAP file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* @file pcap2ts.c | |
* | |
* 2015-2022 Sun Dro ([email protected]) | |
* | |
* @brief Extract MPEGTS payload from PCAP file. | |
* Usage: pcap2ts <input> <output> <verbose> | |
* Example: pcap2ts dump.pcap payload.ts 1 | |
* | |
* Compile command: | |
* gcc -Wall -O2 pcap2ts.c -o pcap2ts -lxutils -lpthread -lpcap | |
* | |
* Dependencies: | |
* libpcap: https://github.com/the-tcpdump-group/libpcap | |
* libxutils: https://github.com/kala13x/libxutils | |
*/ | |
#include <xutils/xstd.h> | |
#include <xutils/crypt.h> | |
#include <xutils/xlog.h> | |
#include <xutils/xfs.h> | |
#include <xutils/rtp.h> | |
#include <xutils/ts.h> | |
#include <pcap.h> | |
#define TS_PACKET_SIZE 188 | |
#define RTP_HEADER_SIZE 12 | |
#define RTP_PACKET_SIZE TS_PACKET_SIZE + RTP_HEADER_SIZE | |
typedef struct { | |
xfile_t *pOutFile; | |
size_t nPackets; | |
} user_context_t; | |
static void hex_dump(const uint8_t *pData, size_t nSize) | |
{ | |
uint8_t *pHex = XCrypt_HEX(pData, &nSize, XSTR_SPACE, 20, XFALSE); | |
if (pHex != NULL) | |
{ | |
printf("\n%s\n\n", (char*)pHex); | |
free(pHex); | |
} | |
} | |
static size_t dump_rtp_data(uint8_t *pBuffer, size_t nLength, xfile_t *pOutFile) | |
{ | |
size_t nOffset = 0, nPackets = 0; | |
xrtp_header_t rtpHdr; | |
xts_packet_t tsPkt; | |
while (nLength >= TS_PACKET_SIZE) | |
{ | |
if (pBuffer[nOffset] == 0x47) | |
{ | |
if (XTSParser_Parse(&tsPkt, &pBuffer[nOffset], TS_PACKET_SIZE) <= 0) | |
{ | |
xloge("Failed to parse MPEG-TS packet"); | |
hex_dump(&pBuffer[nOffset], TS_PACKET_SIZE); | |
break; | |
} | |
xlogd("Parsed TS packet: CC(%u), PID(%u), PUSI(%u)", | |
tsPkt.header.continuty_counter, tsPkt.header.PID, | |
tsPkt.header.payload_unit_start_indicator); | |
if (XFile_Write(pOutFile, &pBuffer[nOffset], TS_PACKET_SIZE) <= 0) | |
{ | |
xloge("Failed to write data to output file: %s", strerror(errno)); | |
break; | |
} | |
nLength -= TS_PACKET_SIZE; | |
nOffset += TS_PACKET_SIZE; | |
nPackets++; | |
continue; | |
} | |
int nPayloadPosit = XRTP_ParseHeader(&rtpHdr, &pBuffer[nOffset], nLength); | |
if (nPayloadPosit <= 0) | |
{ | |
xloge("Failed to parse RTP header"); | |
break; | |
} | |
nOffset += nPayloadPosit; | |
nLength -= nPayloadPosit; | |
} | |
return nPackets; | |
} | |
void packet_callback(uint8_t *pContext, const struct pcap_pkthdr *pHeader, const uint8_t* pPacket) | |
{ | |
const struct ether_header *pEthHdr = (const struct ether_header *)pPacket; | |
if (ntohs(pEthHdr->ether_type) != ETHERTYPE_IP) return; | |
const struct ip *pIpHdr = (struct ip *)(pPacket + sizeof(struct ether_header)); | |
if (pIpHdr->ip_p != IPPROTO_UDP) return; | |
size_t nOffset = sizeof(struct ip) + sizeof(struct ether_header); | |
struct udphdr *pUdpHdr = (struct udphdr*)(pPacket + nOffset); | |
nOffset += sizeof(struct udphdr); | |
uint8_t *pData = (uint8_t*)(pPacket + nOffset); | |
user_context_t *pUserCtx = (user_context_t *)pContext; | |
pUserCtx->nPackets += dump_rtp_data(pData, ntohs(pUdpHdr->len), pUserCtx->pOutFile); | |
} | |
int main(int argc, char *argv[]) | |
{ | |
xlog_defaults(); | |
xlog_enable(XLOG_INFO); | |
if (argc < 3) | |
{ | |
xloge("Please specify input and output files."); | |
xlogi("Usage: %s <input> <output> <debug>", argv[0]); | |
xlogi("Example: %s dump.rtp output.ts 1", argv[0]); | |
return XSTDERR; | |
} | |
if (argc == 4 && atoi(argv[3])) | |
xlog_enable(XLOG_DEBUG); | |
char sStatus[XSTR_MIN]; | |
int nStatus = XSTDNON; | |
xfile_t outFile; | |
if (XFile_Open(&outFile, argv[2], "cw", NULL) < 0) | |
{ | |
xloge("Failed to open output file: %s (%s)", argv[2], strerror(errno)); | |
return XSTDERR; | |
} | |
pcap_t *pHandle = pcap_open_offline(argv[1], sStatus); | |
if (pHandle == NULL) | |
{ | |
xloge("Failed to open pcap file: %s (%s)", argv[1], sStatus); | |
XFile_Close(&outFile); | |
return XSTDERR; | |
} | |
user_context_t userCtx; | |
userCtx.pOutFile = &outFile; | |
userCtx.nPackets = XSTDNON; | |
if (pcap_loop(pHandle, 0, packet_callback, (uint8_t*)&userCtx) < 0) | |
{ | |
xloge("Failed process pcap data: %s", pcap_geterr(pHandle)); | |
nStatus = XSTDERR; | |
} | |
xlogi("Exctracted %zu TS packets.", userCtx.nPackets); | |
XFile_Close(&outFile); | |
pcap_close(pHandle); | |
return nStatus; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment