int main (int argc, char ** argv) { int pid; int pids[MAXPIDS]; char *fname; ssize_t written; int i; pthread_t rcst; int fd; if (argc < 4 ) { dprintf("Usage: streamfile file vpid apid [ pid3 pid4 ... ] (HEX-values without leading 0x!)\n"); dprintf("file: filename without trailing '.ts'\n"); return EXIT_FAILURE; } // set signal handler for clean termination signal(SIGTERM, clean_exit); buf = (unsigned char *) malloc(IN_SIZE); memset(buf, 0x00, IN_SIZE); if (buf == NULL) { perror("malloc buf"); return EXIT_FAILURE; } i = 1; while (argv[i][0] == '-') { if (!strcmp(argv[i], "-s")) silent = 1; if (!strcmp(argv[i], "-l")) sscanf(argv[++i], "%d", &limit); i++; } if (limit <= 0) limit=2; fname = argv[i++]; for (; i < argc; i++) { sscanf(argv[i], "%x", &pid); if (pid>0x1fff){ printf ("invalid pid 0x%04x specified\n",pid); return EXIT_FAILURE; } pids[demuxfd_count] = pid; if ((demuxfd[demuxfd_count] = setPesFilter(pid)) < 0) break; dprintf("set filter for pid 0x%x\n", pid); demuxfd_count++; } // create and delete temp-file to wakeup the disk from standby sprintf(buf, "%s.tmp", fname); fd = open(buf, O_SYNC | O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK, S_IRUSR | S_IWUSR); write(fd, buf, IN_SIZE); fdatasync(fd); close(fd); unlink(buf); if ((dvrfd = open(DVRDEV, O_RDONLY)) < 0) { free(buf); perror ("[streamfile]: open dvr"); return EXIT_FAILURE; } ringbuf = ringbuffer_create (RINGBUFFERSIZE); pthread_create (&rcst, 0, FileThread, fname); /* write raw transport stream */ int offset=0; ringbuffer_data_t vec[2]; ssize_t r=0; ssize_t todo; ssize_t todo2; while (!exit_flag) { r = read(dvrfd, buf, IN_SIZE); if (r > 0) { offset = sync_byte_offset(buf, r); if (offset != -1) break; } } written = ringbuffer_write(ringbuf, buf + offset, r - offset); // TODO: Retry if (written != r - offset) { dprintf("PANIC: wrote less than requested to ringbuffer, written %d, requested %d\n", written, r - offset); exit_flag = 1; } todo = IN_SIZE - (r - offset); if (todo == 0) todo = IN_SIZE; while (!exit_flag) { ringbuffer_get_write_vector(ringbuf, &(vec[0])); todo2 = todo - vec[0].len; if (todo2 < 0) { todo2 = 0; } else { if (todo2 > vec[1].len) { dprintf("PANIC: not enough space in ringbuffer, available %d, needed %d\n", vec[0].len + vec[1].len, todo + todo2); exit_flag = 1; } todo = vec[0].len; } while (!exit_flag) { r = read(dvrfd, vec[0].buf, todo); if (r > 0) { ringbuffer_write_advance(ringbuf, r); if (todo == r) { if (todo2 == 0) goto next; todo = todo2; todo2 = 0; vec[0].buf = vec[1].buf; } else { vec[0].buf += r; todo -= r; } } } next: todo = IN_SIZE; } //sleep(1); // give FileThread some time to write remaining content of ringbuffer to file // pthread_kill(rcst, SIGKILL); while (demuxfd_count > 0) unsetPesFilter(demuxfd[--demuxfd_count]); close(dvrfd); pthread_join(rcst,NULL); free(buf); ringbuffer_free(ringbuf); dprintf("End of main(). All filters are unset now.\n"); return EXIT_SUCCESS; }
void * DMXThread(void * v_arg) { pthread_t file_thread; struct filenames_t filename_data; char filename_extension[3]; ringbuffer_data_t vec[2]; ssize_t written; ssize_t todo; ssize_t todo2; unsigned char buf[TS_SIZE]; int offset = 0; ssize_t r = 0; struct pollfd pfd = {*(int*)v_arg, POLLIN|POLLERR,0 }; int pres; ringbuffer_t * ringbuf = ringbuffer_create(ringbuffersize); filename_data.ringbuffer = ringbuf; if (v_arg == &dvrfd) { filename_data.extension = "ts"; } else { for (int i = 0; i < MAXPIDS; i++) if (v_arg == (&(demuxfd[i]))) sprintf(filename_extension, "%u", i); filename_data.extension = filename_extension; } pthread_create(&file_thread, 0, FileThread, &filename_data); if (v_arg == &dvrfd) while (exit_flag == STREAM2FILE_STATUS_RUNNING) { if ((pres=poll (&pfd, 1, 15000))>0) { if (!(pfd.revents&POLLIN)) { printf ("PANIC: error reading from demux, bailing out\n"); exit_flag = STREAM2FILE_STATUS_READ_FAILURE; } r = read(*(int *)v_arg, &(buf[0]), TS_SIZE); if (r > 0) { offset = sync_byte_offset(&(buf[0]), r); if (offset != -1) break; } } else if (!pres) { printf ("[stream2file]: timeout from demux\n"); } } else offset = 0; written = ringbuffer_write(ringbuf, (char *)&(buf[offset]), r - offset); // TODO: Retry if (written != r - offset) { printf("PANIC: wrote less than requested to ringbuffer, written %d, requested %d\n", written, r - offset); exit_flag = STREAM2FILE_STATUS_BUFFER_OVERFLOW; } todo = IN_SIZE - (r - offset); /* IN_SIZE > TS_SIZE => todo > 0 */ while (exit_flag == STREAM2FILE_STATUS_RUNNING) { ringbuffer_get_write_vector(ringbuf, &(vec[0])); todo2 = todo - vec[0].len; if (todo2 < 0) { todo2 = 0; } else { if (((size_t)todo2) > vec[1].len) { printf("PANIC: not enough space in ringbuffer, available %d, needed %d\n", vec[0].len + vec[1].len, todo + todo2); exit_flag = STREAM2FILE_STATUS_BUFFER_OVERFLOW; } todo = vec[0].len; } while (exit_flag == STREAM2FILE_STATUS_RUNNING) { if ((pres=poll (&pfd, 1, 15000))>0) { if (!(pfd.revents&POLLIN)) { printf ("PANIC: error reading from demux, bailing out\n"); exit_flag = STREAM2FILE_STATUS_READ_FAILURE; } r = read(*(int *)v_arg, vec[0].buf, todo); if (r > 0) { ringbuffer_write_advance(ringbuf, r); if (todo == r) { if (todo2 == 0) goto next; todo = todo2; todo2 = 0; vec[0].buf = vec[1].buf; } else { vec[0].buf += r; todo -= r; } } } else if (!pres){ printf ("[stream2file]: timeout reading from demux\n"); goto next; } } next: todo = IN_SIZE; } if (v_arg == &dvrfd) close(*(int *)v_arg); else unsetPesFilter(*(int *)v_arg); pthread_join(file_thread, NULL); ringbuffer_free(ringbuf); if (v_arg == &dvrfd) while (demuxfd_count > 0) unsetPesFilter(demuxfd[--demuxfd_count]); DEC_BUSY_COUNT; if ((v_arg == &dvrfd) || (v_arg == (&(demuxfd[0])))) { CEventServer eventServer; eventServer.registerEvent2(NeutrinoMessages::EVT_RECORDING_ENDED, CEventServer::INITID_NEUTRINO, "/tmp/neutrino.sock"); stream2file_status2_t s; s.status = exit_flag; strncpy(s.dir,dirname(myfilename),100); eventServer.sendEvent(NeutrinoMessages::EVT_RECORDING_ENDED, CEventServer::INITID_NEUTRINO, &s, sizeof(s)); printf("[stream2file] pthreads exit code: %u\n", exit_flag); } pthread_exit(NULL); }
void cRecord::DMXThread() { pthread_t file_thread; ringbuffer_data_t vec[2]; ssize_t written; ssize_t todo = 0; ssize_t todo2; unsigned char buf[TS_SIZE]; int offset = 0; ssize_t r = 0; struct pollfd pfd; int pres; fprintf(stderr, "%s:%s >\n", __FILE__, __FUNCTION__); pfd.fd = dvrfd; pfd.events = POLLIN|POLLERR; pfd.revents = 0; ringbuffer_t * ringbuf = ringbuffer_create(ringbuffersize); if (!ringbuf) { exit_flag = STREAM2FILE_STATUS_WRITE_OPEN_FAILURE; fprintf(stderr, "[stream2file]: error allocating ringbuffer! (out of memory?)\n"); } else fprintf(stderr, "[stream2file] allocated ringbuffer size: %ld\n", ringbuffer_write_space(ringbuf)); ringbuffer = ringbuf; if (pthread_create(&file_thread, 0, execute_file_thread, this) != 0) { exit_flag = STREAM2FILE_STATUS_WRITE_OPEN_FAILURE; fprintf(stderr, "[stream2file]: error creating file_thread! (out of memory?)\n"); } while (exit_flag == STREAM2FILE_STATUS_RUNNING) { if ((pres=poll (&pfd, 1, 15000))>0) { if (!(pfd.revents&POLLIN)) { fprintf(stderr, "[stream2file]: PANIC: error reading from demux, bailing out\n"); exit_flag = STREAM2FILE_STATUS_READ_FAILURE; } r = read(dvrfd, &(buf[0]), TS_SIZE); if (r > 0) { offset = sync_byte_offset(&(buf[0]), r); if (offset != -1) break; } } else if (!pres) { fprintf(stderr, "[stream2file]: timeout from demux\n"); } } if (exit_flag == STREAM2FILE_STATUS_RUNNING) { written = ringbuffer_write(ringbuf, (char *)&(buf[offset]), r - offset); // TODO: Retry if (written != r - offset) { fprintf(stderr, "PANIC: wrote less than requested to ringbuffer, written %d, requested %d\n", written, r - offset); exit_flag = STREAM2FILE_STATUS_BUFFER_OVERFLOW; } todo = IN_SIZE - (r - offset); } /* IN_SIZE > TS_SIZE => todo > 0 */ while (exit_flag == STREAM2FILE_STATUS_RUNNING) { ringbuffer_get_write_vector(ringbuf, &(vec[0])); todo2 = todo - vec[0].len; if (todo2 < 0) { todo2 = 0; } else { if (((size_t)todo2) > vec[1].len) { fprintf(stderr, "PANIC: not enough space in ringbuffer, available %d, needed %d\n", vec[0].len + vec[1].len, todo + todo2); exit_flag = STREAM2FILE_STATUS_BUFFER_OVERFLOW; } todo = vec[0].len; } while (exit_flag == STREAM2FILE_STATUS_RUNNING) { if ((pres=poll (&pfd, 1, 5000))>0) { if (!(pfd.revents&POLLIN)) { fprintf(stderr, "PANIC: error reading from demux, bailing out\n"); exit_flag = STREAM2FILE_STATUS_READ_FAILURE; } r = read(dvrfd, vec[0].buf, todo); if (r > 0) { ringbuffer_write_advance(ringbuf, r); if (todo == r) { if (todo2 == 0) goto next; todo = todo2; todo2 = 0; vec[0].buf = vec[1].buf; } else { vec[0].buf += r; todo -= r; } } } else if (!pres){ fprintf(stderr, "[stream2file]: timeout reading from demux\n"); exit_flag = STREAM2FILE_STATUS_READ_FAILURE; } } next: todo = IN_SIZE; } close(dvrfd); pthread_join(file_thread, NULL); if (ringbuf) ringbuffer_free(ringbuf); while (demuxfd_count > 0) unsetPesFilter(demuxfd[--demuxfd_count]); #ifdef needed //fixme: do we need it? CEventServer eventServer; eventServer.registerEvent2(NeutrinoMessages::EVT_RECORDING_ENDED, CEventServer::INITID_NEUTRINO, "/tmp/neutrino.sock"); stream2file_status2_t s; s.status = exit_flag; strncpy(s.filename,basename(myfilename),512); s.filename[511] = '\0'; strncpy(s.dir,dirname(myfilename),100); s.dir[99] = '\0'; eventServer.sendEvent(NeutrinoMessages::EVT_RECORDING_ENDED, CEventServer::INITID_NEUTRINO, &s, sizeof(s)); fprintf(stderr, "[stream2file]: pthreads exit code: %i, dir: '%s', filename: '%s' myfilename: '%s'\n", exit_flag, s.dir, s.filename, myfilename); #endif fprintf(stderr, "%s:%s <\n", __FILE__, __FUNCTION__); pthread_exit(NULL); }