1 /*
2  * Copyright (C) 2003-2020 the xine project
3  * Copyright (C) 2003 J.Asselman <j.asselman@itsec-ps.nl>
4  *
5  * This file is part of xine, a free video player.
6  *
7  * xine is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * xine is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
20  *
21  * v4l input plugin
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 
28 #include <unistd.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 
35 /* From GStreamer's v4l plugin:
36  * Because of some really cool feature in video4linux1, also known as
37  * 'not including sys/types.h and sys/time.h', we had to include it
38  * ourselves. In all their intelligence, these people decided to fix
39  * this in the next version (video4linux2) in such a cool way that it
40  * breaks all compilations of old stuff...
41  * The real problem is actually that linux/time.h doesn't use proper
42  * macro checks before defining types like struct timeval. The proper
43  * fix here is to either fuck the kernel header (which is what we do
44  * by defining _LINUX_TIME_H, an innocent little hack) or by fixing it
45  * upstream, which I'll consider doing later on. If you get compiler
46  * errors here, check your linux/time.h && sys/time.h header setup.
47 */
48 #define _LINUX_TIME_H
49 
50 #include <linux/videodev.h>
51 #include <sys/ioctl.h>
52 #include <sys/mman.h>
53 #include <errno.h>
54 
55 /* Used to capture the audio data */
56 #define ALSA_PCM_NEW_HW_PARAMS_API
57 #define ALSA_PCM_NEW_SW_PARAMS_API
58 #ifdef HAVE_ALSA
59 #include <alsa/asoundlib.h>
60 #endif
61 
62 #define XINE_ENABLE_EXPERIMENTAL_FEATURES
63 
64 /********** logging **********/
65 /* #define LOG_MODULE "input_v4l" */
66 #define LOG_VERBOSE
67 /*
68 #define LOG
69 */
70 
71 #ifdef LOG
72 #define LOG_MODULE log_line_prefix()
73 
log_line_prefix()74 static char *log_line_prefix()
75 {
76     static int print_timestamp = 1;
77     struct timeval now;
78     struct tm now_tm;
79     char buffer[64];
80 
81     if( print_timestamp ) {
82         gettimeofday( &now, NULL );
83         localtime_r( &now.tv_sec, &now_tm );
84         strftime( buffer, sizeof( buffer ), "%Y-%m-%d %H:%M:%S", &now_tm );
85         printf( "%s.%6.6ld: ", buffer, now.tv_usec );
86     }
87     return "input_v4l";
88 }
89 #endif
90 
91 #include <xine/xine_internal.h>
92 #include <xine/xineutils.h>
93 #include <xine/input_plugin.h>
94 
95 #define NUM_FRAMES  15
96 
97 /* Our CPU can't handle de-interlacing at 768. */
98 #define MAX_RES 640
99 
100 typedef struct {
101 	int width;
102 	int height;
103 } resolution_t;
104 
105 static const resolution_t resolutions[] = {
106 	{ 768, 576 },
107 	{ 640, 480 },
108 	{ 384, 288 },
109 	{ 320, 240 },
110 	{ 160, 120 }
111 };
112 
113 #define NUM_RESOLUTIONS  (sizeof(resolutions)/sizeof(resolutions[0]))
114 #define RADIO_DEV        "/dev/radio0"
115 #define VIDEO_DEV        "/dev/video0"
116 #ifdef HAVE_ALSA
117 #define AUDIO_DEV	 "plughw:0,0"
118 #endif
119 
120 static const char *const tv_standard_names[] = { "AUTO", "PAL", "NTSC", "SECAM", "OLD", NULL };
121 static const int tv_standard_values[] = { VIDEO_MODE_AUTO, VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_SECAM, -1 };
122 
123 #if !defined(NDELAY) && defined(O_NDELAY)
124 #define FNDELAY O_NDELAY
125 #endif
126 
127 typedef struct pvrscr_s pvrscr_t;
128 
129 typedef struct {
130   input_plugin_t           input_plugin;
131 
132   xine_stream_t           *stream;
133   char                    *mrl;
134 
135   off_t                    curpos;
136 
137   int		           old_interlace;
138   int		           old_zoomx;
139   int		           old_zoomy;
140   int		           audio_only;
141 
142   buf_element_t           *frames_base;
143   void                    *audio_content_base;
144   void                    *video_content_base;
145 
146   /* Audio */
147   buf_element_t           *aud_frames;
148   pthread_mutex_t          aud_frames_lock;
149   pthread_cond_t           aud_frame_freed;
150 
151 #ifdef HAVE_ALSA
152   /* Handle for the PCM device */
153   snd_pcm_t	          *pcm_handle;
154 
155   /* Record stream (via line 1) */
156   snd_pcm_stream_t         pcm_stream;
157 
158   /* Information and configuration for the PCM stream */
159   snd_pcm_hw_params_t     *pcm_hwparams;
160 
161   /* Name of the PCM device, plughw:0,0?=>soundcard,device*/
162   char		          *pcm_name;
163 
164   /* Use alsa to capture the sound (for a/v sync) */
165   char		           audio_capture;
166 
167   int                      exact_rate;         /* Actual sample rate
168 						  sndpcm_hw_params_set_rate_near */
169   int                      dir;                /* exact rate == rate --> dir =  0
170 						  exact rate  < rate --> dir = -1
171 						  exact rate  > rate --> dir =  1 */
172 
173   unsigned char           *pcm_data;
174 
175   int64_t                  pts_aud_start;
176 #endif
177 
178   int                      audio_header_sent;
179 
180   int                      rate;               /* Sample rate */
181   int                      periods;            /* Number of periods */
182   int                      periodsize;         /* Periodsize in bytes */
183   int                      bits;
184 
185   /* Video */
186   buf_element_t           *vid_frames;
187   pthread_mutex_t          vid_frames_lock;
188   pthread_cond_t           vid_frame_freed;
189 
190   int                      video_fd;
191   int		           radio_fd;
192 
193   int                      input;
194   int                      tuner;
195   unsigned long	           frequency;
196   unsigned long            calc_frequency;
197   char		          *tuner_name;
198 
199   int		           radio;   /* ask for a radio channel */
200   int		           channel; /* channel number */
201 
202   struct video_channel     video_channel;
203   struct video_tuner       video_tuner;
204   struct video_capability  video_cap;
205   struct video_audio       audio;
206   struct video_audio       audio_saved;
207   struct video_mbuf        gb_buffers;
208 
209   int                      video_header_sent;
210 
211   int                      frame_format;
212   const resolution_t      *resolution;
213   int                      frame_size;
214   int                      use_mmap;
215   uint8_t                 *video_buf;
216   int                      gb_frame;
217   struct video_mmap        gb_buf;
218   int64_t                  start_time;
219 
220   xine_event_queue_t      *event_queue;
221 
222   pvrscr_t                *scr;
223   int	                   scr_tuning;
224 
225 } v4l_input_plugin_t;
226 
227 /*
228  * ***************************************************
229  * unix System Clock Reference + fine tuning
230  *
231  * This code is copied and paste from the input_pvr.c
232  *
233  * the fine tuning option is used to change play
234  * speed in order to regulate fifo usage, that is,
235  * trying to match the rate of generated data.
236  *
237  * OBS: use with audio.synchronization.av_sync_method=resample
238  * ***************************************************
239  */
240 
241 #define SCR_PAUSED -2
242 #define SCR_FW -3
243 #define SCR_SKIP -4
244 
245 struct pvrscr_s {
246   scr_plugin_t     scr;
247 
248   struct timeval   cur_time;
249   int64_t          cur_pts;
250   int              xine_speed;
251   double           speed_factor;
252   double           speed_tuning;
253 
254   pthread_mutex_t  lock;
255 };
256 
pvrscr_get_priority(scr_plugin_t * scr)257 static int pvrscr_get_priority(scr_plugin_t *scr)
258 {
259   (void)scr;
260   return 10; /* high priority */
261 }
262 
263 /* Only call this when already mutex locked */
pvrscr_set_pivot(pvrscr_t * this)264 static void pvrscr_set_pivot(pvrscr_t *this)
265 {
266   struct   timeval tv;
267   int64_t pts;
268   double   pts_calc;
269 
270   xine_monotonic_clock(&tv, NULL);
271   pts_calc = (tv.tv_sec  - this->cur_time.tv_sec) * this->speed_factor;
272   pts_calc += (tv.tv_usec - this->cur_time.tv_usec) * this->speed_factor / 1e6;
273   pts      = this->cur_pts + pts_calc;
274 
275   /* This next part introduces a one off inaccuracy
276    * to the scr due to rounding tv to pts.
277    */
278   this->cur_time.tv_sec  = tv.tv_sec;
279   this->cur_time.tv_usec = tv.tv_usec;
280   this->cur_pts          = pts;
281 
282   return;
283 }
284 
pvrscr_set_fine_speed(scr_plugin_t * scr,int speed)285 static int pvrscr_set_fine_speed (scr_plugin_t *scr, int speed)
286 {
287   pvrscr_t *this = (pvrscr_t*) scr;
288 
289   pthread_mutex_lock (&this->lock);
290 
291   pvrscr_set_pivot( this );
292   this->xine_speed   = speed;
293   this->speed_factor = (double) speed * 90000.0 / XINE_FINE_SPEED_NORMAL *
294     this->speed_tuning;
295 
296   pthread_mutex_unlock (&this->lock);
297 
298   return speed;
299 }
300 
pvrscr_speed_tuning(pvrscr_t * this,double factor)301 static void pvrscr_speed_tuning (pvrscr_t *this, double factor)
302 {
303   pthread_mutex_lock (&this->lock);
304 
305   pvrscr_set_pivot( this );
306   this->speed_tuning = factor;
307   this->speed_factor  = (double) this->xine_speed * 90000.0 / XINE_FINE_SPEED_NORMAL *
308     this->speed_tuning;
309 
310   pthread_mutex_unlock (&this->lock);
311 }
312 
pvrscr_adjust(scr_plugin_t * scr,int64_t vpts)313 static void pvrscr_adjust (scr_plugin_t *scr, int64_t vpts)
314 {
315   pvrscr_t        *this = (pvrscr_t*) scr;
316   struct timeval   tv;
317 
318   pthread_mutex_lock (&this->lock);
319 
320   xine_monotonic_clock(&tv, NULL);
321   this->cur_time.tv_sec  = tv.tv_sec;
322   this->cur_time.tv_usec = tv.tv_usec;
323   this->cur_pts          = vpts;
324 
325   pthread_mutex_unlock (&this->lock);
326 }
327 
pvrscr_start(scr_plugin_t * scr,int64_t start_vpts)328 static void pvrscr_start (scr_plugin_t *scr, int64_t start_vpts)
329 {
330   pvrscr_t *this = (pvrscr_t*) scr;
331 
332   pthread_mutex_lock (&this->lock);
333 
334   xine_monotonic_clock(&this->cur_time, NULL);
335   this->cur_pts = start_vpts;
336 
337   pthread_mutex_unlock (&this->lock);
338 
339   pvrscr_set_fine_speed (&this->scr, XINE_FINE_SPEED_NORMAL);
340 }
341 
pvrscr_get_current(scr_plugin_t * scr)342 static int64_t pvrscr_get_current (scr_plugin_t *scr)
343 {
344   pvrscr_t        *this = (pvrscr_t*) scr;
345   struct timeval   tv;
346   int64_t          pts;
347   double           pts_calc;
348 
349   pthread_mutex_lock (&this->lock);
350 
351   xine_monotonic_clock(&tv, NULL);
352 
353   pts_calc = (tv.tv_sec  - this->cur_time.tv_sec) * this->speed_factor;
354   pts_calc += (tv.tv_usec - this->cur_time.tv_usec) * this->speed_factor / 1e6;
355   pts      = this->cur_pts + pts_calc;
356 
357   pthread_mutex_unlock (&this->lock);
358 
359 /*printf("returning pts %lld\n", pts);*/
360   return pts;
361 }
362 
pvrscr_exit(scr_plugin_t * scr)363 static void pvrscr_exit (scr_plugin_t *scr)
364 {
365    pvrscr_t *this = (pvrscr_t*) scr;
366 
367    pthread_mutex_destroy (&this->lock);
368    free(this);
369 }
370 
pvrscr_init(void)371 static pvrscr_t *XINE_MALLOC pvrscr_init (void)
372 {
373    pvrscr_t *this;
374 
375    this = calloc(1, sizeof(pvrscr_t));
376 
377    this->scr.interface_version = 3;
378    this->scr.get_priority      = pvrscr_get_priority;
379    this->scr.set_fine_speed    = pvrscr_set_fine_speed;
380    this->scr.adjust            = pvrscr_adjust;
381    this->scr.start             = pvrscr_start;
382    this->scr.get_current       = pvrscr_get_current;
383    this->scr.exit              = pvrscr_exit;
384 
385    pthread_mutex_init (&this->lock, NULL);
386 
387    pvrscr_speed_tuning(this, 1.0 );
388    pvrscr_set_fine_speed (&this->scr, XINE_SPEED_PAUSE);
389 #ifdef SCRLOG
390    printf("input_v4l: scr init complete\n");
391 #endif
392 
393    return this;
394 }
395 
396 /*** END COPY AND PASTE from PVR**************************/
397 
398 /*** The following is copy and past from net_buf_ctrl ****/
report_progress(xine_stream_t * stream,int p)399 static void report_progress (xine_stream_t *stream, int p)
400 {
401    xine_event_t             event;
402    xine_progress_data_t     prg;
403 
404    if (p == SCR_PAUSED) {
405       prg.description = _("Buffer underrun...");
406       p = 0;
407    } else
408    if (p == SCR_FW) {
409       prg.description = _("Buffer overrun...");
410       p = 100;
411    } else
412       prg.description = _("Adjusting...");
413 
414    prg.percent = (p>100)?100:p;
415 
416    event.type        = XINE_EVENT_PROGRESS;
417    event.data        = &prg;
418    event.data_length = sizeof (xine_progress_data_t);
419 
420    xine_event_send (stream, &event);
421 }
422 
423 /**** END COPY AND PASTE from net_buf_ctrl ***************/
424 
425 static int search_by_tuner(v4l_input_plugin_t *this, char *input_source);
426 static int search_by_channel(v4l_input_plugin_t *this, char *input_source);
427 static void v4l_event_handler(v4l_input_plugin_t *this);
428 
429 /**
430  * Allocate an audio frame.
431  */
alloc_aud_frame(v4l_input_plugin_t * this)432 inline static buf_element_t *alloc_aud_frame (v4l_input_plugin_t *this)
433 {
434    buf_element_t *frame;
435 
436    lprintf("alloc_aud_frame. trying to get lock...\n");
437 
438    pthread_mutex_lock (&this->aud_frames_lock) ;
439 
440    lprintf("got the lock\n");
441 
442    while (!this->aud_frames) {
443       lprintf("no audio frame available...\n");
444       pthread_cond_wait (&this->aud_frame_freed, &this->aud_frames_lock);
445    }
446 
447    frame = this->aud_frames;
448    this->aud_frames = this->aud_frames->next;
449 
450    pthread_mutex_unlock (&this->aud_frames_lock);
451 
452    lprintf("alloc_aud_frame done\n");
453 
454    return frame;
455 }
456 
457 /**
458  * Stores an audio frame.
459  */
store_aud_frame(buf_element_t * frame)460 static void store_aud_frame (buf_element_t *frame)
461 {
462    v4l_input_plugin_t *this = (v4l_input_plugin_t *) frame->source;
463 
464    lprintf("store_aud_frame\n");
465 
466    pthread_mutex_lock (&this->aud_frames_lock) ;
467 
468    frame->next      = this->aud_frames;
469    this->aud_frames = frame;
470 
471    pthread_cond_signal (&this->aud_frame_freed);
472    pthread_mutex_unlock (&this->aud_frames_lock);
473 }
474 
475 /**
476  * Allocate a video frame.
477  */
alloc_vid_frame(v4l_input_plugin_t * this)478 inline static buf_element_t *alloc_vid_frame (v4l_input_plugin_t *this)
479 {
480   buf_element_t *frame;
481 
482   lprintf("alloc_vid_frame. trying to get lock...\n");
483 
484   pthread_mutex_lock (&this->vid_frames_lock) ;
485 
486   lprintf("got the lock\n");
487 
488   while (!this->vid_frames) {
489     lprintf("no video frame available...\n");
490     pthread_cond_wait (&this->vid_frame_freed, &this->vid_frames_lock);
491   }
492 
493   frame            = this->vid_frames;
494   this->vid_frames = this->vid_frames->next;
495 
496   pthread_mutex_unlock (&this->vid_frames_lock);
497 
498   lprintf("alloc_vid_frame done\n");
499 
500   return frame;
501 }
502 
503 /**
504  * Stores a video frame.
505  */
store_vid_frame(buf_element_t * frame)506 static void store_vid_frame (buf_element_t *frame)
507 {
508 
509   v4l_input_plugin_t *this = (v4l_input_plugin_t *) frame->source;
510 
511   lprintf("store_vid_frame\n");
512 
513   pthread_mutex_lock (&this->vid_frames_lock) ;
514 
515   frame->next      = this->vid_frames;
516   this->vid_frames = frame;
517 
518   pthread_cond_signal (&this->vid_frame_freed);
519   pthread_mutex_unlock (&this->vid_frames_lock);
520 }
521 
extract_mrl(v4l_input_plugin_t * this,const char * mrl)522 static int extract_mrl(v4l_input_plugin_t *this, const char *mrl)
523 {
524   char   *tuner_name = NULL;
525   int     frequency  = 0;
526   const char   *locator    = NULL;
527   const char   *begin      = NULL;
528 
529   if (mrl == NULL) {
530     lprintf("Someone passed an empty mrl\n");
531     return 0;
532   }
533 
534   for (locator = mrl; *locator != '\0' && *locator !=  '/' ; locator++);
535 
536   /* Get tuner name */
537   if (*locator == '/') {
538     begin = ++locator;
539 
540     for (; *locator != '\0' && *locator != '/' ; locator++);
541 
542     tuner_name = (char *) strndup(begin, locator - begin);
543 
544     /* Get frequency, if available */
545     sscanf(locator, "/%d", &frequency);
546 
547     /* cannot use xprintf to log in this routine */
548     lprintf("input_v4l: Tuner name: %s frequency %d\n", tuner_name, frequency );
549   }
550 
551   this->frequency  = frequency;
552   this->tuner_name = tuner_name;
553 
554   return 1;
555 }
556 
set_frequency(v4l_input_plugin_t * this,unsigned long frequency)557 static int set_frequency(v4l_input_plugin_t *this, unsigned long frequency)
558 {
559   int  ret = 0;
560   int  fd;
561 
562   if (this->video_fd > 0)
563     fd = this->video_fd;
564   else
565     fd = this->radio_fd;
566 
567   if (frequency != 0) {
568     /* FIXME: Don't assume tuner 0 ? */
569     this->tuner = 0;
570     ret = ioctl(fd, VIDIOCSTUNER, &this->tuner);
571     lprintf("(%d) Response on set tuner to %d\n", ret, this->tuner);
572     this->video_tuner.tuner = this->tuner;
573 
574     if (this->video_tuner.flags & VIDEO_TUNER_LOW) {
575       this->calc_frequency = frequency * 16;
576     } else {
577       this->calc_frequency = (frequency * 16) / 1000;
578     }
579 
580     ret = ioctl(fd, VIDIOCSFREQ, &this->calc_frequency);
581 
582     xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
583             "input_v4l: set frequency (%ld) returned: %d\n", frequency, ret);
584   } else {
585     xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
586             "input_v4l: No frequency given. Expected syntax: v4l:/tuner/frequency\n"
587             "input_v4l: Using currently tuned settings\n");
588   }
589 
590   this->frequency = frequency;
591 
592   if (ret < 0)
593     return ret;
594   else
595     return 1;
596 }
597 
set_input_source(v4l_input_plugin_t * this,char * input_source)598 static int set_input_source(v4l_input_plugin_t *this, char *input_source)
599 {
600   int ret = 0;
601 
602   if ((ret = search_by_channel(this, input_source)) != 1) {
603     ret = search_by_tuner(this, input_source);
604   }
605 
606   return ret;
607 }
608 
search_by_tuner(v4l_input_plugin_t * this,char * input_source)609 static int search_by_tuner(v4l_input_plugin_t *this, char *input_source)
610 {
611   int  ret       = 0;
612   int  fd        = 0;
613   int  cur_tuner = 0;
614 
615   if (this->video_fd > 0)
616     fd = this->video_fd;
617   else
618     fd = this->radio_fd;
619 
620   this->video_tuner.tuner = cur_tuner;
621   ioctl(fd, VIDIOCGCAP, &this->video_cap);
622 
623   lprintf("This device has %d channel(s)\n", this->video_cap.channels);
624 
625   for (ret = ioctl(fd, VIDIOCGTUNER, &this->video_tuner);
626        ret == 0 && this->video_cap.channels > cur_tuner && strstr(this->video_tuner.name, input_source) == NULL;
627        cur_tuner++) {
628 
629     this->video_tuner.tuner = cur_tuner;
630 
631     lprintf("(%d) V4L device currently set to: \n", ret);
632     lprintf("Tuner:  %d\n", this->video_tuner.tuner);
633     lprintf("Name:   %s\n", this->video_tuner.name);
634     if (this->video_tuner.flags & VIDEO_TUNER_LOW) {
635       lprintf("Range:  %ld - %ld\n", this->video_tuner.rangelow / 16,  this->video_tuner.rangehigh * 16);
636     } else {
637       lprintf("Range:  %ld - %ld\n", this->video_tuner.rangelow * 1000 / 16, this->video_tuner.rangehigh * 1000 / 16);
638     }
639   }
640 
641   lprintf("(%d) V4L device final: \n", ret);
642   lprintf("Tuner:  %d\n", this->video_tuner.tuner);
643   lprintf("Name:   %s\n", this->video_tuner.name);
644   if (this->video_tuner.flags & VIDEO_TUNER_LOW) {
645     lprintf("Range:  %ld - %ld\n", this->video_tuner.rangelow / 16,  this->video_tuner.rangehigh * 16);
646   } else {
647     lprintf("Range:  %ld - %ld\n", this->video_tuner.rangelow * 1000 / 16, this->video_tuner.rangehigh * 1000 / 16);
648   }
649 
650   if (strstr(this->video_tuner.name, input_source) == NULL)
651     return -1;
652 
653   return 1;
654 }
655 
search_by_channel(v4l_input_plugin_t * this,char * input_source)656 static int search_by_channel(v4l_input_plugin_t *this, char *input_source)
657 {
658   int  ret = 0;
659   int  fd  = 0;
660   cfg_entry_t *tv_standard_entry;
661 
662   lprintf("input_source: %s\n", input_source);
663 
664   this->input = 0;
665 
666   if (this->video_fd > 0)
667     fd = this->video_fd;
668   else
669     fd = this->radio_fd;
670 
671   /* Tune into channel */
672   if (strlen(input_source) > 0) {
673     for( this->video_channel.channel = 0;
674          ioctl(fd, VIDIOCGCHAN, &this->video_channel) == 0;
675          this->video_channel.channel++ ) {
676 
677       lprintf("V4L device currently set to:\n");
678       lprintf("Channel: %d\n", this->video_channel.channel);
679       lprintf("Name:    %s\n", this->video_channel.name);
680       lprintf("Tuners:  %d\n", this->video_channel.tuners);
681       lprintf("Flags:   %d\n", this->video_channel.flags);
682       lprintf("Type:    %d\n", this->video_channel.type);
683       lprintf("Norm:    %d\n", this->video_channel.norm);
684 
685       if (strstr(this->video_channel.name, input_source) != NULL) {
686         this->input = this->video_channel.channel;
687         break;
688       }
689     }
690 
691     if (strstr(this->video_channel.name, input_source) == NULL) {
692       xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("Tuner name not found\n"));
693       return -1;
694     }
695 
696     tv_standard_entry = this->stream->xine->config->lookup_entry(this->stream->xine->config,
697                                                    "media.video4linux.tv_standard");
698     this->tuner_name = input_source;
699     if (tv_standard_entry->num_value != 0) {
700       this->video_channel.norm = tv_standard_values[ tv_standard_entry->num_value ];
701       xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
702               "input_v4l: TV Standard configured as STD %s (%d)\n",
703               tv_standard_names[ tv_standard_entry->num_value ], this->video_channel.norm );
704         ret = ioctl(fd, VIDIOCSCHAN, &this->video_channel);
705     } else
706         ret = ioctl(fd, VIDIOCSCHAN, &this->input);
707 
708     lprintf("(%d) Set channel to %d\n", ret, this->input);
709   } else {
710     xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
711             "input_v4l: Not setting video source. No source given\n");
712   }
713   ret = ioctl(fd, VIDIOCGTUNER, &this->video_tuner);
714 
715   lprintf("(%d) Flags %d\n", ret, this->video_tuner.flags);
716 
717   lprintf("VIDEO_TUNER_PAL %s set\n", this->video_tuner.flags & VIDEO_TUNER_PAL ? "" : "not");
718   lprintf("VIDEO_TUNER_NTSC %s set\n", this->video_tuner.flags & VIDEO_TUNER_NTSC ? "" : "not");
719   lprintf("VIDEO_TUNER_SECAM %s set\n", this->video_tuner.flags & VIDEO_TUNER_SECAM ? "" : "not");
720   lprintf("VIDEO_TUNER_LOW %s set\n", this->video_tuner.flags & VIDEO_TUNER_LOW ? "" : "not");
721   lprintf("VIDEO_TUNER_NORM %s set\n", this->video_tuner.flags & VIDEO_TUNER_NORM ? "" : "not");
722   lprintf("VIDEO_TUNER_STEREO_ON %s set\n", this->video_tuner.flags & VIDEO_TUNER_STEREO_ON ? "" : "not");
723   lprintf("VIDEO_TUNER_RDS_ON %s set\n", this->video_tuner.flags & VIDEO_TUNER_RDS_ON ? "" : "not");
724   lprintf("VIDEO_TUNER_MBS_ON %s set\n", this->video_tuner.flags & VIDEO_TUNER_MBS_ON ? "" : "not");
725 
726   switch (this->video_tuner.mode) {
727   case VIDEO_MODE_PAL:
728     lprintf("The tuner is in PAL mode\n");
729     break;
730   case VIDEO_MODE_NTSC:
731     lprintf("The tuner is in NTSC mode\n");
732     break;
733   case VIDEO_MODE_SECAM:
734     lprintf("The tuner is in SECAM mode\n");
735     break;
736   case VIDEO_MODE_AUTO:
737     lprintf("The tuner is in AUTO mode\n");
738     break;
739   }
740 
741   return 1;
742 }
743 
allocate_frames(v4l_input_plugin_t * this,unsigned dovideo)744 static void allocate_frames(v4l_input_plugin_t *this, unsigned dovideo)
745 {
746   const size_t framescount = dovideo ? 2*NUM_FRAMES : NUM_FRAMES;
747 
748   /* Allocate a single memory area for both audio and video frames */
749   buf_element_t *frames = this->frames_base =
750     calloc(framescount, sizeof(buf_element_t));
751   extra_info_t  *infos  =
752     calloc(framescount, sizeof(extra_info_t));
753 
754   int i;
755 
756   uint8_t *audio_content = this->audio_content_base =
757     calloc(NUM_FRAMES, this->periodsize);
758 
759   /* Set up audio frames */
760   for (i = 0; i < NUM_FRAMES; i++) {
761     /* Audio frame */
762     frames[i].content     = audio_content;
763     frames[i].type	   = BUF_AUDIO_LPCM_LE;
764     frames[i].source      = this;
765     frames[i].free_buffer = store_aud_frame;
766     frames[i].extra_info  = &infos[i];
767 
768     audio_content += this->periodsize;
769     store_aud_frame(&frames[i]);
770   }
771 
772   if ( dovideo ) {
773     uint8_t *video_content = this->video_content_base =
774       calloc(NUM_FRAMES, this->frame_size);
775 
776     /* Set up video frames */
777     for (i = NUM_FRAMES; i < 2*NUM_FRAMES; i++) {
778       /* Video frame */
779       frames[i].content     = video_content;
780       frames[i].type	     = this->frame_format;
781       frames[i].source      = this;
782       frames[i].free_buffer = store_vid_frame;
783       frames[i].extra_info  = &infos[i];
784 
785       video_content += this->frame_size;
786       store_vid_frame(&frames[i]);
787     }
788   }
789 }
790 
unmute_audio(v4l_input_plugin_t * this)791 static void unmute_audio(v4l_input_plugin_t *this)
792 {
793   int fd;
794 
795   lprintf("unmute_audio\n");
796 
797   if (this->video_fd > 0)
798     fd = this->video_fd;
799   else
800     fd = this->radio_fd;
801 
802   ioctl(fd, VIDIOCGAUDIO, &this->audio);
803   memcpy(&this->audio_saved, &this->audio, sizeof(this->audio));
804 
805   this->audio.flags  &= ~VIDEO_AUDIO_MUTE;
806   this->audio.volume = 0xD000;
807 
808   ioctl(fd, VIDIOCSAUDIO, &this->audio);
809 }
810 
open_radio_capture_device(v4l_input_plugin_t * this)811 static int open_radio_capture_device(v4l_input_plugin_t *this)
812 {
813   int          tuner_found = 0;
814   cfg_entry_t *entry;
815 
816   lprintf("open_radio_capture_device\n");
817 
818   entry = this->stream->xine->config->lookup_entry(this->stream->xine->config,
819                                                    "media.video4linux.radio_device");
820 
821   if((this->radio_fd = xine_open_cloexec(entry->str_value, O_RDWR)) < 0) {
822     xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
823             "input_v4l: error opening v4l device (%s): %s\n",
824             entry->str_value, strerror(errno));
825     return 0;
826   }
827 
828   lprintf("Device opened, radio %d\n", this->radio_fd);
829 
830   if (set_input_source(this, this->tuner_name) > 0)
831     tuner_found = 1;
832 
833   _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, 1);
834   _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 0);
835 
836   /* Pre-allocate some frames for audio so it doesn't have to be done during
837    * capture */
838   allocate_frames(this, 0);
839 
840   this->audio_only = 1;
841 
842   /* Unmute audio off video capture device */
843   unmute_audio(this);
844 
845   set_frequency(this, this->frequency);
846 
847   if (tuner_found)
848     return 1;
849   else
850     return 2;
851 }
852 
853 /**
854  * Open the video capture device.
855  *
856  * This opens the video capture device and if given, selects a tuner from
857  * which the signal should be grabbed.
858  * @return 1 on success, 0 on failure.
859  */
open_video_capture_device(v4l_input_plugin_t * this)860 static int open_video_capture_device(v4l_input_plugin_t *this)
861 {
862   int          found       = 0;
863   int          tuner_found = 0;
864   int          ret;
865   unsigned int j;
866   cfg_entry_t *entry;
867 
868   lprintf("open_video_capture_device\n");
869 
870   entry = this->stream->xine->config->lookup_entry(this->stream->xine->config,
871                                                    "media.video4linux.video_device");
872 
873   /* Try to open the video device */
874   if((this->video_fd = xine_open_cloexec(entry->str_value, O_RDWR)) < 0) {
875     xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
876             "input_v4l: error opening v4l device (%s): %s\n",
877             entry->str_value, strerror(errno));
878     return 0;
879   }
880 
881   lprintf("Device opened, tv %d\n", this->video_fd);
882 
883   /* figure out the resolution */
884   for (j = 0; j < NUM_RESOLUTIONS; j++)
885     {
886       if (resolutions[j].width <= this->video_cap.maxwidth
887 	  && resolutions[j].height <= this->video_cap.maxheight
888 	  && resolutions[j].width <= MAX_RES)
889 	{
890 	  found = 1;
891 	  break;
892 	}
893     }
894 
895   if (found == 0 || resolutions[j].width < this->video_cap.minwidth
896       || resolutions[j].height < this->video_cap.minheight)
897     {
898       /* Looks like the device does not support one of the preset resolutions */
899       lprintf("Grab device does not support any preset resolutions");
900       return 0;
901     }
902 
903   this->resolution = &resolutions[j];
904 
905   _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, 1);
906   _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 1);
907 
908   /* Pre-allocate some frames for audio and video so it doesn't have to be
909    * done during capture */
910   allocate_frames(this, 1);
911 
912   /* Unmute audio off video capture device */
913   unmute_audio(this);
914 
915   if (strlen(this->tuner_name) > 0) {
916     /* Tune into source and given frequency */
917     if (set_input_source(this, this->tuner_name) <= 0)
918       return 0;
919     else
920       tuner_found = 1;
921   }
922 
923   set_frequency(this, this->frequency);
924 
925   /* Test for mmap video access */
926   ret = ioctl(this->video_fd,VIDIOCGMBUF, &this->gb_buffers);
927 
928   if (ret < 0) {
929     /* Device driver does not support mmap */
930     /* try to use read based access */
931     struct video_picture pict;
932     int                  val;
933 
934     ioctl(this->video_fd, VIDIOCGPICT, &pict);
935 
936     /* try to choose a suitable video format */
937     pict.palette = VIDEO_PALETTE_YUV420P;
938     ret          = ioctl(this->video_fd, VIDIOCSPICT, &pict);
939     if (ret < 0) {
940       pict.palette = VIDEO_PALETTE_YUV422;
941       ret          = ioctl(this->video_fd, VIDIOCSPICT, &pict);
942       if (ret < 0) {
943 	close (this->video_fd);
944 	this->video_fd = -1;
945 	lprintf("Grab: no colour space format found\n");
946 	return 0;
947       }
948       else
949 	lprintf("Grab: format YUV 4:2:2\n");
950     }
951     else
952       lprintf("Grab: format YUV 4:2:0\n");
953 
954     this->frame_format = pict.palette;
955     val                = 1;
956     ioctl(this->video_fd, VIDIOCCAPTURE, &val);
957 
958     this->use_mmap = 0;
959 
960   } else {
961     /* Good, device driver support mmap. Mmap the memory */
962     lprintf("using mmap, size %d\n", this->gb_buffers.size);
963     this->video_buf = mmap(0, this->gb_buffers.size,
964 			   PROT_READ|PROT_WRITE, MAP_SHARED,
965 			   this->video_fd,0);
966     if ((unsigned char*)-1 == this->video_buf) {
967       /* mmap failed. */;
968       perror("mmap");
969       close (this->video_fd);
970       return 0;
971     }
972     this->gb_frame = 0;
973 
974     /* start to grab the first frame */
975     this->gb_buf.frame  = (this->gb_frame + 1) % this->gb_buffers.frames;
976     this->gb_buf.height = resolutions[j].height;
977     this->gb_buf.width  = resolutions[j].width;
978     this->gb_buf.format = VIDEO_PALETTE_YUV420P;
979 
980     ret = ioctl(this->video_fd, VIDIOCMCAPTURE, &this->gb_buf);
981     if (ret < 0 && errno != EAGAIN) {
982       /* try YUV422 */
983       this->gb_buf.format = VIDEO_PALETTE_YUV422;
984 
985       ret = ioctl(this->video_fd, VIDIOCMCAPTURE, &this->gb_buf);
986     }
987     else
988       lprintf("(%d) YUV420 should work\n", ret);
989 
990     if (ret < 0) {
991       if (errno != EAGAIN) {
992 	lprintf("grab device does not support suitable format\n");
993       } else {
994 	lprintf("grab device does not receive any video signal\n");
995       }
996       close (this->video_fd);
997       return 0;
998     }
999     this->frame_format = this->gb_buf.format;
1000     this->use_mmap     = 1;
1001   }
1002 
1003   switch(this->frame_format) {
1004   case VIDEO_PALETTE_YUV420P:
1005     this->frame_format = BUF_VIDEO_I420;
1006     this->frame_size = (resolutions[j].width * resolutions[j].height * 3) / 2;
1007     break;
1008   case VIDEO_PALETTE_YUV422:
1009     this->frame_format = BUF_VIDEO_YUY2;
1010     this->frame_size = resolutions[j].width * resolutions[j].height * 2;
1011     break;
1012   }
1013 
1014   /* Strip the vbi / sync signal from the image by zooming in */
1015   this->old_zoomx = xine_get_param(this->stream, XINE_PARAM_VO_ZOOM_X);
1016   this->old_zoomy = xine_get_param(this->stream, XINE_PARAM_VO_ZOOM_Y);
1017 
1018   xine_set_param(this->stream, XINE_PARAM_VO_ZOOM_X, 103);
1019   xine_set_param(this->stream, XINE_PARAM_VO_ZOOM_Y, 103);
1020 
1021   /* Pre-allocate some frames for audio and video so it doesn't have to be
1022    * done during capture */
1023   allocate_frames(this, 1);
1024 
1025   /* If we made it here, everything went ok */
1026   this->audio_only = 0;
1027   if (tuner_found)
1028     return 1;
1029   else
1030     /* Not a real error, appart that the tuner name is unknown to us */
1031     return 2;
1032 }
1033 
1034 /**
1035  * Open audio capture device.
1036  *
1037  * This function opens an alsa capture device. This will be used to capture
1038  * audio data from.
1039  */
open_audio_capture_device(v4l_input_plugin_t * this)1040 static int open_audio_capture_device(v4l_input_plugin_t *this)
1041 {
1042 #ifdef HAVE_ALSA
1043   int mode = 0;
1044   snd_pcm_uframes_t buf_size = (this->periodsize * this->periods) >> 2;
1045   lprintf("open_audio_capture_device\n");
1046 
1047   /* Allocate the snd_pcm_hw_params_t structure on the stack. */
1048   snd_pcm_hw_params_alloca(&this->pcm_hwparams);
1049 
1050   /* If we are not capturing video, open the sound device in blocking mode,
1051    * otherwise xine gets too many NULL bufs and doesn't seem to handle them
1052    * correctly. If we are capturing video, open the sound device in non-
1053    * blocking mode, otherwise we will loose video frames while waiting */
1054   if(!this->audio_only)
1055     mode = SND_PCM_NONBLOCK;
1056 
1057   /* Open the PCM device. */
1058   if(snd_pcm_open(&this->pcm_handle, this->pcm_name, this->pcm_stream, mode) < 0) {
1059     xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
1060             "input_v4l: Error opening PCM device: %s\n", this->pcm_name);
1061     this->audio_capture = 0;
1062   }
1063 
1064   /* Get parameters */
1065   if (this->audio_capture &&
1066       (snd_pcm_hw_params_any(this->pcm_handle, this->pcm_hwparams) < 0)) {
1067     xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
1068             "input_v4l: Broken configuration for PCM device: No configurations available\n");
1069     this->audio_capture = 0;
1070   }
1071 
1072   /* Set access type */
1073   if (this->audio_capture &&
1074       (snd_pcm_hw_params_set_access(this->pcm_handle, this->pcm_hwparams,
1075 				    SND_PCM_ACCESS_RW_INTERLEAVED) < 0)) {
1076     xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
1077             "input_v4l: Error setting SND_PCM_ACCESS_RW_INTERLEAVED\n");
1078     this->audio_capture = 0;
1079   }
1080 
1081   /* Set sample format */
1082   if (this->audio_capture &&
1083       (snd_pcm_hw_params_set_format(this->pcm_handle,
1084 				    this->pcm_hwparams, SND_PCM_FORMAT_S16_LE) < 0)) {
1085     xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
1086             "input_v4l: Error setting SND_PCM_FORMAT_S16_LE\n");
1087     this->audio_capture = 0;
1088   }
1089 
1090   /* Set sample rate */
1091   this->exact_rate = this->rate;
1092   if (this->audio_capture &&
1093       (snd_pcm_hw_params_set_rate_near(this->pcm_handle, this->pcm_hwparams,
1094                                        &this->exact_rate, &this->dir) < 0)) {
1095     xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
1096             "input_v4l: Error setting samplerate\n");
1097     this->audio_capture = 0;
1098   }
1099   if (this->audio_capture && this->dir != 0) {
1100     xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
1101             "input_v4l: Samplerate %d Hz is not supported by your hardware\n", this->rate);
1102     xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
1103             "input_v4l: Using %d instead\n", this->exact_rate);
1104   }
1105 
1106   /* Set number of channels */
1107   if (this->audio_capture &&
1108       (snd_pcm_hw_params_set_channels(this->pcm_handle, this->pcm_hwparams, 2) < 0)) {
1109     xprintf(this->stream->xine, XINE_VERBOSITY_LOG, "input_v4l: Error setting PCM channels\n");
1110     this->audio_capture = 0;
1111   }
1112 
1113   if (this->audio_capture &&
1114       (snd_pcm_hw_params_set_periods(this->pcm_handle, this->pcm_hwparams, this->periods, 0) < 0)) {
1115     xprintf(this->stream->xine, XINE_VERBOSITY_LOG, "input_v4l: Error setting PCM periods\n");
1116     this->audio_capture = 0;
1117   }
1118 
1119   /* Set buffersize */
1120   if (this->audio_capture &&
1121       (snd_pcm_hw_params_set_buffer_size_near(this->pcm_handle,
1122 					 this->pcm_hwparams,
1123 					 &buf_size) < 0)) {
1124     xprintf(this->stream->xine, XINE_VERBOSITY_LOG, "input_v4l: Error setting PCM buffer size to %d\n", (int)buf_size );
1125     this->audio_capture = 0;
1126   }
1127 
1128   /* Apply HW parameter settings */
1129   if (this->audio_capture &&
1130       (snd_pcm_hw_params(this->pcm_handle, this->pcm_hwparams) < 0)) {
1131     xprintf(this->stream->xine, XINE_VERBOSITY_LOG, "input_v4l: Error Setting PCM HW params\n");
1132     this->audio_capture = 0;
1133   }
1134 
1135   if (this->audio_capture) {
1136     lprintf("Allocating memory for PCM capture :%d\n", this->periodsize);
1137     this->pcm_data = (unsigned char*) malloc(this->periodsize);
1138   } else
1139     this->pcm_data = NULL;
1140 
1141   lprintf("Audio device succesfully configured\n");
1142 #endif
1143   return 0;
1144 }
1145 
1146 /**
1147  * Adjust realtime speed
1148  *
1149  * If xine is playing at normal speed, tries to adjust xines playing speed to
1150  * avoid buffer overrun and buffer underrun
1151  */
v4l_adjust_realtime_speed(v4l_input_plugin_t * this,fifo_buffer_t * fifo,int speed)1152 static int v4l_adjust_realtime_speed(v4l_input_plugin_t *this, fifo_buffer_t *fifo, int speed)
1153 {
1154   int  num_used, num_free;
1155   int  scr_tuning = this->scr_tuning;
1156 
1157   if (fifo == NULL)
1158     return 0;
1159 
1160   num_used = fifo->size(fifo);
1161   num_free = NUM_FRAMES - num_used;
1162 
1163   if (!this->audio_only && num_used == 0 && scr_tuning != SCR_PAUSED) {
1164     /* Buffer is empty, and we did not pause playback */
1165     report_progress(this->stream, SCR_PAUSED);
1166 
1167     xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
1168 	    "input_v4l: Buffer empty, pausing playback (used: %d, num_free: %d)\n",
1169 	    num_used, num_free);
1170 
1171     _x_set_speed(this->stream, XINE_SPEED_PAUSE);
1172     this->stream->xine->clock->set_option (this->stream->xine->clock, CLOCK_SCR_ADJUSTABLE, 0);
1173 
1174     this->scr_tuning = SCR_PAUSED;
1175     /*      pvrscr_speed_tuning(this->scr, 0.0); */
1176 
1177   } else if (num_free <= 1 && scr_tuning != SCR_SKIP) {
1178     this->scr_tuning = SCR_SKIP;
1179     xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
1180             "input_v4l: Buffer full, skipping (used: %d, free: %d)\n", num_used, num_free);
1181     return 0;
1182   } else if (scr_tuning == SCR_PAUSED) {
1183     if (2 * num_used > num_free) {
1184       /* Playback was paused, but we have normal buffer usage again */
1185       xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
1186 	      "input_v4l: Resuming from paused (used: %d, free: %d)\n", num_used, num_free);
1187 
1188       this->scr_tuning = 0;
1189 
1190       pvrscr_speed_tuning(this->scr, 1.0);
1191 
1192       _x_set_speed(this->stream, XINE_SPEED_NORMAL);
1193       this->stream->xine->clock->set_option (this->stream->xine->clock, CLOCK_SCR_ADJUSTABLE, 1);
1194     }
1195   } else if (scr_tuning == SCR_SKIP) {
1196     if (num_used < 2 * num_free) {
1197       xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
1198               "input_v4l: Resuming from skipping (used: %d, free %d)\n", num_used, num_free);
1199       this->scr_tuning = 0;
1200     } else {
1201       return 0;
1202     }
1203   } else if (speed == XINE_SPEED_NORMAL) {
1204     if (num_used > 2 * num_free)
1205       /* buffer used > 2/3. Increase playback speed to avoid buffer
1206        * overrun */
1207       scr_tuning = +1;
1208     else if (num_free > 2 * num_used)
1209       /* Buffer used < 1/3. Decrease playback speed to avoid buffer
1210        * underrun */
1211       scr_tuning = -1;
1212     else if ((scr_tuning > 0 && num_free > num_used) ||
1213 	     (scr_tuning < 0 && num_used > num_free))
1214       /* Buffer usage is ok again. Set playback speed to normal */
1215       scr_tuning = 0;
1216 
1217     /* Check if speed adjustment should be changed */
1218     if (scr_tuning != this->scr_tuning) {
1219       this->scr_tuning = scr_tuning;
1220       xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
1221               "input_v4l: scr tuning = %d (used: %d, free: %d)\n",
1222               scr_tuning, num_used, num_free);
1223       pvrscr_speed_tuning(this->scr, 1.0 + (0.01 * scr_tuning));
1224     }
1225   } else if (this->scr_tuning) {
1226     /* Currently speed adjustment is on. But xine is not playing at normal
1227      * speed, so there is no reason why we should try to adjust our playback
1228      * speed
1229      */
1230     this->scr_tuning = 0;
1231 
1232     xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
1233             "input_v4l: scr tuning resetting (used: %d, free: %d\n", num_used, num_free);
1234 
1235     pvrscr_speed_tuning(this->scr, 1.0);
1236   }
1237 
1238   return 1;
1239 }
1240 
1241 /**
1242  * Plugin read.
1243  * This function is not supported by the plugin.
1244  */
v4l_plugin_read(input_plugin_t * this_gen,void * buf,off_t len)1245 static off_t v4l_plugin_read (input_plugin_t *this_gen, void *buf, off_t len) {
1246   lprintf("Read not supported\n");
1247   (void)this_gen;
1248   (void)buf;
1249   (void)len;
1250   return 0;
1251 }
1252 
1253 /**
1254  * Get time.
1255  * Gets a pts time value.
1256  */
get_time(void)1257 inline static int64_t get_time(void) {
1258   struct timeval tv;
1259 
1260   xine_monotonic_clock(&tv,NULL);
1261 
1262   return (int64_t) tv.tv_sec * 90000 + (int64_t) tv.tv_usec * 9 / 100;
1263 }
1264 
1265 
1266 /**
1267  * Plugin read block
1268  * Reads one data block. This is either an audio frame or an video frame
1269  */
v4l_plugin_read_block(input_plugin_t * this_gen,fifo_buffer_t * fifo,off_t todo)1270 static buf_element_t *v4l_plugin_read_block (input_plugin_t *this_gen, fifo_buffer_t *fifo, off_t todo)
1271 {
1272   v4l_input_plugin_t   *this = (v4l_input_plugin_t *) this_gen;
1273   buf_element_t        *buf = NULL;
1274   uint8_t              *ptr;
1275   static char           video = 0;
1276   int                   speed = _x_get_speed(this->stream);
1277 
1278 #ifndef LOG
1279   (void)todo;
1280 #endif
1281   v4l_event_handler(this);
1282 
1283 #ifdef HAVE_ALSA
1284   if (!this->audio_header_sent) {
1285     lprintf("sending audio header\n");
1286 
1287     buf = alloc_aud_frame (this);
1288 
1289     buf->size          = 0;
1290     buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAME_END;
1291 
1292     buf->decoder_info[0] = 0;
1293     buf->decoder_info[1] = this->exact_rate;
1294     buf->decoder_info[2] = this->bits;
1295     buf->decoder_info[3] = 2;
1296 
1297     this->audio_header_sent = 1;
1298 
1299     return buf;
1300   }
1301 #endif
1302 
1303   if (!this->audio_only && !this->video_header_sent) {
1304     xine_bmiheader bih;
1305 
1306     lprintf("sending video header");
1307 
1308     memset(&bih, 0, sizeof(bih));
1309     bih.biSize   = sizeof(xine_bmiheader);
1310     bih.biWidth  = this->resolution->width;
1311     bih.biHeight = this->resolution->height;
1312 
1313     buf = alloc_vid_frame (this);
1314 
1315     buf->size          = sizeof(xine_bmiheader);
1316     buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAME_END;
1317 
1318     memcpy(buf->content, &bih, sizeof(xine_bmiheader));
1319 
1320     this->video_header_sent = 1;
1321 
1322     return buf;
1323   }
1324 
1325   if (!this->audio_only) {
1326     if (!v4l_adjust_realtime_speed(this, fifo, speed)) {
1327       return NULL;
1328     }
1329   }
1330 
1331   if (!this->audio_only)
1332     video = !video;
1333   else
1334     video = 0;
1335 
1336   lprintf("%lld bytes...\n", todo);
1337 
1338   if (this->start_time == 0)
1339     /* Create a start pts value */
1340     this->start_time = get_time(); /* this->stream->xine->clock->get_current_time(this->stream->xine->clock); */
1341 
1342   if (video) {
1343     /* Capture video */
1344     buf = alloc_vid_frame (this);
1345     buf->decoder_flags = BUF_FLAG_FRAME_START|BUF_FLAG_FRAME_END;
1346 
1347     this->gb_buf.frame = this->gb_frame;
1348 
1349     lprintf("VIDIOCMCAPTURE\n");
1350 
1351     while (ioctl(this->video_fd, VIDIOCMCAPTURE, &this->gb_buf) < 0) {
1352       lprintf("Upper while loop\n");
1353       if (errno == EAGAIN) {
1354 	lprintf("Cannot sync\n");
1355 	continue;
1356       } else {
1357 	perror("VIDIOCMCAPTURE");
1358 	buf->free_buffer(buf);
1359 	return NULL;
1360       }
1361     }
1362 
1363     this->gb_frame = (this->gb_frame + 1) % this->gb_buffers.frames;
1364 
1365     while (ioctl(this->video_fd, VIDIOCSYNC, &this->gb_frame) < 0 &&
1366 	   (errno == EAGAIN || errno == EINTR))
1367       {
1368 	lprintf("Waiting for videosync\n");
1369       }
1370 
1371     /* printf ("grabbing frame #%d\n", frame_num); */
1372 
1373     ptr      = this->video_buf + this->gb_buffers.offsets[this->gb_frame];
1374     buf->pts = get_time(); /* this->stream->xine->clock->get_current_time(this->stream->xine->clock); */
1375     xine_fast_memcpy (buf->content, ptr, this->frame_size);
1376   }
1377 #ifdef HAVE_ALSA
1378   else if (this->audio_capture) {
1379     /* Record audio */
1380     int pcmreturn;
1381 
1382     if ((pcmreturn = snd_pcm_readi(this->pcm_handle, this->pcm_data, (this->periodsize)>> 2)) < 0) {
1383       switch (pcmreturn) {
1384       case -EAGAIN:
1385 	/* No data available at the moment */
1386 	break;
1387       case -EBADFD:     /* PCM device in wrong state */
1388 	xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
1389                 "input_v4l: PCM is not in the right state\n");
1390 	break;
1391       case -EPIPE:      /* Buffer overrun */
1392 	xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
1393                 "input_v4l: PCM buffer Overrun (lost some samples)\n");
1394 	/* On buffer overrun we need to re prepare the capturing pcm device */
1395 	snd_pcm_prepare(this->pcm_handle);
1396 	break;
1397       default:	      /* Unknown */
1398 	xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
1399                 "input_v4l: Unknown PCM error code: %d\n", pcmreturn);
1400 	snd_pcm_prepare(this->pcm_handle);
1401       }
1402     } else {
1403       /* Succesfully read audio data */
1404 
1405       if (this->pts_aud_start) {
1406 	buf = alloc_aud_frame (this);
1407         buf->decoder_flags = 0;
1408       }
1409 
1410       /* We want the pts on the start of the sample. As the soundcard starts
1411        * sampling a new sample as soon as the read function returned with a
1412        * success we will save the current pts and assign the current pts to
1413        * that sample when we read it
1414        */
1415 
1416       /* Assign start pts to sample */
1417       if (buf)
1418 	buf->pts = this->pts_aud_start;
1419 
1420       /* Save start pts */
1421       this->pts_aud_start = get_time(); /* this->stream->xine->clock->get_current_time(this->stream->xine->clock); */
1422 
1423       if (!buf)
1424 	/* Skip first sample as we don't have a good pts for this one */
1425 	return NULL;
1426 
1427       lprintf("Audio: Data read: %d [%d, %d]. Pos: %d\n",
1428 	       pcmreturn, (int) (*this->pcm_data), (int) (*(this->pcm_data + this->periodsize - 3)),
1429 	       (int) this->curpos);
1430 
1431 
1432       /* Tell decoder the number of bytes we have read */
1433       buf->size = pcmreturn<<2;
1434 
1435       this->curpos++;
1436 
1437       xine_fast_memcpy(buf->content, this->pcm_data, buf->size);
1438     }
1439   }
1440 #endif
1441 
1442   lprintf("read block done\n");
1443 
1444   return buf;
1445 }
1446 
1447 /**
1448  * Plugin seek.
1449  * Not supported by the plugin.
1450  */
v4l_plugin_seek(input_plugin_t * this_gen,off_t offset,int origin)1451 static off_t v4l_plugin_seek (input_plugin_t *this_gen, off_t offset, int origin) {
1452   v4l_input_plugin_t *this = (v4l_input_plugin_t *) this_gen;
1453 
1454   (void)this_gen;
1455 #ifndef LOG
1456   (void)offset;
1457   (void)origin;
1458 #endif
1459   lprintf("seek %lld bytes, origin %d\n", offset, origin);
1460   return this->curpos;
1461 }
1462 
1463 /**
1464  * Plugin get length.
1465  * This is a live stream, and as such does not have an known end.
1466  */
v4l_plugin_get_length(input_plugin_t * this_gen)1467 static off_t v4l_plugin_get_length (input_plugin_t *this_gen) {
1468   /*
1469     v4l_input_plugin_t   *this = (v4l_input_plugin_t *) this_gen;
1470     off_t                 length;
1471   */
1472 
1473   (void)this_gen;
1474   return -1;
1475 }
1476 
1477 /**
1478  * Plugin get capabilitiets.
1479  * This plugin does not support any special capabilities.
1480  */
v4l_plugin_get_capabilities(input_plugin_t * this_gen)1481 static uint32_t v4l_plugin_get_capabilities (input_plugin_t *this_gen)
1482 {
1483   v4l_input_plugin_t   *this = (v4l_input_plugin_t *) this_gen;
1484 
1485   if (this->audio_only)
1486     return 0x10;
1487   else
1488     return 0; /* 0x10: Has audio only. */
1489 }
1490 
1491 /**
1492  * Plugin get block size.
1493  * Unsupported by the plugin.
1494  */
v4l_plugin_get_blocksize(input_plugin_t * this_gen)1495 static uint32_t v4l_plugin_get_blocksize (input_plugin_t *this_gen)
1496 {
1497   (void)this_gen;
1498   return 0;
1499 }
1500 
1501 /**
1502  * Plugin get current pos.
1503  * Unsupported by the plugin.
1504  */
v4l_plugin_get_current_pos(input_plugin_t * this_gen)1505 static off_t v4l_plugin_get_current_pos (input_plugin_t *this_gen){
1506   v4l_input_plugin_t *this = (v4l_input_plugin_t *) this_gen;
1507 
1508   /*
1509     printf ("current pos is %lld\n", this->curpos);
1510   */
1511 
1512   return this->curpos;
1513 }
1514 
1515 /**
1516  * Event handler.
1517  *
1518  * Processes events from a frontend. This way frequencies can be changed
1519  * without closing the v4l plugin.
1520  */
v4l_event_handler(v4l_input_plugin_t * this)1521 static void v4l_event_handler (v4l_input_plugin_t *this) {
1522   xine_event_t *event;
1523 
1524   while ((event = xine_event_get (this->event_queue))) {
1525     xine_set_v4l2_data_t *v4l2_data = event->data;
1526 
1527     switch (event->type) {
1528     case XINE_EVENT_SET_V4L2:
1529       if( v4l2_data->input != this->input ||
1530 	  v4l2_data->channel != this->channel ||
1531 	  v4l2_data->frequency != this->frequency ) {
1532 
1533 	this->input     = v4l2_data->input;
1534 	this->channel   = v4l2_data->channel;
1535 	this->frequency = v4l2_data->frequency;
1536 
1537 	lprintf("Switching to input:%d chan:%d freq:%.2f\n",
1538 		 v4l2_data->input,
1539 		 v4l2_data->channel,
1540 		 (float)v4l2_data->frequency);
1541 
1542 	set_frequency(this, this->frequency);
1543 	_x_demux_flush_engine(this->stream);
1544       }
1545       break;
1546       /*	 default:
1547 
1548       lprintf("Got an event, type 0x%08x\n", event->type);
1549       */
1550     }
1551 
1552     xine_event_free (event);
1553   }
1554 }
1555 
1556 /**
1557  * Dispose plugin.
1558  *
1559  * Closes the plugin, restore the V4L device in the initial state (volume) and
1560  * frees the allocated memory
1561  */
v4l_plugin_dispose(input_plugin_t * this_gen)1562 static void v4l_plugin_dispose (input_plugin_t *this_gen) {
1563   v4l_input_plugin_t *this = (v4l_input_plugin_t *) this_gen;
1564 
1565   _x_freep(&this->mrl);
1566 
1567   if (this->scr) {
1568     this->stream->xine->clock->unregister_scr(this->stream->xine->clock, &this->scr->scr);
1569     this->scr->scr.exit(&this->scr->scr);
1570   }
1571 
1572   /* Close and free video device */
1573   _x_freep(&this->tuner_name);
1574 
1575   /* Close video device only if device was opened */
1576   if (this->video_fd > 0) {
1577 
1578     /* Restore v4l audio volume */
1579     lprintf("Restoring v4l audio volume %d\n",
1580 	     ioctl(this->video_fd, VIDIOCSAUDIO, &this->audio_saved));
1581     ioctl(this->video_fd, VIDIOCSAUDIO, &this->audio_saved);
1582 
1583     /* Unmap memory */
1584     if (this->video_buf != NULL &&
1585 	munmap(this->video_buf, this->gb_buffers.size) != 0) {
1586       xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
1587               "input_v4l: Could not unmap video memory: %s\n", strerror(errno));
1588     } else
1589       lprintf("Succesfully unmapped video memory (size %d)\n", this->gb_buffers.size);
1590 
1591     lprintf("Closing video filehandler %d\n", this->video_fd);
1592 
1593     /* Now close the video device */
1594     if (close(this->video_fd) != 0)
1595       xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
1596               "input_v4l: Error while closing video file handler: %s\n", strerror(errno));
1597     else
1598       lprintf("Video device succesfully closed\n");
1599 
1600     /* Restore zoom setting */
1601     xine_set_param(this->stream, XINE_PARAM_VO_ZOOM_X, this->old_zoomx);
1602     xine_set_param(this->stream, XINE_PARAM_VO_ZOOM_Y, this->old_zoomy);
1603   }
1604 
1605   if (this->radio_fd > 0) {
1606     close(this->radio_fd);
1607   }
1608 
1609 #ifdef HAVE_ALSA
1610   /* Close audio device */
1611   if (this->pcm_handle) {
1612     snd_pcm_drop(this->pcm_handle);
1613     snd_pcm_close(this->pcm_handle);
1614   }
1615 
1616   _x_freep(&this->pcm_data);
1617   _x_freep(&this->pcm_name);
1618 #endif
1619 
1620   if (this->event_queue)
1621     xine_event_dispose_queue (this->event_queue);
1622 
1623   /* All the frames, both video and audio, are allocated in a single
1624      memory area pointed by the frames_base pointer. The content of
1625      the frames is divided in two areas, one pointed by
1626      audio_content_base and the other by video_content_base. The
1627      extra_info structures are all allocated in the first frame
1628      data. */
1629   _x_freep(&this->audio_content_base);
1630   _x_freep(&this->video_content_base);
1631   if (this->frames_base)
1632     _x_freep(&this->frames_base->extra_info);
1633   _x_freep(&this->frames_base);
1634 
1635 #ifdef LOG
1636   printf("\n");
1637 #endif
1638 
1639   free (this);
1640 
1641   lprintf("plugin     Bye bye! \n");
1642 }
1643 
1644 /**
1645  * Get MRL.
1646  *
1647  * Get the current MRL used by the plugin.
1648  */
v4l_plugin_get_mrl(input_plugin_t * this_gen)1649 static const char* v4l_plugin_get_mrl (input_plugin_t *this_gen) {
1650   v4l_input_plugin_t *this = (v4l_input_plugin_t *) this_gen;
1651 
1652   return this->mrl;
1653 }
1654 
v4l_plugin_get_optional_data(input_plugin_t * this_gen,void * data,int data_type)1655 static int v4l_plugin_get_optional_data (input_plugin_t *this_gen,
1656                                          void *data, int data_type) {
1657   /* v4l_input_plugin_t *this = (v4l_input_plugin_t *) this_gen; */
1658 
1659   (void)this_gen;
1660   (void)data;
1661   (void)data_type;
1662   return INPUT_OPTIONAL_UNSUPPORTED;
1663 }
1664 
v4l_plugin_radio_open(input_plugin_t * this_gen)1665 static int v4l_plugin_radio_open (input_plugin_t *this_gen)
1666 {
1667   v4l_input_plugin_t *this = (v4l_input_plugin_t *) this_gen;
1668 
1669   if(open_radio_capture_device(this) != 1)
1670     return 0;
1671 
1672   open_audio_capture_device(this);
1673 
1674 #ifdef HAVE_ALSA
1675   this->start_time     = 0;
1676   this->pts_aud_start  = 0;
1677   this->curpos         = 0;
1678   this->event_queue    = xine_event_new_queue (this->stream);
1679 #endif
1680 
1681   return 1;
1682 }
1683 
1684 
v4l_plugin_video_open(input_plugin_t * this_gen)1685 static int v4l_plugin_video_open (input_plugin_t *this_gen)
1686 {
1687   v4l_input_plugin_t *this = (v4l_input_plugin_t *) this_gen;
1688   int64_t             time;
1689 
1690   if(!open_video_capture_device(this))
1691     return 0;
1692 
1693   open_audio_capture_device(this);
1694 
1695 #ifdef HAVE_ALSA
1696   this->pts_aud_start = 0;
1697 #endif
1698   this->start_time    = 0;
1699   this->curpos        = 0;
1700 
1701   /* Register our own scr provider */
1702   time                = this->stream->xine->clock->get_current_time(this->stream->xine->clock);
1703   this->scr           = pvrscr_init();
1704   this->scr->scr.start(&this->scr->scr, time);
1705   this->stream->xine->clock->register_scr(this->stream->xine->clock, &this->scr->scr);
1706   this->scr_tuning    = 0;
1707 
1708   /* enable resample method */
1709   this->stream->xine->config->update_num(this->stream->xine->config, "audio.synchronization.av_sync_method", 1);
1710 
1711   this->event_queue = xine_event_new_queue (this->stream);
1712 
1713   return 1;
1714 }
1715 
1716 /**
1717  * Create a new instance.
1718  *
1719  * Creates a new instance of the plugin. Doesn't initialise the V4L device,
1720  * does initialise the structure.
1721  */
v4l_class_get_instance(input_class_t * cls_gen,xine_stream_t * stream,const char * data)1722 static input_plugin_t *v4l_class_get_instance (input_class_t *cls_gen,
1723 					       xine_stream_t *stream, const char *data)
1724 {
1725   /* v4l_input_class_t  *cls = (v4l_input_class_t *) cls_gen; */
1726   v4l_input_plugin_t *this;
1727 #ifdef HAVE_ALSA
1728   cfg_entry_t        *entry;
1729 #endif
1730 
1731   /* Example mrl:  v4l:/Television/62500 */
1732   if(!data || strncasecmp(data, "v4l:/", 5)) {
1733     return NULL;
1734   }
1735 
1736   this = calloc(1, sizeof (v4l_input_plugin_t));
1737   if (!this)
1738     return NULL;
1739 
1740   this->stream        = stream;
1741   this->mrl           = strdup(data);
1742   if (!this->mrl) {
1743     free(this);
1744     return NULL;
1745   }
1746   this->video_buf     = NULL;
1747   this->video_fd      = -1;
1748   this->radio_fd      = -1;
1749   this->event_queue   = NULL;
1750   this->scr           = NULL;
1751 #ifdef HAVE_ALSA
1752   this->pcm_data      = NULL;
1753   this->pcm_hwparams  = NULL;
1754 
1755   extract_mrl(this, this->mrl);
1756 
1757   /* Audio */
1758   this->pcm_stream    = SND_PCM_STREAM_CAPTURE;
1759   entry = this->stream->xine->config->lookup_entry(this->stream->xine->config,
1760                                                    "media.video4linux.audio_device");
1761   this->pcm_name      = strdup (entry->str_value);
1762   this->audio_capture = 1;
1763   if (!this->pcm_name) {
1764     v4l_plugin_dispose(&this->input_plugin);
1765     return NULL;
1766   }
1767 #endif
1768   this->rate          = 44100;
1769   this->periods       = 2;
1770   this->periodsize    = 2 * 8192;
1771   this->bits          = 16;
1772 
1773   pthread_mutex_init (&this->aud_frames_lock, NULL);
1774   pthread_cond_init  (&this->aud_frame_freed, NULL);
1775 
1776   pthread_mutex_init (&this->vid_frames_lock, NULL);
1777   pthread_cond_init  (&this->vid_frame_freed, NULL);
1778 
1779   this->input_plugin.get_capabilities  = v4l_plugin_get_capabilities;
1780   this->input_plugin.read              = v4l_plugin_read;
1781   this->input_plugin.read_block        = v4l_plugin_read_block;
1782   this->input_plugin.seek              = v4l_plugin_seek;
1783   this->input_plugin.get_current_pos   = v4l_plugin_get_current_pos;
1784   this->input_plugin.get_length        = v4l_plugin_get_length;
1785   this->input_plugin.get_blocksize     = v4l_plugin_get_blocksize;
1786   this->input_plugin.get_mrl           = v4l_plugin_get_mrl;
1787   this->input_plugin.dispose           = v4l_plugin_dispose;
1788   this->input_plugin.get_optional_data = v4l_plugin_get_optional_data;
1789   this->input_plugin.input_class       = cls_gen;
1790 
1791   return &this->input_plugin;
1792 }
1793 
v4l_class_get_video_instance(input_class_t * cls_gen,xine_stream_t * stream,const char * data)1794 static input_plugin_t *v4l_class_get_video_instance (input_class_t *cls_gen,
1795 						     xine_stream_t *stream, const char *data)
1796 {
1797   v4l_input_plugin_t  *this  = NULL;
1798   int                  is_ok = 1;
1799   cfg_entry_t         *entry;
1800 
1801   this = (v4l_input_plugin_t *) v4l_class_get_instance (cls_gen, stream, data);
1802 
1803   if (this)
1804     this->input_plugin.open = v4l_plugin_video_open;
1805   else
1806     return NULL;
1807 
1808   entry = this->stream->xine->config->lookup_entry(this->stream->xine->config,
1809                                                    "media.video4linux.video_device");
1810 
1811   /* Try to open the video device */
1812   if((this->video_fd = xine_open_cloexec(entry->str_value, O_RDWR)) < 0) {
1813     xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
1814             "input_v4l: error opening v4l device (%s): %s\n",
1815             entry->str_value, strerror(errno));
1816     is_ok = 0;
1817   } else
1818     lprintf("Device opened, tv %d\n", this->video_fd);
1819 
1820   /* Get capabilities */
1821   if (is_ok && ioctl(this->video_fd, VIDIOCGCAP, &this->video_cap) < 0) {
1822     xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
1823             "input_v4l: v4l card doesn't support some features needed by xine\n");
1824     is_ok = 0;;
1825   }
1826 
1827   if (is_ok && !(this->video_cap.type & VID_TYPE_CAPTURE)) {
1828     /* Capture is not supported by the device. This is a must though! */
1829     xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
1830             "input_v4l: v4l card doesn't support frame grabbing\n");
1831     is_ok = 0;
1832   }
1833 
1834   if (is_ok && set_input_source(this, this->tuner_name) <= 0) {
1835     xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
1836             "input_v4l: unable to locate the tuner name (%s) on your v4l card\n",
1837             this->tuner_name);
1838     is_ok = 0;
1839   }
1840 
1841   if (this->video_fd > 0) {
1842     close(this->video_fd);
1843     this->video_fd = -1;
1844   }
1845 
1846   if (!is_ok) {
1847     v4l_plugin_dispose((input_plugin_t *) this);
1848     return NULL;
1849   }
1850 
1851   return &this->input_plugin;
1852 }
1853 
1854 
v4l_class_get_radio_instance(input_class_t * cls_gen,xine_stream_t * stream,const char * data)1855 static input_plugin_t *v4l_class_get_radio_instance (input_class_t *cls_gen,
1856 						     xine_stream_t *stream, const char *data)
1857 {
1858   v4l_input_plugin_t *this  = NULL;
1859   int                 is_ok = 1;
1860   cfg_entry_t        *entry;
1861 
1862   if (strstr(data, "Radio") == NULL)
1863     return NULL;
1864 
1865   this = (v4l_input_plugin_t *) v4l_class_get_instance (cls_gen, stream, data);
1866 
1867   if (this)
1868     this->input_plugin.open = v4l_plugin_radio_open;
1869   else
1870     return NULL;
1871 
1872   entry = this->stream->xine->config->lookup_entry(this->stream->xine->config,
1873                                                    "media.video4linux.radio_device");
1874 
1875   if((this->radio_fd = xine_open_cloexec(entry->str_value, O_RDWR)) < 0) {
1876     xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
1877             "input_v4l: error opening v4l device (%s): %s\n",
1878             entry->str_value, strerror(errno));
1879     is_ok = 0;
1880   } else
1881     lprintf("Device opened, radio %d\n", this->radio_fd);
1882 
1883   if (is_ok && set_input_source(this, this->tuner_name) <= 0) {
1884     xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
1885             "input_v4l: unable to locate the tuner name (%s) on your v4l card\n",
1886             this->tuner_name);
1887     is_ok = 0;
1888   }
1889 
1890   if (this->radio_fd > 0) {
1891     close(this->radio_fd);
1892     this->radio_fd = -1;
1893   }
1894 
1895   if (!is_ok) {
1896     v4l_plugin_dispose((input_plugin_t *) this);
1897     return NULL;
1898   }
1899 
1900   return &this->input_plugin;
1901 }
1902 
1903 
1904 /*
1905  * v4l input plugin class stuff
1906  */
init_video_class(xine_t * xine,const void * data)1907 static void *init_video_class (xine_t *xine, const void *data)
1908 {
1909   static const input_class_t v4l_video_input_class = {
1910     .get_instance       = v4l_class_get_video_instance,
1911     .identifier         = "v4l",
1912     .description        = N_("v4l tv input plugin"),
1913     .get_dir            = NULL,
1914     .get_autoplay_list  = NULL,
1915     .dispose            = NULL,
1916     .eject_media        = NULL,
1917   };
1918 
1919   config_values_t    *config = xine->config;
1920 
1921   config->register_filename (config, "media.video4linux.video_device",
1922 			   VIDEO_DEV, XINE_CONFIG_STRING_IS_DEVICE_NAME,
1923 			   _("v4l video device"),
1924 			   _("The path to your Video4Linux video device."),
1925 			   10, NULL, NULL);
1926 #ifdef HAVE_ALSA
1927   config->register_filename (config, "media.video4linux.audio_device",
1928 			   AUDIO_DEV, 0,
1929 			   _("v4l ALSA audio input device"),
1930 			   _("The name of the audio device which corresponds "
1931 			     "to your Video4Linux video device."),
1932 			   10, NULL, NULL);
1933 #endif
1934   config->register_enum (config, "media.video4linux.tv_standard", 0 /* auto */,
1935                         (char **)tv_standard_names, _("v4l TV standard"),
1936                         _("Selects the TV standard of the input signals. "
1937                         "Either: AUTO, PAL, NTSC or SECAM. "), 20, NULL, NULL);
1938 
1939   (void)data;
1940   return (void *)&v4l_video_input_class;
1941 }
1942 
init_radio_class(xine_t * xine,const void * data)1943 static void *init_radio_class (xine_t *xine, const void *data)
1944 {
1945   static const input_class_t v4l_radio_input_class = {
1946     .get_instance       = v4l_class_get_radio_instance,
1947     .identifier         = "v4l",
1948     .description        = N_("v4l radio input plugin"),
1949     .get_dir            = NULL,
1950     .get_autoplay_list  = NULL,
1951     .dispose            = NULL,
1952     .eject_media        = NULL,
1953   };
1954 
1955   config_values_t *config = xine->config;
1956 
1957   config->register_filename (config, "media.video4linux.radio_device",
1958 			   RADIO_DEV, XINE_CONFIG_STRING_IS_DEVICE_NAME,
1959 			   _("v4l radio device"),
1960 			   _("The path to your Video4Linux radio device."),
1961 			   10, NULL, NULL);
1962 
1963   (void)data;
1964   return (void *)&v4l_radio_input_class;
1965 }
1966 
1967 /*
1968  * exported plugin catalog entry
1969  */
1970 
1971 const plugin_info_t xine_plugin_info[] EXPORTED = {
1972   /* type, API, "name", version, special_info, init_function */
1973   { PLUGIN_INPUT | PLUGIN_MUST_PRELOAD, 18, "v4l_radio", XINE_VERSION_CODE, NULL, init_radio_class },
1974   { PLUGIN_INPUT | PLUGIN_MUST_PRELOAD, 18, "v4l_tv", XINE_VERSION_CODE, NULL, init_video_class },
1975   { PLUGIN_NONE, 0, NULL, 0, NULL, NULL }
1976 };
1977 
1978 /*
1979  * vim:sw=3:sts=3:
1980  */
1981