1 #define _FILE_OFFSET_BITS 64
3 #include <linux/dvb/frontend.h>
4 #include <linux/dvb/dmx.h>
5 #include <linux/dvb/audio.h>
6 #include <linux/dvb/version.h>
21 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
23 #define DTV_STREAM_ID DTV_ISDBS_TS_ID
25 #define DVB_READ_BUFFER_SIZE 188 * 128
26 #define DVB_WRITE_BUFFER_SIZE 1024 * 1024
27 #define DMX_BUFFER_SIZE 1024 * 1024
28 #define RING_BUFFER_SIZE 1024 * 1024 * 16
35 pthread_mutex_t rb_mtx;
46 void * record_read(void * priv);
47 void * record_write(void * priv);
49 // TODO: switchable between VRB(virtual ring buffer) and MRB(My Ring Buffer)
51 void mrb_init(mrb* rb, size_t size) {
52 rb->rb_ptr = malloc(size);
53 rb->rb_wt = rb->rb_rt = rb->rb_ab = 0;
54 pthread_mutex_init(&rb->rb_mtx, NULL);
57 void mrb_destroy(mrb* rb) {
59 pthread_mutex_destroy(&rb->rb_mtx);
62 size_t mrb_data_len(mrb* rb) {
66 bool mrb_put(mrb* rb, char *source, size_t size) {
69 if ( rb->rb_ab + size > RING_BUFFER_SIZE ) {
70 // RingBuffer overflow.
73 if ( rb->rb_wt + size <= RING_BUFFER_SIZE ) {
74 // written bytes + newly added bytes <= buffer max size
75 memcpy(rb->rb_ptr + rb->rb_wt, source, size);
76 rb->rb_wt = rb->rb_wt + size;
79 // written bytes + newly added bytes > buffer max size
81 partial = RING_BUFFER_SIZE - rb->rb_wt;
82 memcpy(rb->rb_ptr + rb->rb_wt, source, partial);
83 memcpy(rb->rb_ptr, source + partial, size - partial);
84 rb->rb_wt = rb->rb_wt + size - RING_BUFFER_SIZE;
86 pthread_mutex_lock(&rb->rb_mtx);
88 pthread_mutex_unlock(&rb->rb_mtx);
93 bool mrb_get(mrb* rb, char *target, size_t size) {
96 if ( rb->rb_ab < size ) {
97 // RingBuffer underflow.
100 if ( rb->rb_rt + size <= RING_BUFFER_SIZE ) {
101 // read bytes + newly taken bytes <= buffer max size
102 memcpy(target, rb->rb_ptr + rb->rb_rt, size);
103 rb->rb_rt = rb->rb_rt + size;
106 // read bytes + newly taken bytes > buffer max size
108 partial = RING_BUFFER_SIZE - rb->rb_rt;
109 memcpy(target, rb->rb_ptr + rb->rb_rt, partial);
110 memcpy(target + partial, rb->rb_ptr, size - partial);
111 rb->rb_rt = rb->rb_rt + size - RING_BUFFER_SIZE;
113 pthread_mutex_lock(&rb->rb_mtx);
115 pthread_mutex_unlock(&rb->rb_mtx);
120 static int search(int adapter_nr, unsigned int frequency, unsigned int ts_id)
124 struct dvb_frontend_info info;
125 struct dtv_property prop[3];
126 struct dtv_properties props;
130 sprintf(file, "/dev/dvb/adapter%d/frontend0", adapter_nr);
131 if ((fd = open(file, (O_RDWR | O_CREAT | O_TRUNC), 0666)) < 0) {
136 if (ioctl(fd, FE_GET_INFO, &info) < 0) {
137 perror("ioctl FE_GET_INFO");
141 if (info.type == FE_QPSK || info.type == FE_OFDM) {
143 fprintf(stderr, "Unknown type of adapter\n");
147 prop[0].cmd = DTV_FREQUENCY;
148 prop[0].u.data = frequency;
149 prop[1].cmd = DTV_STREAM_ID;
150 prop[1].u.data = ts_id;
151 prop[2].cmd = DTV_TUNE;
156 if ((ioctl(fd, FE_SET_PROPERTY, &props)) < 0) {
157 perror("ioctl FE_SET_PROPERTY");
161 for (i = 0; i < 4; i++) {
162 if (ioctl(fd, FE_READ_STATUS, &status) < 0) {
163 perror("ioctl FE_READ_STATUS");
166 if (status & FE_HAS_LOCK) {
167 fprintf(stderr, "Successfully tuned to %d(%d).\n",
174 fprintf(stderr, "Failed to tune (status %02x).\n", status);
181 static int track(int adapter_nr)
185 struct dmx_pes_filter_params filter;
188 filter.input = DMX_IN_FRONTEND;
189 filter.output = DMX_OUT_TS_TAP;
190 filter.pes_type = DMX_PES_VIDEO;
191 filter.flags = DMX_IMMEDIATE_START;
193 sprintf(file, "/dev/dvb/adapter%d/demux0", adapter_nr);
194 if ((fd = open(file, O_RDWR)) < 0) {
199 if (ioctl(fd, DMX_SET_PES_FILTER, &filter) < 0) {
200 perror("ioctl DMX_SET_PES_FILTER");
207 void record(int adapter_nr, char* output, int rectime) {
210 pthread_t read_thread, write_thread;
213 fout = open(output, (O_WRONLY | O_CREAT | O_TRUNC), 0666);
215 printf("output file open failed\n");
218 sprintf(input, "/dev/dvb/adapter%d/dvr0", adapter_nr);
219 fin = open(input, (O_RDONLY));
220 ioctl(fin, DMX_SET_BUFFER_SIZE, DMX_BUFFER_SIZE);
222 mrb_init(&arg.rb, RING_BUFFER_SIZE);
224 arg.rectime = rectime;
227 pthread_create(&read_thread , NULL, record_read , &arg);
228 pthread_create(&write_thread, NULL, record_write, &arg);
229 pthread_join(write_thread, NULL);
230 pthread_join(read_thread, NULL);
232 mrb_destroy(&arg.rb);
237 void * record_read(void * priv) {
239 time_t start_time, current_time;
240 char* buf = malloc(DVB_READ_BUFFER_SIZE);
241 my_thread_arg* p = (my_thread_arg*)priv;
243 start_time = time(NULL);
245 rt = read(p->fin, buf, DVB_READ_BUFFER_SIZE);
246 //printf("read %d %d\n", p->fin, rt);
248 printf("dvr0 file read failed\n");
254 printf("read overflow, continue\n");
257 printf("read finished. err=%d\n", errno);
262 mrb_put(&p->rb, buf, rt);
264 // TODO: time() at each DVB_READ_BUFFER_SIZE bytes read is not efficient, reduce frequency
265 current_time = time(NULL);
266 if ( current_time - start_time > p->rectime || p->done ) {
275 void * record_write(void * priv) {
276 ssize_t rt = 0, wt, shift;
277 char* buf = malloc(DVB_WRITE_BUFFER_SIZE);
278 my_thread_arg* p = (my_thread_arg*)priv;
281 if ( mrb_get(&p->rb, buf, DVB_WRITE_BUFFER_SIZE) ) {
283 rt = DVB_WRITE_BUFFER_SIZE;
285 else if ( p->done && mrb_data_len(&p->rb) > 0) {
286 // insufficient buffer, but no more buffer fill
287 rt = mrb_data_len(&p->rb);
288 mrb_get(&p->rb, buf, mrb_data_len(&p->rb));
290 else if ( p->done ) {
299 while ( ( wt = write(p->fout, buf + shift, rt) ) > 0) {
300 //printf("write %d %d\n", p->fout, rt);
302 if ( rt == 0 ) break;
306 // [buf] is not correctly written to [fout]
307 printf("output file write failed. err=%d\n", errno);
316 int main(int argc, char *argv[]) {
326 fprintf(stderr, "Usage : %s adapter_nr channel tsid rectime output\n", argv[0]);
327 fprintf(stderr, " channel can be freqency or channel(TE1/BS1/CS1)\n");
328 fprintf(stderr, "Version: 0.0.2\n");
331 adapter_nr = strtol(argv[1], NULL, 0);
332 channel_freq = strtol(argv[2], NULL, 10);
333 channel_id = strtol(argv[3], NULL, 10);
334 rectime = atoi(argv[4]);
336 if ( channel_freq == 0 ) {
337 channel_phys = atoi(argv[2] + 2);
338 if ( toupper(*argv[2]) == 'T' && toupper(*(argv[2] + 1)) == 'E' && channel_phys != 0 ) {
339 channel_freq = ( 473 + (channel_phys - 13) * 6 ) * 1000000 + 142857;
341 else if ( toupper(*argv[2]) == 'B' && toupper(*(argv[2] + 1)) == 'S' && channel_phys != 0 ) {
342 channel_freq = (channel_phys - 1) * 38360 / 2 + 1049480;
344 else if ( toupper(*argv[2]) == 'C' && toupper(*(argv[2] + 1)) == 'S' && channel_phys != 0 ) {
345 channel_freq = (channel_phys - 2) * 40000 / 2 + 1613000;
347 fprintf(stderr, "channel_freq = %d\n", channel_freq);
350 fd = search(adapter_nr, channel_freq, channel_id);
354 ret = track(adapter_nr);
355 record(adapter_nr, argv[5], rectime);