Skip to content

Instantly share code, notes, and snippets.

@kala13x
Last active June 27, 2022 14:33
Show Gist options
  • Save kala13x/0995fa8c8a020b3f7ed50d218b74fc5e to your computer and use it in GitHub Desktop.
Save kala13x/0995fa8c8a020b3f7ed50d218b74fc5e to your computer and use it in GitHub Desktop.
Extract MPEGTS payload from PCAP file
/*!
* @file pcap2ts.c
*
* 2015-2022 Sun Dro (f4tb0y@protonmail.com)
*
* @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