1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <time.h>
6 #include <fcntl.h>
7 #include <sys/ioctl.h>
8 #include <sys/types.h>
9 #include <sys/mman.h>
10 #include <sys/stat.h>
11 #include <sys/time.h>
12 #include <sys/resource.h>
13 #include <sys/soundcard.h>
14 #include <linux/wait.h>
15 #include <errno.h>
16 #include "nuppelvideo.h"
17 
18 #define MEAN_DO_NO_WANT_V4L2
19 #include <linux/videodev.h>
20 
21 
22 
23 #include "ffv1.h"
24 // we need the BTTV_FIELDNR, so we really know how many frames we lose
25 #define BTTV_FIELDNR            _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int)
26 
27 static  struct video_mmap mm;
28 static  struct video_mbuf vm;
29 static struct video_channel vchan;
30 static  struct video_audio va;
31 static  struct video_tuner vt;
32 static struct video_audio origaudio;
33 static  unsigned char *buf;
34 
35 extern int quiet;
36 
37 extern struct vidbuffertype *videobuffer;
38 extern int				 video_buffer_count;   // should be a setting from command line  6.3MB 384x288x40
39 				                            //                                       23.2MB 704x576x40
40 extern long int  			video_buffer_size;
41 
42 
43 static int fd;
44 static void bufferit(unsigned char *buf);
45 static int usebttv=0;
46 static struct timeval now, stm;
47 static struct timezone tzone;
48 static v4linfo vinfo;
49 static unsigned int tf=0;
50 /*
51 	Init the video input
52 */
53 
initVideoDev(char * videodevice,v4linfo * info)54 int initVideoDev(char *videodevice, v4linfo *info )
55 {
56 long int v4lfrequency=0;
57 int volume=-1;
58 
59 	memcpy(&vinfo,info,sizeof(vinfo));
60  	fd = open(videodevice, O_RDWR|O_CREAT);
61   	if(fd<=0)
62   	{
63     		perror("open");
64     		return 0;
65   	}
66 
67   	if(ioctl(fd, VIDIOCGMBUF, &vm)<0)
68   	{
69   		perror("VIDIOCMCAPTUREi0");
70 		return 0;
71   	}
72   	if(vm.frames<2)
73   	{
74 	  	fprintf(stderr, "stoopid prog want min 2 cap buffs!\n");
75   		return 0;
76   	}
77 
78   // fprintf(stderr, "We have vm.frames=%d\n", vm.frames);
79 
80   	buf = (unsigned char*)mmap(0, vm.size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
81   	if (buf<=0)
82   	{
83    		perror("mmap");
84    		return 0;
85   	}
86 
87 
88   	vchan.channel = info->channel;
89   	if(ioctl(fd, VIDIOCGCHAN, &vchan)<0) perror("VIDIOCGCHAN");
90 
91   	// choose the right input
92   	if(ioctl(fd, VIDIOCSCHAN, &vchan)<0) perror("VIDIOCSCHAN");
93 
94   	// if channel has a audio/tuner then activate it
95         // this was a check for VIDEO_VC_AUDIO, but somehow my saa7134 card only reports
96         // VIDEO_VC_TUNER, and it definitely has audio. Maybe one could omit this check completely?!?
97   	if ( (vchan.flags & VIDEO_VC_TUNER)==VIDEO_VC_TUNER) {
98     	// we assume only a channel with audio can have a tuner therefore
99     	// we only tune here if we are supposed to
100     	if (info->frequency != 0.0)
101 	{
102       		v4lfrequency  = ((unsigned long)info->frequency)*16;
103       		v4lfrequency |= ((unsigned long)( (info->frequency-(v4lfrequency/16))*100 )*16)/100; // ??????
104       		if (ioctl(fd, VIDIOCSFREQ, &v4lfrequency)<0) perror("VIDIOCSFREQ");
105       		if (!quiet) fprintf(stderr, "tuner frequency set to '%5.4f' MHz.\n", info->frequency);
106     	}
107     	if (!quiet) fprintf(stderr, "%s\n", "unmuting tv-audio");
108     	// audio hack, to enable audio from tvcard, in case we use a tuner
109     	va.audio = 0; // use audio channel 0
110     	if (ioctl(fd, VIDIOCGAUDIO, &va)<0) perror("VIDIOCGAUDIO");
111     	origaudio = va;
112     	if (!quiet) fprintf(stderr, "audio volume was '%d'\n", va.volume);
113     	va.audio = 0;
114     	va.flags &= ~VIDEO_AUDIO_MUTE; // now this really has to work
115 
116     	if ((volume==-1 && va.volume<32768) || volume!=-1) {
117       	if (volume==-1)
118 	{
119         	va.volume = 32768;            // no more silence 8-)
120       	}
121 	 else
122 	 {
123         	va.volume = volume;
124       	}
125       	if (!quiet) fprintf(stderr, "audio volume set to '%d'\n", va.volume);
126     	}
127     	if (ioctl(fd, VIDIOCSAUDIO, &va)<0) perror("VIDIOCSAUDIO");
128   } else {
129     if (!quiet) fprintf(stderr, "channel '%d' has no tuner (composite)\n", info->channel);
130   }
131 
132   // setting video mode
133   vt.tuner = 0;
134   if(ioctl(fd, VIDIOCGTUNER, &vt)<0) perror("VIDIOCGTUNER");
135   if (info->ntsc)         { vt.flags |= VIDEO_TUNER_NTSC;  vt.mode |= VIDEO_MODE_NTSC; }
136     else if (info->secam) { vt.flags |= VIDEO_TUNER_SECAM; vt.mode |= VIDEO_MODE_SECAM; }
137       else          { vt.flags |= VIDEO_TUNER_PAL;   vt.mode |= VIDEO_MODE_PAL; }
138   vt.tuner = 0;
139   if(ioctl(fd, VIDIOCSTUNER, &vt)<0) perror("VIDIOCSTUNER");
140 
141   // make sure we use the right input
142   if(ioctl(fd, VIDIOCSCHAN, &vchan)<0) perror("VIDIOCSCHAN");
143 
144   mm.height = info->height;
145   mm.width  = info->width;
146   mm.format = VIDEO_PALETTE_YUV420P    ; /* YCrCb422 */
147 
148   mm.frame  = 0;
149   if(ioctl(fd, VIDIOCMCAPTURE, &mm)<0) perror("VIDIOCMCAPTUREi0");
150   mm.frame  = 1;
151   if(ioctl(fd, VIDIOCMCAPTURE, &mm)<0) perror("VIDIOCMCAPTUREi1");
152 
153   	printf("Video init successfull\n");
154 	return 1;
155   }
156 
157 
closeVideoDev(void)158 void closeVideoDev (void)
159 {
160   	// if channel has a audio then activate it
161   	if ((vchan.flags & VIDEO_VC_TUNER)==VIDEO_VC_TUNER) {
162       printf("resetting audio!\n");
163       if (ioctl(fd, VIDIOCSAUDIO, &origaudio)<0) perror("VIDIOCSAUDIO");
164 
165     }
166 }
167 /*
168 	Main loop for capturing video
169 
170 */
captureVideoDev(void)171   void captureVideoDev( void )
172   {
173   int frame;
174   	while(1) {
175     		frame=0;
176     		mm.frame  = 0;
177     		if(ioctl(fd, VIDIOCSYNC, &frame)<0) perror("VIDIOCSYNC0");
178     		else
179 		{
180       			if(ioctl(fd, VIDIOCMCAPTURE, &mm)<0) perror("VIDIOCMCAPTURE0");
181       			DP("Captured 0er");
182       			bufferit(buf+vm.offsets[0]);
183     		}
184     		frame=1;
185     		mm.frame  = 1;
186     		if(ioctl(fd, VIDIOCSYNC, &frame)<0) perror("VIDIOCSYNC1");
187     		else
188 		{
189       			if(ioctl(fd, VIDIOCMCAPTURE, &mm)<0) perror("VIDIOCMCAPTURE1");
190       			DP("Captured 1er");
191       			bufferit(buf+vm.offsets[1]);
192     		}
193   }
194 }
195 /*-----------------------------------------------------------*/
bufferit(unsigned char * buf)196 void bufferit(unsigned char *buf)
197 {
198  static long int act_video_buffer=0;
199  int act;
200  long tcres;
201  //static int firsttc=0;
202  static int oldtc=0;
203  int fn;
204 
205  act = act_video_buffer;
206 
207  if (! videobuffer[act].freeToBuffer) {
208    // we have to skip the current frame :-(
209    // fprintf(stderr, "\rran out of free VIDEO framepages :-(");
210    // the fprint only made things slower
211    return;
212  }
213 
214  // get current time for timecode
215  gettimeofday(&now, &tzone);
216 
217  tcres = (now.tv_sec-stm.tv_sec)*1000 + now.tv_usec/1000 - stm.tv_usec/1000;
218 
219  if (usebttv) {
220    // i hate it when interfaces changes and a non existent ioctl doesn't make an error
221    // and doesn't return -1, returning 0 instead and making no error is really weird
222    if (ioctl(fd, BTTV_FIELDNR, &tf)) {
223      perror("BTTV_FIELDNR");
224      usebttv = 0;
225      fprintf(stderr, "\nbttv_fieldnr not supported by bttv-driver"
226                      "\nuse insmod/modprobe bttv card=YOURCARD field_nr=1 to activate f.n."
227                      "\nfalling back to timecode routine to determine lost frames\n");
228    }
229    if (tf==0) {
230      usebttv = 0;
231      fprintf(stderr, "\nbttv_fieldnr not supported by bttv-driver"
232                      "\nuse insmod/modprobe bttv card=YOURCARD field_nr=1 to activate f.n."
233                      "\nfalling back to timecode routine to determine lost frames\n");
234    }
235  }
236 
237  // here is the non preferable timecode - drop algorithm - fallback
238  if (!usebttv) {
239 
240    if (tf==0) {
241      tf = 2;
242    } else {
243      fn = tcres - oldtc;
244 
245      // the difference should be less than 1,5*timeperframe or we have
246      // missed at least one frame, this code might be inaccurate!
247 
248      if (vinfo.ntsc) {
249        fn = fn/33;
250      } else {
251        fn = fn/40;
252      }
253      if (fn==0) fn=1;
254      tf+= 2*fn; // two fields
255    }
256  }
257  oldtc = tcres;
258 
259  if (! videobuffer[act].freeToBuffer) {
260    return; // we can't buffer the current frame
261  }
262 
263  videobuffer[act].sample = tf;
264  videobuffer[act].timecode = tcres;
265 
266 DP("buffered frame");
267 
268  memcpy(videobuffer[act].buffer_offset, buf, video_buffer_size);
269 
270  videobuffer[act].freeToBuffer = 0;
271  act_video_buffer++;
272  if (act_video_buffer >= video_buffer_count) act_video_buffer = 0; // cycle to begin of buffer
273  videobuffer[act].freeToEncode = 1; // last setting to prevent race conditions
274 
275  return;
276 }
277 
278