r1009: Move the dependencies to newer package names
[cinelerra_cv/mob.git] / cinelerra / dvbtune.C
bloba3901873c40a7661d9790892ccea316f93f0e668
1 #include "bcwindowbase.inc"
2 #include "clip.h"
3 #include "condition.h"
4 #include "devicedvbinput.inc"
5 #include "dvbtune.h"
6 #include "mutex.h"
8 #include <errno.h>
9 #include <fcntl.h>
10 #ifdef HAVE_DVB
11 #include <linux/dvb/dmx.h>
12 #include <linux/dvb/frontend.h>
13 #endif
14 #include <stdio.h>
15 #include <string.h>
16 #include <sys/ioctl.h>
17 #include <unistd.h>
22 /* Frequency tables ripped straight off of pchdtv source code. */
23 /* DVB frequencies for US broadcast */
24 /* First two entries are to make the entries
25    line up with the channel number as index */
26 static unsigned long ntsc_dvb[ ] = {
27   0,  0,  57,  63,  69,  79,  85, 177, 183, 189 ,
28   195, 201, 207, 213, 473, 479, 485, 491, 497, 503 ,
29   509, 515, 521, 527, 533, 539, 545, 551, 557, 563 ,
30   569, 575, 581, 587, 593, 599, 605, 611, 617, 623 ,
31   629, 635, 641, 647, 653, 659, 665, 671, 677, 683 ,
32   689, 695, 701, 707, 713, 719, 725, 731, 737, 743 ,
33   749, 755, 761, 767, 773, 779, 785, 791, 797, 803 ,
34   809, 815, 821, 827, 833, 839, 845, 851, 857, 863 ,
35   869, 875, 881, 887, 893, 899, 905, 911, 917, 923 ,
36   929, 935, 941, 947, 953, 959, 965, 971, 977, 983 ,
37   989, 995, 1001, 1007, 1013, 1019, 1025, 1031, 1037, 1043
40 static unsigned long catv_dvb[] = {
41   0, 0, 57, 63, 69, 79, 85, 177, 183, 189,
42   195, 201, 207, 213, 123, 129, 135, 141, 147, 153,
43   159, 165, 171, 219, 225, 231, 237, 243, 249, 255,
44   261, 267, 273, 279, 285, 291, 297, 303, 309, 315,
45   321, 327, 333, 339, 345, 351, 357, 363, 369, 375,
46   381, 387, 393, 399, 405, 411, 417, 423, 429, 435,
47   441, 447, 453, 459, 465, 471, 477, 483, 489, 495,
48   501, 507, 513, 519, 525, 531, 537, 543, 549, 555,
49   561, 567, 573, 579, 585, 591, 597, 603, 609, 615,
50   621, 627, 633, 639, 645,  93,  99, 105, 111, 117,
51   651, 657, 663, 669, 675, 681, 687, 693, 699, 705,
52   711, 717, 723, 729, 735, 741, 747, 753, 759, 765,
53   771, 777, 783, 789, 795, 781, 807, 813, 819, 825,
54   831, 837, 843, 849, 855, 861, 867, 873, 879, 885,
55   891, 897, 903, 909, 915, 921, 927, 933, 939, 945,
56   951, 957, 963, 969, 975, 981, 987, 993, 999
61 DVBTune::DVBTune(RenderFarmClientThread *client)
62  : TunerServer(client)
64         reset();
65         buffer_lock = new Mutex("DVBTune::buffer_lock");
68 DVBTune::~DVBTune()
70         delete [] buffer;
71         delete buffer_lock;
72         delete thread;
73         delete status;
76 void DVBTune::reset()
78         frontend_fd = -1;
79         audio_fd = -1;
80         video_fd = -1;
81         dvr_fd = -1;
82         buffer = 0;
83         buffer_size = 0;
84         buffer_allocated = 0;
85         thread = 0;
86         status = 0;
87         has_lock = 0;
90 int DVBTune::open_tuner()
92 #ifdef HAVE_DVB
93         char frontend_path[BCTEXTLEN];
94         char demux_path[BCTEXTLEN];
95         char dvr_path[BCTEXTLEN];
97         sprintf(frontend_path, "/dev/dvb/adapter%d/frontend%d",
98                 get_device_number(),
99                 0);
100         sprintf(demux_path, "/dev/dvb/adapter%d/demux%d",
101                 get_device_number(),
102                 0);
103         sprintf(dvr_path, "/dev/dvb/adapter%d/dvr%d",
104                 get_device_number(),
105                 0);
114         if((frontend_fd = ::open(frontend_path, O_RDWR)) < 0) 
115         {
116                 fprintf(stderr, 
117                         "DVBTune::open_tuner %s: %s\n",
118                         frontend_path,
119                         strerror(errno));
120                 return 1;
121         }
124 // Open transport stream for reading
125         if((dvr_fd = ::open(dvr_path, O_RDONLY)) < 0)
126         {
127                 fprintf(stderr, 
128                         "DVBTune::open_tuner %s: %s\n",
129                         dvr_path,
130                         strerror(errno));
131                 return 1;
132         }
134         struct dvb_frontend_parameters frontend_param;
135         bzero(&frontend_param, sizeof(frontend_param));
137 // Set frequency
138         int index = CLIP(TunerServer::get_channel(), 2, 69);
139         int table = TunerServer::get_table();
140         switch(table)
141         {
142                 case NETTUNE_AIR:
143                         frontend_param.frequency = ntsc_dvb[index] * 1000000;
144                         frontend_param.u.vsb.modulation = VSB_8;
145                         break;
146                 case NETTUNE_CABLE:
147                 frontend_param.frequency = catv_dvb[index] * 1000000;
148                 frontend_param.u.vsb.modulation = QAM_AUTO;
149                         break;
150         }
153         if(ioctl(frontend_fd, FE_SET_FRONTEND, &frontend_param) < 0)
154         {
155                 fprintf(stderr, 
156                         "DVBTune::open_tuner FE_SET_FRONTEND frequency=%d: %s",
157                         frontend_param.frequency,
158                         strerror(errno));
159                 return 1;
160         }
162         if((video_fd = ::open(demux_path, O_RDWR)) < 0)
163         {
164                 fprintf(stderr,
165                         "DVBTune::open_tuner %s for video: %s\n",
166                         demux_path,
167                         strerror(errno));
168                 return 1;
169         }
171 //printf("DVBTune::open_tuner 0x%x 0x%x\n", get_audio_pid(), get_video_pid());
172 // Setting exactly one PES filter to 0x2000 dumps the entire
173 // transport stream.
174         struct dmx_pes_filter_params pesfilter;
175         if(!get_video_pid() && !get_audio_pid())
176         {
177                 pesfilter.pid = 0x2000;
178                 pesfilter.input = DMX_IN_FRONTEND;
179                 pesfilter.output = DMX_OUT_TS_TAP;
180                 pesfilter.pes_type = DMX_PES_OTHER;
181                 pesfilter.flags = DMX_IMMEDIATE_START;
182                 if(ioctl(video_fd, DMX_SET_PES_FILTER, &pesfilter) < 0)
183                 {
184                         fprintf(stderr, 
185                                 "DVBTune::open_tuner DMX_SET_PES_FILTER for raw: %s\n", 
186                                 strerror(errno));
187                         return 1;
188                 }
189         }
192         if(get_video_pid())
193         {
196         pesfilter.pid = get_video_pid();
197         pesfilter.input = DMX_IN_FRONTEND;
198         pesfilter.output = DMX_OUT_TS_TAP;
199         pesfilter.pes_type = DMX_PES_VIDEO;
200         pesfilter.flags = DMX_IMMEDIATE_START;
201                 if(ioctl(video_fd, DMX_SET_PES_FILTER, &pesfilter) < 0)
202                 {
203                         fprintf(stderr, 
204                                 "DVBTune::open_tuner DMX_SET_PES_FILTER for video: %s\n",       
205                                 strerror(errno));
206                         return 1;
207                 }
208         }
210         if(get_audio_pid())
211         {
212                 if((audio_fd = ::open(demux_path, O_RDWR)) < 0)
213                 {
214                         fprintf(stderr,
215                                 "DVBTune::open_tuner %s for audio: %s\n",
216                                 demux_path,
217                                 strerror(errno));
218                         return 1;
219                 }
221         pesfilter.pid = get_audio_pid();
222         pesfilter.input = DMX_IN_FRONTEND;
223         pesfilter.output = DMX_OUT_TS_TAP;
224         pesfilter.pes_type = DMX_PES_AUDIO;
225         pesfilter.flags = DMX_IMMEDIATE_START;
226                 if(ioctl(audio_fd, DMX_SET_PES_FILTER, &pesfilter) < 0)
227                 {
228                         fprintf(stderr, 
229                                 "DVBTune::open_tuner DMX_SET_PES_FILTER for audio: %s\n",       
230                                 strerror(errno));
231                         return 1;
232                 }
233         }
240         if(!thread)
241         {
242                 thread = new DVBTuneThread(this);
243                 thread->start();
244         }
246         if(!status)
247         {
248                 status = new DVBTuneStatus(this);
249                 status->start();
250         }
251         return 0;
252 #endif
253         return 1;
256 int DVBTune::close_tuner()
258         delete thread;
259         delete status;
260         delete [] buffer;
262         if(frontend_fd >= 0) close(frontend_fd);
263         if(audio_fd >= 0) close(audio_fd);
264         if(video_fd >= 0) close(video_fd);
265         if(dvr_fd >= 0) close(dvr_fd);
266         reset();
267         
268         return 0;
273 int DVBTune::get_signal_strength(int *current_power, int *current_lock)
275         if(has_lock)
276         {
277                 *current_power = 10;
278                 *current_lock = 1;
279         }
280         else
281         {
282                 *current_power = 0;
283                 *current_lock = 0;
284         }
285         
287         return 0;
290 int DVBTune::read_data(unsigned char *data, int size)
292         int buffer_size = 0;
294 // Poll if not enough data
295         buffer_lock->lock("DVBTune::read_data 2");
296         buffer_size = this->buffer_size;
297         buffer_lock->unlock();
299         if(buffer_size < size)
300         {
301                 usleep(100000);
302                 return 0;
303         }
306 // Copy data over
307         memcpy(data, buffer, size);
308 // Shift buffer over
309         buffer_lock->lock("DVBTune::read_data 2");
310         int new_size = buffer_size - size;
311         for(int i = 0, j = size; i < new_size; i++, j++)
312         {
313                 buffer[i] = buffer[j];
314         }
315         this->buffer_size -= size;
316         buffer_lock->unlock();
318         return size;
327 #define BUFFER_SIZE 0x100000
328 #define MAX_BUFFER_SIZE 0x10000000
329 DVBTuneThread::DVBTuneThread(DVBTune *server)
330  : Thread(1, 0, 0)
332         this->server = server;
333         temp = new unsigned char[BUFFER_SIZE];
336 DVBTuneThread::~DVBTuneThread()
338         Thread::cancel();
339         Thread::join();
340         delete [] temp;
343 void DVBTuneThread::run()
345         while(1)
346         {
347                 Thread::enable_cancel();
349 // Pretend to be blocking if no signal
350                 while(!server->has_lock)
351                 {
352                         usleep(1000000);
353                 }
356                 int result = ::read(server->dvr_fd, temp, BUFFER_SIZE);
357                 Thread::disable_cancel();
358 // This happens if buffer overrun.
359                 if(result < 0)
360                 {
361                         printf("DVBTuneThread::run: %s\n", strerror(errno));
362                         result = 0;
363                 }
364                 else
365 // Discard if server full.
366                 if(server->buffer_size > MAX_BUFFER_SIZE)
367                 {
368                         ;
369                 }
370                 else
371 // Store in server buffer.
372                 {
373                         server->buffer_lock->lock("DVBTuneThread::run");
374                         if(!server->buffer || 
375                                 server->buffer_allocated < server->buffer_size + result)
376                         {
377                                 int new_allocation = server->buffer_size + result;
378                                 unsigned char *new_buffer = new unsigned char[new_allocation];
379                                 memcpy(new_buffer, server->buffer, server->buffer_size);
380                                 delete [] server->buffer;
382                                 server->buffer = new_buffer;
383                                 server->buffer_allocated = new_allocation;
384                         }
386                         memcpy(server->buffer + server->buffer_size, temp, result);
387                         server->buffer_size += result;
388                         server->buffer_lock->unlock();
389                 }
390         }
403 DVBTuneStatus::DVBTuneStatus(DVBTune *server)
404  : Thread(1, 0, 0)
406         this->server = server;
409 DVBTuneStatus::~DVBTuneStatus()
411         Thread::cancel();
412         Thread::join();
415 void DVBTuneStatus::run()
417 #ifdef HAVE_DVB
418         while(1)
419         {
420                 fe_status_t status;
421                 uint16_t snr, signal;
422                 uint32_t ber, uncorrected_blocks;
425                 bzero(&status, sizeof(status));
426                 Thread::enable_cancel();
427                 ioctl(server->frontend_fd, FE_READ_STATUS, &status);
428                 ioctl(server->frontend_fd, FE_READ_SIGNAL_STRENGTH, &signal);
429                 ioctl(server->frontend_fd, FE_READ_SNR, &snr);
430                 ioctl(server->frontend_fd, FE_READ_BER, &ber);
431                 ioctl(server->frontend_fd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks);
432                 Thread::disable_cancel();
434 //      printf ("DVBTuneStatus::run %02x | signal %04x | snr %04x | "
435 //              "ber %08x | unc %08x | ",
436 //              status, signal, snr, ber, uncorrected_blocks);
437                 if (status & FE_HAS_LOCK)
438                 {
439                         printf("DVBTuneStatus::run FE_HAS_LOCK\n");
440                 }
442                 if(status & FE_HAS_LOCK) server->has_lock = 1;
443                 sleep(1);
444         }
445 #endif