X-Git-Url: http://git.osdn.net/view?p=rec10%2Frec10-git.git;a=blobdiff_plain;f=tunerec%2Ftunerec.c;h=bce1a509ca1b2ebec757737d1cb04e3be0774a15;hp=9bcf0ea85a664dd73b7ccef179345f60ed3100f9;hb=0a45e038c6050197a919a1b59e6ecc95cb05df90;hpb=84e1fb811a91d13741e3ea60c5f3bc7f88fa6a6f diff --git a/tunerec/tunerec.c b/tunerec/tunerec.c index 9bcf0ea..bce1a50 100755 --- a/tunerec/tunerec.c +++ b/tunerec/tunerec.c @@ -1,3 +1,5 @@ +#define _FILE_OFFSET_BITS 64 + #include #include #include @@ -8,28 +10,125 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#ifndef DTV_STREAM_ID +#define DTV_STREAM_ID DTV_ISDBS_TS_ID +#endif +#define DVB_READ_BUFFER_SIZE 188 * 128 +#define DVB_WRITE_BUFFER_SIZE 1024 * 1024 +#define DMX_BUFFER_SIZE 1024 * 1024 +#define RING_BUFFER_SIZE 1024 * 1024 * 16 + +typedef struct { + void* rb_ptr; + int rb_wt; + int rb_rt; + int rb_ab; + pthread_mutex_t rb_mtx; +} mrb; + +typedef struct { + int fin; + int fout; + int rectime; + mrb rb; + bool done; +} my_thread_arg; + +void * record_read(void * priv); +void * record_write(void * priv); + +// TODO: switchable between VRB(virtual ring buffer) and MRB(My Ring Buffer) + +void mrb_init(mrb* rb, size_t size) { + rb->rb_ptr = malloc(size); + rb->rb_wt = rb->rb_rt = rb->rb_ab = 0; + pthread_mutex_init(&rb->rb_mtx, NULL); +} + +void mrb_destroy(mrb* rb) { + free(rb->rb_ptr); + pthread_mutex_destroy(&rb->rb_mtx); +} + +size_t mrb_data_len(mrb* rb) { + return rb->rb_ab; +} + +bool mrb_put(mrb* rb, char *source, size_t size) { + int partial; + + if ( rb->rb_ab + size > RING_BUFFER_SIZE ) { + // RingBuffer overflow. + return false; + } + if ( rb->rb_wt + size <= RING_BUFFER_SIZE ) { + // written bytes + newly added bytes <= buffer max size + memcpy(rb->rb_ptr + rb->rb_wt, source, size); + rb->rb_wt = rb->rb_wt + size; + } + else { + // written bytes + newly added bytes > buffer max size + // wrap around. + partial = RING_BUFFER_SIZE - rb->rb_wt; + memcpy(rb->rb_ptr + rb->rb_wt, source, partial); + memcpy(rb->rb_ptr, source + partial, size - partial); + rb->rb_wt = rb->rb_wt + size - RING_BUFFER_SIZE; + } + pthread_mutex_lock(&rb->rb_mtx); + rb->rb_ab += size; + pthread_mutex_unlock(&rb->rb_mtx); -struct channel { - int id; - const char *name; - unsigned int frequency; - unsigned int ts_id; -}; -static int search(int adapter_nr,struct channel *ch) + return true; +} + +bool mrb_get(mrb* rb, char *target, size_t size) { + int partial; + + if ( rb->rb_ab < size ) { + // RingBuffer underflow. + return false; + } + if ( rb->rb_rt + size <= RING_BUFFER_SIZE ) { + // read bytes + newly taken bytes <= buffer max size + memcpy(target, rb->rb_ptr + rb->rb_rt, size); + rb->rb_rt = rb->rb_rt + size; + } + else { + // read bytes + newly taken bytes > buffer max size + // wrap around. + partial = RING_BUFFER_SIZE - rb->rb_rt; + memcpy(target, rb->rb_ptr + rb->rb_rt, partial); + memcpy(target + partial, rb->rb_ptr, size - partial); + rb->rb_rt = rb->rb_rt + size - RING_BUFFER_SIZE; + } + pthread_mutex_lock(&rb->rb_mtx); + rb->rb_ab -= size; + pthread_mutex_unlock(&rb->rb_mtx); + + return true; +} + +static int search(int adapter_nr, unsigned int frequency, unsigned int ts_id) { char file[256]; int fd; struct dvb_frontend_info info; - struct channel *channel; struct dtv_property prop[3]; struct dtv_properties props; int i; fe_status_t status; sprintf(file, "/dev/dvb/adapter%d/frontend0", adapter_nr); - if ((fd = open(file, O_RDWR)) < 0) { + if ((fd = open(file, (O_RDWR | O_CREAT | O_TRUNC), 0666)) < 0) { perror("open"); return -1; } @@ -39,27 +138,16 @@ static int search(int adapter_nr,struct channel *ch) goto out; } - if (info.type == FE_QPSK) { - channel = ch; - //channel = lookup_channel(channel_id, isdbs_channels, - // ARRAY_SIZE(isdbs_channels)); - } else if (info.type == FE_OFDM) { - channel = ch; - //channel = lookup_channel(channel_id, isdbt_channels, - // ARRAY_SIZE(isdbt_channels)); + if (info.type == FE_QPSK || info.type == FE_OFDM) { } else { fprintf(stderr, "Unknown type of adapter\n"); goto out; } - if (channel == NULL) { - fprintf(stderr, "Unknown id of channel\n"); - goto out; - } prop[0].cmd = DTV_FREQUENCY; - prop[0].u.data = channel->frequency; - prop[1].cmd = DTV_ISDBS_TS_ID; - prop[1].u.data = channel->ts_id; + prop[0].u.data = frequency; + prop[1].cmd = DTV_STREAM_ID; + prop[1].u.data = ts_id; prop[2].cmd = DTV_TUNE; props.props = prop; @@ -76,15 +164,14 @@ static int search(int adapter_nr,struct channel *ch) goto out; } if (status & FE_HAS_LOCK) { - fprintf(stderr, "Successfully tuned to %d(%d) .\n", - channel->frequency,channel->ts_id); + fprintf(stderr, "Successfully tuned to %d(%d).\n", + frequency, ts_id); return 0; } usleep(250 * 1000); } - fprintf(stderr, "Failed to tune to %s (status %02x).\n", - channel->name, status); + fprintf(stderr, "Failed to tune (status %02x).\n", status); out: close(fd); @@ -109,83 +196,165 @@ static int track(int adapter_nr) return -1; } - if (ioctl(fd, DMX_SET_PES_FILTER, &filter) < 0) { perror("ioctl DMX_SET_PES_FILTER"); close(fd); return -1; } + return 0; } void record(int adapter_nr, char* output, int rectime) { int fin, fout; char input[256]; - time_t start_time, current_time; - char buf[1316]; - ssize_t rt, wt; - int size_remain; + pthread_t read_thread, write_thread; + my_thread_arg arg; - fout = open(output, (O_WRONLY | O_CREAT | O_TRUNC)); + fout = open(output, (O_WRONLY | O_CREAT | O_TRUNC), 0666); if ( fout < 0 ) { printf("output file open failed\n"); return; } sprintf(input, "/dev/dvb/adapter%d/dvr0", adapter_nr); - start_time = time(NULL); fin = open(input, (O_RDONLY)); - while ( rt = read(fin, buf, 1316) ) { - while ( wt = write(fout, buf, rt) ) { - rt -= wt; - if ( rt == 0 ) break; - if ( wt == 0 ) { - printf("output file write failed\n"); + ioctl(fin, DMX_SET_BUFFER_SIZE, DMX_BUFFER_SIZE); + + mrb_init(&arg.rb, RING_BUFFER_SIZE); + arg.done = false; + arg.rectime = rectime; + arg.fin = fin; + arg.fout = fout; + pthread_create(&read_thread , NULL, record_read , &arg); + pthread_create(&write_thread, NULL, record_write, &arg); + pthread_join(write_thread, NULL); + pthread_join(read_thread, NULL); + + mrb_destroy(&arg.rb); + close(fin); + close(fout); +} + +void * record_read(void * priv) { + ssize_t rt; + time_t start_time, current_time; + char* buf = malloc(DVB_READ_BUFFER_SIZE); + my_thread_arg* p = (my_thread_arg*)priv; + + start_time = time(NULL); + while ( 1 ) { + rt = read(p->fin, buf, DVB_READ_BUFFER_SIZE); + //printf("read %d %d\n", p->fin, rt); + if ( rt == 0 ) { + printf("dvr0 file read failed\n"); + goto error; + } + if ( rt < 0 ) { + switch (errno) { + case EOVERFLOW: + printf("read overflow, continue\n"); + continue; + default: + printf("read finished. err=%d\n", errno); goto error; } } + + mrb_put(&p->rb, buf, rt); + + // TODO: time() at each DVB_READ_BUFFER_SIZE bytes read is not efficient, reduce frequency current_time = time(NULL); - if ( current_time - start_time > rectime ) { + if ( current_time - start_time > p->rectime || p->done ) { break; } } + error: + p->done = true; + return NULL; +} + +void * record_write(void * priv) { + ssize_t rt = 0, wt, shift; + char* buf = malloc(DVB_WRITE_BUFFER_SIZE); + my_thread_arg* p = (my_thread_arg*)priv; + + while ( 1 ) { + if ( mrb_get(&p->rb, buf, DVB_WRITE_BUFFER_SIZE) ) { + // sufficient buffer + rt = DVB_WRITE_BUFFER_SIZE; + } + else if ( p->done && mrb_data_len(&p->rb) > 0) { + // insufficient buffer, but no more buffer fill + rt = mrb_data_len(&p->rb); + mrb_get(&p->rb, buf, mrb_data_len(&p->rb)); + } + else if ( p->done ) { + // normal exit + break; + } + else { + usleep(100); + } + shift = 0; + while ( ( wt = write(p->fout, buf + shift, rt) ) > 0) { + //printf("write %d %d\n", p->fout, rt); + rt -= wt; + if ( rt == 0 ) break; + shift += wt; + } + if ( rt > 0 ) { + // [buf] is not correctly written to [fout] + printf("output file write failed. err=%d\n", errno); + goto error; + } + } error: - close(fin); - close(fout); + p->done = true; + return NULL; } int main(int argc, char *argv[]) { int adapter_nr; - int channel_id; int channel_freq; + int channel_phys; + int channel_id; int fd; int ret; int rectime; - if (argc <= 2) { - fprintf(stderr, "Usage: %s adapter_nr freq [tsid]\n", argv[0]); + if (argc != 6) { + fprintf(stderr, "Usage : %s adapter_nr channel tsid rectime output\n", argv[0]); + fprintf(stderr, " channel can be freqency or channel(TE1/BS1/CS1)\n"); + fprintf(stderr, "Version: 0.0.2\n"); return 1; } - struct channel *ch; adapter_nr = strtol(argv[1], NULL, 0); channel_freq = strtol(argv[2], NULL, 10); - channel_id=0; - if (argc >= 4){ - channel_id = strtol(argv[3], NULL, 10); - } - if ( argc == 5 ) { - rectime = atoi(argv[4]); - } - struct channel ch1 ={0,"",channel_freq,channel_id}; - ch = &ch1; - //struct channel ch;//{ 1, "NHK BS-1", 1318000, 0x40f1 } - //ch={0,"",argv} - fd = search(adapter_nr, ch); + channel_id = strtol(argv[3], NULL, 10); + rectime = atoi(argv[4]); + + if ( channel_freq == 0 ) { + channel_phys = atoi(argv[2] + 2); + if ( toupper(*argv[2]) == 'T' && toupper(*(argv[2] + 1)) == 'E' && channel_phys != 0 ) { + channel_freq = ( 473 + (channel_phys - 13) * 6 ) * 1000000 + 142857; + } + else if ( toupper(*argv[2]) == 'B' && toupper(*(argv[2] + 1)) == 'S' && channel_phys != 0 ) { + channel_freq = (channel_phys - 1) * 38360 / 2 + 1049480; + } + else if ( toupper(*argv[2]) == 'C' && toupper(*(argv[2] + 1)) == 'S' && channel_phys != 0 ) { + channel_freq = (channel_phys - 2) * 40000 / 2 + 1613000; + } + fprintf(stderr, "channel_freq = %d\n", channel_freq); + } + + fd = search(adapter_nr, channel_freq, channel_id); if (fd < 0) return 1; ret = track(adapter_nr); - record(adapter_nr, argv[3], rectime); + record(adapter_nr, argv[5], rectime); close(fd); return ret < 0; } +