Skip to content

Commit 790470f

Browse files
author
Ross Newman
committed
New raw RTP streaming class and pure virtual base class.
1 parent 2c7d27c commit 790470f

File tree

3 files changed

+357
-0
lines changed

3 files changed

+357
-0
lines changed

camera/camera.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* camera base class
3+
*/
4+
5+
#ifndef __CAMERA_H__
6+
#define __CAMERA_H__
7+
#include <climits>
8+
class camera
9+
{
10+
public:
11+
camera(int height, int width) { mWidth = width; mHeight = height; };
12+
~camera() {};
13+
14+
virtual bool Open() = 0;
15+
16+
virtual void Close() = 0;
17+
18+
// Capture frame
19+
virtual bool Capture( void** cpu, void** cuda, unsigned long timeout=ULONG_MAX ) = 0;
20+
21+
inline uint32_t GetWidth() const { return mWidth; }
22+
inline uint32_t GetHeight() const { return mHeight; }
23+
inline uint32_t GetPixelDepth() const { return mDepth; }
24+
inline uint32_t GetSize() const { return mSize; }
25+
26+
protected:
27+
uint32_t mWidth;
28+
uint32_t mHeight;
29+
uint32_t mDepth;
30+
uint32_t mSize;
31+
};
32+
33+
#endif

