├── .gitignore ├── stream └── test.264 ├── Makefile ├── test ├── src │ └── main.cpp └── Makefile ├── README ├── rtpencoder ├── Makefile ├── inc │ └── rtpencoder.h └── src │ └── rtpencoder.cpp └── common └── inc └── rtpcommon.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.a 3 | *.so 4 | rtptest 5 | -------------------------------------------------------------------------------- /stream/test.264: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinydigger/RTPH264Streaming/HEAD/stream/test.264 -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SUBDIRS = ./rtpencoder ../test 2 | 3 | .PHONY:all 4 | all: 5 | mkdir -p ./target 6 | mkdir -p ./rtpencoder/src/obj 7 | mkdir -p ./test/src/obj 8 | 9 | @list='$(SUBDIRS)';for subdir in $$list; do \ 10 | cd $$subdir && make; \ 11 | done 12 | 13 | .PHONY:clean 14 | clean: 15 | 16 | @list='$(SUBDIRS)';for subdir in $$list; do \ 17 | cd $$subdir && make clean; \ 18 | done 19 | rm -rf ./target 20 | -------------------------------------------------------------------------------- /test/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define DEST_PORT_DEFAULT 5004 13 | 14 | int main(int argc, char *argv[]) 15 | { 16 | char *testfile = argv[1]; 17 | char *destaddr = argv[2]; 18 | int port = atoi(argv[3]); 19 | 20 | rtpencoder rtp_encoder(testfile, destaddr, port, RTP_PAYLOAD_H264); 21 | rtp_encoder.start(); 22 | 23 | while(rtp_encoder.rtp_get_state() == RTP_STATE_EXECUTING) { 24 | sleep(1); 25 | } 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | DESCRIPTION: 2 | This is a project for RTP streaming with H264 payload. It provides rtp encoder and decoder libraries, which can be used as a rtp sender and receiver. 3 | Test app is also available for understanding how to use rtp libraries. 4 | COMPILE: 5 | Run 'make' in root dir. RTP lib and test app will be generated in target folder. 6 | 7 | USAGE EXAMPLE: 8 | 1. Use gstreamer as receiver: gst-launch-1.0 udpsrc port=5004 caps="application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, payload=(int)96" ! rtph264depay ! avdec_h264 ! autovideosink 9 | 10 | 2. Run 'rtpencoder test.264 127.0.0.1 5004' as sender. It will parse a local h264 file encode it to RTP package and send to localhost's port 5004. 11 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | CC := g++ 2 | CFLAGS := -fPIC 3 | 4 | INC_DIR_COMMON := ../common/inc 5 | INC_DIR_ENCODER := ../rtpencoder/inc 6 | SRC_DIR := ./src 7 | OBJ_DIR := $(SRC_DIR)/obj 8 | 9 | TARGET_DIR := ../target 10 | TARGET := rtpencoder 11 | INSTALL_LIB_PATH := $(TARGET_DIR) 12 | ENCODER_LIB := librtpencoder.a 13 | EXT_LIB := -lpthread 14 | 15 | CFLAGS += -I$(INC_DIR_COMMON) -I$(INC_DIR_ENCODER) 16 | 17 | SOURCE = $(wildcard $(SRC_DIR)/*.cpp) 18 | SOURCER = $(notdir $(SOURCE)) 19 | OBJS = $(patsubst %.cpp,%.o,$(SOURCER)) 20 | OBJS := $(foreach X,$(OBJS),$(OBJ_DIR)/$(X)) 21 | 22 | $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp 23 | $(CC) $(CFLAGS) -c -o $@ $< 24 | 25 | $(TARGET):$(OBJS) 26 | $(CC) -o $(TARGET_DIR)/$(TARGET) $(OBJS) \ 27 | $(INSTALL_LIB_PATH)/$(ENCODER_LIB) $(EXT_LIB) 28 | 29 | .PHONY:clean 30 | clean: 31 | rm -rf $(OBJ_DIR) 32 | -------------------------------------------------------------------------------- /rtpencoder/Makefile: -------------------------------------------------------------------------------- 1 | CC := g++ 2 | CFLAGS := -fPIC 3 | LDFLAGS = -lpthread 4 | 5 | INC_DIR_COMMON := ../common/inc 6 | INC_DIR_ENCODER := ./inc 7 | SRC_DIR := ./src 8 | OBJ_DIR := $(SRC_DIR)/obj 9 | 10 | INSTALL_LIB_PATH := ../target 11 | LIB_TARGET_STATIC := librtpencoder.a 12 | LIB_TARGET_SHARE := librtpencoder.so 13 | 14 | CFLAGS += -I$(INC_DIR_COMMON) -I$(INC_DIR_ENCODER) 15 | 16 | SOURCE = $(wildcard $(SRC_DIR)/*.cpp) 17 | SOURCER = $(notdir $(SOURCE)) 18 | OBJS = $(patsubst %.cpp,%.o,$(SOURCER)) 19 | 20 | OBJS := $(foreach X,$(OBJS),$(OBJ_DIR)/$(X)) 21 | $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp 22 | $(CC) $(CFLAGS) $(LDFLAGS) -c -o $@ $< 23 | 24 | all: $(LIB_TARGET_STATIC) $(LIB_TARGET_SHARE) 25 | 26 | $(LIB_TARGET_STATIC):$(OBJS) 27 | ar cr $@ $(OBJS) 28 | install -m 0755 $(LIB_TARGET_STATIC) $(INSTALL_LIB_PATH) 29 | rm -rf $(LIB_TARGET_STATIC) 30 | 31 | $(LIB_TARGET_SHARE):$(OBJS) 32 | g++ -shared -o $@ $(OBJS) 33 | install -m 0755 $(LIB_TARGET_SHARE) $(INSTALL_LIB_PATH) 34 | rm -rf $(LIB_TARGET_SHARE) 35 | 36 | .PHONY:clean 37 | clean: 38 | rm -rf $(OBJ_DIR) 39 | rm -rf $(INSTALL_LIB_PATH)/$(LIB_TARGET_STATIC) 40 | rm -rf $(INSTALL_LIB_PATH)/$(LIB_TARGET_SHARE) 41 | -------------------------------------------------------------------------------- /rtpencoder/inc/rtpencoder.h: -------------------------------------------------------------------------------- 1 | #ifndef RTPENCODER_H 2 | #define RTPENCODER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | class rtpencoder 15 | { 16 | public: 17 | rtpencoder(char *filename, char *addr, uint32_t dest_port, RTP_PAYLOAD_TYPE payload_type); 18 | 19 | ~rtpencoder(); 20 | 21 | RTP_RETCODE init(char *filename, char *addr, uint32_t dest_port, RTP_PAYLOAD_TYPE payload_type); 22 | 23 | RTP_RETCODE start(); 24 | 25 | RTP_RETCODE stop(); 26 | 27 | 28 | RTP_STATE rtp_get_state() { return m_rtp_state; }; 29 | 30 | void rtp_set_state(RTP_STATE state) { m_rtp_state = state; }; 31 | 32 | uint32_t make_rtp_pkt(const uint8_t* data, uint32_t len, 33 | RTPH264_MODE mode, uint8_t cu_pack_num, uint8_t fu_pack_num); 34 | 35 | uint32_t encode_stream_pkt(uint8_t *buf, uint32_t len); 36 | 37 | uint32_t read_packet(uint8_t *buf, bool *eof); 38 | 39 | uint32_t send_packet(uint8_t *rtp_pkt, uint32_t len); 40 | 41 | private: 42 | FILE *m_file; 43 | int m_socket; 44 | uint8_t *m_rtp_pkt; 45 | unsigned long m_base_time; 46 | unsigned long m_cur_time; 47 | 48 | pthread_t m_rtpencoder_tid; 49 | RTP_STATE m_rtp_state; 50 | RTP_SETUP_INFO *m_setup_info; 51 | RTP_PKT_INFO *m_pkt_info; 52 | 53 | sockaddr_in m_faraddr; 54 | }; 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /common/inc/rtpcommon.h: -------------------------------------------------------------------------------- 1 | #ifndef _RTPCOMMON_H 2 | #define _RTPCOMMON_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define MTU_SIZE 1500 10 | #define RTP_H264_MAX_PKT_SIZE MTU_SIZE 11 | #define RTP_HDR_SIZE 12 12 | #define RTP_H264_MAX_NAL_DATA_SIZE (RTP_H264_MAX_PKT_SIZE - RTP_HDR_SIZE) 13 | 14 | 15 | //only support H264 payload now 16 | typedef enum RTP_PAYLOAD_TYPE 17 | { 18 | RTP_PAYLOAD_MPEG2_TS = 33, 19 | RTP_PAYLOAD_H264 = 96 20 | } RTP_PAYLOAD_TYPE; 21 | 22 | //parameters to setup rtp streaming 23 | typedef struct RTP_SETUP_INFO 24 | { 25 | uint32_t addr; 26 | uint32_t localport; 27 | uint32_t destport; 28 | RTP_PAYLOAD_TYPE payloadtype; 29 | } RTP_SETUP_INFO; 30 | 31 | typedef struct RTP_PKT_INFO 32 | { 33 | uint32_t payloadtype; 34 | uint32_t ssrc; 35 | uint16_t sequenceno; 36 | } RTP_PKT_INFO; 37 | 38 | typedef enum RTP_RETCODE 39 | { 40 | RTP_SUCCESS = 0, 41 | RTP_ERROR, 42 | RTP_BUSY 43 | } RTP_RETCODE; 44 | 45 | typedef enum RTP_STATE 46 | { 47 | RTP_STATE_INIT, 48 | RTP_STATE_READY, 49 | RTP_STATE_PAUSE, 50 | RTP_STATE_EXECUTING 51 | } RTP_STATE; 52 | 53 | typedef enum RTPH264_MODE 54 | { 55 | SINGLE_NAL_MODE, 56 | FU_A_MODE 57 | } RTPH264_MODE; 58 | 59 | typedef enum RTPH264_HEADER_TYPE 60 | { 61 | STAP_A = 24, 62 | STAP_B = 25, 63 | MTAP16 = 26, 64 | MTAP24 = 27, 65 | FU_A = 28, 66 | FU_B = 29 67 | } RTPH264_HEADER_TYPE; 68 | 69 | typedef struct nalu_header 70 | { 71 | uint8_t type: 5; 72 | uint8_t nri: 2; 73 | uint8_t f: 1; 74 | } __attribute__ ((packed)) nalu_header_t; 75 | 76 | typedef struct nalu 77 | { 78 | int startcodeprefix_len; 79 | unsigned len; 80 | unsigned max_size; 81 | int forbidden_bit; 82 | int nal_reference_idc; 83 | int nal_unit_type; 84 | char *buf; 85 | unsigned short lost_packets; 86 | } nalu_t; 87 | 88 | typedef struct fu_indicator 89 | { 90 | uint8_t type: 5; 91 | uint8_t nri: 2; 92 | uint8_t f: 1; 93 | } __attribute__ ((packed)) fu_indicator_t; 94 | 95 | typedef struct fu_header 96 | { 97 | uint8_t type: 5; 98 | uint8_t r: 1; 99 | uint8_t e: 1; 100 | uint8_t s: 1; 101 | } __attribute__ ((packed)) fu_header_t; 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /rtpencoder/src/rtpencoder.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define RTP_INPUT_BUF_SIZE (1920 * 1080) 15 | #define RTP_READ_FILE_BYTES (1024 * 1024) 16 | 17 | rtpencoder::rtpencoder(char *filename, char *addr, uint32_t port, RTP_PAYLOAD_TYPE payload_type) 18 | : m_socket(0), 19 | m_file(NULL), 20 | m_rtp_pkt(NULL), 21 | m_base_time(0), 22 | m_cur_time(0), 23 | m_rtp_state(RTP_STATE_INIT), 24 | m_setup_info(new RTP_SETUP_INFO), 25 | m_pkt_info(new RTP_PKT_INFO) 26 | { 27 | init(filename, addr, port, payload_type); 28 | m_rtp_pkt = new uint8_t[RTP_H264_MAX_PKT_SIZE]; 29 | } 30 | 31 | rtpencoder::~rtpencoder() 32 | { 33 | if (m_setup_info) { 34 | delete m_setup_info; 35 | m_setup_info = NULL; 36 | } 37 | 38 | if (m_pkt_info) { 39 | delete m_pkt_info; 40 | m_pkt_info = NULL; 41 | } 42 | 43 | if (m_file) { 44 | fclose(m_file); 45 | m_file = NULL; 46 | } 47 | 48 | if (m_rtp_pkt) { 49 | delete [] m_rtp_pkt; 50 | m_rtp_pkt = NULL; 51 | } 52 | } 53 | 54 | RTP_RETCODE rtpencoder::init(char *filename, char *addr, uint32_t port, RTP_PAYLOAD_TYPE payload_type) 55 | { 56 | RTP_RETCODE ret = RTP_SUCCESS; 57 | uint8_t optval = 255; 58 | uint32_t buffer_size = 1024 * 1024; 59 | struct timeval tval; 60 | tval.tv_sec = 2; 61 | tval.tv_usec = 0; 62 | 63 | if (NULL != filename && NULL != addr && port > 0) { 64 | m_file = fopen(filename, "r"); 65 | if (m_file == NULL) { 66 | printf ("input file open failed\n"); 67 | return RTP_ERROR; 68 | } 69 | 70 | m_setup_info->addr = inet_addr(addr); 71 | m_setup_info->destport = port; 72 | m_setup_info->payloadtype = payload_type; 73 | 74 | memset(&m_faraddr, 0, sizeof(sockaddr_in)); 75 | m_faraddr.sin_addr.s_addr = m_setup_info->addr; 76 | m_faraddr.sin_family = AF_INET; 77 | m_faraddr.sin_port = htons((uint16_t)m_setup_info->destport); 78 | 79 | //socket configuration 80 | m_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 81 | setsockopt(m_socket, IPPROTO_IP,IP_TTL, (const char*)&optval, 1); 82 | setsockopt(m_socket, SOL_SOCKET,SO_SNDBUF, (const char*)&buffer_size, 4); 83 | setsockopt(m_socket, SOL_SOCKET, SO_SNDTIMEO, (struct timeval *)&tval, (socklen_t)sizeof(struct timeval)); 84 | 85 | //synchronization source (SSRC) identifier 86 | m_pkt_info->ssrc = 0; 87 | m_pkt_info->sequenceno = 0; 88 | m_pkt_info->payloadtype = uint32_t(payload_type); 89 | 90 | rtp_set_state(RTP_STATE_READY); 91 | printf ("rtp init success\n"); 92 | } 93 | else { 94 | ret = RTP_ERROR; 95 | printf ("rtp init failed\n"); 96 | } 97 | 98 | return ret; 99 | } 100 | 101 | bool find_nal_startcode(uint8_t *buf, uint32_t len) 102 | { 103 | bool bFound = false; 104 | 105 | // The start code could be 3 or 4 bytes 106 | if(len == 3) { 107 | if(*buf == 0x0 && *(buf + 1) == 0x0 && *(buf + 2) == 0x1) 108 | bFound = true; 109 | } 110 | else if(len == 4) { 111 | if(*buf == 0x0 && *(buf + 1) == 0x0 && *(buf + 2) == 0x0 && *(buf + 3) == 0x1) 112 | bFound = true; 113 | } 114 | else { 115 | printf("Invalid start code len\n"); 116 | } 117 | 118 | return bFound; 119 | } 120 | 121 | //get current time (millsecond) 122 | unsigned long get_cur_time() 123 | { 124 | unsigned long msec; 125 | struct timeval tv; 126 | 127 | gettimeofday(&tv, NULL); 128 | msec = ((unsigned long)tv.tv_sec * 1000) + ((unsigned long)tv.tv_usec / 1000); 129 | 130 | return msec; 131 | } 132 | 133 | /* function to read a complete 134 | * 135 | * return valve: 136 | * -1 - invalid bufffer or start code 137 | * 0 - need more data to complete a nal 138 | * >0 - nal length 139 | */ 140 | uint32_t parse_nal(uint8_t * buf, uint32_t len, uint32_t *startcode_len) 141 | { 142 | uint32_t ret_len = 0; 143 | 144 | if (NULL == buf || len <= 3) { 145 | printf ("invalid input buffer, size: %d\n", len); 146 | return -1; 147 | } 148 | 149 | if (true == find_nal_startcode(buf, 3)) { 150 | *startcode_len = 3; 151 | } 152 | else if (true == find_nal_startcode(buf, 4)) { 153 | *startcode_len = 4; 154 | } 155 | else { 156 | printf ("error: cannot find start code\n"); 157 | return -1; 158 | } 159 | 160 | 161 | // If we find the next start code, then we are done 162 | for (uint32_t i = 0; i < len - *startcode_len; i ++) { 163 | if (true == find_nal_startcode(buf + *startcode_len + i, *startcode_len)) { 164 | ret_len = i + *startcode_len; 165 | break; 166 | } 167 | } 168 | 169 | return ret_len; 170 | } 171 | 172 | void* worker_func(void *arg) 173 | { 174 | rtpencoder *rtpenc = (rtpencoder *)arg; 175 | uint8_t *inbuf = new uint8_t[RTP_INPUT_BUF_SIZE]; 176 | uint32_t read_len = 0; 177 | uint32_t send_len = 0; 178 | bool eof = false; 179 | 180 | while (RTP_STATE_EXECUTING == rtpenc->rtp_get_state()) { 181 | //read, packetise and send 182 | read_len = rtpenc->read_packet(inbuf, &eof); 183 | 184 | if (read_len > 0 && false == eof) { 185 | // framerate control 186 | usleep(1000 * 30); 187 | send_len = rtpenc->encode_stream_pkt(inbuf, read_len); 188 | printf("rtp send %d bytes\n", send_len); 189 | } 190 | else { 191 | break; 192 | } 193 | } 194 | 195 | finished: 196 | printf("rtp encoder work func finished\n"); 197 | rtpenc->rtp_set_state(RTP_STATE_READY); 198 | delete [] inbuf; 199 | } 200 | 201 | uint32_t rtpencoder::make_rtp_pkt(const uint8_t* data, uint32_t len, 202 | RTPH264_MODE mode, uint8_t cu_pack_num, uint8_t fu_pack_num) 203 | { 204 | uint8_t marker_bit = 0; 205 | uint32_t last_pkt_size = 0; 206 | nalu_header_t *nalu_hdr; 207 | fu_header_t *fu_hdr; 208 | fu_indicator_t *fu_ind; 209 | 210 | if(!data || !len) { 211 | printf("Encode Invalid params or no Data to encode"); 212 | return -1; 213 | } 214 | 215 | // RTP timestamp with 90000 scale 216 | m_cur_time = (get_cur_time() - m_base_time) * 90; 217 | 218 | int index = 0; 219 | 220 | // version = 2 221 | m_rtp_pkt[index++] = (uint8_t)(2 << 6); 222 | 223 | marker_bit = (FU_A_MODE == mode && cu_pack_num == fu_pack_num - 1) ? 1 : 0; 224 | 225 | // marker bit 226 | m_rtp_pkt[index] = (uint8_t)(marker_bit << 7); 227 | 228 | m_rtp_pkt[index++] |= (uint8_t)m_pkt_info->payloadtype; 229 | 230 | m_rtp_pkt[index++] = (uint8_t)(m_pkt_info->sequenceno >> 8); 231 | 232 | m_rtp_pkt[index++] = (uint8_t)(m_pkt_info->sequenceno); 233 | 234 | m_pkt_info->sequenceno += 1; 235 | 236 | //Timestamp 237 | m_rtp_pkt[index++] = (uint8_t)(m_cur_time >> 24); 238 | m_rtp_pkt[index++] = (uint8_t)(m_cur_time >> 16); 239 | m_rtp_pkt[index++] = (uint8_t)(m_cur_time >> 8 ); 240 | m_rtp_pkt[index++] = (uint8_t)(m_cur_time >> 0 ); 241 | 242 | //TX SSRC 243 | m_rtp_pkt[index++] = (uint8_t)(m_pkt_info->ssrc >> 24); 244 | m_rtp_pkt[index++] = (uint8_t)(m_pkt_info->ssrc >> 16); 245 | m_rtp_pkt[index++] = (uint8_t)(m_pkt_info->ssrc >> 8); 246 | m_rtp_pkt[index++] = (uint8_t)(m_pkt_info->ssrc >> 0); 247 | 248 | //NALU header. 249 | switch (mode) 250 | { 251 | case SINGLE_NAL_MODE: 252 | nalu_hdr = (nalu_header_t *) &m_rtp_pkt[index]; 253 | nalu_hdr->f = (data[0] & 0x80) >> 7; /* bit0 */ 254 | nalu_hdr->nri = (data[0] & 0x60) >> 5; /* bit1~2 */ 255 | nalu_hdr->type = (data[0] & 0x1f); 256 | index ++; 257 | memcpy(m_rtp_pkt + index, data + 1, len - 1); /* skip the first byte */ 258 | return len + index - 1; 259 | case FU_A_MODE: 260 | fu_ind = (fu_indicator_t *) &m_rtp_pkt[index]; 261 | fu_ind->f = (data[0] & 0x80) >> 7; 262 | fu_ind->nri = (data[0] & 0x60) >> 5; 263 | fu_ind->type = 28; 264 | index ++; 265 | // first FU-A package 266 | if (cu_pack_num == 0) 267 | { 268 | fu_hdr = (fu_header_t *) &m_rtp_pkt[index]; 269 | fu_hdr->s = 1; 270 | fu_hdr->e = 0; 271 | fu_hdr->r = 0; 272 | fu_hdr->type = data[0] & 0x1f; 273 | index ++; 274 | memcpy(m_rtp_pkt + index, data + 1, RTP_H264_MAX_NAL_DATA_SIZE - 1); 275 | return index + RTP_H264_MAX_NAL_DATA_SIZE - 1; 276 | } 277 | // between FU-A package 278 | else if (cu_pack_num < fu_pack_num - 1) 279 | { 280 | fu_hdr = (fu_header_t *) &m_rtp_pkt[index]; 281 | fu_hdr->s = 0; 282 | fu_hdr->e = 0; 283 | fu_hdr->r = 0; 284 | fu_hdr->type = data[0] & 0x1f; 285 | index ++; 286 | memcpy(m_rtp_pkt + index, data + cu_pack_num * RTP_H264_MAX_NAL_DATA_SIZE, 287 | RTP_H264_MAX_NAL_DATA_SIZE); 288 | return index + RTP_H264_MAX_NAL_DATA_SIZE; 289 | } 290 | // last FU-A package 291 | else 292 | { 293 | fu_hdr = (fu_header_t *) &m_rtp_pkt[index]; 294 | fu_hdr->s = 0; 295 | fu_hdr->e = 1; 296 | fu_hdr->r = 0; 297 | fu_hdr->type = data[0] & 0x1f; 298 | index ++; 299 | last_pkt_size = len % RTP_H264_MAX_NAL_DATA_SIZE ? 300 | len % RTP_H264_MAX_NAL_DATA_SIZE : RTP_H264_MAX_NAL_DATA_SIZE; 301 | memcpy(m_rtp_pkt + index, data + cu_pack_num * RTP_H264_MAX_NAL_DATA_SIZE, 302 | last_pkt_size); 303 | return index + last_pkt_size; 304 | } 305 | } 306 | } 307 | 308 | uint32_t rtpencoder::encode_stream_pkt(uint8_t *buf, uint32_t len) 309 | { 310 | uint8_t fu_pack_num; // FU-A total package number 311 | uint8_t cu_pack_num; // FU-A current package number for processing 312 | uint32_t pkt_offset = RTP_HDR_SIZE; // RTP pkt header offset 313 | uint32_t pkt_size = 0; 314 | uint32_t bytes_sent = 0; // total sent bytes 315 | uint32_t bytes_sent_cu = 0; // current package sent bytes 316 | 317 | RTPH264_MODE mode = (len < RTP_H264_MAX_NAL_DATA_SIZE) ? SINGLE_NAL_MODE : FU_A_MODE; 318 | 319 | if (SINGLE_NAL_MODE == mode) { 320 | pkt_size = make_rtp_pkt(buf, len, mode, 0, 0); 321 | bytes_sent = send_packet(m_rtp_pkt, pkt_size); 322 | } 323 | else if (FU_A_MODE == mode) { 324 | fu_pack_num = len % RTP_H264_MAX_NAL_DATA_SIZE ? 325 | (len / RTP_H264_MAX_NAL_DATA_SIZE + 1) : len / RTP_H264_MAX_NAL_DATA_SIZE; 326 | 327 | cu_pack_num = 0; 328 | while (cu_pack_num < fu_pack_num) { 329 | pkt_size = make_rtp_pkt(buf, len, mode, cu_pack_num, fu_pack_num); 330 | bytes_sent_cu = send_packet(m_rtp_pkt, pkt_size); 331 | bytes_sent += bytes_sent_cu; 332 | cu_pack_num ++; 333 | } 334 | } 335 | 336 | return bytes_sent; 337 | } 338 | 339 | uint32_t rtpencoder::send_packet(uint8_t *rtp_pkt, uint32_t len) 340 | { 341 | uint32_t bytes_sned = 0; 342 | 343 | if (NULL != rtp_pkt && len > 0) { 344 | bytes_sned = sendto(m_socket, rtp_pkt, len, 0, 345 | (struct sockaddr*)&m_faraddr, (socklen_t)sizeof(m_faraddr)); 346 | if (bytes_sned == 0 || bytes_sned == -1) { 347 | printf("rtpencoder failed to send packet, error:%d\n", errno); 348 | return -1; 349 | } 350 | } 351 | else { 352 | printf("Invalid rtp packet\n"); 353 | return -1; 354 | } 355 | 356 | return bytes_sned; 357 | } 358 | 359 | //read payload data from file. for h264/avc, it's a nal without start code. 360 | uint32_t rtpencoder::read_packet(uint8_t *buf, bool *eof) 361 | { 362 | uint32_t read_len = 0, parse_len = 0, startcode_len = 0; 363 | static uint32_t offset = 0; 364 | static uint8_t *buf_read = NULL; 365 | *eof = false; 366 | RTP_PAYLOAD_TYPE payload_type = m_setup_info->payloadtype; 367 | 368 | if (NULL == buf_read) 369 | buf_read = new uint8_t[RTP_READ_FILE_BYTES * 10]; //Max buffer size is 10M bytes 370 | 371 | if (payload_type == RTP_PAYLOAD_H264) { 372 | if (offset > 0) { 373 | // We still have remaining data in buf_read, parse it 374 | parse_len = parse_nal(buf_read, offset, &startcode_len); 375 | if (parse_len > startcode_len) { 376 | memcpy(buf, buf_read + startcode_len, parse_len - startcode_len); 377 | offset = offset - parse_len; 378 | memcpy(buf_read, buf_read + parse_len, offset); 379 | return parse_len; 380 | } 381 | } 382 | 383 | while (parse_len <= 0) { 384 | read_len = fread(buf_read + offset, 1, RTP_READ_FILE_BYTES, m_file); 385 | if (read_len <= 0) { 386 | if (offset > 0) { 387 | //last nal cannot be parsed, just return remaining bytes 388 | memcpy(buf, buf_read, offset); 389 | parse_len = offset; 390 | offset = 0; 391 | return parse_len; 392 | } 393 | else { 394 | //reach EOF or error happened, finish reading 395 | goto finished; 396 | } 397 | } 398 | else { 399 | parse_len = parse_nal(buf_read, offset + read_len, &startcode_len); 400 | if (parse_len > startcode_len) { 401 | memcpy(buf, buf_read + startcode_len, parse_len - startcode_len); 402 | offset = offset + read_len - parse_len; 403 | memcpy(buf_read, buf_read + parse_len, offset); 404 | } 405 | else if (parse_len == 0) { 406 | offset += read_len; 407 | } 408 | else { 409 | //Invalid buffer or buffer length 410 | return -1; 411 | } 412 | } 413 | } 414 | } 415 | else { 416 | printf ("unsupport payload type: %d\n", payload_type); 417 | return -1; 418 | } 419 | 420 | return parse_len - startcode_len; 421 | 422 | finished: 423 | *eof = true; 424 | delete []buf_read; 425 | return 0; 426 | } 427 | 428 | RTP_RETCODE rtpencoder::start() 429 | { 430 | if (rtp_get_state() != RTP_STATE_READY) { 431 | printf("Invalid state\n"); 432 | return RTP_ERROR; 433 | } 434 | 435 | rtp_set_state(RTP_STATE_EXECUTING); 436 | 437 | pthread_create(&m_rtpencoder_tid, NULL, &worker_func, this); 438 | pthread_detach(m_rtpencoder_tid); 439 | 440 | //mark start time 441 | m_base_time = get_cur_time(); 442 | 443 | return RTP_SUCCESS; 444 | } 445 | 446 | RTP_RETCODE rtpencoder::stop() 447 | { 448 | rtp_set_state(RTP_STATE_READY); 449 | 450 | return RTP_SUCCESS; 451 | } 452 | --------------------------------------------------------------------------------