Credit Andrew - improve in-tree documentation
[goodguy/cinelerra.git] / cinelerra / dvbtune.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "guicast/bcwindowbase.inc"
23 #include "guicast/clip.h"
24 #include "condition.h"
25 #include "devicedvbinput.inc"
26 #include "dvbtune.h"
27 #include "mutex.h"
28
29 #include <errno.h>
30 #include <fcntl.h>
31 #ifdef HAVE_DVB
32 #include <linux/dvb/dmx.h>
33 #include <linux/dvb/frontend.h>
34 #endif
35 #include <stdio.h>
36 #include <string.h>
37 #include <sys/ioctl.h>
38 #include <unistd.h>
39
40
41
42
43 #ifdef HAVE_DVB
44 /* Frequency tables ripped straight off of pchdtv source code. */
45 /* DVB frequencies for US broadcast */
46 /* First two entries are to make the entries
47    line up with the channel number as index */
48 static unsigned long ntsc_dvb[ ] = {
49   0,  0,  57,  63,  69,  79,  85, 177, 183, 189 ,
50   195, 201, 207, 213, 473, 479, 485, 491, 497, 503 ,
51   509, 515, 521, 527, 533, 539, 545, 551, 557, 563 ,
52   569, 575, 581, 587, 593, 599, 605, 611, 617, 623 ,
53   629, 635, 641, 647, 653, 659, 665, 671, 677, 683 ,
54   689, 695, 701, 707, 713, 719, 725, 731, 737, 743 ,
55   749, 755, 761, 767, 773, 779, 785, 791, 797, 803 ,
56   809, 815, 821, 827, 833, 839, 845, 851, 857, 863 ,
57   869, 875, 881, 887, 893, 899, 905, 911, 917, 923 ,
58   929, 935, 941, 947, 953, 959, 965, 971, 977, 983 ,
59   989, 995, 1001, 1007, 1013, 1019, 1025, 1031, 1037, 1043
60 };
61
62 static unsigned long catv_dvb[] = {
63   0, 0, 57, 63, 69, 79, 85, 177, 183, 189,
64   195, 201, 207, 213, 123, 129, 135, 141, 147, 153,
65   159, 165, 171, 219, 225, 231, 237, 243, 249, 255,
66   261, 267, 273, 279, 285, 291, 297, 303, 309, 315,
67   321, 327, 333, 339, 345, 351, 357, 363, 369, 375,
68   381, 387, 393, 399, 405, 411, 417, 423, 429, 435,
69   441, 447, 453, 459, 465, 471, 477, 483, 489, 495,
70   501, 507, 513, 519, 525, 531, 537, 543, 549, 555,
71   561, 567, 573, 579, 585, 591, 597, 603, 609, 615,
72   621, 627, 633, 639, 645,  93,  99, 105, 111, 117,
73   651, 657, 663, 669, 675, 681, 687, 693, 699, 705,
74   711, 717, 723, 729, 735, 741, 747, 753, 759, 765,
75   771, 777, 783, 789, 795, 781, 807, 813, 819, 825,
76   831, 837, 843, 849, 855, 861, 867, 873, 879, 885,
77   891, 897, 903, 909, 915, 921, 927, 933, 939, 945,
78   951, 957, 963, 969, 975, 981, 987, 993, 999
79 };
80 #endif
81
82
83
84 DVBTune::DVBTune(RenderFarmClientThread *client)
85  : TunerServer(client)
86 {
87         reset();
88         buffer_lock = new Mutex("DVBTune::buffer_lock");
89 }
90
91 DVBTune::~DVBTune()
92 {
93         delete [] buffer;
94         delete buffer_lock;
95         delete thread;
96         delete status;
97 }
98
99 void DVBTune::reset()
100 {
101         frontend_fd = -1;
102         audio_fd = -1;
103         video_fd = -1;
104         dvr_fd = -1;
105         buffer = 0;
106         buffer_size = 0;
107         buffer_allocated = 0;
108         thread = 0;
109         status = 0;
110         has_lock = 0;
111 }
112
113 int DVBTune::open_tuner()
114 {
115 #ifdef HAVE_DVB
116         char frontend_path[BCTEXTLEN];
117         char demux_path[BCTEXTLEN];
118         char dvr_path[BCTEXTLEN];
119
120         sprintf(frontend_path, "/dev/dvb/adapter%d/frontend%d",
121                 get_device_number(),
122                 0);
123         sprintf(demux_path, "/dev/dvb/adapter%d/demux%d",
124                 get_device_number(),
125                 0);
126         sprintf(dvr_path, "/dev/dvb/adapter%d/dvr%d",
127                 get_device_number(),
128                 0);
129
130
131
132
133
134
135
136
137         if((frontend_fd = ::open(frontend_path, O_RDWR)) < 0)
138         {
139                 fprintf(stderr,
140                         "DVBTune::open_tuner %s: %s\n",
141                         frontend_path,
142                         strerror(errno));
143                 return 1;
144         }
145
146
147 // Open transport stream for reading
148         if((dvr_fd = ::open(dvr_path, O_RDONLY)) < 0)
149         {
150                 fprintf(stderr,
151                         "DVBTune::open_tuner %s: %s\n",
152                         dvr_path,
153                         strerror(errno));
154                 return 1;
155         }
156
157         struct dvb_frontend_parameters frontend_param;
158         bzero(&frontend_param, sizeof(frontend_param));
159
160 // Set frequency
161         int index = CLIP(TunerServer::get_channel(), 2, 69);
162         int table = TunerServer::get_table();
163         switch(table)
164         {
165                 case NETTUNE_AIR:
166                         frontend_param.frequency = ntsc_dvb[index] * 1000000;
167                         frontend_param.u.vsb.modulation = VSB_8;
168                         break;
169                 case NETTUNE_CABLE:
170                 frontend_param.frequency = catv_dvb[index] * 1000000;
171                 frontend_param.u.vsb.modulation = QAM_AUTO;
172                         break;
173         }
174
175
176         if(ioctl(frontend_fd, FE_SET_FRONTEND, &frontend_param) < 0)
177         {
178                 fprintf(stderr,
179                         "DVBTune::open_tuner FE_SET_FRONTEND frequency=%d: %s",
180                         frontend_param.frequency,
181                         strerror(errno));
182                 return 1;
183         }
184
185         if((video_fd = ::open(demux_path, O_RDWR)) < 0)
186         {
187                 fprintf(stderr,
188                         "DVBTune::open_tuner %s for video: %s\n",
189                         demux_path,
190                         strerror(errno));
191                 return 1;
192         }
193
194 //printf("DVBTune::open_tuner 0x%x 0x%x\n", get_audio_pid(), get_video_pid());
195 // Setting exactly one PES filter to 0x2000 dumps the entire
196 // transport stream.
197         struct dmx_pes_filter_params pesfilter;
198         if(!get_video_pid() && !get_audio_pid())
199         {
200                 pesfilter.pid = 0x2000;
201                 pesfilter.input = DMX_IN_FRONTEND;
202                 pesfilter.output = DMX_OUT_TS_TAP;
203                 pesfilter.pes_type = DMX_PES_OTHER;
204                 pesfilter.flags = DMX_IMMEDIATE_START;
205                 if(ioctl(video_fd, DMX_SET_PES_FILTER, &pesfilter) < 0)
206                 {
207                         fprintf(stderr,
208                                 "DVBTune::open_tuner DMX_SET_PES_FILTER for raw: %s\n",
209                                 strerror(errno));
210                         return 1;
211                 }
212         }
213
214
215         if(get_video_pid())
216         {
217
218
219         pesfilter.pid = get_video_pid();
220         pesfilter.input = DMX_IN_FRONTEND;
221         pesfilter.output = DMX_OUT_TS_TAP;
222         pesfilter.pes_type = DMX_PES_VIDEO;
223         pesfilter.flags = DMX_IMMEDIATE_START;
224                 if(ioctl(video_fd, DMX_SET_PES_FILTER, &pesfilter) < 0)
225                 {
226                         fprintf(stderr,
227                                 "DVBTune::open_tuner DMX_SET_PES_FILTER for video: %s\n",
228                                 strerror(errno));
229                         return 1;
230                 }
231         }
232
233         if(get_audio_pid())
234         {
235                 if((audio_fd = ::open(demux_path, O_RDWR)) < 0)
236                 {
237                         fprintf(stderr,
238                                 "DVBTune::open_tuner %s for audio: %s\n",
239                                 demux_path,
240                                 strerror(errno));
241                         return 1;
242                 }
243
244         pesfilter.pid = get_audio_pid();
245         pesfilter.input = DMX_IN_FRONTEND;
246         pesfilter.output = DMX_OUT_TS_TAP;
247         pesfilter.pes_type = DMX_PES_AUDIO;
248         pesfilter.flags = DMX_IMMEDIATE_START;
249                 if(ioctl(audio_fd, DMX_SET_PES_FILTER, &pesfilter) < 0)
250                 {
251                         fprintf(stderr,
252                                 "DVBTune::open_tuner DMX_SET_PES_FILTER for audio: %s\n",
253                                 strerror(errno));
254                         return 1;
255                 }
256         }
257
258
259
260
261
262
263         if(!thread)
264         {
265                 thread = new DVBTuneThread(this);
266                 thread->start();
267         }
268
269         if(!status)
270         {
271                 status = new DVBTuneStatus(this);
272                 status->start();
273         }
274         return 0;
275 #endif
276         return 1;
277 }
278
279 int DVBTune::close_tuner()
280 {
281         delete thread;
282         delete status;
283         delete [] buffer;
284
285         if(frontend_fd >= 0) close(frontend_fd);
286         if(audio_fd >= 0) close(audio_fd);
287         if(video_fd >= 0) close(video_fd);
288         if(dvr_fd >= 0) close(dvr_fd);
289         reset();
290
291         return 0;
292 }
293
294
295
296 int DVBTune::get_signal_strength(int *current_power, int *current_lock)
297 {
298         if(has_lock)
299         {
300                 *current_power = 10;
301                 *current_lock = 1;
302         }
303         else
304         {
305                 *current_power = 0;
306                 *current_lock = 0;
307         }
308
309
310         return 0;
311 }
312
313 int DVBTune::read_data(unsigned char *data, int size)
314 {
315         int buffer_size = 0;
316
317 // Poll if not enough data
318         buffer_lock->lock("DVBTune::read_data 2");
319         buffer_size = this->buffer_size;
320         buffer_lock->unlock();
321
322         if(buffer_size < size)
323         {
324                 usleep(100000);
325                 return 0;
326         }
327
328
329 // Copy data over
330         memcpy(data, buffer, size);
331 // Shift buffer over
332         buffer_lock->lock("DVBTune::read_data 2");
333         int new_size = buffer_size - size;
334         for(int i = 0, j = size; i < new_size; i++, j++)
335         {
336                 buffer[i] = buffer[j];
337         }
338         this->buffer_size -= size;
339         buffer_lock->unlock();
340
341         return size;
342 }
343
344
345
346
347
348
349
350 #define BUFFER_SIZE 0x100000
351 #define MAX_BUFFER_SIZE 0x10000000
352 DVBTuneThread::DVBTuneThread(DVBTune *server)
353  : Thread(1, 0, 0)
354 {
355         this->server = server;
356         temp = new unsigned char[BUFFER_SIZE];
357 }
358
359 DVBTuneThread::~DVBTuneThread()
360 {
361         Thread::cancel();
362         Thread::join();
363         delete [] temp;
364 }
365
366 void DVBTuneThread::run()
367 {
368         while(1)
369         {
370                 Thread::enable_cancel();
371
372 // Pretend to be blocking if no signal
373                 while(!server->has_lock)
374                 {
375                         usleep(1000000);
376                 }
377
378
379                 int result = ::read(server->dvr_fd, temp, BUFFER_SIZE);
380                 Thread::disable_cancel();
381 // This happens if buffer overrun.
382                 if(result < 0)
383                 {
384                         printf("DVBTuneThread::run: %s\n", strerror(errno));
385                         result = 0;
386                 }
387                 else
388 // Discard if server full.
389                 if(server->buffer_size > MAX_BUFFER_SIZE)
390                 {
391                         ;
392                 }
393                 else
394 // Store in server buffer.
395                 {
396                         server->buffer_lock->lock("DVBTuneThread::run");
397                         if(!server->buffer ||
398                                 server->buffer_allocated < server->buffer_size + result)
399                         {
400                                 int new_allocation = server->buffer_size + result;
401                                 unsigned char *new_buffer = new unsigned char[new_allocation];
402                                 memcpy(new_buffer, server->buffer, server->buffer_size);
403                                 delete [] server->buffer;
404
405                                 server->buffer = new_buffer;
406                                 server->buffer_allocated = new_allocation;
407                         }
408
409                         memcpy(server->buffer + server->buffer_size, temp, result);
410                         server->buffer_size += result;
411                         server->buffer_lock->unlock();
412                 }
413         }
414 }
415
416
417
418
419
420
421
422
423
424
425
426 DVBTuneStatus::DVBTuneStatus(DVBTune *server)
427  : Thread(1, 0, 0)
428 {
429         this->server = server;
430 }
431
432 DVBTuneStatus::~DVBTuneStatus()
433 {
434         Thread::cancel();
435         Thread::join();
436 }
437
438 void DVBTuneStatus::run()
439 {
440 #ifdef HAVE_DVB
441         while(1)
442         {
443                 fe_status_t status;
444                 uint16_t snr, signal;
445                 uint32_t ber, uncorrected_blocks;
446
447
448                 bzero(&status, sizeof(status));
449                 Thread::enable_cancel();
450                 ioctl(server->frontend_fd, FE_READ_STATUS, &status);
451                 ioctl(server->frontend_fd, FE_READ_SIGNAL_STRENGTH, &signal);
452                 ioctl(server->frontend_fd, FE_READ_SNR, &snr);
453                 ioctl(server->frontend_fd, FE_READ_BER, &ber);
454                 ioctl(server->frontend_fd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks);
455                 Thread::disable_cancel();
456
457 //      printf ("DVBTuneStatus::run %02x | signal %04x | snr %04x | "
458 //              "ber %08x | unc %08x | ",
459 //              status, signal, snr, ber, uncorrected_blocks);
460                 if (status & FE_HAS_LOCK)
461                 {
462                         printf("DVBTuneStatus::run FE_HAS_LOCK\n");
463                 }
464
465                 if(status & FE_HAS_LOCK) server->has_lock = 1;
466                 sleep(1);
467         }
468 #endif
469 }
470
471
472
473
474
475
476
477
478
479
480
481
482