/****************************************************************************** Description.: this function is called first, in order to initialize this plugin and pass a parameter string Input Value.: parameters Return Value: 0 if everything is OK, non-zero otherwise ******************************************************************************/ int output_init(output_parameter *param, int id) { int i; delay = 0; pglobal = param->global; pglobal->out[id].name = (char *) malloc((1+strlen(OUTPUT_PLUGIN_NAME))*sizeof(char)); sprintf(pglobal->out[id].name, "%s", OUTPUT_PLUGIN_NAME); DBG("OUT plugin %d name: %s\n", id, pglobal->out[id].name); param->argv[0] = OUTPUT_PLUGIN_NAME; /* show all parameters for DBG purposes */ for(i = 0; i < param->argc; i++) { DBG("argv[%d]=%s\n", i, param->argv[i]); } reset_getopt(); while(1) { int option_index = 0, c = 0; static struct option long_options[] = { {"h", no_argument, 0, 0 }, {"help", no_argument, 0, 0}, {0, 0, 0, 0} }; c = getopt_long_only(param->argc, param->argv, "", long_options, &option_index); /* no more options to parse */ if(c == -1) break; /* unrecognized option */ if(c == '?') { help(); return 1; } switch(option_index) { /* h, help */ case 0: case 1: DBG("case 0,1\n"); help(); return 1; break; } } if(!(input_number < pglobal->incnt)) { OPRINT("ERROR: the %d input_plugin number is too much only %d plugins loaded\n", input_number, param->global->incnt); return 1; } OPRINT("Starting OpenCV.....\n"); OPRINT("input plugin.....: %d: %s\n", input_number, pglobal->in[input_number].plugin); param->global->out[id].parametercount = 0; return 0; }
/****************************************************************************** Description.: clean up allocated ressources Input Value.: unused argument Return Value: - ******************************************************************************/ void worker_cleanup(void *arg) { static unsigned char first_run = 1; if(!first_run) { DBG("already cleaned up ressources\n"); return; } first_run = 0; OPRINT("cleaning up ressources allocated by worker thread\n"); }
/****************************************************************************** Description.: clean up allocated ressources Input Value.: unused argument Return Value: - ******************************************************************************/ void worker_cleanup(void *arg) { static unsigned char first_run = 1; if(!first_run) { DBG("already cleaned up ressources\n"); return; } first_run = 0; OPRINT("cleaning up ressources allocated by worker thread\n"); if(frame != NULL) { free(frame); } //close tcp socket client_tcp_destory(); }
/****************************************************************************** Description.: clean up allocated resources Input Value.: unused argument Return Value: - ******************************************************************************/ void worker_cleanup(void *arg) { static unsigned char first_run = 1; if (mjpgFileName != NULL) { close(fd); } if(!first_run) { DBG("already cleaned up resources\n"); return; } first_run = 0; OPRINT("cleaning up resources allocated by worker thread\n"); if(frame != NULL) { free(frame); } close(fd); }
/****************************************************************************** Description.: clean up allocated ressources Input Value.: unused argument Return Value: - ******************************************************************************/ void worker_cleanup(void *arg) { static unsigned char first_run = 1; int i; if (mjpgFileName != NULL) { close(fd); } if(!first_run) { DBG("already cleaned up ressources\n"); return; } first_run = 0; OPRINT("cleaning up ressources allocated by worker thread\n"); if(frame != NULL) { free(frame); } close(fd); // cleanup zmq zmq_close (publisher); zmq_ctx_destroy (context); // Free the allocated serialized buffer free(buf); // Free protobuf message for (i = 0; i < pbPackage.n_frame; ++i) { free(pbPackage.frame[i]); } free(pbPackage.frame); }
int output_cmd(int plugin_id, unsigned int control_id, unsigned int group, int value, char *valueStr) { int i = 0; DBG("command (%d, value: %d) for group %d triggered for plugin instance #%02d\n", control_id, value, group, plugin_id); switch(group) { case IN_CMD_GENERIC: for(i = 0; i < pglobal->out[plugin_id].parametercount; i++) { if((pglobal->out[plugin_id].out_parameters[i].ctrl.id == control_id) && (pglobal->out[plugin_id].out_parameters[i].group == IN_CMD_GENERIC)) { DBG("Generic control found (id: %d): %s\n", control_id, pglobal->out[plugin_id].out_parameters[i].ctrl.name); switch(control_id) { case OUT_FILE_CMD_TAKE: { if (valueStr != NULL) { int frame_size = 0; unsigned char *tmp_framebuffer = NULL; if(pthread_mutex_lock(&pglobal->in[input_number].db)) { DBG("Unable to lock mutex\n"); return -1; } /* read buffer */ frame_size = pglobal->in[input_number].size; /* check if buffer for frame is large enough, increase it if necessary */ if(frame_size > max_frame_size) { DBG("increasing buffer size to %d\n", frame_size); max_frame_size = frame_size + (1 << 16); if((tmp_framebuffer = realloc(frame, max_frame_size)) == NULL) { pthread_mutex_unlock(&pglobal->in[input_number].db); LOG("not enough memory\n"); return -1; } frame = tmp_framebuffer; } /* copy frame to our local buffer now */ memcpy(frame, pglobal->in[input_number].buf, frame_size); /* allow others to access the global buffer again */ pthread_mutex_unlock(&pglobal->in[input_number].db); DBG("writing file: %s\n", valueStr); int fd; /* open file for write */ if((fd = open(valueStr, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) { OPRINT("could not open the file %s\n", valueStr); return -1; } /* save picture to file */ //if(write(fileno(stdout), frame, frame_size) < 0) { if(fwrite(frame, sizeof(unsigned char), frame_size, stdout) < 0) { OPRINT("could not write to file %s\n", valueStr); perror("fwrite()"); close(fd); return -1; } close(fd); } else { DBG("No filename specified\n"); return -1; } } break; case OUT_FILE_CMD_FILENAME: { DBG("Not yet implemented\n"); return -1; } break; default: { DBG("Unknown command\n"); return -1; } break; } DBG("Ctrl %s new value: %d\n", pglobal->out[plugin_id].out_parameters[i].ctrl.name, value); return 0; } } DBG("Requested generic control (%d) did not found\n", control_id); return -1; break; } return 0; }
/****************************************************************************** Description.: this function is called first, in order to initialize this plugin and pass a parameter string Input Value.: parameters Return Value: 0 if everything is OK, non-zero otherwise ******************************************************************************/ int output_init(output_parameter *param, int id) { int i; pglobal = param->global; pglobal->out[id].name = malloc((1+strlen(OUTPUT_PLUGIN_NAME))*sizeof(char)); sprintf(pglobal->out[id].name, "%s", OUTPUT_PLUGIN_NAME); DBG("OUT plugin %d name: %s\n", id, pglobal->out[id].name); param->argv[0] = OUTPUT_PLUGIN_NAME; /* show all parameters for DBG purposes */ for(i = 0; i < param->argc; i++) { DBG("argv[%d]=%s\n", i, param->argv[i]); } reset_getopt(); while(1) { int option_index = 0, c = 0; static struct option long_options[] = { {"h", no_argument, 0, 0 }, {"help", no_argument, 0, 0}, {"f", required_argument, 0, 0}, {"folder", required_argument, 0, 0}, {"s", required_argument, 0, 0}, {"size", required_argument, 0, 0}, {"e", required_argument, 0, 0}, {"exceed", required_argument, 0, 0}, {"i", required_argument, 0, 0}, {"input", required_argument, 0, 0}, {"m", required_argument, 0, 0}, {"mjpeg", required_argument, 0, 0}, {"a", required_argument, 0, 0}, {"address", required_argument, 0, 0}, {"b", required_argument, 0, 0}, {"buffer_size", required_argument, 0, 0}, {0, 0, 0, 0} }; c = getopt_long_only(param->argc, param->argv, "", long_options, &option_index); /* no more options to parse */ if(c == -1) break; /* unrecognized option */ if(c == '?') { help(); return 1; } switch(option_index) { /* h, help */ case 0: case 1: DBG("case 0,1\n"); help(); return 1; break; /* f, folder */ case 2: case 3: DBG("case 2,3\n"); folder = malloc(strlen(optarg) + 1); strcpy(folder, optarg); if(folder[strlen(folder)-1] == '/') folder[strlen(folder)-1] = '\0'; break; /* s, size */ case 4: case 5: DBG("case 4,5\n"); ringbuffer_size = atoi(optarg); break; /* e, exceed */ case 6: case 7: DBG("case 6,7\n"); ringbuffer_exceed = atoi(optarg); break; /* i, input*/ case 8: case 9: DBG("case 8,9\n"); input_number = atoi(optarg); break; /* m mjpeg */ case 10: case 11: DBG("case 10,11\n"); mjpgFileName = strdup(optarg); break; /* a address */ case 12: case 13: DBG("case 12,13\n"); zmqAddress = strdup(optarg); break; /* buffer_size */ case 14: case 15: DBG("case 14,15\n"); zmqBufferSize = atoi(optarg); break; } } if(!(input_number < pglobal->incnt)) { OPRINT("ERROR: the %d input_plugin number is too much only %d plugins loaded\n", input_number, param->global->incnt); return 1; } OPRINT("output folder.....: %s\n", folder); OPRINT("input plugin.....: %d: %s\n", input_number, pglobal->in[input_number].plugin); if (mjpgFileName == NULL) { if(ringbuffer_size > 0) { OPRINT("ringbuffer size...: %d to %d\n", ringbuffer_size, ringbuffer_size + ringbuffer_exceed); } else { OPRINT("ringbuffer size...: %s\n", "no ringbuffer"); } } else { char *fnBuffer = malloc(strlen(mjpgFileName) + strlen(folder) + 3); sprintf(fnBuffer, "%s/%s", folder, mjpgFileName); OPRINT("output file.......: %s\n", fnBuffer); if((fd = open(fnBuffer, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) { OPRINT("could not open the file %s\n", fnBuffer); free(fnBuffer); return 1; } free(fnBuffer); } param->global->out[id].parametercount = 2; param->global->out[id].out_parameters = (control*) calloc(2, sizeof(control)); control take_ctrl; take_ctrl.group = IN_CMD_GENERIC; take_ctrl.menuitems = NULL; take_ctrl.value = 1; take_ctrl.class_id = 0; take_ctrl.ctrl.id = OUT_FILE_CMD_TAKE; take_ctrl.ctrl.type = V4L2_CTRL_TYPE_BUTTON; strcpy((char*) take_ctrl.ctrl.name, "Take snapshot"); take_ctrl.ctrl.minimum = 0; take_ctrl.ctrl.maximum = 1; take_ctrl.ctrl.step = 1; take_ctrl.ctrl.default_value = 0; param->global->out[id].out_parameters[0] = take_ctrl; control filename_ctrl; filename_ctrl.group = IN_CMD_GENERIC; filename_ctrl.menuitems = NULL; filename_ctrl.value = 1; filename_ctrl.class_id = 0; filename_ctrl.ctrl.id = OUT_FILE_CMD_FILENAME; filename_ctrl.ctrl.type = V4L2_CTRL_TYPE_STRING; strcpy((char*) filename_ctrl.ctrl.name, "Filename"); filename_ctrl.ctrl.minimum = 0; filename_ctrl.ctrl.maximum = 32; filename_ctrl.ctrl.step = 1; filename_ctrl.ctrl.default_value = 0; param->global->out[id].out_parameters[1] = filename_ctrl; return 0; }
/****************************************************************************** Description.: this is the main worker thread it loops forever, grabs a fresh frame and stores it to file Input Value.: Return Value: ******************************************************************************/ void *worker_thread(void *arg) { int ok = 1, frame_size = 0, rc = 0; char buffer1[1024] = {0}, buffer2[1024] = {0}; unsigned long long counter = 0; unsigned char *tmp_framebuffer = NULL; // Prepare our context and publisher //char zmqAddress[20]; if (zmqAddress == NULL) { LOG("No ZMQ address specified"); } context = zmq_ctx_new (); publisher = zmq_socket (context, ZMQ_PUB); //snprintf(zmqAddress, 20u, "epgm://eth0;239.1.1.1:%i", zmqPort); if (zmq_bind (publisher, zmqAddress) == -1) { LOG("Couldn't create zmq socket.\n"); } unsigned len; // Length of serialized data char topic[] = "frames"; struct timeval timestamp; int i; buf = NULL; for (i = 0; i < MAX_ZMQ_BUFFER_SIZE; ++i) { frames[i] = NULL; } pbPackage.n_frame = zmqBufferSize; if ((pbPackage.frame = malloc(sizeof(Pb__Package__Frame*) * pbPackage.n_frame)) == NULL) { LOG("not enough memory\n"); } for (i = 0; i < pbPackage.n_frame; ++i) { if ((pbPackage.frame[i] = malloc(sizeof(Pb__Package__Frame))) == NULL) { LOG("not enough memory\n"); } pb__package__frame__init(pbPackage.frame[i]); } /* set cleanup handler to cleanup allocated ressources */ pthread_cleanup_push(worker_cleanup, NULL); while(ok >= 0 && !pglobal->stop) { DBG("waiting for fresh frame\n"); pthread_mutex_lock(&pglobal->in[input_number].db); pthread_cond_wait(&pglobal->in[input_number].db_update, &pglobal->in[input_number].db); /* read buffer */ frame_size = pglobal->in[input_number].size; /* set the right frame to store the data */ frame = frames[zmqBufferPos]; /* check if buffer for frame is large enough, increase it if necessary */ if((frame_size > max_frame_size) || (frame == NULL)) { DBG("increasing buffer size to %d\n", frame_size); if (frame_size > max_frame_size) { max_frame_size = frame_size + (1 << 16); } if((tmp_framebuffer = realloc(frame, max_frame_size)) == NULL) { pthread_mutex_unlock(&pglobal->in[input_number].db); LOG("not enough memory\n"); return NULL; } if ((setvbuf(stdout, NULL, _IOFBF, max_frame_size)) != 0) { DBG("setvbuf failed.\n"); } frame = tmp_framebuffer; } /* copy v4l2_buffer timeval to user space */ timestamp = pglobal->in[input_number].timestamp; /* copy frame to our local buffer now */ memcpy(frame, pglobal->in[input_number].buf, frame_size); /* resync again with the frame buffer */ frames[zmqBufferPos] = frame; /* allow others to access the global buffer again */ pthread_mutex_unlock(&pglobal->in[input_number].db); if (mjpgFileName == NULL) { // single files with ringbuffer mode DBG("Packaging data: %lld\n", counter); counter++; begin = clock(); /* allocate enough memory to store a serialized string */ if ((buf == NULL) || (bufferSize < (max_frame_size * zmqBufferSize + 20))) { bufferSize = (max_frame_size * zmqBufferSize + 20); buf = realloc(buf, bufferSize); if (buf == NULL) { LOG("Not enough memory"); } } /* fill protobuf data */ pbPackage.frame[zmqBufferPos]->timestamp_unix = (u_int32_t)time(NULL); pbPackage.frame[zmqBufferPos]->timestamp_s = (u_int32_t)timestamp.tv_sec; pbPackage.frame[zmqBufferPos]->timestamp_us = (u_int32_t)timestamp.tv_usec; pbPackage.frame[zmqBufferPos]->blob.data = frame; pbPackage.frame[zmqBufferPos]->blob.len = frame_size; zmqBufferPos++; if (zmqBufferPos == zmqBufferSize) { DBG("transmitting ZMQ: %lld\n", counter); /* pack protobuf data */ len = pb__package__get_packed_size(&pbPackage); DBG("packing data: %i %i", max_frame_size, len); pb__package__pack(&pbPackage, buf); DBG("sending data"); // send data using zmq if ((zmq_send(publisher, topic, strlen(topic), ZMQ_SNDMORE) == -1) || (zmq_send(publisher, buf, len, 0) == -1)) { DBG("ZMQ Transmission failure"); } zmqBufferPos = 0; } end = clock(); DBG("Time1: %f\n", (double)(end-begin) / CLOCKS_PER_SEC); begin = clock(); /* call the command if user specified one, pass current filename as argument */ if(command != NULL) { memset(buffer1, 0, sizeof(buffer1)); /* buffer2 still contains the filename, pass it to the command as parameter */ snprintf(buffer1, sizeof(buffer1), "%s \"%s\"", command, buffer2); DBG("calling command %s", buffer1); /* in addition provide the filename as environment variable */ if((rc = setenv("MJPG_FILE", buffer2, 1)) != 0) { LOG("setenv failed (return value %d)\n", rc); } /* execute the command now */ if((rc = system(buffer1)) != 0) { LOG("command failed (return value %d)\n", rc); } } end = clock(); DBG("Time2: %f\n", (double)(end-begin) / CLOCKS_PER_SEC); begin = clock(); /* * maintain ringbuffer * do not maintain ringbuffer for each picture, this saves ressources since * each run of the maintainance function involves sorting/malloc/free operations */ if(ringbuffer_exceed <= 0) { /* keep ringbuffer excactly at specified siOUTPUT_PLUGIN_NAMEze */ maintain_ringbuffer(ringbuffer_size); } else if(counter == 1 || counter % (ringbuffer_exceed + 1) == 0) { DBG("counter: %llu, will clean-up now\n", counter); maintain_ringbuffer(ringbuffer_size); } end = clock(); DBG("Time3: %f\n", (double)(end-begin) / CLOCKS_PER_SEC); } else { // recording to MJPG file DBG("Entered else branch!\n"); /* save picture to file */ //if(write(fileno(stdout), frame, frame_size) < 0) { if(fwrite(frame, sizeof(unsigned char), frame_size, stdout) < 0) { OPRINT("could not write to file %s\n", buffer2); perror("fwrite()"); close(fd); return NULL; } } } /* cleanup now */ pthread_cleanup_pop(1); return NULL; }
/****************************************************************************** Description.: this function is called first, in order to initialise this plugin and pass a parameter string Input Value.: parameters Return Value: 0 if everything is ok, non-zero otherwise ******************************************************************************/ int output_init(output_parameter *param) { int i; param->argv[0] = OUTPUT_PLUGIN_NAME; /* show all parameters for DBG purposes */ for(i = 0; i < param->argc; i++) { DBG("argv[%d]=%s\n", i, param->argv[i]); } reset_getopt(); while(1) { int option_index = 0, c = 0; static struct option long_options[] = { {"h", no_argument, 0, 0 }, {"help", no_argument, 0, 0}, {"p", required_argument, 0, 0}, {"port", required_argument, 0, 0}, {"i", required_argument, 0, 0}, {"input", required_argument, 0, 0}, {0, 0, 0, 0} }; c = getopt_long_only(param->argc, param->argv, "", long_options, &option_index); /* no more options to parse */ if(c == -1) break; /* unrecognized option */ if(c == '?') { help(); return 1; } switch(option_index) { /* h, help */ case 0: case 1: DBG("case 0,1\n"); help(); return 1; break; case 2: case 3: DBG("case 2,3\n"); port = atoi(optarg); break; /* i, input */ case 4: case 5: DBG("case 4,5\n"); input_number = atoi(optarg); break; } } pglobal = param->global; if(!(input_number < pglobal->incnt)) { OPRINT("ERROR: the %d input_plugin number is too much only %d plugins loaded\n", input_number, pglobal->incnt); return 1; } OPRINT("input plugin.....: %d: %s\n", input_number, pglobal->in[input_number].plugin); OPRINT("UDP port..........: %s\n", "disabled"); return 0; }
/****************************************************************************** Description.: this is the main worker thread it loops forever, grabs a fresh frame and stores it to file Input Value.: Return Value: ******************************************************************************/ void *worker_thread(void *arg) { int ok = 1; int frame_size = 0; unsigned char *tmp_framebuffer = NULL; struct sockaddr_in addr; int sd; bzero(&addr, sizeof(addr)); /* set cleanup handler to cleanup allocated ressources */ pthread_cleanup_push(worker_cleanup, NULL); // set TCP server data structures --------------------------- if(port <= 0) { OPRINT("a valid TCP port must be provided\n"); return NULL; } addr.sin_addr.s_addr = inet_addr(server); addr.sin_family = AF_INET; addr.sin_port = htons(port); // ----------------------------------------------------------- struct timeval imageProcessingStart; struct timeval imageProcessingStop; struct timeval socketStart; struct timeval socketStop; while (ok >= 0 && !pglobal->stop) { //DBG("waiting for fresh frame\n"); gettimeofday(&imageProcessingStart, NULL); pthread_mutex_lock(&pglobal->in[input_number].db); pthread_cond_wait(&pglobal->in[input_number].db_update, &pglobal->in[input_number].db); /* read buffer */ frame_size = pglobal->in[input_number].size; /* check if buffer for frame is large enough, increase it if necessary */ if(frame_size > max_frame_size) { DBG("increasing buffer size to %d\n", frame_size); max_frame_size = frame_size + (1 << 16); if((tmp_framebuffer = realloc(frame, max_frame_size)) == NULL) { pthread_mutex_unlock(&pglobal->in[input_number].db); LOG("not enough memory\n"); return NULL; } frame = tmp_framebuffer; } /* copy frame to our local buffer now */ memcpy(frame, pglobal->in[input_number].buf, frame_size); /* allow others to access the global buffer again */ pthread_mutex_unlock(&pglobal->in[input_number].db); gettimeofday(&imageProcessingStop, NULL); printDuration(&imageProcessingStart, &imageProcessingStop, "Image"); /* Send image */ gettimeofday(&socketStart, NULL); DBG("Create connection to %s:%d\n", server, port); sd = socket(AF_INET, SOCK_STREAM, 0); // Test usleep(200 * 1000); if (connect(sd , (struct sockaddr*) &addr , sizeof(addr)) == 0) { DBG("Connection to %s:%d established\n", server, port); if (!send(sd, frame, frame_size, 0)) { perror("Image was not send"); } DBG("Closing connection to %s:%d\n", server, port); close(sd); } else { perror("connect"); } gettimeofday(&socketStop, NULL); printDuration(&socketStart, &socketStop, "Socket"); } DBG("Ending TCP worker thread\n"); /* cleanup now */ pthread_cleanup_pop(1); return NULL; }
/****************************************************************************** Description.: this is the main worker thread it loops forever, grabs a fresh frame and stores it to file Input Value.: Return Value: ******************************************************************************/ void *worker_thread(void *arg) { int ok = 1, frame_size = 0, rc = 0; char buffer1[1024] = {0}; unsigned char *tmp_framebuffer = NULL; /* set cleanup handler to cleanup allocated ressources */ pthread_cleanup_push(worker_cleanup, NULL); // set UDP server data structures --------------------------- if(port <= 0) { OPRINT("a valid UDP port must be provided\n"); return NULL; } struct sockaddr_in addr; int sd; int bytes; unsigned int addr_len = sizeof(addr); char udpbuffer[1024] = {0}; sd = socket(PF_INET, SOCK_DGRAM, 0); bzero(&addr, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(port); if(bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0) perror("bind"); // ----------------------------------------------------------- while(ok >= 0 && !pglobal->stop) { DBG("waiting for a UDP message\n"); // UDP receive --------------------------------------------- memset(udpbuffer, 0, sizeof(udpbuffer)); bytes = recvfrom(sd, udpbuffer, sizeof(udpbuffer), 0, (struct sockaddr*)&addr, &addr_len); // --------------------------------------------------------- DBG("waiting for fresh frame\n"); pthread_mutex_lock(&pglobal->in[input_number].db); pthread_cond_wait(&pglobal->in[input_number].db_update, &pglobal->in[input_number].db); /* read buffer */ frame_size = pglobal->in[input_number].size; /* check if buffer for frame is large enough, increase it if necessary */ if(frame_size > max_frame_size) { DBG("increasing buffer size to %d\n", frame_size); max_frame_size = frame_size + (1 << 16); if((tmp_framebuffer = realloc(frame, max_frame_size)) == NULL) { pthread_mutex_unlock(&pglobal->in[input_number].db); LOG("not enough memory\n"); return NULL; } frame = tmp_framebuffer; } /* copy frame to our local buffer now */ memcpy(frame, pglobal->in[input_number].buf, frame_size); /* allow others to access the global buffer again */ pthread_mutex_unlock(&pglobal->in[input_number].db); /* only save a file if a name came in with the UDP message */ if(strlen(udpbuffer) > 0) { DBG("writing file: %s\n", udpbuffer); /* open file for write. Path must pre-exist */ if((fd = open(udpbuffer, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) { OPRINT("could not open the file %s\n", udpbuffer); return NULL; } /* save picture to file */ if(write(fd, frame, frame_size) < 0) { OPRINT("could not write to file %s\n", udpbuffer); perror("write()"); close(fd); return NULL; } close(fd); } // send back client's message that came in udpbuffer sendto(sd, udpbuffer, bytes, 0, (struct sockaddr*)&addr, sizeof(addr)); /* call the command if user specified one, pass current filename as argument */ if(command != NULL) { memset(buffer1, 0, sizeof(buffer1)); /* udpbuffer still contains the filename, pass it to the command as parameter */ snprintf(buffer1, sizeof(buffer1), "%s \"%s\"", command, udpbuffer); DBG("calling command %s", buffer1); /* in addition provide the filename as environment variable */ if((rc = setenv("MJPG_FILE", udpbuffer, 1)) != 0) { LOG("setenv failed (return value %d)\n", rc); } /* execute the command now */ if((rc = system(buffer1)) != 0) { LOG("command failed (return value %d)\n", rc); } } } // close UDP port if(port > 0) close(sd); /* cleanup now */ pthread_cleanup_pop(1); return NULL; }
/****************************************************************************** Description.: Initialize this plugin. parse configuration parameters, store the parsed values in global variables Input Value.: All parameters to work with. Among many other variables the "param->id" is quite important - it is used to distinguish between several server instances Return Value: 0 if everything is OK, other values signal an error ******************************************************************************/ int output_init(output_parameter *param, int id) { int i; int port; char *credentials, *www_folder; char nocommands; DBG("output #%02d\n", param->id); port = htons(8080); credentials = NULL; www_folder = NULL; nocommands = 0; param->argv[0] = OUTPUT_PLUGIN_NAME; /* show all parameters for DBG purposes */ for(i = 0; i < param->argc; i++) { DBG("argv[%d]=%s\n", i, param->argv[i]); } reset_getopt(); while(1) { int option_index = 0, c = 0; static struct option long_options[] = { {"h", no_argument, 0, 0 }, {"help", no_argument, 0, 0}, {"p", required_argument, 0, 0}, {"port", required_argument, 0, 0}, {"c", required_argument, 0, 0}, {"credentials", required_argument, 0, 0}, {"w", required_argument, 0, 0}, {"www", required_argument, 0, 0}, {"n", no_argument, 0, 0}, {"nocommands", no_argument, 0, 0}, {0, 0, 0, 0} }; c = getopt_long_only(param->argc, param->argv, "", long_options, &option_index); /* no more options to parse */ if(c == -1) break; /* unrecognized option */ if(c == '?') { help(); return 1; } switch(option_index) { /* h, help */ case 0: case 1: DBG("case 0,1\n"); help(); return 1; break; /* p, port */ case 2: case 3: DBG("case 2,3\n"); port = htons(atoi(optarg)); break; /* c, credentials */ case 4: case 5: DBG("case 4,5\n"); credentials = strdup(optarg); break; /* w, www */ case 6: case 7: DBG("case 6,7\n"); www_folder = malloc(strlen(optarg) + 2); strcpy(www_folder, optarg); if(optarg[strlen(optarg)-1] != '/') strcat(www_folder, "/"); break; /* n, nocommands */ case 8: case 9: DBG("case 8,9\n"); nocommands = 1; break; } } servers[param->id].id = param->id; servers[param->id].pglobal = param->global; servers[param->id].conf.port = port; servers[param->id].conf.credentials = credentials; servers[param->id].conf.www_folder = www_folder; servers[param->id].conf.nocommands = nocommands; OPRINT("www-folder-path...: %s\n", (www_folder == NULL) ? "disabled" : www_folder); OPRINT("HTTP TCP port.....: %d\n", ntohs(port)); OPRINT("username:password.: %s\n", (credentials == NULL) ? "disabled" : credentials); OPRINT("commands..........: %s\n", (nocommands) ? "disabled" : "enabled"); return 0; }
/****************************************************************************** Description.: this function is called first, in order to initialise this plugin and pass a parameter string Input Value.: parameters Return Value: 0 if everything is ok, non-zero otherwise ******************************************************************************/ int output_init(output_parameter *param) { char *argv[MAX_ARGUMENTS]={NULL}; int argc=1, i; delay = 10000; /* convert the single parameter-string to an array of strings */ argv[0] = OUTPUT_PLUGIN_NAME; if ( param->parameter_string != NULL && strlen(param->parameter_string) != 0 ) { char *arg=NULL, *saveptr=NULL, *token=NULL; arg=(char *)strdup(param->parameter_string); if ( strchr(arg, ' ') != NULL ) { token=strtok_r(arg, " ", &saveptr); if ( token != NULL ) { argv[argc] = strdup(token); argc++; while ( (token=strtok_r(NULL, " ", &saveptr)) != NULL ) { argv[argc] = strdup(token); argc++; if (argc >= MAX_ARGUMENTS) { OPRINT("ERROR: too many arguments to output plugin\n"); return 1; } } } } } /* show all parameters for DBG purposes */ for (i=0; i<argc; i++) { DBG("argv[%d]=%s\n", i, argv[i]); } reset_getopt(); while(1) { int option_index = 0, c=0; static struct option long_options[] = \ { {"h", no_argument, 0, 0}, {"help", no_argument, 0, 0}, {"d", required_argument, 0, 0}, {"delay", required_argument, 0, 0}, {0, 0, 0, 0} }; c = getopt_long_only(argc, argv, "", long_options, &option_index); /* no more options to parse */ if (c == -1) break; /* unrecognized option */ if (c == '?'){ help(); return 1; } switch (option_index) { /* h, help */ case 0: case 1: DBG("case 0,1\n"); help(); return 1; break; /* d, delay */ case 2: case 3: DBG("case 2,3\n"); delay = atoi(optarg); break; } } pglobal = param->global; OPRINT("delay.............: %d\n", delay); return 0; }
/****************************************************************************** Description.: this is the main worker thread it loops forever, grabs a fresh frame, decompressed the JPEG and displays the decoded data using SDL Input Value.: Return Value: ******************************************************************************/ void *worker_thread(void *arg) { int frame_size = 0, firstrun = 1; SDL_Surface *screen = NULL, *image = NULL; decompressed_image rgbimage; /* initialze the buffer for the decompressed image */ rgbimage.buffersize = 0; rgbimage.buffer = NULL; /* initialze the SDL video subsystem */ if(SDL_Init(SDL_INIT_VIDEO) < 0) { fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError()); exit(EXIT_FAILURE); } /* just allocate a large buffer for the JPEGs */ if((frame = malloc(4096 * 1024)) == NULL) { OPRINT("not enough memory for worker thread\n"); exit(EXIT_FAILURE); } /* set cleanup handler to cleanup allocated ressources */ pthread_cleanup_push(worker_cleanup, NULL); while(!pglobal->stop) { DBG("waiting for fresh frame\n"); pthread_mutex_lock(&pglobal->in[input_number].db); pthread_cond_wait(&pglobal->in[plugin_number].db_update, &pglobal->in[plugin_number].db); /* read buffer */ frame_size = pglobal->in[plugin_number].size; memcpy(frame, pglobal->in[plugin_number].buf, frame_size); pthread_mutex_unlock(&pglobal->in[plugin_number].db); /* decompress the JPEG and store results in memory */ if(decompress_jpeg(frame, frame_size, &rgbimage)) { DBG("could not properly decompress JPEG data\n"); continue; } if(firstrun) { /* create the primary surface (the visible window) */ screen = SDL_SetVideoMode(rgbimage.width, rgbimage.height, 0, SDL_ANYFORMAT | SDL_HWSURFACE); SDL_WM_SetCaption("MJPG-Streamer Viewer", NULL); /* create a SDL surface to display the data */ image = SDL_AllocSurface(SDL_SWSURFACE, rgbimage.width, rgbimage.height, 24, #if SDL_BYTEORDER == SDL_LIL_ENDIAN 0x0000FF, 0x00FF00, 0xFF0000, #else 0xFF0000, 0x00FF00, 0x0000FF, #endif 0); /* copy the decoded data across */ memcpy(image->pixels, rgbimage.buffer, rgbimage.width * rgbimage.height * 3); free(rgbimage.buffer); /* now, that we know the dimensions, we can directly copy to the right surface */ rgbimage.buffer = image->pixels; rgbimage.buffersize = rgbimage.width * rgbimage.height * 3; firstrun = 0; } /* copy the image to the primary surface */ SDL_BlitSurface(image, NULL, screen, NULL); /* redraw the whole surface */ SDL_Flip(screen); } pthread_cleanup_pop(1); /* get rid of the image */ SDL_FreeSurface(image); return NULL; }
void printDuration(struct timeval *start, struct timeval *end, char * text) { #ifdef PRINT_TIMESTAMPS OPRINT("%s: Start: %d:%d, End: %d:%d, Duration: %d:%d\n", text, start->tv_sec, start->tv_usec, end->tv_sec, end->tv_usec, end->tv_sec - start->tv_sec, end->tv_usec - start->tv_usec); #endif }
/****************************************************************************** Description.: this function is called first, in order to initialise this plugin and pass a parameter string Input Value.: parameters Return Value: 0 if everything is ok, non-zero otherwise ******************************************************************************/ int output_init(output_parameter *param) { int i; delay = 0; param->argv[0] = OUTPUT_PLUGIN_NAME; /* show all parameters for DBG purposes */ for(i = 0; i < param->argc; i++) { DBG("argv[%d]=%s\n", i, param->argv[i]); } reset_getopt(); while(1) { int option_index = 0, c = 0; static struct option long_options[] = { {"h", no_argument, 0, 0 }, {"help", no_argument, 0, 0}, {"f", required_argument, 0, 0}, {"folder", required_argument, 0, 0}, {"d", required_argument, 0, 0}, {"delay", required_argument, 0, 0}, {"c", required_argument, 0, 0}, {"command", required_argument, 0, 0}, {"p", required_argument, 0, 0}, {"port", required_argument, 0, 0}, {"i", required_argument, 0, 0}, {"input", required_argument, 0, 0}, {0, 0, 0, 0} }; c = getopt_long_only(param->argc, param->argv, "", long_options, &option_index); /* no more options to parse */ if(c == -1) break; /* unrecognized option */ if(c == '?') { help(); return 1; } switch(option_index) { /* h, help */ case 0: case 1: DBG("case 0,1\n"); help(); return 1; break; /* f, folder */ case 2: case 3: DBG("case 2,3\n"); folder = malloc(strlen(optarg) + 1); strcpy(folder, optarg); if(folder[strlen(folder)-1] == '/') folder[strlen(folder)-1] = '\0'; break; /* d, delay */ case 4: case 5: DBG("case 4,5\n"); delay = atoi(optarg); break; /* c, command */ case 6: case 7: DBG("case 6,7\n"); command = strdup(optarg); break; /* p, port */ case 8: case 9: DBG("case 8,9\n"); port = atoi(optarg); break; /* i, input */ case 10: case 11: DBG("case 10,11\n"); input_number = atoi(optarg); break; } } pglobal = param->global; if(!(input_number < pglobal->incnt)) { OPRINT("ERROR: the %d input_plugin number is too much only %d plugins loaded\n", input_number, pglobal->incnt); return 1; } OPRINT("input plugin.....: %d: %s\n", input_number, pglobal->in[input_number].plugin); OPRINT("output folder.....: %s\n", folder); OPRINT("delay after save..: %d\n", delay); OPRINT("command...........: %s\n", (command == NULL) ? "disabled" : command); if(port > 0) { OPRINT("UDP port..........: %d\n", port); } else { OPRINT("UDP port..........: %s\n", "disabled"); } return 0; }
/****************************************************************************** Description.: this function is called first, in order to initialise this plugin and pass a parameter string Input Value.: parameters Return Value: 0 if everything is ok, non-zero otherwise ******************************************************************************/ int output_init(output_parameter *param) { int i; delay = 10000; param->argv[0] = OUTPUT_PLUGIN_NAME; /* show all parameters for DBG purposes */ for(i = 0; i < param->argc; i++) { DBG("argv[%d]=%s\n", i, param->argv[i]); } reset_getopt(); while(1) { int option_index = 0, c = 0; static struct option long_options[] = { {"h", no_argument, 0, 0 }, {"help", no_argument, 0, 0}, {"d", required_argument, 0, 0}, {"delay", required_argument, 0, 0}, {"i", required_argument, 0, 0}, {"input", required_argument, 0, 0}, {0, 0, 0, 0} }; c = getopt_long_only(param->argc, param->argv, "", long_options, &option_index); /* no more options to parse */ if(c == -1) break; /* unrecognized option */ if(c == '?') { help(); return 1; } switch(option_index) { /* h, help */ case 0: case 1: DBG("case 0,1\n"); help(); return 1; break; /* d, delay */ case 2: case 3: DBG("case 2,3\n"); delay = atoi(optarg); break; /* i input */ case 4: case 5: plugin_number = atoi(optarg); break; } } pglobal = param->global; OPRINT("delay.............: %d\n", delay); return 0; }
/****************************************************************************** Description.: this function is called first, in order to initialize this plugin and pass a parameter string Input Value.: parameters Return Value: 0 if everything is OK, non-zero otherwise ******************************************************************************/ int output_init(output_parameter *param) { int i; param->argv[0] = OUTPUT_PLUGIN_NAME; /* show all parameters for DBG purposes */ for(i = 0; i < param->argc; i++) { DBG("argv[%d]=%s\n", i, param->argv[i]); } reset_getopt(); while(1) { int option_index = 0, c = 0; static struct option long_options[] = { {"h", no_argument, 0, 0 }, {"help", no_argument, 0, 0}, {"s", required_argument, 0, 0}, {"server", required_argument, 0, 0}, {"p", required_argument, 0, 0}, {"port", required_argument, 0, 0}, {0, 0, 0, 0} }; c = getopt_long_only(param->argc, param->argv, "", long_options, &option_index); /* no more options to parse */ if(c == -1) break; /* unrecognized option */ if(c == '?') { help(); return 1; } switch(option_index) { /* h, help */ case 0: case 1: DBG("case 0,1\n"); help(); return 1; break; /* s, server */ case 2: case 3: DBG("case 2,3\n"); server = malloc(strlen(optarg) + 1); strcpy(server, optarg); break; /* p, port */ case 4: case 5: DBG("case 4,5\n"); port = atoi(optarg); break; } } pglobal = param->global; OPRINT("server.....: %s\n", server); OPRINT("port.......: %d\n", port); return 0; }
/****************************************************************************** Description.: Open a TCP socket and wait for clients to connect. If clients connect, start a new thread for each accepted connection. Input Value.: arg is a pointer to the globals struct Return Value: always NULL, will only return on exit ******************************************************************************/ void * HTTPDServerThread::Run( void ) { struct sockaddr_in addr; struct sockaddr_in client_addr; socklen_t addr_len = sizeof(struct sockaddr_in); int on; pthread_cleanup_push( CleanUpTrampoline, (void * ) this ); /* open socket for server */ fd = socket(PF_INET, SOCK_STREAM, 0); if ( fd < 0 ) { fprintf(stderr, "socket failed\n"); exit(EXIT_FAILURE); } /* ignore "socket already in use" errors */ on = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { perror("setsockopt(SO_REUSEADDR) failed"); exit(EXIT_FAILURE); } /* perhaps we will use this keep-alive feature oneday */ /* setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)); */ /* configure server address to listen to all local IPs */ memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons( server->GetHTTPPort() ); int e = inet_pton(AF_INET, server->GetHTTPAddr(), & addr.sin_addr ); if ( e <= 0 ) { if ( e == 0 ) { std::cerr << "Unable to parse addresse " << server->GetHTTPAddr() << std::endl; std::exit(2); } if ( e < 0 ) { perror("inet_pton failed:"); std::exit(2); } } if ( bind( fd, (struct sockaddr*)&addr, sizeof(addr)) != 0 ) { perror("bind:"); OPRINT("%s(): bind(%d) failed", __FUNCTION__, server->GetHTTPPort() ); closelog(); exit(EXIT_FAILURE); } /* start listening on socket */ if ( listen( fd, 10) != 0 ) { fprintf(stderr, "listen failed\n"); exit(EXIT_FAILURE); } /* create a child for every client that connects */ while ( 1 /*!pglobal->stop*/ ) { // //int *pfd = (int *)malloc(sizeof(int)); // cfd *pcfd = (cfd*)malloc(sizeof(cfd)); // if (pcfd == NULL) { // fprintf(stderr, "failed to allocate (a very small amount of) memory\n"); // exit(EXIT_FAILURE); //} DBG("waiting for clients to connect\n"); int cfd = accept( fd, (struct sockaddr *)&client_addr, &addr_len); HTTPDClientThread * client = new HTTPDClientThread( GetServer(), cfd ); /* start new thread that will handle this TCP connected client */ DBG("create thread to handle client that just established a connection\n"); syslog(LOG_INFO, "serving client: %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); if( client->StartAndDetach() != 0 ) { DBG("could not launch another client thread\n"); ::close(fd); } } DBG("leaving server thread, calling cleanup function now\n"); pthread_cleanup_pop(1); return NULL; }
/****************************************************************************** Description.: this is the main worker thread it loops forever, grabs a fresh frame and stores it to file Input Value.: Return Value: ******************************************************************************/ void *worker_thread(void *arg) { int ok = 1, frame_size = 0, rc = 0; char buffer1[1024] = {0}, buffer2[1024] = {0}; unsigned long long counter = 0; time_t t; struct tm *now; unsigned char *tmp_framebuffer = NULL; /* set cleanup handler to cleanup allocated resources */ pthread_cleanup_push(worker_cleanup, NULL); while(ok >= 0 && !pglobal->stop) { DBG("waiting for fresh frame\n"); pthread_mutex_lock(&pglobal->in[input_number].db); pthread_cond_wait(&pglobal->in[input_number].db_update, &pglobal->in[input_number].db); /* read buffer */ frame_size = pglobal->in[input_number].size; /* check if buffer for frame is large enough, increase it if necessary */ if(frame_size > max_frame_size) { DBG("increasing buffer size to %d\n", frame_size); max_frame_size = frame_size + (1 << 16); if((tmp_framebuffer = realloc(frame, max_frame_size)) == NULL) { pthread_mutex_unlock(&pglobal->in[input_number].db); LOG("not enough memory\n"); return NULL; } frame = tmp_framebuffer; } /* copy frame to our local buffer now */ memcpy(frame, pglobal->in[input_number].buf, frame_size); /* allow others to access the global buffer again */ pthread_mutex_unlock(&pglobal->in[input_number].db); if (mjpgFileName == NULL) { // single files with ringbuffer mode /* prepare filename */ memset(buffer1, 0, sizeof(buffer1)); memset(buffer2, 0, sizeof(buffer2)); /* get current time */ t = time(NULL); now = localtime(&t); if(now == NULL) { perror("localtime"); return NULL; } /* prepare string, add time and date values */ if(strftime(buffer1, sizeof(buffer1), "%%s/%Y_%m_%d_%H_%M_%S_picture_%%09llu.jpg", now) == 0) { OPRINT("strftime returned 0\n"); free(frame); frame = NULL; return NULL; } /* finish filename by adding the foldername and a counter value */ snprintf(buffer2, sizeof(buffer2), buffer1, folder, counter); counter++; DBG("writing file: %s\n", buffer2); /* open file for write */ if((fd = open(buffer2, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) { OPRINT("could not open the file %s\n", buffer2); return NULL; } /* save picture to file */ if(write(fd, frame, frame_size) < 0) { OPRINT("could not write to file %s\n", buffer2); perror("write()"); close(fd); return NULL; } close(fd); /* link the picture as fixed name file */ if (linkFileName) { snprintf(buffer1, sizeof(buffer1), "%s/%s", folder, linkFileName); unlink(buffer1); (void) link(buffer2, buffer1); } /* call the command if user specified one, pass current filename as argument */ if(command != NULL) { memset(buffer1, 0, sizeof(buffer1)); /* buffer2 still contains the filename, pass it to the command as parameter */ snprintf(buffer1, sizeof(buffer1), "%s \"%s\"", command, buffer2); DBG("calling command %s", buffer1); /* in addition provide the filename as environment variable */ if((rc = setenv("MJPG_FILE", buffer2, 1)) != 0) { LOG("setenv failed (return value %d)\n", rc); } /* execute the command now */ if((rc = system(buffer1)) != 0) { LOG("command failed (return value %d)\n", rc); } } /* * maintain ringbuffer * do not maintain ringbuffer for each picture, this saves resources since * each run of the maintainance function involves sorting/malloc/free operations */ if(ringbuffer_exceed <= 0) { /* keep ringbuffer excactly at specified siOUTPUT_PLUGIN_NAMEze */ maintain_ringbuffer(ringbuffer_size); } else if(counter == 1 || counter % (ringbuffer_exceed + 1) == 0) { DBG("counter: %llu, will clean-up now\n", counter); maintain_ringbuffer(ringbuffer_size); } } else { // recording to MJPG file /* save picture to file */ if(write(fd, frame, frame_size) < 0) { OPRINT("could not write to file %s\n", buffer2); perror("write()"); close(fd); return NULL; } } /* if specified, wait now */ if(delay > 0) { usleep(1000 * delay); } } /* cleanup now */ pthread_cleanup_pop(1); return NULL; }
/****************************************************************************** Description.: this is the main worker thread it loops forever, grabs a fresh frame and calculates focus Input Value.: Return Value: ******************************************************************************/ void *worker_thread( void *arg ) { int frame_size=0; double sv=-1.0, max_sv=100.0, delta=500; int focus=255, step=10, max_focus=100, search_focus=1; if ( (frame = malloc(256*1024)) == NULL ) { OPRINT("not enough memory for worker thread\n"); exit(EXIT_FAILURE); } /* set cleanup handler to cleanup allocated ressources */ pthread_cleanup_push(worker_cleanup, NULL); while ( !pglobal->stop ) { DBG("waiting for fresh frame\n"); pthread_cond_wait(&pglobal->db_update, &pglobal->db); /* read buffer */ frame_size = pglobal->size; memcpy(frame, pglobal->buf, frame_size); pthread_mutex_unlock( &pglobal->db ); /* process frame */ sv = getFrameSharpnessValue(frame, frame_size); DBG("sharpness is: %f\n", sv); if ( search_focus || (ABS(sv-max_sv) > delta) ) { DBG("adjusting focus: %d\n", focus); /* entered because focus changed */ if ( !search_focus ) { DBG("starting to search for focus\n"); max_focus = 255; focus = 255; max_sv = -1.0; search_focus = 1; } if ( focus <= 0 ) { focus = max_focus; DBG("max focus found at: %d\n", max_focus); search_focus = 0; } if ( search_focus ) { if (sv > max_sv) { /* sharpness is better then max now */ DBG("found better focus at: %d\n", focus); max_focus = focus; max_sv = sv; } focus = MIN(MAX(focus-step,0), 255); DBG("decrement focus now to: %d\n", focus); focus = pglobal->in.cmd(IN_CMD_FOCUS_SET, focus); } } if ( (delay > 0) && !search_focus ) { usleep(1000*delay); } } pthread_cleanup_pop(1); return NULL; }
/****************************************************************************** Description.: this is the main worker thread it loops forever, grabs a fresh frame and stores it to file Input Value.: Return Value: ******************************************************************************/ void *worker_thread(void *arg) { int ok = 1, frame_size = 0, rc = 0; char buffer1[1024] = {0}; unsigned char *tmp_framebuffer = NULL; /* set cleanup handler to cleanup allocated ressources */ pthread_cleanup_push(worker_cleanup, NULL); if(port <= 0) { OPRINT("a valid UDP port must be provided\n"); return NULL; } struct sockaddr_in addr; int sd; int bytes; unsigned int addr_len = sizeof(addr); char udpbuffer[1024] = {0}; sd = socket(PF_INET, SOCK_DGRAM, 0); bzero(&addr, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr(ip); addr.sin_port = htons(port); while(ok >= 0 && !pglobal->stop) { DBG("waiting for fresh frame\n"); pthread_mutex_lock(&pglobal->in[input_number].db); pthread_cond_wait(&pglobal->in[input_number].db_update, &pglobal->in[input_number].db); /* read buffer */ frame_size = pglobal->in[input_number].size; /* check if buffer for frame is large enough, increase it if necessary */ if(frame_size > max_frame_size) { DBG("increasing buffer size to %d\n", frame_size); max_frame_size = frame_size + (1 << 16); if((tmp_framebuffer = realloc(frame, max_frame_size)) == NULL) { pthread_mutex_unlock(&pglobal->in[input_number].db); LOG("not enough memory\n"); return NULL; } frame = tmp_framebuffer; } /* copy frame to our local buffer now */ memcpy(frame, pglobal->in[input_number].buf, frame_size); /* allow others to access the global buffer again */ pthread_mutex_unlock(&pglobal->in[input_number].db); // send frame to udp server printf("send: %d kb\n", frame_size/1024); output_sendto(sd, frame, frame_size, &addr); /* call the command if user specified one, pass current filename as argument */ if(command != NULL) { /* execute the command now */ if((rc = system(buffer1)) != 0) { LOG("command failed (return value %d)\n", rc); } } // /* if specified, wait now */ // if(delay > 0) { // usleep(1000 * delay); // } } // close UDP port if(port > 0) close(sd); /* cleanup now */ pthread_cleanup_pop(1); return NULL; }