| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292 |
- # include <stdio.h>
- # include <stdint.h>
- # include <stdlib.h>
- # include <unistd.h>
- # include <string.h>
- # include <errno.h>
- # include <getopt.h>
- # include <sys/types.h>
- # include <sys/stat.h>
- # include <fcntl.h>
- # include <arpa/inet.h>
- struct fpv
- {
- uint32_t len;
- uint8_t type;
- uint32_t ms;
- uint8_t pad[8];
- } __attribute__((packed));
- size_t out(int fd, struct sockaddr_in *to, uint8_t *data, size_t len)
- {
- int res = 0;
- while (len > 0) {
- size_t n = len;
- if (n > 1400) {
- n = 1400;
- }
- if ((n = sendto(fd, data, n, 0, (struct sockaddr*)to, sizeof(struct sockaddr_in))) > 0) {
- len -= n;
- data += n;
- res += n;
- } else {
- if (errno != EAGAIN) {
- printf("write: %s\n", strerror(errno));
- } else {
- continue;
- }
- break;
- }
- }
- return res;
- }
- enum
- {
- NUT_CODED_SLICE_NON_IDR = 1, // Coded slice of a non-IDR picture
- NUT_CODED_SLICE_IDR = 5, // Coded slice of an IDR picture
- NUT_SPS = 7, // Sequence parameter set
- NUT_PPS = 8 // Picture parameter set
- };
- struct parameter_set
- {
- uint8_t data[256];
- size_t length;
- int found;
- };
- size_t out_v(int fd, struct sockaddr_in *to, uint8_t *data, int len)
- {
- static struct parameter_set sps = { .data = { 0, }, .length = 0, .found = 0 };
- static struct parameter_set pps = { .data = { 0, }, .length = 0, .found = 0 };
- static struct parameter_set *ps = NULL;
- static struct { uint8_t data[4]; int length; } marker = { .length = 0, .data = { 0, } };
- struct { uint8_t data[4096]; int length; } pkt = { .length = 0 };
- int p;
- for (p = 0; p < len; p++) {
- int c = data[p];
- if (marker.length == 4) {
- if (memcmp(marker.data, "\x00\x00\x00\x01", 4) == 0) {
- switch (c & 0x1F) {
- case NUT_SPS:
- memset(ps = &sps, 0, sizeof(sps));
- sps.found = 1;
- break;
- case NUT_PPS:
- memset(ps = &pps, 0, sizeof(pps));
- pps.found = 1;
- break;
- case NUT_CODED_SLICE_NON_IDR:
- case NUT_CODED_SLICE_IDR:
- if (sps.found == 0 && sps.length > 0) {
- int i; for (i = 0; i < sps.length; i++) {
- if (pkt.length < sizeof(pkt.data)) {
- pkt.data[pkt.length++] = sps.data[i];
- }
- }
- }
- sps.found = 0;
- if (pps.found == 0 && pps.length > 0) {
- int i; for (i = 0; i < pps.length; i++) {
- if (pkt.length < sizeof(pkt.data)) {
- pkt.data[pkt.length++] = pps.data[i];
- }
- }
- }
- pps.found = 0;
- default:
- ps = NULL;
- break;
- }
- marker.data[0] = 0;
- marker.data[1] = 0;
- marker.data[2] = 0;
- marker.data[3] = 0;
- marker.length = 0;
- } else {
- marker.data[0] = marker.data[1];
- marker.data[1] = marker.data[2];
- marker.data[2] = marker.data[3];
- marker.data[3] = c & 0xFF;
- }
- } else {
- marker.data[marker.length++] = c & 0xFF;;
- }
- if (ps != NULL) {
- if (ps->length < sizeof(ps->data)) {
- ps->data[ps->length++] = c & 0xFF;
- } else {
- memset(ps, 0, sizeof(*ps));
- ps = NULL;
- }
- }
- if (pkt.length < sizeof(pkt.data)) {
- pkt.data[pkt.length++] = c & 0xFF;
- }
- }
- return out(fd, to, pkt.data, pkt.length);
- }
- size_t in(int fd, uint8_t *data, size_t len)
- {
- int res = 0;
- while (len > 0) {
- size_t n = read(fd, data, len);
- if (n > 0) {
- len -= n;
- data += n;
- res += n;
- } else {
- if (n < 0) {
- if (errno != EAGAIN) {
- printf("read: %s\n", strerror(errno));
- } else {
- continue;
- }
- }
- break;
- }
- }
- return res;
- }
- static const char short_options[] = "s:e:t:";
- static const struct option long_options[] =
- {
- { "start", required_argument, NULL, 's' },
- { "end", required_argument, NULL, 'e' },
- { "to", required_argument, NULL, 't' },
- { 0, 0, NULL, 0 }
- };
- static int opt_s = -1;
- static int opt_e = -1;
- static char *opt_t = "127.255.255.255";
- int main(int argc, char *argv[])
- {
- struct fpv fpv;
- static uint8_t data[8 * 1024 * 1024];
- int i;
- for (;;) {
- int c;
- if ((c = getopt_long_only(argc, argv, short_options, long_options, &i)) == -1) {
- break;
- }
- switch (c) {
- case 's':
- opt_s = atoi(optarg);
- break;
- case 'e':
- opt_e = atoi(optarg);
- break;
- case 't':
- opt_t = optarg;
- break;
- case 0:
- break;
- default:
- return 1;
- }
- }
- struct sockaddr_in all;
- int on = 1;
- int udp;
- memset(&all, 0, sizeof(all));
- all.sin_family = AF_INET;
- all.sin_addr.s_addr = inet_addr(opt_t);
- all.sin_port = htons(0);
- udp = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
- setsockopt(udp, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
- if ((argc - optind) < 1) {
- return 1;
- }
- for (i = 0; (optind + i) < argc; i++) {
- int fd = open(argv[optind + i], O_RDONLY);
- int ms = 0;
- if (fd >= 0) {
- while (1) {
- if (in(fd, (uint8_t*)&fpv, sizeof(fpv)) > 0) {
- int play = 1;
- if (opt_s > 0 && fpv.ms < opt_s) {
- play = 0;
- }
- if (opt_e > 0 && fpv.ms >= opt_e) {
- break;
- }
- if (play) {
- int sleep = fpv.ms - ms;
- if (sleep > 0) {
- usleep(sleep * 1000);
- }
- }
- ms = fpv.ms;
- if (in(fd, data, fpv.len) > 0) {
- if (!play) {
- continue;
- }
- switch (fpv.type) {
- case 0:
- all.sin_port = htons(5000);
- break;
- case 2:
- all.sin_port = htons(14550);
- break;
- case 5:
- all.sin_port = htons(5003);
- break;
- default:
- continue;
- }
- out(udp, &all, data, fpv.len);
- } else {
- break;
- }
- } else {
- break;
- }
- }
- close(fd);
- }
- }
- return 0;
- }
|