camera/rtpStream.cpp

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
#include "rtpStream.h"
2+
3+
typedef struct float4 {
4+
float x;
5+
float y;
6+
float z;
7+
float w;
8+
} float4;
9+
10+
/*
11+
* error - wrapper for perror
12+
*/
13+
void error(char *msg) {
14+
perror(msg);
15+
exit(0);
16+
}
17+
18+
void rgbtoyuv(int y, int x, char* yuv, char* rgb)
19+
{
20+
int c,cc,R,G,B,Y,U,V;
21+
int size;
22+
23+
cc=0;
24+
size = x*3;
25+
for (c=0;c<size;c+=3)
26+
{
27+
R=rgb[c];
28+
G=rgb[c+1];
29+
B=rgb[c+2];
30+
/* sample luma for every pixel */
31+
Y = (0.257 * R) + (0.504 * G) + (0.098 * B) + 16;
32+
yuv[cc]=Y;
33+
if (c % 2 == 0)
34+
{
35+
V = (0.439 * R) - (0.368 * G) - (0.071 * B) + 128;
36+
yuv[cc+1]=V;
37+
}
38+
else
39+
{
40+
U = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128;
41+
yuv[cc+1]=U;
42+
}
43+
cc+=2;
44+
}
45+
}
46+
47+
/* Broadcast the stream to port 5004 */
48+
rtpStream::rtpStream(int height, int width, char* hostname, int portno) :
49+
camera(height, width)
50+
{
51+
strcpy(mHostname, hostname);
52+
mPortNo = portno;
53+
mFrame = 0;
54+
}
55+
56+
bool rtpStream::Open()
57+
{
58+
/* socket: create the socket */
59+
mSockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
60+
if (mSockfd < 0)
61+
{
62+
printf("ERROR opening socket");
63+
return error;
64+
}
65+
66+
/* gethostbyname: get the server's DNS entry */
67+
mServer = gethostbyname(mHostname);
68+
if (mServer == NULL) {
69+
fprintf(stderr,"ERROR, no such host as %s\n", mHostname);
70+
exit(0);
71+
}
72+
73+
/* build the server's Internet address */
74+
bzero((char *) &mServeraddr, sizeof(mServeraddr));
75+
mServeraddr.sin_family = AF_INET;
76+
bcopy((char *)mServer->h_addr,
77+
(char *)&mServeraddr.sin_addr.s_addr, mServer->h_length);
78+
mServeraddr.sin_port = htons(mPortNo);
79+
80+
/* send the message to the server */
81+
mServerlen = sizeof(mServeraddr);
82+
83+
return true;
84+
}
85+
86+
void rtpStream::Close()
87+
{
88+
close(mSockfd);
89+
}
90+
91+
#if ARM
92+
void rtpStream::endianswap32(uint32_t *data, int length)
93+
{
94+
int c = 0;
95+
for (c=0;c<length;c++)
96+
data[c] = __bswap_32 (data[c]);
97+
}
98+
99+
void rtpStream::endianswap16(uint16_t *data, int length)
100+
{
101+
int c = 0;
102+
for (c=0;c<length;c++)
103+
data[c] = __bswap_16 (data[c]);
104+
}
105+
#endif
106+
107+
void rtpStream::update_header(header *packet, int line, int last, int32_t timestamp, int32_t source)
108+
{
109+
bzero((char *)packet, sizeof(header));
110+
packet->rtp.protocol = RTP_VERSION << 30;
111+
packet->rtp.protocol = packet->rtp.protocol | RTP_PAYLOAD_TYPE << 16;
112+
packet->rtp.protocol = packet->rtp.protocol | sequence_number++;
113+
/* leaving other fields as zero TODO Fix*/
114+
packet->rtp.timestamp = timestamp += (Hz90 / RTP_FRAMERATE);
115+
packet->rtp.source = source;
116+
packet->payload.extended_sequence_number = 0; /* TODO : Fix extended seq numbers */
117+
packet->payload.line[0].length = MAX_BUFSIZE;
118+
packet->payload.line[0].line_number = line;
119+
packet->payload.line[0].offset = 0;
120+
if (last==1)
121+
{
122+
packet->rtp.protocol = packet->rtp.protocol | 1 << 23;
123+
}
124+
#if 0
125+
printf("0x%x, 0x%x, 0x%x \n", packet->rtp.protocol, packet->rtp.timestamp, packet->rtp.source);
126+
printf("0x%x, 0x%x, 0x%x \n", packet->payload.line[0].length, packet->payload.line[0].line_number, packet->payload.line[0].offset);
127+
#endif
128+
}
129+
130+
int rtpStream::Transmit(char* rgbframe)
131+
{
132+
rtp_packet packet;
133+
char *yuv;
134+
int c=0;
135+
int n=0;
136+
137+
138+
sequence_number=0;
139+
140+
#if 0
141+
#if 0
142+
float4 *RGBAf = (float4*)rgbframe;
143+
144+
// RGBAf to RGB
145+
for( int y=0; y < 100; y++ )
146+
{
147+
for( int x=0; x < mWidth; x++ )
148+
{
149+
rgbframe[(y*(mWidth*3))+(x*3)] = (char)RGBAf[(y*mWidth)+x].x;
150+
rgbframe[(y*(mWidth*3))+(x*3)+1] = (char)RGBAf[(y*mWidth)+x].y;
151+
rgbframe[(y*(mWidth*3))+(x*3)+2] = (char)RGBAf[(y*mWidth)+x].z;
152+
}
153+
}
154+
#else
155+
for( int y=0; y < mHeight; y++ )
156+
{
157+
for( int x=0; x < mWidth; x+=3 )
158+
{
159+
rgbframe[(y*(mWidth*3))+(x*3)] = (char)0xff;
160+
rgbframe[(y*(mWidth*3))+(x*3)+1] = (char)0;
161+
rgbframe[(y*(mWidth*3))+(x*3)+2] = (char)0;
162+
}
163+
}
164+
#endif
165+
#endif
166+
167+
168+
/* get a message from the user */
169+
bzero(packet.data, MAX_BUFSIZE);
170+
171+
/* send a frame */
172+
{
173+
struct timeval NTP_value;
174+
int32_t time = 10000;
175+
176+
for (c=0;c<(mHeight);c++)
177+
{
178+
int x,last = 0;
179+
if (c==mHeight-1) last=1;
180+
update_header((header*)&packet, c, last, time, RTP_SOURCE);
181+
x = c * (mWidth * 3);
182+
183+
#if 1
184+
rgbtoyuv(mHeight, mWidth, packet.data, (char*)&rgbframe[x]);
185+
#else
186+
memcpy((char*)packet.data, (char*)&rgbframe[x], mWidth* 3);
187+
#endif
188+
189+
#if ARM
190+
endianswap32((uint32_t *)&packet, sizeof(rtp_header)/4);
191+
endianswap16((uint16_t *)&packet.head.payload, sizeof(payload_header)/2);
192+
#endif
193+
n = sendto(mSockfd, (char *)&packet, sizeof(rtp_packet), 0, (const sockaddr*)&mServeraddr, mServerlen);
194+
if (n < 0)
195+
fprintf(stderr, "ERROR in sendto");
196+
}
197+
198+
printf("Sent frame %d\n", mFrame++);
199+
}
200+
201+
return 0;
202+
}
203+

