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