rendered paste body#include <curl/curl.h>#include <pthread.h>#include <fcntl.h>#include <semaphore.h>#include <sys/socket.h>#include <netinet/in.h>char boundary[128];struct image { pthread_mutex_t lock; char *data; int length; int received;};sem_t new_image;struct image curr_image, next_image;static size_t write_cb(void *data, size_t size, size_t nmemb, void *stream) { static int state = 0; char *tmp; int msize = size * nmemb; int retval = size * nmemb; /* char *tmp = strstr(data, "\377\330\377\340\000\020JFIF\000"); JPEG Header */ size *= nmemb; while(msize > 0) { char *tmp1, *tmp2; if(state == 0 && !strncmp(data, boundary, strlen(boundary))) { state = 1; data += strlen(boundary); msize -= strlen(boundary); } else if(state == 0 && !strncmp(data+2, boundary, strlen(boundary))) { state = 1; data += strlen(boundary) + 2; msize -= strlen(boundary) + 2; } else if(state == 1 && (tmp1 = strstr(data, "Content-Length: "))) { tmp2 = index(tmp1, '\r'); *tmp2 = '\0'; pthread_mutex_lock(&next_image.lock); next_image.length = atoi(data + 16); next_image.data = (char *)malloc(next_image.length); next_image.received = 0; pthread_mutex_unlock(&next_image.lock); msize -= ((void *)tmp2+2)-(data); data = tmp2+2; state = 2; } else if(state == 2 && (tmp1 = strstr(data, "Content-Type: "))) { tmp1 = data + strlen("Content-Type: image/jpeg\r\n\r\n"); msize -= (int)((void *)tmp1 - (void *)data); data = tmp1; state = 3; } else if(state == 3) { int copy; pthread_mutex_lock(&next_image.lock); /* Determine how much to copy */ copy = (next_image.length - next_image.received > msize ? msize : next_image.length - next_image.received); memcpy(next_image.data + next_image.received, data, copy); /* Include this in our received count */ next_image.received += copy; data += copy; if(next_image.length == next_image.received) { /* If we received it all, lock the current and replace it */ pthread_mutex_lock(&curr_image.lock); if(curr_image.data) free(curr_image.data); curr_image.data = next_image.data; curr_image.length = next_image.length; curr_image.received = next_image.received; pthread_mutex_unlock(&curr_image.lock); /* Notify the other thread */ sem_post(&new_image); /* Drop the "next image" information, * since it is now current image */ next_image.data = NULL; next_image.length = 0; next_image.received = 0; state = 0; } msize -= copy; if(msize >= 2) { msize -= 2; data += 2; } pthread_mutex_unlock(&next_image.lock); } } return retval;}static size_t header_cb(void *data, size_t size, size_t nmemb, void *stream) { if(size * nmemb > 14 && !strncasecmp(data, "Content-Type: ", 14)) { char *tmp; tmp = index(data, ';'); snprintf(boundary, 128, "--%s", tmp + 10); } return size * nmemb;}static void *reader_thread(void *arg) { CURL *curl; curl = curl_easy_init(); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb); curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_cb); curl_easy_setopt(curl, CURLOPT_URL, (char *)arg); curl_easy_perform(curl); curl_easy_cleanup(curl); pthread_exit(0);}pthread_mutex_t clientlock;struct client { int fd; int first; struct sockaddr_in sa; struct client *next;};struct client *clientlist = NULL;static void *listen_thread(void *arg) { int lfd, res, tmp; struct sockaddr_in sa; struct client *c; sa.sin_family = AF_INET; sa.sin_port = htons(9194); sa.sin_addr.s_addr = INADDR_ANY; lfd = socket(AF_INET, SOCK_STREAM, 0); bind(lfd, (struct sockaddr *)&sa, sizeof(sa)); listen(lfd, 20); tmp = sizeof(sa); while((res = accept(lfd, (struct sockaddr *)&sa, &tmp))) { pthread_mutex_lock(&clientlock); c = clientlist; while(c) { if(c->fd == -1) break; c = c->next; } if(!c) { c = (struct client *)malloc(sizeof(struct client)); memcpy(&c->sa, &sa, sizeof(sa)); c->next = clientlist; clientlist = c; } c->first = 1; c->fd = res;#define HELLO "HTTP/1.0 200 OK\r\nConnection: close\r\nPragma: no-cache\r\nCache-Controler: no-cache\r\nContent-Type: multipart/x-mixed-replace;boundary=Juigt9G7bb7sfdgsdZGIDFsjhn\r\n\r\n" write(c->fd, HELLO, strlen(HELLO)); pthread_mutex_unlock(&clientlock); printf("Client connected.\n"); }}static void *writer_thread(void *arg) { int framecnt = 0; while(1) { int fd; char buf[1024]; struct client *c; int cnt; sem_wait(&new_image); pthread_testcancel(); pthread_mutex_lock(&curr_image.lock); pthread_mutex_lock(&clientlock); c = clientlist; cnt = 0; while(c) { if(c->fd != -1) { if(c->first) { snprintf(buf, 1024, "%sContent-Length: %d\r\nContent-Type: image/jpeg\r\n\r\n", boundary, curr_image.length); c->first = 0; } else { snprintf(buf, 1024, "Content-Length: %d\r\nContent-Type: image/jpeg\r\n\r\n", curr_image.length); } write(c->fd, buf, strlen(buf)); if(write(c->fd, curr_image.data, curr_image.length) < curr_image.length) { shutdown(c->fd, 2); close(c->fd); c->fd = -1; } write(c->fd, "\r\n", 2); write(c->fd, boundary, strlen(boundary)); cnt++; } c = c->next; } snprintf(buf, 30, "tmp%04d.jpg", framecnt++%100); fd = open(buf , O_WRONLY | O_TRUNC | O_CREAT, 0666); write(fd, curr_image.data, curr_image.length); close(fd); printf("Wrote %d bytes to %d clients (%d bytes total)\n", curr_image.length, cnt, cnt * curr_image.length); pthread_mutex_unlock(&clientlock); pthread_mutex_unlock(&curr_image.lock); }}int main(int argc, char **argv) { pthread_t reader; pthread_t writer; pthread_t listen_t; curr_image.data = 0; next_image.data = 0; if(argc < 1) { printf("not enough parameters. provide URL to stream.\n"); exit(0); } sem_init(&new_image, 0, 0); curl_global_init(CURL_GLOBAL_NOTHING); pthread_create(&reader, NULL, reader_thread, argv[1]); pthread_create(&writer, NULL, writer_thread, NULL); pthread_create(&listen_t, NULL, listen_thread, NULL); pthread_join(reader, NULL); curl_global_cleanup();}