camera/rtpStream.h

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/* Example RTP packet from wireshark
2+
Real-Time Transport Protocol
3+
10.. .... = Version: RFC 1889 Version (2)
4+
..0. .... = Padding: False
5+
...0 .... = Extension: False
6+
.... 0000 = Contributing source identifiers count: 0
7+
0... .... = Marker: False
8+
Payload type: DynamicRTP-Type-96 (96)
9+
Sequence number: 34513
10+
Timestamp: 2999318601
11+
Synchronization Source identifier: 0xdccae7a8 (3704285096)
12+
Payload: 000003c000a08000019e00a2000029292929f06e29292929...
13+
*/
14+
15+
/*
16+
17+
Gstreamer1.0 working example UYVY streaming
18+
===========================================
19+
gst-launch-1.0 videotestsrc num_buffers ! video/x-raw, format=UYVY, framerate=25/1, width=640, height=480 ! queue ! rtpvrawpay ! udpsink host=127.0.0.1 port=5004
20+
21+
gst-launch-1.0 udpsrc port=5004 caps="application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)RAW, sampling=(string)YCbCr-4:2:2, depth=(string)8, width=(string)480, height=(string)480, payload=(int)96" ! queue ! rtpvrawdepay ! queue ! xvimagesink sync=false
22+
23+
24+
Use his program to stream data to the udpsc example above on the tegra X1
25+
26+
*/
27+
28+
#ifndef __RTP_STREAM_H__
29+
#define __RTP_STREAM_H__
30+
31+
#include <byteswap.h>
32+
#include <stdio.h>
33+
#include <stdlib.h>
34+
#include <string.h>
35+
#include <unistd.h>
36+
#include <sys/types.h>
37+
#include <sys/socket.h>
38+
#include <netinet/in.h>
39+
#include <netdb.h>
40+
#include "camera.h"
41+
42+
43+
#define ARM 1 /* Perform endian swap */
44+
#define RTP_VERSION 0x2 /* RFC 1889 Version 2 */
45+
#define RTP_PADDING 0x0
46+
#define RTP_EXTENSION 0x0
47+
#define RTP_MARKER 0x0
48+
#define RTP_PAYLOAD_TYPE 0x60 /* 96 Dynamic Type */
49+
#define RTP_SOURCE 0x12345678 /* Sould be unique */
50+
#define RTP_FRAMERATE 25
51+
52+
#define Hz90 90000
53+
#define NUM_LINES_PER_PACKET 1 /* can have more that one line in a packet */
54+
#define MAX_BUFSIZE 1280 * 3 /* allow for RGB data upto 1280 pixels wide */
55+
56+
static unsigned long sequence_number;
57+
58+
/* 12 byte RTP Raw video header */
59+
typedef struct
60+
{
61+
int32_t protocol;
62+
int32_t timestamp;
63+
int32_t source;
64+
} rtp_header;
65+
66+
67+
typedef struct __attribute__((__packed__))
68+
{
69+
int16_t length;
70+
int16_t line_number;
71+
int16_t offset;
72+
} line_header;
73+
74+
typedef struct __attribute__((__packed__))
75+
{
76+
int16_t extended_sequence_number;
77+
line_header line[NUM_LINES_PER_PACKET];
78+
} payload_header;
79+
80+
81+
typedef struct __attribute__((__packed__))
82+
{
83+
rtp_header rtp;
84+
payload_header payload;
85+
} header;
86+
87+
typedef struct
88+
{
89+
header head;
90+
char data[MAX_BUFSIZE];
91+
} rtp_packet;
92+
93+
94+
/**
95+
* rtpstream RGB data
96+
*/
97+
class rtpStream : public camera
98+
{
99+
public:
100+
rtpStream(int height, int width, char* hosstname, int port);
101+
int Transmit(char* rgbframe);
102+
bool Open();
103+
void Close();
104+
bool Capture( void** cpu, void** cuda, unsigned long timeout=ULONG_MAX ) { return false; };
105+
private:
106+
int mSockfd;
107+
int mPortNo;
108+
struct sockaddr_in mServeraddr;
109+
struct hostent *mServer;
110+
int mServerlen;
111+
unsigned int mFrame;
112+
char mHostname[100];
113+
void update_header(header *packet, int line, int last, int32_t timestamp, int32_t source);
114+
#if ARM
115+
void endianswap32(uint32_t *data, int length);
116+
void endianswap16(uint16_t *data, int length);
117+
#endif
118+
};
119+
120+
121+
#endif

0 commit comments

Comments
 (0)