|
- #include <stdint.h>
- #include "sockutil.h"
- #include "sys/pollfd.h"
- #include "sys/thread.h"
- #include "rtp-demuxer.h"
- #include "rtp-profile.h"
- #include "rtp-payload.h"
- #include "rtcp-header.h"
- #include "rtp.h"
- #include "time64.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
-
- #if defined(OS_WINDOWS)
- #define strcasecmp _stricmp
- #endif
-
- struct rtp_context_t
- {
- FILE *fp;
- FILE *frtp;
-
- char encoding[64];
- socket_t socket[2];
- struct sockaddr_storage ss[2];
-
- char rtp_buffer[64 * 1024];
- char rtcp_buffer[32 * 1024];
-
- struct rtp_demuxer_t* demuxer;
- };
-
- static int rtp_read(struct rtp_context_t* ctx, socket_t s)
- {
- int r;
- uint8_t size[2];
- static int i, n = 0;
- socklen_t len;
- struct sockaddr_storage ss;
- len = sizeof(ss);
-
- r = recvfrom(s, ctx->rtp_buffer, sizeof(ctx->rtp_buffer), 0, (struct sockaddr*)&ss, &len);
- if (r < 12)
- return -1;
- assert(0 == socket_addr_compare((const struct sockaddr*) & ss, (const struct sockaddr*) & ctx->ss[0]));
-
- n += r;
- if(0 == i++ % 100)
- printf("packet: %d, seq: %u, size: %d/%d\n", i, ((uint8_t)ctx->rtp_buffer[2] << 8) | (uint8_t)ctx->rtp_buffer[3], r, n);
-
- size[0] = r >> 8;
- size[1] = r >> 0;
- fwrite(size, 1, sizeof(size), ctx->frtp);
- fwrite(ctx->rtp_buffer, 1, r, ctx->frtp);
-
- r = rtp_demuxer_input(ctx->demuxer, ctx->rtp_buffer, r);
- return r;
- }
-
- static int rtcp_read(struct rtp_context_t* ctx, socket_t s)
- {
- int r;
- socklen_t len;
- struct sockaddr_storage ss;
- len = sizeof(ss);
- r = recvfrom(s, ctx->rtcp_buffer, sizeof(ctx->rtcp_buffer), 0, (struct sockaddr*)&ss, &len);
- if (r < 12)
- return -1;
- assert(0 == socket_addr_compare((const struct sockaddr*)&ss, (const struct sockaddr*)&ctx->ss[1]));
-
- r = rtp_demuxer_input(ctx->demuxer, ctx->rtcp_buffer, r);
- if (RTCP_BYE == r)
- {
- printf("finished\n");
- }
- fflush(ctx->fp);
- return r;
- }
-
- static int rtp_receiver(struct rtp_context_t* ctx, socket_t rtp[2], int timeout)
- {
- int i, r;
- // int interval;
- time64_t clock;
- struct pollfd fds[2];
-
- for (i = 0; i < 2; i++)
- {
- fds[i].fd = rtp[i];
- fds[i].events = POLLIN;
- fds[i].revents = 0;
- }
-
- clock = time64_now();
- while (1)
- {
- // RTCP report
- r = rtp_demuxer_rtcp(ctx->demuxer, ctx->rtcp_buffer, sizeof(ctx->rtcp_buffer));
- if (r > 0)
- r = socket_sendto(rtp[1], ctx->rtcp_buffer, r, 0, (const struct sockaddr*) & ctx->ss[1], socket_addr_len((const struct sockaddr*) & ctx->ss[1]));
-
- r = poll(fds, 2, timeout);
- while (-1 == r && EINTR == errno)
- r = poll(fds, 2, timeout);
-
- if (0 == r)
- {
- continue; // timeout
- }
- else if (r < 0)
- {
- return r; // error
- }
- else
- {
- if (0 != fds[0].revents)
- {
- rtp_read(ctx, rtp[0]);
- fds[0].revents = 0;
- }
-
- if (0 != fds[1].revents)
- {
- rtcp_read(ctx, rtp[1]);
- fds[1].revents = 0;
- }
- }
- }
- return r;
- }
-
- static int rtp_onpacket(void* param, const void *packet, int bytes, uint32_t timestamp, int flags)
- {
- const uint8_t start_code[] = { 0, 0, 0, 1 };
- struct rtp_context_t* ctx;
- ctx = (struct rtp_context_t*)param;
- if (0 == strcmp("H264", ctx->encoding) || 0 == strcmp("H265", ctx->encoding))
- {
- fwrite(start_code, 1, 4, ctx->fp);
- }
- else if (0 == strcasecmp("mpeg4-generic", ctx->encoding))
- {
- uint8_t adts[7];
- int len = bytes + 7;
- uint8_t profile = 2;
- uint8_t sampling_frequency_index = 4;
- uint8_t channel_configuration = 2;
- adts[0] = 0xFF; /* 12-syncword */
- adts[1] = 0xF0 /* 12-syncword */ | (0 << 3)/*1-ID*/ | (0x00 << 2) /*2-layer*/ | 0x01 /*1-protection_absent*/;
- adts[2] = ((profile - 1) << 6) | ((sampling_frequency_index & 0x0F) << 2) | ((channel_configuration >> 2) & 0x01);
- adts[3] = ((channel_configuration & 0x03) << 6) | ((len >> 11) & 0x03); /*0-original_copy*/ /*0-home*/ /*0-copyright_identification_bit*/ /*0-copyright_identification_start*/
- adts[4] = (uint8_t)(len >> 3);
- adts[5] = ((len & 0x07) << 5) | 0x1F;
- adts[6] = 0xFC | ((len / 1024) & 0x03);
- fwrite(adts, 1, sizeof(adts), ctx->fp);
- }
- else if (0 == strcmp("MP4A-LATM", ctx->encoding))
- {
- // add ADTS header
- }
- fwrite(packet, 1, bytes, ctx->fp);
- (void)timestamp;
- (void)flags;
-
- if (0 == strcmp("H264", ctx->encoding))
- {
- uint8_t type = *(uint8_t*)packet & 0x1f;
- if (0 < type && type <= 5)
- {
- // VCL frame
- }
- }
- else if (0 == strcmp("H265", ctx->encoding))
- {
- uint8_t type = (*(uint8_t*)packet >> 1) & 0x3f;
- if (type <= 32)
- {
- // VCL frame
- }
- }
-
- return 0;
- }
-
- static int STDCALL rtp_worker(void* param)
- {
- struct rtp_context_t* ctx;
- ctx = (struct rtp_context_t*)param;
-
- rtp_receiver(ctx, ctx->socket, 2000);
-
- rtp_demuxer_destroy(&ctx->demuxer);
- fclose(ctx->frtp);
- fclose(ctx->fp);
- free(ctx);
- return 0;
- }
-
- void rtp_receiver_test(socket_t rtp[2], const char* peer, int peerport[2], int payload, const char* encoding)
- {
- size_t n;
- pthread_t t;
- struct rtp_context_t* ctx;
- const struct rtp_profile_t* profile;
-
- ctx = malloc(sizeof(*ctx));
- if(!ctx) return;
- snprintf(ctx->rtp_buffer, sizeof(ctx->rtp_buffer), "%s.%d.%d.%s", peer, peerport[0], payload, encoding);
- snprintf(ctx->rtcp_buffer, sizeof(ctx->rtcp_buffer), "%s.%d.%d.%s.rtp", peer, peerport[0], payload, encoding);
- ctx->fp = fopen(ctx->rtp_buffer, "wb");
- ctx->frtp = fopen(ctx->rtcp_buffer, "wb");
-
- socket_getrecvbuf(rtp[0], &n);
- socket_setrecvbuf(rtp[0], 512*1024);
- socket_getrecvbuf(rtp[0], &n);
-
- profile = rtp_profile_find(payload);
- ctx->demuxer = rtp_demuxer_create(100, profile ? profile->frequency : 90000, payload, encoding, rtp_onpacket, ctx);
- if (NULL == ctx->demuxer)
- return; // ignore
-
- assert(0 == socket_addr_from(&ctx->ss[0], NULL, peer, (u_short)peerport[0]));
- assert(0 == socket_addr_from(&ctx->ss[1], NULL, peer, (u_short)peerport[1]));
- //assert(0 == connect(rtp[0], (struct sockaddr*)&ctx->ss[0], len));
- //assert(0 == connect(rtp[1], (struct sockaddr*)&ctx->ss[1], len));
-
- snprintf(ctx->encoding, sizeof(ctx->encoding), "%s", encoding);
- ctx->socket[0] = rtp[0];
- ctx->socket[1] = rtp[1];
- if (0 == thread_create(&t, rtp_worker, ctx))
- thread_detach(t);
- }
-
- static struct rtp_context_t* s_ctx[8];
- void* rtp_receiver_tcp_test(uint8_t interleave1, uint8_t interleave2, int payload, const char* encoding)
- {
- struct rtp_context_t* ctx;
- const struct rtp_profile_t* profile;
-
- ctx = malloc(sizeof(struct rtp_context_t));
- if(!ctx) return NULL;
- snprintf(ctx->rtp_buffer, sizeof(ctx->rtp_buffer), "tcp.%d.%s", payload, encoding);
- snprintf(ctx->rtcp_buffer, sizeof(ctx->rtcp_buffer), "tcp.%d.%s.rtp", payload, encoding);
- ctx->fp = fopen(ctx->rtp_buffer, "wb");
- ctx->frtp = fopen(ctx->rtcp_buffer, "wb");
- snprintf(ctx->encoding, sizeof(ctx->encoding), "%s", encoding);
- assert(interleave1 / 2 < sizeof(s_ctx) / sizeof(s_ctx[0]));
- s_ctx[interleave1 / 2] = ctx;
-
- profile = rtp_profile_find(payload);
- ctx->demuxer = rtp_demuxer_create(100, profile ? profile->frequency : 90000, payload, encoding, rtp_onpacket, ctx);
- return ctx;
- }
-
- void rtp_receiver_tcp_input(uint8_t channel, const void* data, uint16_t bytes)
- {
- int r;
- uint8_t size[2];
- struct rtp_context_t* ctx = s_ctx[channel / 2];
-
- if (0 == channel % 2)
- {
- size[0] = bytes >> 8;
- size[1] = bytes >> 0;
- fwrite(size, 1, sizeof(size), ctx->frtp);
- fwrite(data, 1, bytes, ctx->frtp);
- }
-
- if (ctx->demuxer)
- {
- r = rtp_demuxer_input(ctx->demuxer, data, bytes);
- assert(r >= 0);
- }
- }
|