Mercurial > mplayer.hg
annotate libmpdemux/tvi_v4l2.c @ 18001:a2683ee7cb5a
fix descrambling of asf file,
where signed buffer could cause erroneous values to be filled in descrable variables,
add misssing check for one of these variables
and restore sign of these variables as insurance that these checks will work even in such case.
author | iive |
---|---|
date | Thu, 30 Mar 2006 23:06:18 +0000 |
parents | 7bf483eaa99a |
children | 8ceb31f028ee |
rev | line source |
---|---|
10536 | 1 /* |
2 ** Video 4 Linux 2 input | |
3 ** | |
4 ** This file is part of MPlayer, see http://mplayerhq.hu/ for info. | |
5 ** | |
6 ** (c) 2003 Martin Olschewski <olschewski@zpr.uni-koeln.de> | |
7 ** (c) 2003 Jindrich Makovicka <makovick@kmlinux.fjfi.cvut.cz> | |
8 ** | |
9 ** File licensed under the GPL, see http://www.fsf.org/ for more info. | |
10 ** | |
11 ** Some ideas are based on works from | |
16536 | 12 ** Alex Beregszaszi <alex@fsn.hu> |
10536 | 13 ** Gerd Knorr <kraxel@bytesex.org> |
14 ** | |
15 ** CODE IS UNDER DEVELOPMENT, NO FEATURE REQUESTS PLEASE! | |
16 */ | |
17 | |
18 /* | |
19 | |
20 known issues: | |
21 - norm setting isn't consistent with tvi_v4l | |
22 - the same for volume/bass/treble/balance | |
23 | |
24 */ | |
25 | |
26 #include "config.h" | |
27 | |
28 #if defined(USE_TV) && defined(HAVE_TV_V4L2) | |
29 | |
30 #include <errno.h> | |
31 #include <fcntl.h> | |
32 #include <pthread.h> | |
33 #include <stdio.h> | |
34 #include <string.h> | |
35 #include <sys/ioctl.h> | |
36 #include <sys/mman.h> | |
37 #include <sys/time.h> | |
38 #include <sys/types.h> | |
39 #include <unistd.h> | |
40 #ifdef HAVE_SYS_SYSINFO_H | |
41 #include <sys/sysinfo.h> | |
42 #endif | |
16442 | 43 #include <linux/types.h> |
44 #include <linux/videodev2.h> | |
17012 | 45 #include "mp_msg.h" |
46 #include "libvo/img_format.h" | |
47 #include "libaf/af_format.h" | |
10536 | 48 #include "tv.h" |
49 #include "audio_in.h" | |
50 | |
51 /* information about this file */ | |
52 static tvi_info_t info = { | |
53 "Video 4 Linux 2 input", | |
54 "v4l2", | |
55 "Martin Olschewski <olschewski@zpr.uni-koeln.de>", | |
56 "first try, more to come ;-)" | |
57 }; | |
58 | |
59 struct map { | |
60 struct v4l2_buffer buf; | |
61 void *addr; | |
62 size_t len; | |
63 }; | |
64 | |
65 #define BUFFER_COUNT 6 | |
66 | |
67 /* private data */ | |
68 typedef struct { | |
69 /* video */ | |
70 char *video_dev; | |
71 int video_fd; | |
72 int mp_format; | |
73 struct v4l2_capability capability; | |
74 struct v4l2_input input; | |
75 struct v4l2_format format; | |
76 struct v4l2_standard standard; | |
77 struct v4l2_tuner tuner; | |
78 struct map *map; | |
79 int mapcount; | |
80 int frames; | |
10851 | 81 volatile long long first_frame; |
10536 | 82 long long curr_frame; |
83 /* audio video interleaving ;-) */ | |
84 volatile int streamon; | |
85 pthread_t audio_grabber_thread; | |
86 pthread_mutex_t skew_mutex; | |
87 | |
88 /* 2nd level video buffers */ | |
89 int first; | |
90 int immediate_mode; | |
91 | |
92 int video_buffer_size_max; | |
93 volatile int video_buffer_size_current; | |
94 unsigned char **video_ringbuffer; | |
95 long long *video_timebuffer; | |
96 volatile int video_head; | |
97 volatile int video_tail; | |
98 volatile int video_cnt; | |
99 pthread_t video_grabber_thread; | |
100 pthread_mutex_t video_buffer_mutex; | |
101 | |
102 /* audio */ | |
103 char *audio_dev; | |
104 audio_in_t audio_in; | |
105 | |
106 long long audio_start_time; | |
107 int audio_buffer_size; | |
108 int aud_skew_cnt; | |
109 unsigned char *audio_ringbuffer; | |
110 long long *audio_skew_buffer; | |
10653 | 111 long long *audio_skew_delta_buffer; |
10536 | 112 volatile int audio_head; |
113 volatile int audio_tail; | |
114 volatile int audio_cnt; | |
115 volatile long long audio_skew; | |
116 volatile double audio_skew_factor; | |
117 volatile long long audio_skew_measure_time; | |
118 volatile int audio_drop; | |
119 volatile int shutdown; | |
120 | |
15464 | 121 int audio_inited; |
10536 | 122 double audio_secs_per_block; |
15449 | 123 long long audio_usecs_per_block; |
10536 | 124 long long audio_skew_total; |
10653 | 125 long long audio_skew_delta_total; |
10536 | 126 long audio_recv_blocks_total; |
127 long audio_sent_blocks_total; | |
15449 | 128 pthread_mutex_t audio_mutex; |
129 int audio_insert_null_samples; | |
130 volatile long audio_null_blocks_inserted; | |
131 volatile long long dropped_frames_timeshift; | |
132 long long dropped_frames_compensated; | |
10536 | 133 } priv_t; |
134 | |
135 #include "tvi_def.h" | |
136 | |
137 static void *audio_grabber(void *data); | |
138 static void *video_grabber(void *data); | |
139 | |
140 /**********************************************************************\ | |
141 | |
142 Only few of the fourccs are the same in v4l2 and mplayer: | |
143 | |
144 IMGFMT_YVU9 == V4L2_PIX_FMT_YVU410 | |
145 IMGFMT_YV12 == V4L2_PIX_FMT_YVU420 | |
146 IMGFMT_NV12 == V4L2_PIX_FMT_NV12 | |
147 IMGFMT_422P == V4L2_PIX_FMT_YUV422P | |
148 IMGFMT_411P == V4L2_PIX_FMT_YUV411P | |
149 IMGFMT_UYVY == V4L2_PIX_FMT_UYVY | |
150 IMGFMT_Y41P == V4L2_PIX_FMT_Y41P | |
151 | |
152 This may be an useful translation table for some others: | |
153 | |
154 IMGFMT_RGB8 == V4L2_PIX_FMT_RGB332 | |
15449 | 155 IMGFMT_BGR15 == V4L2_PIX_FMT_RGB555 |
156 IMGFMT_BGR16 == V4L2_PIX_FMT_RGB565 | |
10536 | 157 IMGFMT_RGB24 == V4L2_PIX_FMT_RGB24 |
158 IMGFMT_RGB32 == V4L2_PIX_FMT_RGB32 | |
159 IMGFMT_BGR24 == V4L2_PIX_FMT_BGR24 | |
160 IMGFMT_BGR32 == V4L2_PIX_FMT_BGR32 | |
161 IMGFMT_Y800 == V4L2_PIX_FMT_GREY | |
162 IMGFMT_IF09 == V4L2_PIX_FMT_YUV410 | |
163 IMGFMT_I420 == V4L2_PIX_FMT_YUV420 | |
164 IMGFMT_YUY2 == V4L2_PIX_FMT_YUYV | |
165 | |
166 \**********************************************************************/ | |
167 | |
168 /* | |
169 ** Translate a mplayer fourcc to a video4linux2 pixel format. | |
170 */ | |
171 static int fcc_mp2vl(int fcc) | |
172 { | |
173 switch (fcc) { | |
174 case IMGFMT_RGB8: return V4L2_PIX_FMT_RGB332; | |
15418 | 175 case IMGFMT_BGR15: return V4L2_PIX_FMT_RGB555; |
176 case IMGFMT_BGR16: return V4L2_PIX_FMT_RGB565; | |
10536 | 177 case IMGFMT_RGB24: return V4L2_PIX_FMT_RGB24; |
178 case IMGFMT_RGB32: return V4L2_PIX_FMT_RGB32; | |
179 case IMGFMT_BGR24: return V4L2_PIX_FMT_BGR24; | |
180 case IMGFMT_BGR32: return V4L2_PIX_FMT_BGR32; | |
181 case IMGFMT_Y800: return V4L2_PIX_FMT_GREY; | |
182 case IMGFMT_IF09: return V4L2_PIX_FMT_YUV410; | |
183 case IMGFMT_I420: return V4L2_PIX_FMT_YUV420; | |
184 case IMGFMT_YUY2: return V4L2_PIX_FMT_YUYV; | |
17199
9164ef9a1834
remove now useless YV12 plane swap hack, patch by Luc Gallant lucgallant at gmail com
henry
parents:
17012
diff
changeset
|
185 case IMGFMT_YV12: return V4L2_PIX_FMT_YVU420; |
11657 | 186 case IMGFMT_UYVY: return V4L2_PIX_FMT_UYVY; |
10536 | 187 } |
188 return fcc; | |
189 } | |
190 | |
191 /* | |
192 ** Translate a video4linux2 fourcc aka pixel format to mplayer. | |
193 */ | |
194 static int fcc_vl2mp(int fcc) | |
195 { | |
196 switch (fcc) { | |
197 case V4L2_PIX_FMT_RGB332: return IMGFMT_RGB8; | |
15418 | 198 case V4L2_PIX_FMT_RGB555: return IMGFMT_BGR15; |
199 case V4L2_PIX_FMT_RGB565: return IMGFMT_BGR16; | |
10536 | 200 case V4L2_PIX_FMT_RGB24: return IMGFMT_RGB24; |
201 case V4L2_PIX_FMT_RGB32: return IMGFMT_RGB32; | |
202 case V4L2_PIX_FMT_BGR24: return IMGFMT_BGR24; | |
203 case V4L2_PIX_FMT_BGR32: return IMGFMT_BGR32; | |
204 case V4L2_PIX_FMT_GREY: return IMGFMT_Y800; | |
205 case V4L2_PIX_FMT_YUV410: return IMGFMT_IF09; | |
206 case V4L2_PIX_FMT_YUV420: return IMGFMT_I420; | |
17199
9164ef9a1834
remove now useless YV12 plane swap hack, patch by Luc Gallant lucgallant at gmail com
henry
parents:
17012
diff
changeset
|
207 case V4L2_PIX_FMT_YVU420: return IMGFMT_YV12; |
10536 | 208 case V4L2_PIX_FMT_YUYV: return IMGFMT_YUY2; |
11657 | 209 case V4L2_PIX_FMT_UYVY: return IMGFMT_UYVY; |
10536 | 210 } |
211 return fcc; | |
212 } | |
213 | |
214 /* | |
215 ** Translate a video4linux2 fourcc aka pixel format | |
216 ** to a human readable string. | |
217 */ | |
218 static char *pixfmt2name(int pixfmt) | |
219 { | |
220 static char unknown[24]; | |
221 | |
222 switch (pixfmt) { | |
223 case V4L2_PIX_FMT_RGB332: return "RGB332"; | |
224 case V4L2_PIX_FMT_RGB555: return "RGB555"; | |
225 case V4L2_PIX_FMT_RGB565: return "RGB565"; | |
226 case V4L2_PIX_FMT_RGB555X: return "RGB555X"; | |
227 case V4L2_PIX_FMT_RGB565X: return "RGB565X"; | |
228 case V4L2_PIX_FMT_BGR24: return "BGR24"; | |
229 case V4L2_PIX_FMT_RGB24: return "RGB24"; | |
230 case V4L2_PIX_FMT_BGR32: return "BGR32"; | |
231 case V4L2_PIX_FMT_RGB32: return "RGB32"; | |
232 case V4L2_PIX_FMT_GREY: return "GREY"; | |
233 case V4L2_PIX_FMT_YVU410: return "YVU410"; | |
234 case V4L2_PIX_FMT_YVU420: return "YVU420"; | |
235 case V4L2_PIX_FMT_YUYV: return "YUYV"; | |
236 case V4L2_PIX_FMT_UYVY: return "UYVY"; | |
237 /* case V4L2_PIX_FMT_YVU422P: return "YVU422P"; */ | |
238 /* case V4L2_PIX_FMT_YVU411P: return "YVU411P"; */ | |
239 case V4L2_PIX_FMT_YUV422P: return "YUV422P"; | |
240 case V4L2_PIX_FMT_YUV411P: return "YUV411P"; | |
241 case V4L2_PIX_FMT_Y41P: return "Y41P"; | |
242 case V4L2_PIX_FMT_NV12: return "NV12"; | |
243 case V4L2_PIX_FMT_NV21: return "NV21"; | |
244 case V4L2_PIX_FMT_YUV410: return "YUV410"; | |
245 case V4L2_PIX_FMT_YUV420: return "YUV420"; | |
246 case V4L2_PIX_FMT_YYUV: return "YYUV"; | |
247 case V4L2_PIX_FMT_HI240: return "HI240"; | |
248 case V4L2_PIX_FMT_WNVA: return "WNVA"; | |
249 } | |
250 sprintf(unknown, "unknown (0x%x)", pixfmt); | |
251 return unknown; | |
252 } | |
253 | |
254 | |
255 /* | |
256 ** Gives the depth of a video4linux2 fourcc aka pixel format in bits. | |
257 */ | |
258 static int pixfmt2depth(int pixfmt) | |
259 { | |
260 switch (pixfmt) { | |
261 case V4L2_PIX_FMT_RGB332: | |
262 return 8; | |
263 case V4L2_PIX_FMT_RGB555: | |
264 case V4L2_PIX_FMT_RGB565: | |
265 case V4L2_PIX_FMT_RGB555X: | |
266 case V4L2_PIX_FMT_RGB565X: | |
267 return 16; | |
268 case V4L2_PIX_FMT_BGR24: | |
269 case V4L2_PIX_FMT_RGB24: | |
270 return 24; | |
271 case V4L2_PIX_FMT_BGR32: | |
272 case V4L2_PIX_FMT_RGB32: | |
273 return 32; | |
274 case V4L2_PIX_FMT_GREY: | |
275 return 8; | |
276 case V4L2_PIX_FMT_YVU410: | |
277 return 9; | |
278 case V4L2_PIX_FMT_YVU420: | |
279 return 12; | |
280 case V4L2_PIX_FMT_YUYV: | |
281 case V4L2_PIX_FMT_UYVY: | |
282 case V4L2_PIX_FMT_YUV422P: | |
283 case V4L2_PIX_FMT_YUV411P: | |
284 return 16; | |
285 case V4L2_PIX_FMT_Y41P: | |
286 case V4L2_PIX_FMT_NV12: | |
287 case V4L2_PIX_FMT_NV21: | |
288 return 12; | |
289 case V4L2_PIX_FMT_YUV410: | |
290 return 9; | |
291 case V4L2_PIX_FMT_YUV420: | |
292 return 12; | |
293 case V4L2_PIX_FMT_YYUV: | |
294 return 16; | |
295 case V4L2_PIX_FMT_HI240: | |
296 return 8; | |
297 | |
298 } | |
299 return 0; | |
300 } | |
301 | |
302 static int amode2v4l(int amode) | |
303 { | |
304 switch (amode) { | |
305 case 0: | |
306 return V4L2_TUNER_MODE_MONO; | |
307 case 1: | |
308 return V4L2_TUNER_MODE_STEREO; | |
309 case 2: | |
310 return V4L2_TUNER_MODE_LANG1; | |
311 case 3: | |
312 return V4L2_TUNER_MODE_LANG2; | |
313 default: | |
314 return -1; | |
315 } | |
316 } | |
317 | |
318 | |
319 // sets and sanitizes audio buffer/block sizes | |
320 static void setup_audio_buffer_sizes(priv_t *priv) | |
321 { | |
322 int bytes_per_sample = priv->audio_in.bytes_per_sample; | |
16274 | 323 double fps = (double)priv->standard.frameperiod.denominator / |
10536 | 324 priv->standard.frameperiod.numerator; |
325 int seconds = priv->video_buffer_size_max/fps; | |
326 | |
327 if (seconds < 5) seconds = 5; | |
328 if (seconds > 500) seconds = 500; | |
329 | |
330 // make the audio buffer at least as the video buffer capacity (or 5 seconds) long | |
331 priv->audio_buffer_size = 1 + seconds*priv->audio_in.samplerate | |
332 *priv->audio_in.channels | |
333 *bytes_per_sample/priv->audio_in.blocksize; | |
334 if (priv->audio_buffer_size < 256) priv->audio_buffer_size = 256; | |
335 | |
336 // make the skew buffer at least 1 second long | |
337 priv->aud_skew_cnt = 1 + 1*priv->audio_in.samplerate | |
338 *priv->audio_in.channels | |
339 *bytes_per_sample/priv->audio_in.blocksize; | |
340 if (priv->aud_skew_cnt < 16) priv->aud_skew_cnt = 16; | |
341 | |
342 mp_msg(MSGT_TV, MSGL_V, "Audio capture - buffer %d blocks of %d bytes, skew average from %d meas.\n", | |
343 priv->audio_buffer_size, priv->audio_in.blocksize, priv->aud_skew_cnt); | |
344 } | |
345 | |
15464 | 346 static void init_audio(priv_t *priv) |
347 { | |
348 if (priv->audio_inited) return; | |
349 | |
350 if (!tv_param_noaudio) { | |
351 #if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) | |
352 if (tv_param_alsa) | |
353 audio_in_init(&priv->audio_in, AUDIO_IN_ALSA); | |
354 else | |
355 audio_in_init(&priv->audio_in, AUDIO_IN_OSS); | |
356 #else | |
357 audio_in_init(&priv->audio_in, AUDIO_IN_OSS); | |
358 #endif | |
359 | |
360 if (priv->audio_dev) { | |
361 audio_in_set_device(&priv->audio_in, priv->audio_dev); | |
362 } | |
363 | |
364 audio_in_set_samplerate(&priv->audio_in, 44100); | |
365 if (priv->capability.capabilities & V4L2_CAP_TUNER) { | |
366 if (priv->tuner.audmode == V4L2_TUNER_MODE_STEREO) { | |
367 audio_in_set_channels(&priv->audio_in, 2); | |
368 } else { | |
369 audio_in_set_channels(&priv->audio_in, 1); | |
370 } | |
371 } else { | |
372 if (tv_param_forcechan >= 0) { | |
373 audio_in_set_channels(&priv->audio_in, tv_param_forcechan); | |
374 } else { | |
375 audio_in_set_channels(&priv->audio_in, 2); | |
376 } | |
377 } | |
378 | |
379 if (audio_in_setup(&priv->audio_in) < 0) return; | |
380 | |
381 priv->audio_inited = 1; | |
382 } | |
383 } | |
384 | |
10536 | 385 #if 0 |
386 /* | |
387 ** the number of milliseconds elapsed between time0 and time1 | |
388 */ | |
389 static size_t difftv(struct timeval time1, struct timeval time0) | |
390 { | |
391 return (time1.tv_sec - time0.tv_sec) * 1000 + | |
392 (time1.tv_usec - time0.tv_usec) / 1000; | |
393 } | |
394 #endif | |
395 | |
396 /* | |
397 ** Get current video capture format. | |
398 */ | |
399 static int getfmt(priv_t *priv) | |
400 { | |
401 int i; | |
402 | |
403 priv->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
404 if ((i = ioctl(priv->video_fd, VIDIOC_G_FMT, &priv->format)) < 0) { | |
405 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get format failed: %s\n", | |
406 info.short_name, strerror(errno)); | |
407 } | |
408 return i; | |
409 } | |
410 | |
411 | |
412 /* | |
413 ** Get current video capture standard. | |
414 */ | |
415 static int getstd(priv_t *priv) | |
416 { | |
417 v4l2_std_id id; | |
418 int i=0; | |
419 | |
420 if (ioctl(priv->video_fd, VIDIOC_G_STD, &id) < 0) { | |
421 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get standard failed: %s\n", | |
422 info.short_name, strerror(errno)); | |
423 return -1; | |
424 } | |
425 do { | |
426 priv->standard.index = i++; | |
427 if (ioctl(priv->video_fd, VIDIOC_ENUMSTD, &priv->standard) < 0) { | |
428 return -1; | |
429 } | |
430 } while (priv->standard.id != id); | |
431 return 0; | |
432 } | |
433 | |
434 /***********************************************************************\ | |
435 * * | |
436 * * | |
437 * Interface to mplayer * | |
438 * * | |
439 * * | |
440 \***********************************************************************/ | |
441 | |
442 static int set_mute(priv_t *priv, int value) | |
443 { | |
444 struct v4l2_control control; | |
445 control.id = V4L2_CID_AUDIO_MUTE; | |
446 control.value = value; | |
447 if (ioctl(priv->video_fd, VIDIOC_S_CTRL, &control) < 0) { | |
448 mp_msg(MSGT_TV,MSGL_ERR,"%s: ioctl set mute failed: %s\n", | |
449 info.short_name, strerror(errno)); | |
450 return 0; | |
451 } | |
452 return 1; | |
453 } | |
454 | |
455 /* | |
12860 | 456 ** MPlayer uses values from -100 up to 100 for controls. |
10536 | 457 ** Here they are scaled to what the tv card needs and applied. |
458 */ | |
459 static int set_control(priv_t *priv, struct v4l2_control *control, int val_signed) { | |
460 struct v4l2_queryctrl qctrl; | |
461 | |
462 qctrl.id = control->id; | |
463 if (ioctl(priv->video_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) { | |
464 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query control failed: %s\n", | |
465 info.short_name, strerror(errno)); | |
466 return TVI_CONTROL_FALSE; | |
467 } | |
468 | |
469 if (val_signed) { | |
470 if (control->value < 0) { | |
471 control->value = qctrl.default_value + control->value * | |
472 (qctrl.default_value - qctrl.minimum) / 100; | |
473 } else { | |
474 control->value = qctrl.default_value + control->value * | |
475 (qctrl.maximum - qctrl.default_value) / 100; | |
476 } | |
477 } else { | |
478 if (control->value < 50) { | |
479 control->value = qctrl.default_value + (control->value-50) * | |
480 (qctrl.default_value - qctrl.minimum) / 50; | |
481 } else { | |
482 control->value = qctrl.default_value + (control->value-50) * | |
483 (qctrl.maximum - qctrl.default_value) / 50; | |
484 } | |
485 } | |
486 | |
487 | |
488 if (ioctl(priv->video_fd, VIDIOC_S_CTRL, control) < 0) { | |
489 mp_msg(MSGT_TV, MSGL_ERR,"%s: ioctl set %s %d failed: %s\n", | |
490 info.short_name, qctrl.name, control->value, strerror(errno)); | |
491 return TVI_CONTROL_FALSE; | |
492 } | |
493 mp_msg(MSGT_TV, MSGL_V, "%s: set %s: %d [%d, %d]\n", info.short_name, | |
494 qctrl.name, control->value, qctrl.minimum, qctrl.maximum); | |
495 | |
496 return TVI_CONTROL_TRUE; | |
497 } | |
498 | |
499 | |
500 /* | |
501 ** Scale the control values back to what mplayer needs. | |
502 */ | |
503 static int get_control(priv_t *priv, struct v4l2_control *control, int val_signed) { | |
504 struct v4l2_queryctrl qctrl; | |
505 | |
506 qctrl.id = control->id; | |
507 if (ioctl(priv->video_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) { | |
508 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query control failed: %s\n", | |
509 info.short_name, strerror(errno)); | |
510 return TVI_CONTROL_FALSE; | |
511 } | |
512 | |
513 if (ioctl(priv->video_fd, VIDIOC_G_CTRL, control) < 0) { | |
514 mp_msg(MSGT_TV, MSGL_ERR,"%s: ioctl get %s failed: %s\n", | |
515 info.short_name, qctrl.name, strerror(errno)); | |
516 return TVI_CONTROL_FALSE; | |
517 } | |
518 mp_msg(MSGT_TV, MSGL_V, "%s: get %s: %d [%d, %d]\n", info.short_name, | |
519 qctrl.name, control->value, qctrl.minimum, qctrl.maximum); | |
520 | |
521 if (val_signed) { | |
522 if (control->value < qctrl.default_value) { | |
523 control->value = (control->value - qctrl.default_value) * 100 / | |
524 (qctrl.default_value - qctrl.minimum); | |
525 } else { | |
526 control->value = (control->value - qctrl.default_value) * 100 / | |
527 (qctrl.maximum - qctrl.default_value); | |
528 } | |
529 } else { | |
530 if (control->value < qctrl.default_value) { | |
531 control->value = (control->value - qctrl.default_value) * 50 / | |
532 (qctrl.default_value - qctrl.minimum) + 50; | |
533 } else { | |
534 control->value = (control->value - qctrl.default_value) * 50 / | |
535 (qctrl.maximum - qctrl.default_value) + 50; | |
536 } | |
537 } | |
538 | |
539 return TVI_CONTROL_TRUE; | |
540 } | |
541 | |
542 static int control(priv_t *priv, int cmd, void *arg) | |
543 { | |
544 struct v4l2_control control; | |
545 struct v4l2_frequency frequency; | |
546 | |
547 switch(cmd) { | |
548 case TVI_CONTROL_IS_VIDEO: | |
549 return priv->capability.capabilities & V4L2_CAP_VIDEO_CAPTURE? | |
550 TVI_CONTROL_TRUE: TVI_CONTROL_FALSE; | |
17765
7bf483eaa99a
If we have a tuner, use that as a reason we have audio support, and do
aurel
parents:
17626
diff
changeset
|
551 case TVI_CONTROL_IS_AUDIO: |
7bf483eaa99a
If we have a tuner, use that as a reason we have audio support, and do
aurel
parents:
17626
diff
changeset
|
552 if (tv_param_force_audio) return TVI_CONTROL_TRUE; |
10536 | 553 case TVI_CONTROL_IS_TUNER: |
554 return priv->capability.capabilities & V4L2_CAP_TUNER? | |
555 TVI_CONTROL_TRUE: TVI_CONTROL_FALSE; | |
556 case TVI_CONTROL_IMMEDIATE: | |
557 priv->immediate_mode = 1; | |
558 return TVI_CONTROL_TRUE; | |
559 case TVI_CONTROL_VID_GET_FPS: | |
16289 | 560 *(float *)arg = (float)priv->standard.frameperiod.denominator / |
10536 | 561 priv->standard.frameperiod.numerator; |
562 mp_msg(MSGT_TV, MSGL_V, "%s: get fps: %f\n", info.short_name, | |
563 *(float *)arg); | |
564 return TVI_CONTROL_TRUE; | |
565 case TVI_CONTROL_VID_GET_BITS: | |
566 if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; | |
567 *(int *)arg = pixfmt2depth(priv->format.fmt.pix.pixelformat); | |
568 mp_msg(MSGT_TV, MSGL_V, "%s: get depth: %d\n", info.short_name, | |
569 *(int *)arg); | |
570 return TVI_CONTROL_TRUE; | |
571 case TVI_CONTROL_VID_GET_FORMAT: | |
572 if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; | |
17199
9164ef9a1834
remove now useless YV12 plane swap hack, patch by Luc Gallant lucgallant at gmail com
henry
parents:
17012
diff
changeset
|
573 *(int *)arg = fcc_vl2mp(priv->format.fmt.pix.pixelformat); |
10536 | 574 mp_msg(MSGT_TV, MSGL_V, "%s: get format: %s\n", info.short_name, |
575 pixfmt2name(priv->format.fmt.pix.pixelformat)); | |
576 return TVI_CONTROL_TRUE; | |
577 case TVI_CONTROL_VID_SET_FORMAT: | |
578 if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; | |
579 priv->format.fmt.pix.pixelformat = fcc_mp2vl(*(int *)arg); | |
580 priv->format.fmt.pix.field = V4L2_FIELD_ANY; | |
581 | |
582 priv->mp_format = *(int *)arg; | |
583 mp_msg(MSGT_TV, MSGL_V, "%s: set format: %s\n", info.short_name, | |
584 pixfmt2name(priv->format.fmt.pix.pixelformat)); | |
585 if (ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) { | |
586 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set format failed: %s\n", | |
587 info.short_name, strerror(errno)); | |
588 return TVI_CONTROL_FALSE; | |
589 } | |
16186
e861f9b7a70e
take into account that VIDIOC_S_FMT might return updated parameters
faust3
parents:
16185
diff
changeset
|
590 /* according to the v4l2 specs VIDIOC_S_FMT should not fail, inflexible drivers |
e861f9b7a70e
take into account that VIDIOC_S_FMT might return updated parameters
faust3
parents:
16185
diff
changeset
|
591 might even always return the default parameters -> update the format here*/ |
e861f9b7a70e
take into account that VIDIOC_S_FMT might return updated parameters
faust3
parents:
16185
diff
changeset
|
592 priv->mp_format = fcc_vl2mp(priv->format.fmt.pix.pixelformat); |
10536 | 593 return TVI_CONTROL_TRUE; |
594 case TVI_CONTROL_VID_GET_WIDTH: | |
595 if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; | |
596 *(int *)arg = priv->format.fmt.pix.width; | |
597 mp_msg(MSGT_TV, MSGL_V, "%s: get width: %d\n", info.short_name, | |
598 *(int *)arg); | |
599 return TVI_CONTROL_TRUE; | |
600 case TVI_CONTROL_VID_CHK_WIDTH: | |
601 return TVI_CONTROL_TRUE; | |
602 case TVI_CONTROL_VID_SET_WIDTH: | |
603 if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; | |
604 priv->format.fmt.pix.width = *(int *)arg; | |
605 mp_msg(MSGT_TV, MSGL_V, "%s: set width: %d\n", info.short_name, | |
606 *(int *)arg); | |
607 if (ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) { | |
608 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set width failed: %s\n", | |
609 info.short_name, strerror(errno)); | |
610 return TVI_CONTROL_FALSE; | |
611 } | |
612 return TVI_CONTROL_TRUE; | |
613 case TVI_CONTROL_VID_GET_HEIGHT: | |
614 if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; | |
615 *(int *)arg = priv->format.fmt.pix.height; | |
616 mp_msg(MSGT_TV, MSGL_V, "%s: get height: %d\n", info.short_name, | |
617 *(int *)arg); | |
618 return TVI_CONTROL_TRUE; | |
619 case TVI_CONTROL_VID_CHK_HEIGHT: | |
620 return TVI_CONTROL_TRUE; | |
621 case TVI_CONTROL_VID_SET_HEIGHT: | |
622 if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; | |
623 priv->format.fmt.pix.height = *(int *)arg; | |
12210 | 624 priv->format.fmt.pix.field = V4L2_FIELD_ANY; |
10536 | 625 mp_msg(MSGT_TV, MSGL_V, "%s: set height: %d\n", info.short_name, |
626 *(int *)arg); | |
627 if (ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) { | |
628 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set height failed: %s\n", | |
629 info.short_name, strerror(errno)); | |
630 return TVI_CONTROL_FALSE; | |
631 } | |
632 return TVI_CONTROL_TRUE; | |
633 case TVI_CONTROL_VID_GET_BRIGHTNESS: | |
634 control.id = V4L2_CID_BRIGHTNESS; | |
635 if (get_control(priv, &control, 1) == TVI_CONTROL_TRUE) { | |
636 *(int *)arg = control.value; | |
637 return TVI_CONTROL_TRUE; | |
638 } | |
639 return TVI_CONTROL_FALSE; | |
640 case TVI_CONTROL_VID_SET_BRIGHTNESS: | |
641 control.id = V4L2_CID_BRIGHTNESS; | |
642 control.value = *(int *)arg; | |
643 return set_control(priv, &control, 1); | |
644 case TVI_CONTROL_VID_GET_HUE: | |
645 control.id = V4L2_CID_HUE; | |
646 if (get_control(priv, &control, 1) == TVI_CONTROL_TRUE) { | |
647 *(int *)arg = control.value; | |
648 return TVI_CONTROL_TRUE; | |
649 } | |
650 return TVI_CONTROL_FALSE; | |
651 case TVI_CONTROL_VID_SET_HUE: | |
652 control.id = V4L2_CID_HUE; | |
653 control.value = *(int *)arg; | |
654 return set_control(priv, &control, 1); | |
655 case TVI_CONTROL_VID_GET_SATURATION: | |
656 control.id = V4L2_CID_SATURATION; | |
657 if (get_control(priv, &control, 1) == TVI_CONTROL_TRUE) { | |
658 *(int *)arg = control.value; | |
659 return TVI_CONTROL_TRUE; | |
660 } | |
661 return TVI_CONTROL_FALSE; | |
662 case TVI_CONTROL_VID_SET_SATURATION: | |
663 control.id = V4L2_CID_SATURATION; | |
664 control.value = *(int *)arg; | |
665 return set_control(priv, &control, 1); | |
666 case TVI_CONTROL_VID_GET_CONTRAST: | |
667 control.id = V4L2_CID_CONTRAST; | |
668 if (get_control(priv, &control, 1) == TVI_CONTROL_TRUE) { | |
669 *(int *)arg = control.value; | |
670 return TVI_CONTROL_TRUE; | |
671 } | |
672 return TVI_CONTROL_FALSE; | |
673 case TVI_CONTROL_VID_SET_CONTRAST: | |
674 control.id = V4L2_CID_CONTRAST; | |
675 control.value = *(int *)arg; | |
676 return set_control(priv, &control, 1); | |
677 case TVI_CONTROL_TUN_GET_FREQ: | |
678 frequency.tuner = 0; | |
679 frequency.type = V4L2_TUNER_ANALOG_TV; | |
680 if (ioctl(priv->video_fd, VIDIOC_G_FREQUENCY, &frequency) < 0) { | |
681 mp_msg(MSGT_TV,MSGL_ERR,"%s: ioctl get frequency failed: %s\n", | |
682 info.short_name, strerror(errno)); | |
683 return TVI_CONTROL_FALSE; | |
684 } | |
685 *(int *)arg = frequency.frequency; | |
686 return TVI_CONTROL_TRUE; | |
687 case TVI_CONTROL_TUN_SET_FREQ: | |
688 #if 0 | |
17626
5627625b0cdb
Don't test the v4l2_input audioset field for audio capabilities but still try changing the mute setting (patch by Jesse Allen < the3dfxdude _at_ gmail.com >)
aurel
parents:
17199
diff
changeset
|
689 set_mute(priv, 1); |
5627625b0cdb
Don't test the v4l2_input audioset field for audio capabilities but still try changing the mute setting (patch by Jesse Allen < the3dfxdude _at_ gmail.com >)
aurel
parents:
17199
diff
changeset
|
690 usleep(100000); // wait to supress noise during switching |
10536 | 691 #endif |
692 frequency.tuner = 0; | |
693 frequency.type = V4L2_TUNER_ANALOG_TV; | |
694 frequency.frequency = *(int *)arg; | |
695 if (ioctl(priv->video_fd, VIDIOC_S_FREQUENCY, &frequency) < 0) { | |
696 mp_msg(MSGT_TV,MSGL_ERR,"%s: ioctl set frequency failed: %s\n", | |
697 info.short_name, strerror(errno)); | |
698 return TVI_CONTROL_FALSE; | |
699 } | |
700 #if 0 | |
17626
5627625b0cdb
Don't test the v4l2_input audioset field for audio capabilities but still try changing the mute setting (patch by Jesse Allen < the3dfxdude _at_ gmail.com >)
aurel
parents:
17199
diff
changeset
|
701 usleep(100000); // wait to supress noise during switching |
5627625b0cdb
Don't test the v4l2_input audioset field for audio capabilities but still try changing the mute setting (patch by Jesse Allen < the3dfxdude _at_ gmail.com >)
aurel
parents:
17199
diff
changeset
|
702 set_mute(priv, 0); |
10536 | 703 #endif |
704 return TVI_CONTROL_TRUE; | |
705 case TVI_CONTROL_TUN_GET_TUNER: | |
10735
8a10d5d0ce86
serious bugs - 1l absinth (changed to absinth against cola inflation)
alex
parents:
10704
diff
changeset
|
706 mp_msg(MSGT_TV, MSGL_V, "%s: get tuner\n",info.short_name); |
10536 | 707 if (ioctl(priv->video_fd, VIDIOC_G_TUNER, &priv->tuner) < 0) { |
708 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get tuner failed: %s\n", | |
709 info.short_name, strerror(errno)); | |
710 return TVI_CONTROL_FALSE; | |
711 } | |
712 return TVI_CONTROL_TRUE; | |
713 case TVI_CONTROL_TUN_SET_TUNER: | |
10735
8a10d5d0ce86
serious bugs - 1l absinth (changed to absinth against cola inflation)
alex
parents:
10704
diff
changeset
|
714 mp_msg(MSGT_TV, MSGL_V, "%s: set tuner\n",info.short_name); |
10536 | 715 if (ioctl(priv->video_fd, VIDIOC_S_TUNER, &priv->tuner) < 0) { |
716 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set tuner failed: %s\n", | |
717 info.short_name, strerror(errno)); | |
718 return TVI_CONTROL_FALSE; | |
719 } | |
720 return TVI_CONTROL_TRUE; | |
721 case TVI_CONTROL_TUN_GET_NORM: | |
722 *(int *)arg = priv->standard.index; | |
723 return TVI_CONTROL_TRUE; | |
724 case TVI_CONTROL_TUN_SET_NORM: | |
725 priv->standard.index = *(int *)arg; | |
726 if (ioctl(priv->video_fd, VIDIOC_ENUMSTD, &priv->standard) < 0) { | |
727 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl enum norm failed: %s\n", | |
728 info.short_name, strerror(errno)); | |
729 return TVI_CONTROL_FALSE; | |
730 } | |
731 mp_msg(MSGT_TV, MSGL_V, "%s: set norm: %s\n", info.short_name, priv->standard.name); | |
732 if (ioctl(priv->video_fd, VIDIOC_S_STD, &priv->standard.id) < 0) { | |
733 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set norm failed: %s\n", | |
734 info.short_name, strerror(errno)); | |
735 return TVI_CONTROL_FALSE; | |
736 } | |
737 return TVI_CONTROL_TRUE; | |
13978 | 738 case TVI_CONTROL_SPC_GET_NORMID: |
739 { | |
740 int i; | |
741 for (i = 0;; i++) { | |
742 struct v4l2_standard standard; | |
743 memset(&standard, 0, sizeof(standard)); | |
744 standard.index = i; | |
745 if (-1 == ioctl(priv->video_fd, VIDIOC_ENUMSTD, &standard)) | |
746 return TVI_CONTROL_FALSE; | |
747 if (!strcasecmp(standard.name, (char *)arg)) { | |
748 *(int *)arg = i; | |
749 return TVI_CONTROL_TRUE; | |
750 } | |
751 } | |
752 return TVI_CONTROL_FALSE; | |
753 } | |
10536 | 754 case TVI_CONTROL_SPC_GET_INPUT: |
755 if (ioctl(priv->video_fd, VIDIOC_G_INPUT, (int *)arg) < 0) { | |
756 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get input failed: %s\n", | |
757 info.short_name, strerror(errno)); | |
758 return TVI_CONTROL_FALSE; | |
759 } | |
760 return TVI_CONTROL_TRUE; | |
761 case TVI_CONTROL_SPC_SET_INPUT: | |
762 mp_msg(MSGT_TV, MSGL_V, "%s: set input: %d\n", info.short_name, *(int *)arg); | |
763 priv->input.index = *(int *)arg; | |
764 if (ioctl(priv->video_fd, VIDIOC_ENUMINPUT, &priv->input) < 0) { | |
765 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl enum input failed: %s\n", | |
766 info.short_name, strerror(errno)); | |
767 return TVI_CONTROL_FALSE; | |
768 } | |
769 if (ioctl(priv->video_fd, VIDIOC_S_INPUT, (int *)arg) < 0) { | |
770 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set input failed: %s\n", | |
771 info.short_name, strerror(errno)); | |
772 return TVI_CONTROL_FALSE; | |
773 } | |
774 return TVI_CONTROL_TRUE; | |
775 case TVI_CONTROL_AUD_GET_FORMAT: | |
15464 | 776 init_audio(priv); |
777 if (!priv->audio_inited) return TVI_CONTROL_FALSE; | |
14245 | 778 *(int *)arg = AF_FORMAT_S16_LE; |
10536 | 779 mp_msg(MSGT_TV, MSGL_V, "%s: get audio format: %d\n", |
780 info.short_name, *(int *)arg); | |
781 return TVI_CONTROL_TRUE; | |
782 case TVI_CONTROL_AUD_GET_SAMPLERATE: | |
15464 | 783 init_audio(priv); |
784 if (!priv->audio_inited) return TVI_CONTROL_FALSE; | |
10536 | 785 *(int *)arg = priv->audio_in.samplerate; |
786 mp_msg(MSGT_TV, MSGL_V, "%s: get audio samplerate: %d\n", | |
787 info.short_name, *(int *)arg); | |
788 return TVI_CONTROL_TRUE; | |
789 case TVI_CONTROL_AUD_GET_SAMPLESIZE: | |
15464 | 790 init_audio(priv); |
791 if (!priv->audio_inited) return TVI_CONTROL_FALSE; | |
792 *(int *)arg = priv->audio_in.bytes_per_sample; | |
10536 | 793 mp_msg(MSGT_TV, MSGL_V, "%s: get audio samplesize: %d\n", |
794 info.short_name, *(int *)arg); | |
795 return TVI_CONTROL_TRUE; | |
796 case TVI_CONTROL_AUD_GET_CHANNELS: | |
15464 | 797 init_audio(priv); |
798 if (!priv->audio_inited) return TVI_CONTROL_FALSE; | |
10536 | 799 *(int *)arg = priv->audio_in.channels; |
800 mp_msg(MSGT_TV, MSGL_V, "%s: get audio channels: %d\n", | |
801 info.short_name, *(int *)arg); | |
802 return TVI_CONTROL_TRUE; | |
803 case TVI_CONTROL_AUD_SET_SAMPLERATE: | |
15464 | 804 init_audio(priv); |
10536 | 805 mp_msg(MSGT_TV, MSGL_V, "%s: set audio samplerate: %d\n", |
806 info.short_name, *(int *)arg); | |
12380 | 807 if (audio_in_set_samplerate(&priv->audio_in, *(int*)arg) < 0) return TVI_CONTROL_FALSE; |
10536 | 808 // setup_audio_buffer_sizes(priv); |
809 return TVI_CONTROL_TRUE; | |
810 } | |
811 mp_msg(MSGT_TV, MSGL_V, "%s: unknown control: %d\n", info.short_name, cmd); | |
812 return(TVI_CONTROL_UNKNOWN); | |
813 } | |
814 | |
815 | |
816 #define PRIV ((priv_t *) (tvi_handle->priv)) | |
817 | |
818 /* handler creator - entry point ! */ | |
819 tvi_handle_t *tvi_init_v4l2(char *video_dev, char *audio_dev) | |
820 { | |
821 tvi_handle_t *tvi_handle; | |
822 | |
823 /* new_handle initializes priv with memset 0 */ | |
824 tvi_handle = new_handle(); | |
825 if (!tvi_handle) { | |
826 return NULL; | |
827 } | |
828 PRIV->video_fd = -1; | |
829 | |
15246
849a6f39964f
use the documented default video device /dev/video0 instead of /dev/video that is missing on most systems
iive
parents:
14245
diff
changeset
|
830 PRIV->video_dev = strdup(video_dev? video_dev: "/dev/video0"); |
10536 | 831 if (!PRIV->video_dev) { |
832 free_handle(tvi_handle); | |
833 return NULL; | |
834 } | |
835 | |
836 if (audio_dev) { | |
837 PRIV->audio_dev = strdup(audio_dev); | |
838 if (!PRIV->audio_dev) { | |
839 free(PRIV->video_dev); | |
840 free_handle(tvi_handle); | |
841 return NULL; | |
842 } | |
843 } | |
844 | |
845 return tvi_handle; | |
846 } | |
847 | |
848 #undef PRIV | |
849 | |
850 | |
851 static int uninit(priv_t *priv) | |
852 { | |
853 int i, frames, dropped = 0; | |
854 | |
855 priv->shutdown = 1; | |
16185 | 856 if(priv->video_grabber_thread) |
857 pthread_join(priv->video_grabber_thread, NULL); | |
10536 | 858 pthread_mutex_destroy(&priv->video_buffer_mutex); |
859 | |
860 if (priv->streamon) { | |
861 struct v4l2_buffer buf; | |
862 | |
863 /* get performance */ | |
11997
48b5bfb25dc0
missing video thread shutdown, frame count rounding fix
henry
parents:
11876
diff
changeset
|
864 frames = 1 + (priv->curr_frame - priv->first_frame + |
48b5bfb25dc0
missing video thread shutdown, frame count rounding fix
henry
parents:
11876
diff
changeset
|
865 priv->standard.frameperiod.numerator * 500000 / |
48b5bfb25dc0
missing video thread shutdown, frame count rounding fix
henry
parents:
11876
diff
changeset
|
866 priv->standard.frameperiod.denominator) * |
10536 | 867 priv->standard.frameperiod.denominator / |
868 priv->standard.frameperiod.numerator / 1000000; | |
869 dropped = frames - priv->frames; | |
870 | |
871 /* turn off streaming */ | |
872 if (ioctl(priv->video_fd, VIDIOC_STREAMOFF, &(priv->map[0].buf.type)) < 0) { | |
873 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl streamoff failed: %s\n", | |
874 info.short_name, strerror(errno)); | |
875 } | |
876 priv->streamon = 0; | |
877 | |
878 /* unqueue all remaining buffers */ | |
879 memset(&buf,0,sizeof(buf)); | |
880 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
881 while (!ioctl(priv->video_fd, VIDIOC_DQBUF, &buf)); | |
882 } | |
883 | |
884 /* unmap all buffers */ | |
885 for (i = 0; i < priv->mapcount; i++) { | |
886 if (munmap(priv->map[i].addr, priv->map[i].len) < 0) { | |
887 mp_msg(MSGT_TV, MSGL_ERR, "%s: munmap capture buffer failed: %s\n", | |
888 info.short_name, strerror(errno)); | |
889 } | |
890 } | |
891 | |
892 /* stop audio thread */ | |
15987 | 893 if (!tv_param_noaudio && priv->audio_grabber_thread) { |
10536 | 894 pthread_join(priv->audio_grabber_thread, NULL); |
895 pthread_mutex_destroy(&priv->skew_mutex); | |
15449 | 896 pthread_mutex_destroy(&priv->audio_mutex); |
10536 | 897 } |
898 | |
17626
5627625b0cdb
Don't test the v4l2_input audioset field for audio capabilities but still try changing the mute setting (patch by Jesse Allen < the3dfxdude _at_ gmail.com >)
aurel
parents:
17199
diff
changeset
|
899 set_mute(priv, 1); |
10536 | 900 |
901 /* free memory and close device */ | |
902 free(priv->map); priv->map = NULL; | |
903 priv->mapcount = 0; | |
16185 | 904 if(priv->video_fd!=-1)close(priv->video_fd); priv->video_fd = -1; |
10536 | 905 free(priv->video_dev); priv->video_dev = NULL; |
906 | |
907 if (priv->video_ringbuffer) { | |
908 int i; | |
909 for (i = 0; i < priv->video_buffer_size_current; i++) { | |
910 free(priv->video_ringbuffer[i]); | |
911 } | |
912 free(priv->video_ringbuffer); | |
913 } | |
914 if (priv->video_timebuffer) | |
915 free(priv->video_timebuffer); | |
916 if (!tv_param_noaudio) { | |
917 if (priv->audio_ringbuffer) | |
918 free(priv->audio_ringbuffer); | |
919 if (priv->audio_skew_buffer) | |
920 free(priv->audio_skew_buffer); | |
10653 | 921 if (priv->audio_skew_delta_buffer) |
922 free(priv->audio_skew_delta_buffer); | |
10536 | 923 } |
924 | |
925 /* show some nice statistics ;-) */ | |
926 mp_msg(MSGT_TV, MSGL_INFO, | |
927 "%s: %d frames successfully processed, %d frames dropped.\n", | |
928 info.short_name, priv->frames, dropped); | |
929 mp_msg(MSGT_TV, MSGL_V, "%s: up to %u video frames buffered.\n", | |
930 info.short_name, priv->video_buffer_size_current); | |
931 return 1; | |
932 } | |
933 | |
934 | |
935 /* initialisation */ | |
936 static int init(priv_t *priv) | |
937 { | |
938 int i; | |
939 | |
940 priv->audio_ringbuffer = NULL; | |
941 priv->audio_skew_buffer = NULL; | |
10653 | 942 priv->audio_skew_delta_buffer = NULL; |
10536 | 943 |
15464 | 944 priv->audio_inited = 0; |
945 | |
10536 | 946 /* Open the video device. */ |
947 priv->video_fd = open(priv->video_dev, O_RDWR); | |
948 if (priv->video_fd < 0) { | |
949 mp_msg(MSGT_TV, MSGL_ERR, "%s: unable to open '%s': %s\n", | |
950 info.short_name, priv->video_dev, strerror(errno)); | |
951 uninit(priv); | |
952 return 0; | |
953 } | |
954 mp_msg(MSGT_TV, MSGL_DBG2, "%s: video fd: %s: %d\n", | |
955 info.short_name, priv->video_dev, priv->video_fd); | |
956 | |
957 /* | |
958 ** Query the video capabilities and current settings | |
959 ** for further control calls. | |
960 */ | |
961 if (ioctl(priv->video_fd, VIDIOC_QUERYCAP, &priv->capability) < 0) { | |
962 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query capabilities failed: %s\n", | |
963 info.short_name, strerror(errno)); | |
964 uninit(priv); | |
965 return 0; | |
966 } | |
967 | |
968 if (!(priv->capability.capabilities & V4L2_CAP_VIDEO_CAPTURE)) | |
969 { | |
970 mp_msg(MSGT_TV, MSGL_ERR, "Device %s is not a video capture device.\n", | |
971 priv->video_dev); | |
972 return 0; | |
973 } | |
974 | |
975 if (getfmt(priv) < 0 || getstd(priv) < 0) { | |
976 uninit(priv); | |
977 return 0; | |
978 } | |
979 /* | |
980 ** if this device has got a tuner query it's settings | |
981 ** otherwise set some nice defaults | |
982 */ | |
983 if (priv->capability.capabilities & V4L2_CAP_TUNER) { | |
984 if (ioctl(priv->video_fd, VIDIOC_G_TUNER, &priv->tuner) < 0) { | |
985 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get tuner failed: %s\n", | |
986 info.short_name, strerror(errno)); | |
987 uninit(priv); | |
988 return 0; | |
989 } | |
990 } | |
991 mp_msg(MSGT_TV, MSGL_INFO, "Selected device: %s\n", priv->capability.card); | |
992 if (priv->capability.capabilities & V4L2_CAP_TUNER) { | |
993 mp_msg(MSGT_TV, MSGL_INFO, " Tuner cap:%s%s%s\n", | |
994 (priv->tuner.capability & V4L2_TUNER_CAP_STEREO) ? " STEREO" : "", | |
995 (priv->tuner.capability & V4L2_TUNER_CAP_LANG1) ? " LANG1" : "", | |
996 (priv->tuner.capability & V4L2_TUNER_CAP_LANG2) ? " LANG2" : ""); | |
997 mp_msg(MSGT_TV, MSGL_INFO, " Tuner rxs:%s%s%s%s\n", | |
998 (priv->tuner.rxsubchans & V4L2_TUNER_SUB_MONO) ? " MONO" : "", | |
999 (priv->tuner.rxsubchans & V4L2_TUNER_SUB_STEREO) ? " STEREO" : "", | |
1000 (priv->tuner.rxsubchans & V4L2_TUNER_SUB_LANG1) ? " LANG1" : "", | |
1001 (priv->tuner.rxsubchans & V4L2_TUNER_SUB_LANG2) ? " LANG2" : ""); | |
1002 } | |
1003 mp_msg(MSGT_TV, MSGL_INFO, " Capabilites:%s%s%s%s%s%s%s%s%s%s%s\n", | |
1004 priv->capability.capabilities & V4L2_CAP_VIDEO_CAPTURE? | |
1005 " video capture": "", | |
1006 priv->capability.capabilities & V4L2_CAP_VIDEO_OUTPUT? | |
1007 " video output": "", | |
1008 priv->capability.capabilities & V4L2_CAP_VIDEO_OVERLAY? | |
1009 " video overlay": "", | |
1010 priv->capability.capabilities & V4L2_CAP_VBI_CAPTURE? | |
1011 " VBI capture device": "", | |
1012 priv->capability.capabilities & V4L2_CAP_VBI_OUTPUT? | |
1013 " VBI output": "", | |
1014 priv->capability.capabilities & V4L2_CAP_RDS_CAPTURE? | |
1015 " RDS data capture": "", | |
1016 priv->capability.capabilities & V4L2_CAP_TUNER? | |
1017 " tuner": "", | |
1018 priv->capability.capabilities & V4L2_CAP_AUDIO? | |
1019 " audio": "", | |
1020 priv->capability.capabilities & V4L2_CAP_READWRITE? | |
1021 " read/write": "", | |
1022 priv->capability.capabilities & V4L2_CAP_ASYNCIO? | |
1023 " async i/o": "", | |
1024 priv->capability.capabilities & V4L2_CAP_STREAMING? | |
1025 " streaming": ""); | |
1026 mp_msg(MSGT_TV, MSGL_INFO, " supported norms:"); | |
1027 for (i = 0;; i++) { | |
1028 struct v4l2_standard standard; | |
1029 memset(&standard, 0, sizeof(standard)); | |
1030 standard.index = i; | |
1031 if (-1 == ioctl(priv->video_fd, VIDIOC_ENUMSTD, &standard)) | |
1032 break; | |
1033 printf(" %d = %s;", i, standard.name); | |
1034 } | |
1035 mp_msg(MSGT_TV, MSGL_INFO, "\n inputs:"); | |
1036 for (i = 0; 1; i++) { | |
1037 struct v4l2_input input; | |
1038 | |
1039 input.index = i; | |
1040 if (ioctl(priv->video_fd, VIDIOC_ENUMINPUT, &input) < 0) { | |
1041 break; | |
1042 } | |
1043 mp_msg(MSGT_TV, MSGL_INFO, " %d = %s;", i, input.name); | |
1044 } | |
1045 if (ioctl(priv->video_fd, VIDIOC_G_INPUT, &i) < 0) { | |
1046 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get input failed: %s\n", | |
1047 info.short_name, strerror(errno)); | |
1048 } | |
1049 mp_msg(MSGT_TV, MSGL_INFO, "\n Current input: %d\n", i); | |
1050 for (i = 0; ; i++) { | |
1051 struct v4l2_fmtdesc fmtdesc; | |
1052 | |
1053 fmtdesc.index = i; | |
1054 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
1055 if (ioctl(priv->video_fd, VIDIOC_ENUM_FMT, &fmtdesc) < 0) { | |
1056 break; | |
1057 } | |
1058 mp_msg(MSGT_TV, MSGL_V, " Format %-6s (%2d bits, %s): %s\n", | |
1059 pixfmt2name(fmtdesc.pixelformat), pixfmt2depth(fmtdesc.pixelformat), | |
1060 fmtdesc.description, vo_format_name(fcc_vl2mp(fmtdesc.pixelformat))); | |
1061 } | |
1062 mp_msg(MSGT_TV, MSGL_INFO, " Current format: %s\n", | |
1063 pixfmt2name(priv->format.fmt.pix.pixelformat)); | |
1064 | |
1065 /* set some nice defaults */ | |
1066 if (getfmt(priv) < 0) return 0; | |
1067 priv->format.fmt.pix.width = 640; | |
1068 priv->format.fmt.pix.height = 480; | |
1069 if (ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) { | |
1070 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set format failed: %s\n", | |
1071 info.short_name, strerror(errno)); | |
1072 uninit(priv); | |
1073 return 0; | |
1074 } | |
1075 | |
1076 // if (!(priv->capability.capabilities & V4L2_CAP_AUDIO) && !tv_param_force_audio) tv_param_noaudio = 1; | |
1077 | |
1078 if (priv->capability.capabilities & V4L2_CAP_TUNER) { | |
1079 struct v4l2_control control; | |
1080 if (tv_param_amode >= 0) { | |
1081 mp_msg(MSGT_TV, MSGL_V, "%s: setting audio mode\n", info.short_name); | |
1082 priv->tuner.audmode = amode2v4l(tv_param_amode); | |
1083 if (ioctl(priv->video_fd, VIDIOC_S_TUNER, &priv->tuner) < 0) { | |
1084 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set tuner failed: %s\n", | |
1085 info.short_name, strerror(errno)); | |
1086 return TVI_CONTROL_FALSE; | |
1087 } | |
1088 } | |
1089 mp_msg(MSGT_TV, MSGL_INFO, "%s: current audio mode is :%s%s%s%s\n", info.short_name, | |
1090 (priv->tuner.audmode == V4L2_TUNER_MODE_MONO) ? " MONO" : "", | |
1091 (priv->tuner.audmode == V4L2_TUNER_MODE_STEREO) ? " STEREO" : "", | |
1092 (priv->tuner.audmode == V4L2_TUNER_MODE_LANG1) ? " LANG1" : "", | |
1093 (priv->tuner.audmode == V4L2_TUNER_MODE_LANG2) ? " LANG2" : ""); | |
1094 | |
1095 if (tv_param_volume >= 0) { | |
1096 control.id = V4L2_CID_AUDIO_VOLUME; | |
1097 control.value = tv_param_volume; | |
1098 set_control(priv, &control, 0); | |
1099 } | |
1100 if (tv_param_bass >= 0) { | |
1101 control.id = V4L2_CID_AUDIO_BASS; | |
1102 control.value = tv_param_bass; | |
1103 set_control(priv, &control, 0); | |
1104 } | |
1105 if (tv_param_treble >= 0) { | |
1106 control.id = V4L2_CID_AUDIO_TREBLE; | |
1107 control.value = tv_param_treble; | |
1108 set_control(priv, &control, 0); | |
1109 } | |
1110 if (tv_param_balance >= 0) { | |
1111 control.id = V4L2_CID_AUDIO_BALANCE; | |
1112 control.value = tv_param_balance; | |
1113 set_control(priv, &control, 0); | |
1114 } | |
1115 } | |
1116 | |
1117 return 1; | |
1118 } | |
1119 | |
1120 static int get_capture_buffer_size(priv_t *priv) | |
1121 { | |
1122 int bufsize, cnt; | |
1123 int w = priv->format.fmt.pix.width; | |
1124 int h = priv->format.fmt.pix.height; | |
1125 int d = pixfmt2depth(priv->format.fmt.pix.pixelformat); | |
1126 int bytesperline = w*d/8; | |
1127 | |
1128 if (tv_param_buffer_size >= 0) { | |
1129 bufsize = tv_param_buffer_size*1024*1024; | |
1130 } else { | |
1131 #ifdef HAVE_SYS_SYSINFO_H | |
1132 struct sysinfo si; | |
1133 | |
1134 sysinfo(&si); | |
1135 if (si.totalram<2*1024*1024) { | |
1136 bufsize = 1024*1024; | |
1137 } else { | |
1138 bufsize = si.totalram/2; | |
1139 } | |
1140 #else | |
1141 bufsize = 16*1024*1024; | |
1142 #endif | |
1143 } | |
1144 | |
1145 cnt = bufsize/(h*bytesperline); | |
1146 if (cnt < 2) cnt = 2; | |
1147 | |
1148 return cnt; | |
1149 } | |
1150 | |
1151 /* that's the real start, we'got the format parameters (checked with control) */ | |
1152 static int start(priv_t *priv) | |
1153 { | |
1154 struct v4l2_requestbuffers request; | |
1155 int i; | |
1156 | |
1157 /* setup audio parameters */ | |
1158 | |
15464 | 1159 init_audio(priv); |
1160 if (!tv_param_noaudio && !priv->audio_inited) return 0; | |
1161 | |
10536 | 1162 /* we need this to size the audio buffer properly */ |
1163 if (priv->immediate_mode) { | |
1164 priv->video_buffer_size_max = 2; | |
1165 } else { | |
1166 priv->video_buffer_size_max = get_capture_buffer_size(priv); | |
1167 } | |
1168 | |
1169 if (!tv_param_noaudio) { | |
1170 setup_audio_buffer_sizes(priv); | |
1171 priv->audio_skew_buffer = (long long*)malloc(sizeof(long long)*priv->aud_skew_cnt); | |
1172 if (!priv->audio_skew_buffer) { | |
1173 mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate skew buffer: %s\n", strerror(errno)); | |
1174 return 0; | |
1175 } | |
10653 | 1176 priv->audio_skew_delta_buffer = (long long*)malloc(sizeof(long long)*priv->aud_skew_cnt); |
1177 if (!priv->audio_skew_delta_buffer) { | |
1178 mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate skew buffer: %s\n", strerror(errno)); | |
1179 return 0; | |
1180 } | |
10536 | 1181 |
1182 priv->audio_ringbuffer = (unsigned char*)malloc(priv->audio_in.blocksize*priv->audio_buffer_size); | |
1183 if (!priv->audio_ringbuffer) { | |
1184 mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate audio buffer: %s\n", strerror(errno)); | |
1185 return 0; | |
1186 } | |
1187 | |
1188 priv->audio_secs_per_block = (double)priv->audio_in.blocksize/(priv->audio_in.samplerate | |
1189 *priv->audio_in.channels | |
1190 *priv->audio_in.bytes_per_sample); | |
15449 | 1191 priv->audio_usecs_per_block = 1e6*priv->audio_secs_per_block; |
10536 | 1192 priv->audio_head = 0; |
1193 priv->audio_tail = 0; | |
1194 priv->audio_cnt = 0; | |
1195 priv->audio_drop = 0; | |
1196 priv->audio_skew = 0; | |
1197 priv->audio_skew_total = 0; | |
10653 | 1198 priv->audio_skew_delta_total = 0; |
10536 | 1199 priv->audio_recv_blocks_total = 0; |
1200 priv->audio_sent_blocks_total = 0; | |
15449 | 1201 priv->audio_null_blocks_inserted = 0; |
1202 priv->audio_insert_null_samples = 0; | |
1203 priv->dropped_frames_timeshift = 0; | |
1204 priv->dropped_frames_compensated = 0; | |
1205 | |
1206 pthread_mutex_init(&priv->skew_mutex, NULL); | |
1207 pthread_mutex_init(&priv->audio_mutex, NULL); | |
10536 | 1208 } |
1209 | |
1210 /* setup video parameters */ | |
1211 if (!tv_param_noaudio) { | |
16289 | 1212 if (priv->video_buffer_size_max < (3*priv->standard.frameperiod.denominator) / |
1213 priv->standard.frameperiod.numerator | |
10536 | 1214 *priv->audio_secs_per_block) { |
1215 mp_msg(MSGT_TV, MSGL_ERR, "Video buffer shorter than 3 times audio frame duration.\n" | |
1216 "You will probably experience heavy framedrops.\n"); | |
1217 } | |
1218 } | |
1219 | |
1220 { | |
1221 int bytesperline = priv->format.fmt.pix.width*pixfmt2depth(priv->format.fmt.pix.pixelformat)/8; | |
1222 | |
1223 mp_msg(MSGT_TV, MSGL_V, "Using a ring buffer for maximum %d frames, %d MB total size.\n", | |
1224 priv->video_buffer_size_max, | |
1225 priv->video_buffer_size_max*priv->format.fmt.pix.height*bytesperline/(1024*1024)); | |
1226 } | |
1227 | |
1228 priv->video_ringbuffer = (unsigned char**)malloc(priv->video_buffer_size_max*sizeof(unsigned char*)); | |
1229 if (!priv->video_ringbuffer) { | |
1230 mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate video buffer: %s\n", strerror(errno)); | |
1231 return 0; | |
1232 } | |
1233 for (i = 0; i < priv->video_buffer_size_max; i++) | |
1234 priv->video_ringbuffer[i] = NULL; | |
1235 priv->video_timebuffer = (long long*)malloc(sizeof(long long) * priv->video_buffer_size_max); | |
1236 if (!priv->video_timebuffer) { | |
1237 mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate time buffer: %s\n", strerror(errno)); | |
1238 return 0; | |
1239 } | |
1240 | |
15449 | 1241 pthread_mutex_init(&priv->video_buffer_mutex, NULL); |
1242 | |
10536 | 1243 priv->video_head = 0; |
1244 priv->video_tail = 0; | |
1245 priv->video_cnt = 0; | |
1246 | |
1247 /* request buffers */ | |
1248 if (priv->immediate_mode) { | |
1249 request.count = 2; | |
1250 } else { | |
1251 request.count = BUFFER_COUNT; | |
1252 } | |
1253 | |
1254 request.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
1255 request.memory = V4L2_MEMORY_MMAP; | |
1256 if (ioctl(priv->video_fd, VIDIOC_REQBUFS, &request) < 0) { | |
1257 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl request buffers failed: %s\n", | |
1258 info.short_name, strerror(errno)); | |
1259 return 0; | |
1260 } | |
1261 | |
1262 /* query buffers */ | |
1263 if (!(priv->map = malloc(sizeof(struct map) * request.count))) { | |
1264 mp_msg(MSGT_TV, MSGL_ERR, "%s: malloc capture buffers failed: %s\n", | |
1265 info.short_name, strerror(errno)); | |
1266 return 0; | |
1267 } | |
1268 | |
1269 /* map and queue buffers */ | |
1270 for (i = 0; i < request.count; i++) { | |
1271 memset(&priv->map[i].buf,0,sizeof(priv->map[i].buf)); | |
1272 priv->map[i].buf.index = i; | |
1273 priv->map[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
1274 priv->map[i].buf.memory = V4L2_MEMORY_MMAP; | |
1275 if (ioctl(priv->video_fd, VIDIOC_QUERYBUF, &(priv->map[i].buf)) < 0) { | |
1276 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query buffer failed: %s\n", | |
1277 info.short_name, strerror(errno)); | |
1278 free(priv->map); | |
1279 priv->map = NULL; | |
1280 return 0; | |
1281 } | |
1282 priv->map[i].addr = mmap (0, priv->map[i].buf.length, PROT_READ | | |
1283 PROT_WRITE, MAP_SHARED, priv->video_fd, priv->map[i].buf.m.offset); | |
1284 if (priv->map[i].addr == MAP_FAILED) { | |
1285 mp_msg(MSGT_TV, MSGL_ERR, "%s: mmap capture buffer failed: %s\n", | |
1286 info.short_name, strerror(errno)); | |
1287 priv->map[i].len = 0; | |
1288 return 0; | |
1289 } | |
1290 priv->map[i].len = priv->map[i].buf.length; | |
1291 /* count up to make sure this is correct everytime */ | |
1292 priv->mapcount++; | |
1293 | |
1294 if (ioctl(priv->video_fd, VIDIOC_QBUF, &(priv->map[i].buf)) < 0) { | |
1295 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl queue buffer failed: %s\n", | |
1296 info.short_name, strerror(errno)); | |
1297 return 0; | |
1298 } | |
1299 } | |
1300 | |
1301 /* start audio thread */ | |
1302 priv->shutdown = 0; | |
1303 priv->audio_skew_measure_time = 0; | |
1304 priv->first_frame = 0; | |
1305 priv->audio_skew = 0; | |
1306 priv->first = 1; | |
1307 | |
17626
5627625b0cdb
Don't test the v4l2_input audioset field for audio capabilities but still try changing the mute setting (patch by Jesse Allen < the3dfxdude _at_ gmail.com >)
aurel
parents:
17199
diff
changeset
|
1308 set_mute(priv, 0); |
10536 | 1309 |
1310 return 1; | |
1311 } | |
1312 | |
1313 | |
1314 #ifdef HAVE_TV_BSDBT848 | |
1315 static double grabimmediate_video_frame(priv_t *priv, char *buffer, int len) | |
1316 { | |
1317 memset(buffer, 0xCC, len); | |
1318 return(1); | |
1319 } | |
1320 #endif /* HAVE_TV_BSDBT848 */ | |
1321 | |
1322 // copies a video frame | |
1323 static inline void copy_frame(priv_t *priv, unsigned char *dest, unsigned char *source) | |
1324 { | |
1325 int w = priv->format.fmt.pix.width; | |
1326 int h = priv->format.fmt.pix.height; | |
1327 int d = pixfmt2depth(priv->format.fmt.pix.pixelformat); | |
1328 int bytesperline = w*d/8; | |
1329 | |
17199
9164ef9a1834
remove now useless YV12 plane swap hack, patch by Luc Gallant lucgallant at gmail com
henry
parents:
17012
diff
changeset
|
1330 memcpy(dest, source, bytesperline * h); |
10536 | 1331 } |
1332 | |
1333 // maximum skew change, in frames | |
1334 #define MAX_SKEW_DELTA 0.6 | |
1335 static void *video_grabber(void *data) | |
1336 { | |
1337 priv_t *priv = (priv_t*)data; | |
15449 | 1338 long long skew, prev_skew, xskew, interval, prev_interval, delta; |
10536 | 1339 int i; |
16962
bdc218b5a49a
Do not hang forever when the card delivers no new data.
reimar
parents:
16536
diff
changeset
|
1340 int err_count = 0; |
10536 | 1341 int framesize = priv->format.fmt.pix.height*priv->format.fmt.pix.width* |
1342 pixfmt2depth(priv->format.fmt.pix.pixelformat)/8; | |
1343 fd_set rdset; | |
1344 struct timeval timeout; | |
1345 struct v4l2_buffer buf; | |
1346 | |
1347 xskew = 0; | |
1348 skew = 0; | |
1349 interval = 0; | |
1350 prev_interval = 0; | |
1351 prev_skew = 0; | |
1352 | |
1353 mp_msg(MSGT_TV, MSGL_V, "%s: going to capture\n", info.short_name); | |
1354 if (ioctl(priv->video_fd, VIDIOC_STREAMON, &(priv->format.type)) < 0) { | |
1355 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl streamon failed: %s\n", | |
1356 info.short_name, strerror(errno)); | |
1357 return 0; | |
1358 } | |
1359 priv->streamon = 1; | |
1360 | |
1361 if (!tv_param_noaudio) { | |
1362 pthread_create(&priv->audio_grabber_thread, NULL, audio_grabber, priv); | |
1363 } | |
1364 | |
1365 for (priv->frames = 0; !priv->shutdown;) | |
1366 { | |
1367 int ret; | |
1368 | |
1369 if (priv->immediate_mode) { | |
1370 while (priv->video_cnt == priv->video_buffer_size_max) { | |
1371 usleep(10000); | |
1372 if (priv->shutdown) { | |
1373 return NULL; | |
1374 } | |
1375 } | |
1376 } | |
1377 | |
1378 FD_ZERO (&rdset); | |
1379 FD_SET (priv->video_fd, &rdset); | |
1380 | |
1381 timeout.tv_sec = 1; | |
1382 timeout.tv_usec = 0; | |
1383 | |
1384 i = select(priv->video_fd + 1, &rdset, NULL, NULL, &timeout); | |
1385 if (i < 0) { | |
1386 mp_msg(MSGT_TV, MSGL_ERR, "%s: select failed: %s\n", | |
1387 info.short_name, strerror(errno)); | |
1388 continue; | |
1389 } | |
1390 else if (i == 0) { | |
1391 mp_msg(MSGT_TV, MSGL_ERR, "%s: select timeout\n", info.short_name); | |
1392 continue; | |
1393 } | |
1394 else if (!FD_ISSET(priv->video_fd, &rdset)) { | |
1395 continue; | |
1396 } | |
1397 | |
1398 memset(&buf,0,sizeof(buf)); | |
1399 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
1400 ret = ioctl(priv->video_fd, VIDIOC_DQBUF, &buf); | |
1401 | |
1402 if (ret < 0) { | |
1403 /* | |
1404 if there's no signal, the buffer might me dequeued | |
1405 so we query all the buffers to see which one we should | |
1406 put back to queue | |
1407 | |
1408 observed with saa7134 0.2.8 | |
1409 don't know if is it a bug or (mis)feature | |
1410 */ | |
1411 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl dequeue buffer failed: %s, idx = %d\n", | |
1412 info.short_name, strerror(errno), buf.index); | |
1413 for (i = 0; i < priv->mapcount; i++) { | |
1414 memset(&buf,0,sizeof(buf)); | |
1415 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
1416 buf.index = i; | |
1417 ret = ioctl(priv->video_fd, VIDIOC_QUERYBUF, &buf); | |
1418 if (ret < 0) { | |
1419 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query buffer failed: %s, idx = %d\n", | |
1420 info.short_name, strerror(errno), buf.index); | |
1421 return 0; | |
1422 } | |
1423 if ((buf.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE)) == V4L2_BUF_FLAG_MAPPED) { | |
1424 if (ioctl(priv->video_fd, VIDIOC_QBUF, &(priv->map[i].buf)) < 0) { | |
1425 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl queue buffer failed: %s\n", | |
1426 info.short_name, strerror(errno)); | |
1427 return 0; | |
1428 } | |
1429 } | |
1430 } | |
1431 continue; | |
1432 } | |
1433 | |
1434 /* store the timestamp of the very first frame as reference */ | |
1435 if (!priv->frames++) { | |
15462 | 1436 if (!tv_param_noaudio) pthread_mutex_lock(&priv->skew_mutex); |
10536 | 1437 priv->first_frame = (long long)1e6*buf.timestamp.tv_sec + buf.timestamp.tv_usec; |
15462 | 1438 if (!tv_param_noaudio) pthread_mutex_unlock(&priv->skew_mutex); |
10536 | 1439 } |
1440 priv->curr_frame = (long long)buf.timestamp.tv_sec*1e6+buf.timestamp.tv_usec; | |
1441 // fprintf(stderr, "idx = %d, ts = %lf\n", buf.index, (double)(priv->curr_frame) / 1e6); | |
1442 | |
1443 interval = priv->curr_frame - priv->first_frame; | |
15449 | 1444 delta = interval - prev_interval; |
10536 | 1445 |
1446 if (!priv->immediate_mode) { | |
1447 // interpolate the skew in time | |
15462 | 1448 if (!tv_param_noaudio) pthread_mutex_lock(&priv->skew_mutex); |
10536 | 1449 xskew = priv->audio_skew + (interval - priv->audio_skew_measure_time)*priv->audio_skew_factor; |
15462 | 1450 if (!tv_param_noaudio) pthread_mutex_unlock(&priv->skew_mutex); |
10536 | 1451 // correct extreme skew changes to avoid (especially) moving backwards in time |
15449 | 1452 if (xskew - prev_skew > delta*MAX_SKEW_DELTA) { |
1453 skew = prev_skew + delta*MAX_SKEW_DELTA; | |
1454 } else if (xskew - prev_skew < -delta*MAX_SKEW_DELTA) { | |
1455 skew = prev_skew - delta*MAX_SKEW_DELTA; | |
10536 | 1456 } else { |
1457 skew = xskew; | |
1458 } | |
1459 } | |
1460 | |
1461 mp_msg(MSGT_TV, MSGL_DBG3, "\nfps = %lf, interval = %lf, a_skew = %f, corr_skew = %f\n", | |
15449 | 1462 delta ? (double)1e6/delta : -1, |
10536 | 1463 (double)1e-6*interval, (double)1e-6*xskew, (double)1e-6*skew); |
1464 mp_msg(MSGT_TV, MSGL_DBG3, "vcnt = %d, acnt = %d\n", priv->video_cnt, priv->audio_cnt); | |
1465 | |
1466 prev_skew = skew; | |
1467 prev_interval = interval; | |
1468 | |
1469 /* allocate a new buffer, if needed */ | |
1470 pthread_mutex_lock(&priv->video_buffer_mutex); | |
1471 if (priv->video_buffer_size_current < priv->video_buffer_size_max) { | |
1472 if (priv->video_cnt == priv->video_buffer_size_current) { | |
1473 unsigned char *newbuf = (unsigned char*)malloc(framesize); | |
1474 if (newbuf) { | |
1475 memmove(priv->video_ringbuffer+priv->video_tail+1, priv->video_ringbuffer+priv->video_tail, | |
1476 (priv->video_buffer_size_current-priv->video_tail)*sizeof(unsigned char *)); | |
1477 memmove(priv->video_timebuffer+priv->video_tail+1, priv->video_timebuffer+priv->video_tail, | |
1478 (priv->video_buffer_size_current-priv->video_tail)*sizeof(long long)); | |
1479 priv->video_ringbuffer[priv->video_tail] = newbuf; | |
1480 if ((priv->video_head >= priv->video_tail) && (priv->video_cnt > 0)) priv->video_head++; | |
1481 priv->video_buffer_size_current++; | |
1482 } | |
1483 } | |
1484 } | |
1485 pthread_mutex_unlock(&priv->video_buffer_mutex); | |
1486 | |
1487 if (priv->video_cnt == priv->video_buffer_size_current) { | |
1488 if (!priv->immediate_mode) { | |
1489 mp_msg(MSGT_TV, MSGL_ERR, "\nvideo buffer full - dropping frame\n"); | |
15449 | 1490 if (priv->audio_insert_null_samples) { |
1491 pthread_mutex_lock(&priv->audio_mutex); | |
1492 priv->dropped_frames_timeshift += delta; | |
1493 pthread_mutex_unlock(&priv->audio_mutex); | |
1494 } | |
10536 | 1495 } |
1496 } else { | |
1497 if (priv->immediate_mode) { | |
1498 priv->video_timebuffer[priv->video_tail] = 0; | |
1499 } else { | |
1500 // compensate for audio skew | |
1501 // negative skew => there are more audio samples, increase interval | |
1502 // positive skew => less samples, shorten the interval | |
1503 priv->video_timebuffer[priv->video_tail] = interval - skew; | |
15449 | 1504 if (priv->audio_insert_null_samples && priv->video_timebuffer[priv->video_tail] > 0) { |
1505 pthread_mutex_lock(&priv->audio_mutex); | |
1506 priv->video_timebuffer[priv->video_tail] += | |
1507 (priv->audio_null_blocks_inserted | |
1508 - priv->dropped_frames_timeshift/priv->audio_usecs_per_block) | |
1509 *priv->audio_usecs_per_block; | |
1510 pthread_mutex_unlock(&priv->audio_mutex); | |
1511 } | |
10536 | 1512 } |
15449 | 1513 |
10536 | 1514 copy_frame(priv, priv->video_ringbuffer[priv->video_tail], priv->map[buf.index].addr); |
1515 priv->video_tail = (priv->video_tail+1)%priv->video_buffer_size_current; | |
1516 priv->video_cnt++; | |
1517 } | |
1518 if (ioctl(priv->video_fd, VIDIOC_QBUF, &buf) < 0) { | |
1519 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl queue buffer failed: %s\n", | |
1520 info.short_name, strerror(errno)); | |
1521 return 0; | |
1522 } | |
1523 } | |
1524 return NULL; | |
1525 } | |
1526 | |
16962
bdc218b5a49a
Do not hang forever when the card delivers no new data.
reimar
parents:
16536
diff
changeset
|
1527 #define MAX_LOOP 50 |
10536 | 1528 static double grab_video_frame(priv_t *priv, char *buffer, int len) |
1529 { | |
1530 double interval; | |
16962
bdc218b5a49a
Do not hang forever when the card delivers no new data.
reimar
parents:
16536
diff
changeset
|
1531 int loop_cnt = 0; |
10536 | 1532 |
1533 if (priv->first) { | |
1534 pthread_create(&priv->video_grabber_thread, NULL, video_grabber, priv); | |
1535 priv->first = 0; | |
1536 } | |
1537 | |
1538 while (priv->video_cnt == 0) { | |
1539 usleep(10000); | |
16962
bdc218b5a49a
Do not hang forever when the card delivers no new data.
reimar
parents:
16536
diff
changeset
|
1540 if (loop_cnt++ > MAX_LOOP) return 0; |
10536 | 1541 } |
1542 | |
1543 pthread_mutex_lock(&priv->video_buffer_mutex); | |
1544 interval = (double)priv->video_timebuffer[priv->video_head]*1e-6; | |
1545 memcpy(buffer, priv->video_ringbuffer[priv->video_head], len); | |
1546 priv->video_cnt--; | |
1547 priv->video_head = (priv->video_head+1)%priv->video_buffer_size_current; | |
1548 pthread_mutex_unlock(&priv->video_buffer_mutex); | |
1549 | |
1550 return interval; | |
1551 } | |
1552 | |
1553 static int get_video_framesize(priv_t *priv) | |
1554 { | |
1555 return priv->format.fmt.pix.sizeimage; | |
1556 } | |
1557 | |
10704 | 1558 //#define DOUBLESPEED |
1559 #ifdef DOUBLESPEED | |
10536 | 1560 // for testing purposes only |
1561 static void read_doublespeed(priv_t *priv) | |
1562 { | |
1563 char *bufx = (char*)malloc(priv->audio_in.blocksize*2); | |
1564 short *s; | |
1565 short *d; | |
1566 int i; | |
1567 | |
1568 audio_in_read_chunk(&priv->audio_in, bufx); | |
1569 audio_in_read_chunk(&priv->audio_in, bufx+priv->audio_in.blocksize); | |
1570 | |
1571 s = bufx; | |
1572 d = priv->audio_ringbuffer+priv->audio_tail*priv->audio_in.blocksize; | |
1573 for (i = 0; i < priv->audio_in.blocksize/2; i++) { | |
1574 *d++ = *s++; | |
1575 *s++; | |
1576 } | |
1577 | |
1578 } | |
10704 | 1579 #endif |
10536 | 1580 |
1581 static void *audio_grabber(void *data) | |
1582 { | |
1583 priv_t *priv = (priv_t*)data; | |
1584 struct timeval tv; | |
1585 int i, audio_skew_ptr = 0; | |
10653 | 1586 long long current_time, prev_skew = 0, prev_skew_uncorr = 0; |
10852 | 1587 long long start_time_avg; |
10536 | 1588 |
1589 gettimeofday(&tv, NULL); | |
10852 | 1590 start_time_avg = priv->audio_start_time = (long long)1e6*tv.tv_sec + tv.tv_usec; |
10536 | 1591 audio_in_start_capture(&priv->audio_in); |
1592 for (i = 0; i < priv->aud_skew_cnt; i++) | |
1593 priv->audio_skew_buffer[i] = 0; | |
10653 | 1594 for (i = 0; i < priv->aud_skew_cnt; i++) |
1595 priv->audio_skew_delta_buffer[i] = 0; | |
10536 | 1596 |
1597 for (; !priv->shutdown;) | |
1598 { | |
10704 | 1599 #ifdef DOUBLESPEED |
1600 read_doublespeed(priv); | |
1601 #else | |
10536 | 1602 if (audio_in_read_chunk(&priv->audio_in, priv->audio_ringbuffer+priv->audio_tail*priv->audio_in.blocksize) < 0) |
1603 continue; | |
10704 | 1604 #endif |
10536 | 1605 pthread_mutex_lock(&priv->skew_mutex); |
1606 if (priv->first_frame == 0) { | |
1607 // there is no first frame yet (unlikely to happen) | |
10810 | 1608 gettimeofday(&tv, NULL); |
10852 | 1609 start_time_avg = priv->audio_start_time = (long long)1e6*tv.tv_sec + tv.tv_usec; |
10536 | 1610 // fprintf(stderr, "warning - first frame not yet available!\n"); |
1611 pthread_mutex_unlock(&priv->skew_mutex); | |
1612 continue; | |
1613 } | |
1614 pthread_mutex_unlock(&priv->skew_mutex); | |
1615 | |
1616 gettimeofday(&tv, NULL); | |
1617 | |
1618 priv->audio_recv_blocks_total++; | |
1619 current_time = (long long)1e6*tv.tv_sec + tv.tv_usec - priv->audio_start_time; | |
1620 | |
10852 | 1621 if (priv->audio_recv_blocks_total < priv->aud_skew_cnt*2) { |
15449 | 1622 start_time_avg += (long long)1e6*tv.tv_sec + tv.tv_usec - priv->audio_usecs_per_block*priv->audio_recv_blocks_total; |
10852 | 1623 priv->audio_start_time = start_time_avg/(priv->audio_recv_blocks_total+1); |
1624 } | |
1625 | |
10536 | 1626 // fprintf(stderr, "spb = %lf, bs = %d, skew = %lf\n", priv->audio_secs_per_block, priv->audio_in.blocksize, |
1627 // (double)(current_time - 1e6*priv->audio_secs_per_block*priv->audio_recv_blocks_total)/1e6); | |
1628 | |
10704 | 1629 // put the current skew into the ring buffer |
10536 | 1630 priv->audio_skew_total -= priv->audio_skew_buffer[audio_skew_ptr]; |
1631 priv->audio_skew_buffer[audio_skew_ptr] = current_time | |
15449 | 1632 - priv->audio_usecs_per_block*priv->audio_recv_blocks_total; |
10536 | 1633 priv->audio_skew_total += priv->audio_skew_buffer[audio_skew_ptr]; |
1634 | |
1635 pthread_mutex_lock(&priv->skew_mutex); | |
10704 | 1636 |
1637 // skew calculation | |
1638 | |
1639 // compute the sliding average of the skews | |
10536 | 1640 if (priv->audio_recv_blocks_total > priv->aud_skew_cnt) { |
1641 priv->audio_skew = priv->audio_skew_total/priv->aud_skew_cnt; | |
1642 } else { | |
10704 | 1643 priv->audio_skew = priv->audio_skew_total/priv->audio_recv_blocks_total; |
10536 | 1644 } |
10653 | 1645 |
10704 | 1646 // put the current skew change (skew-prev_skew) into the ring buffer |
10653 | 1647 priv->audio_skew_delta_total -= priv->audio_skew_delta_buffer[audio_skew_ptr]; |
1648 priv->audio_skew_delta_buffer[audio_skew_ptr] = priv->audio_skew - prev_skew_uncorr; | |
1649 priv->audio_skew_delta_total += priv->audio_skew_delta_buffer[audio_skew_ptr]; | |
10704 | 1650 prev_skew_uncorr = priv->audio_skew; // remember the _uncorrected_ average value |
1651 | |
1652 audio_skew_ptr = (audio_skew_ptr+1) % priv->aud_skew_cnt; // rotate the buffer pointer | |
10653 | 1653 |
10704 | 1654 // sliding average approximates the value in the middle of the interval |
1655 // so interpolate the skew value further to the current time | |
1656 priv->audio_skew += priv->audio_skew_delta_total/2; | |
10653 | 1657 |
10704 | 1658 // now finally, priv->audio_skew contains fairly good approximation |
1659 // of the current value | |
10653 | 1660 |
10536 | 1661 // current skew factor (assuming linearity) |
1662 // used for further interpolation in video_grabber | |
1663 // probably overkill but seems to be necessary for | |
1664 // stress testing by dropping half of the audio frames ;) | |
1665 // especially when using ALSA with large block sizes | |
1666 // where audio_skew remains a long while behind | |
1667 if ((priv->audio_skew_measure_time != 0) && (current_time - priv->audio_skew_measure_time != 0)) { | |
1668 priv->audio_skew_factor = (double)(priv->audio_skew-prev_skew)/(current_time - priv->audio_skew_measure_time); | |
1669 } else { | |
1670 priv->audio_skew_factor = 0.0; | |
1671 } | |
10852 | 1672 |
10536 | 1673 priv->audio_skew_measure_time = current_time; |
1674 prev_skew = priv->audio_skew; | |
10852 | 1675 priv->audio_skew += priv->audio_start_time - priv->first_frame; |
1676 pthread_mutex_unlock(&priv->skew_mutex); | |
1677 | |
1678 // fprintf(stderr, "audio_skew = %lf, delta = %lf\n", (double)priv->audio_skew/1e6, (double)priv->audio_skew_delta_total/1e6); | |
10851 | 1679 |
15449 | 1680 pthread_mutex_lock(&priv->audio_mutex); |
10536 | 1681 if ((priv->audio_tail+1) % priv->audio_buffer_size == priv->audio_head) { |
1682 mp_msg(MSGT_TV, MSGL_ERR, "\ntoo bad - dropping audio frame !\n"); | |
1683 priv->audio_drop++; | |
1684 } else { | |
1685 priv->audio_tail = (priv->audio_tail+1) % priv->audio_buffer_size; | |
1686 priv->audio_cnt++; | |
1687 } | |
15449 | 1688 pthread_mutex_unlock(&priv->audio_mutex); |
10536 | 1689 } |
1690 return NULL; | |
1691 } | |
1692 | |
1693 static double grab_audio_frame(priv_t *priv, char *buffer, int len) | |
1694 { | |
1695 mp_dbg(MSGT_TV, MSGL_DBG2, "grab_audio_frame(priv=%p, buffer=%p, len=%d)\n", | |
1696 priv, buffer, len); | |
1697 | |
15449 | 1698 // hack: if grab_audio_frame is called first, it means we are used by mplayer |
1699 // => switch to the mode which outputs audio immediately, even if | |
1700 // it should be silence | |
1701 if (priv->first) priv->audio_insert_null_samples = 1; | |
1702 | |
1703 pthread_mutex_lock(&priv->audio_mutex); | |
1704 while (priv->audio_insert_null_samples | |
1705 && priv->dropped_frames_timeshift - priv->dropped_frames_compensated >= priv->audio_usecs_per_block) { | |
1706 // some frames were dropped - drop the corresponding number of audio blocks | |
1707 if (priv->audio_drop) { | |
1708 priv->audio_drop--; | |
1709 } else { | |
1710 if (priv->audio_head == priv->audio_tail) break; | |
1711 priv->audio_head = (priv->audio_head+1) % priv->audio_buffer_size; | |
1712 } | |
1713 priv->dropped_frames_compensated += priv->audio_usecs_per_block; | |
10776
80402283a017
Fix immediatemode with mplayer (ie playing both sound and video)
albeu
parents:
10735
diff
changeset
|
1714 } |
80402283a017
Fix immediatemode with mplayer (ie playing both sound and video)
albeu
parents:
10735
diff
changeset
|
1715 |
10536 | 1716 // compensate for dropped audio frames |
1717 if (priv->audio_drop && (priv->audio_head == priv->audio_tail)) { | |
1718 priv->audio_drop--; | |
1719 memset(buffer, 0, len); | |
15449 | 1720 goto out; |
10536 | 1721 } |
1722 | |
15449 | 1723 if (priv->audio_insert_null_samples && (priv->audio_head == priv->audio_tail)) { |
1724 // return silence to avoid desync and stuttering | |
1725 memset(buffer, 0, len); | |
1726 priv->audio_null_blocks_inserted++; | |
1727 goto out; | |
1728 } | |
1729 | |
1730 pthread_mutex_unlock(&priv->audio_mutex); | |
10536 | 1731 while (priv->audio_head == priv->audio_tail) { |
15449 | 1732 // this is mencoder => just wait until some audio is available |
10536 | 1733 usleep(10000); |
1734 } | |
15451 | 1735 pthread_mutex_lock(&priv->audio_mutex); |
10536 | 1736 memcpy(buffer, priv->audio_ringbuffer+priv->audio_head*priv->audio_in.blocksize, len); |
1737 priv->audio_head = (priv->audio_head+1) % priv->audio_buffer_size; | |
1738 priv->audio_cnt--; | |
15449 | 1739 out: |
1740 pthread_mutex_unlock(&priv->audio_mutex); | |
10536 | 1741 priv->audio_sent_blocks_total++; |
1742 return (double)priv->audio_sent_blocks_total*priv->audio_secs_per_block; | |
1743 } | |
1744 | |
1745 static int get_audio_framesize(priv_t *priv) | |
1746 { | |
1747 return(priv->audio_in.blocksize); | |
1748 } | |
1749 | |
10538 | 1750 #endif /* USE_TV && HAVE_TV_V4L2 */ |