bool cRecord::Start(int fd, unsigned short vpid, unsigned short * apids, int numpids) { fprintf(stderr, "%s:%s: fd %d, vpid 0x%02x\n", FILENAME, __FUNCTION__, fd, vpid); fprintf(stderr, "apids: "); for (int i = 0; i < numpids; i++) fprintf(stderr, "0x%02x ", apids[i]); fprintf(stderr, "\n"); file_fd = fd; demuxfd_count = 1 + numpids; //fixme: currently we only deal which what is called write_ts in earlier versions //not splitting is possible, because we dont have the filename here... for (unsigned int i = 0; i < demuxfd_count; i++) { unsigned short pid; if (i == 0) pid = vpid; else pid = apids[i-1]; if ((demuxfd[i] = setPesFilter(pid, DMX_OUT_TS_TAP)) < 0) { for (unsigned int j = 0; j < i; j++) unsetPesFilter(demuxfd[j]); fprintf(stderr, "error setting pes filter\n"); return false; } } if ((dvrfd = open(DVRDEV, O_RDONLY|O_NONBLOCK)) < 0) { while (demuxfd_count > 0) unsetPesFilter(demuxfd[--demuxfd_count]); fprintf(stderr, "error opening dvr device\n"); return false; } fprintf(stderr, "dvrfd %d\n", dvrfd); exit_flag = STREAM2FILE_STATUS_RUNNING; if (pthread_create(&demux_thread[0], 0, execute_demux_thread, this) != 0) { exit_flag = STREAM2FILE_STATUS_WRITE_OPEN_FAILURE; fprintf(stderr, "[stream2file]: error creating thread! (out of memory?)\n"); return false; } time(&record_start_time); fprintf(stderr, "record start time: %lu \n", record_start_time); return true; }
stream2file_error_msg_t start_recording(const char * const filename, const char * const info, const bool with_o_sync, const bool with_fdatasync, const unsigned long long splitsize, const unsigned int numpids, const unsigned short * const pids, const bool write_ts, const unsigned int ringbuffers) { int fd; char buf[FILENAMEBUFFERSIZE]; if (busy_count != 0) { if (exit_flag == STREAM2FILE_STATUS_RUNNING) return STREAM2FILE_BUSY; /* give threads a second to exit */ sleep(1); puts("[stream2file] recording attempt 2"); if (busy_count != 0) return STREAM2FILE_BUSY; } INC_BUSY_COUNT; strcpy(myfilename, filename); // write stream information (should wakeup the disk from standby, too) sprintf(buf, "%s.xml", filename); if ((fd = open(buf, O_SYNC | O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) >= 0) { write(fd, info, strlen(info)); fdatasync(fd); close(fd); } else { DEC_BUSY_COUNT; return STREAM2FILE_INVALID_DIRECTORY; } if (splitsize < TS_SIZE) { limit = 1099511627776ULL; // 1024GB, virtually no splitting } else limit = splitsize; use_o_sync = with_o_sync; use_fdatasync = with_fdatasync; if (ringbuffers < 20) ringbuffersize = IN_SIZE * 20; else ringbuffersize = IN_SIZE * ringbuffers; for (unsigned int i = 0; i < numpids; i++) { if (pids[i] > 0x1fff) { DEC_BUSY_COUNT; return STREAM2FILE_INVALID_PID; } if ((demuxfd[i] = setPesFilter(pids[i], write_ts ? DMX_OUT_TS_TAP : DMX_OUT_TAP)) < 0) { for (unsigned int j = 0; j < i; j++) unsetPesFilter(demuxfd[j]); DEC_BUSY_COUNT; return STREAM2FILE_PES_FILTER_FAILURE; } } demuxfd_count = numpids; if (write_ts) { if ((dvrfd = open(DVRDEV, O_RDONLY)) < 0) { while (demuxfd_count > 0) unsetPesFilter(demuxfd[--demuxfd_count]); DEC_BUSY_COUNT; return STREAM2FILE_DVR_OPEN_FAILURE; } exit_flag = STREAM2FILE_STATUS_RUNNING; pthread_create(&demux_thread[0], 0, DMXThread, &dvrfd); } else { exit_flag = STREAM2FILE_STATUS_RUNNING; for (unsigned int i = 0; i < numpids; i++) { INC_BUSY_COUNT; pthread_create(&demux_thread[i], 0, DMXThread, &demuxfd[i]); } DEC_BUSY_COUNT; } return STREAM2FILE_OK; }
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; }
stream2file_error_msg_t start_recording(const char * const filename, const char * const info, int mode, const bool with_o_sync, const bool with_fdatasync, const unsigned long long splitsize, const unsigned int numpids, const unsigned short * const pids, const bool write_ts, const unsigned int ringbuffers, const bool with_gen_psi ) { int fd; char buf[FILENAMEBUFFERSIZE]; if (busy_count != 0) { if (exit_flag == STREAM2FILE_STATUS_RUNNING) return STREAM2FILE_BUSY; /* give threads a second to exit */ sleep(1); puts("[stream2file]: recording attempt 2"); if (busy_count != 0) return STREAM2FILE_BUSY; } INC_BUSY_COUNT; strcpy(myfilename, filename); mymode = mode; // printf("start_recording: myfilename '%s' filename '%s'\n",myfilename,filename); // write stream information (should wakeup the disk from standby, too) sprintf(buf, "%s.xml", filename); if ((fd = open(buf, O_SYNC|O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, REC_FILE_PERMISSIONS)) >= 0) { write(fd, info, strlen(info)); fdatasync(fd); close(fd); } else { if (errno == EEXIST) printf("[stream2file] INFO: %s already exists, not overwriting\n", buf); else { fprintf(stderr, "[stream2file] trying to create %s, error %d (%m)\n", buf, errno); DEC_BUSY_COUNT; return STREAM2FILE_INVALID_DIRECTORY; } } if (splitsize < TS_SIZE) { limit = 1099511627776ULL; // 1024GB, virtually no splitting } else limit = splitsize; use_o_sync = with_o_sync; use_fdatasync = with_fdatasync; gen_psi = with_gen_psi; if (ringbuffers > 4) ringbuffersize = ((1 << 19) << 4); else ringbuffersize = ((1 << 19) << ringbuffers); printf("[stream2file]: ringbuffersize %d write_ts %d numpids %d\n", ringbuffersize, write_ts, numpids); for (unsigned int i = 0; i < numpids; i++) { if (pids[i] > 0x1fff) { DEC_BUSY_COUNT; return STREAM2FILE_INVALID_PID; } #ifndef HAVE_TRIPLEDRAGON demuxfd[i] = setPesFilter(pids[i], write_ts ? DMX_OUT_TS_TAP : DMX_OUT_TAP); #else demuxfd[i] = setPesFilter(pids[i], OUT_MEMORY); #endif if (demuxfd[i] < 0) { for (unsigned int j = 0; j < i; j++) unsetPesFilter(demuxfd[j]); DEC_BUSY_COUNT; return STREAM2FILE_PES_FILTER_FAILURE; } } demuxfd_count = numpids; if (write_ts) { #ifdef HAVE_TRIPLEDRAGON if ((dvrfd = open(DMXDEV, O_RDWR|O_NONBLOCK)) != -1) { ioctl(dvrfd, DEMUX_SELECT_SOURCE, INPUT_FROM_CHANNEL0); ioctl(dvrfd, DEMUX_SET_BUFFER_SIZE, 230400); struct demux_bucket_para dbp; dbp.unloader.unloader_type = UNLOADER_TYPE_TRANSPORT; dbp.unloader.threshold = 128; // one interrupt per 32kB if (ioctl(dvrfd, DEMUX_FILTER_BUCKET_SET, &dbp) < 0) perror("start_recording DEMUX_FILTER_BUCKET_SET"); } else #else if ((dvrfd = open(DVRDEV, O_RDONLY|O_NONBLOCK)) < 0) #endif { while (demuxfd_count > 0) unsetPesFilter(demuxfd[--demuxfd_count]); DEC_BUSY_COUNT; return STREAM2FILE_DVR_OPEN_FAILURE; } exit_flag = STREAM2FILE_STATUS_RUNNING; if (pthread_create(&demux_thread[0], 0, DMXThread, &dvrfd) != 0) { DEC_BUSY_COUNT; exit_flag = STREAM2FILE_STATUS_RECORDING_THREADS_FAILED; puts("[stream2file]: error creating thread! (out of memory?)"); while (demuxfd_count > 0) unsetPesFilter(demuxfd[--demuxfd_count]); close(dvrfd); return STREAM2FILE_RECORDING_THREADS_FAILED; } #ifdef HAVE_TRIPLEDRAGON if (ioctl(dvrfd, DEMUX_START) < 0) perror("start_recording DEMUX_START"); #endif } else { exit_flag = STREAM2FILE_STATUS_RUNNING; for (unsigned int i = 0; i < numpids; i++) { if (pthread_create(&demux_thread[i], 0, DMXThread, &demuxfd[i]) == 0) INC_BUSY_COUNT; else { DEC_BUSY_COUNT; exit_flag = STREAM2FILE_STATUS_RECORDING_THREADS_FAILED; puts("[stream2file]: error creating thread! (out of memory?)"); return STREAM2FILE_RECORDING_THREADS_FAILED; } } DEC_BUSY_COUNT; } /* this is set to 0 on program start and during stop_recording(). done this way, because stop_recording() is only called on a regular stopped recording. */ if (record_start_time == 0) time(&record_start_time); return STREAM2FILE_OK; }