X-Git-Url: http://git.osdn.net/view?p=rec10%2Frec10-git.git;a=blobdiff_plain;f=tunerec%2Ftunerec.c;h=fad6b6db6e550f46fc08cadeaea1c87d54334de3;hp=f3f3328a3c85b22a8f2a3989a62402b356cb2ac5;hb=27c2b252fe0472b2f24dc9c97aa3e8787bcb02c5;hpb=fc9f3fc7f1d02c8eff5a5f026d7a0fa4a814cdf9 diff --git a/tunerec/tunerec.c b/tunerec/tunerec.c index f3f3328..fad6b6d 100755 --- a/tunerec/tunerec.c +++ b/tunerec/tunerec.c @@ -1,3 +1,5 @@ +#define _FILE_OFFSET_BITS 64 + #include #include #include @@ -7,28 +9,124 @@ #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); +} -struct channel { - int id; - const char *name; - unsigned int frequency; - unsigned int ts_id; -}; -static int search(int adapter_nr,struct channel *ch) +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); + + 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 <= rb->rb_wt ) { + // 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; } @@ -38,27 +136,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; @@ -75,15 +162,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); @@ -108,47 +194,148 @@ 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]; + pthread_t read_thread, write_thread; + my_thread_arg arg; + + 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); + fin = open(input, (O_RDONLY)); + 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[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 > p->rectime || p->done ) { + break; + } + } + error: + p->done = true; + return NULL; +} + +void * record_write(void * priv) { + ssize_t rt = 0, wt, shift; + char buf[DVB_WRITE_BUFFER_SIZE]; + my_thread_arg* p = (my_thread_arg*)priv; - while (1) - sleep(3); + 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); + } - /* never returns */ + 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: + p->done = true; + return NULL; } int main(int argc, char *argv[]) { int adapter_nr; - int channel_id; int channel_freq; + 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 freq tsid rectime output\n", argv[0]); + fprintf(stderr, "Version: 0.0.1\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); - } - 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]); + fd = search(adapter_nr, channel_freq, channel_id); if (fd < 0) return 1; ret = track(adapter_nr); + record(adapter_nr, argv[5], rectime); close(fd); return ret < 0; } +