Mercurial > mplayer.hg
annotate stream/tvi_v4l2.c @ 33671:a460339acfdf
Fix volume and balance bug.
Changing the volume changed the balance as well,
because the calculation for the balance was wrong.
Additionally, use macro FFMAX() and replace
identical code by a call to existing code.
author | ib |
---|---|
date | Tue, 28 Jun 2011 17:52:30 +0000 |
parents | c15dabfa2380 |
children | 389d43c448b3 |
rev | line source |
---|---|
10536 | 1 /* |
28106 | 2 * Video 4 Linux 2 input |
3 * | |
4 * copyright (c) 2003 Martin Olschewski <olschewski@zpr.uni-koeln.de> | |
5 * copyright (c) 2003 Jindrich Makovicka <makovick@gmail.com> | |
6 * | |
7 * Some ideas are based on works from | |
8 * Alex Beregszaszi <alex@fsn.hu> | |
9 * Gerd Knorr <kraxel@bytesex.org> | |
10 * | |
11 * This file is part of MPlayer. | |
12 * | |
13 * MPlayer is free software; you can redistribute it and/or modify | |
14 * it under the terms of the GNU General Public License as published by | |
15 * the Free Software Foundation; either version 2 of the License, or | |
16 * (at your option) any later version. | |
17 * | |
18 * MPlayer is distributed in the hope that it will be useful, | |
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
21 * GNU General Public License for more details. | |
22 * | |
23 * You should have received a copy of the GNU General Public License along | |
24 * with MPlayer; if not, write to the Free Software Foundation, Inc., | |
25 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
26 */ | |
10536 | 27 |
28 /* | |
29 | |
30 known issues: | |
31 - norm setting isn't consistent with tvi_v4l | |
32 - the same for volume/bass/treble/balance | |
33 | |
34 */ | |
35 | |
36 #include "config.h" | |
37 | |
38 #include <errno.h> | |
39 #include <fcntl.h> | |
40 #include <pthread.h> | |
41 #include <stdio.h> | |
42 #include <string.h> | |
43 #include <sys/ioctl.h> | |
44 #include <sys/mman.h> | |
45 #include <sys/time.h> | |
46 #include <sys/types.h> | |
47 #include <unistd.h> | |
27461
5a30f5bc23a0
Rename HAVE_WINSOCK preprocessor condition to HAVE_WINSOCK_H.
diego
parents:
27390
diff
changeset
|
48 #include <math.h> |
10536 | 49 #ifdef HAVE_SYS_SYSINFO_H |
50 #include <sys/sysinfo.h> | |
51 #endif | |
33163 | 52 #ifdef HAVE_SYS_VIDEOIO_H |
53 #include <sys/videoio.h> | |
54 #else | |
16442 | 55 #include <linux/types.h> |
56 #include <linux/videodev2.h> | |
33163 | 57 #endif |
17012 | 58 #include "mp_msg.h" |
19431
ac69ba536915
Explicitly include libmpcodecs/img_format.h and libvo/fastmemcpy.h.
diego
parents:
19271
diff
changeset
|
59 #include "libmpcodecs/img_format.h" |
29759
d287e2785570
Move teletext specific code from stream into libmpcodecs.
cehoyos
parents:
29263
diff
changeset
|
60 #include "libmpcodecs/dec_teletext.h" |
17012 | 61 #include "libaf/af_format.h" |
10536 | 62 #include "tv.h" |
63 #include "audio_in.h" | |
64 | |
22381
6cabac4d35b5
tv driver loading rework. As a side effect "-tv driver=help" option is
voroshil
parents:
21587
diff
changeset
|
65 #define info tvi_info_v4l2 |
23883 | 66 static tvi_handle_t *tvi_init_v4l2(tv_param_t* tv_param); |
10536 | 67 /* information about this file */ |
25689 | 68 const tvi_info_t tvi_info_v4l2 = { |
22381
6cabac4d35b5
tv driver loading rework. As a side effect "-tv driver=help" option is
voroshil
parents:
21587
diff
changeset
|
69 tvi_init_v4l2, |
10536 | 70 "Video 4 Linux 2 input", |
71 "v4l2", | |
72 "Martin Olschewski <olschewski@zpr.uni-koeln.de>", | |
73 "first try, more to come ;-)" | |
74 }; | |
75 | |
76 struct map { | |
77 struct v4l2_buffer buf; | |
78 void *addr; | |
79 size_t len; | |
80 }; | |
81 | |
82 #define BUFFER_COUNT 6 | |
83 | |
23423 | 84 /** video ringbuffer entry */ |
85 typedef struct { | |
86 unsigned char *data; ///< frame contents | |
87 long long timestamp; ///< frame timestamp | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
88 int framesize; ///< actual frame size |
23423 | 89 } video_buffer_entry; |
90 | |
10536 | 91 /* private data */ |
31322
016194f71de3
Fix function pointer types in tvi_functions struct
reimar
parents:
29949
diff
changeset
|
92 typedef struct priv { |
10536 | 93 /* video */ |
23151 | 94 char *video_dev; |
95 int video_fd; | |
23901 | 96 char *vbi_dev; |
97 int vbi_fd; | |
98 int vbi_bufsize; | |
99 int vbi_shutdown; | |
100 pthread_t vbi_grabber_thread; | |
101 void *priv_vbi; | |
10536 | 102 int mp_format; |
23151 | 103 struct v4l2_capability capability; |
10536 | 104 struct v4l2_input input; |
23151 | 105 struct v4l2_format format; |
106 struct v4l2_standard standard; | |
107 struct v4l2_tuner tuner; | |
108 struct map *map; | |
109 int mapcount; | |
110 int frames; | |
10851 | 111 volatile long long first_frame; |
10536 | 112 long long curr_frame; |
113 /* audio video interleaving ;-) */ | |
23151 | 114 volatile int streamon; |
115 pthread_t audio_grabber_thread; | |
116 pthread_mutex_t skew_mutex; | |
10536 | 117 |
118 /* 2nd level video buffers */ | |
119 int first; | |
120 int immediate_mode; | |
121 | |
122 int video_buffer_size_max; | |
123 volatile int video_buffer_size_current; | |
23423 | 124 video_buffer_entry *video_ringbuffer; |
23151 | 125 volatile int video_head; |
126 volatile int video_tail; | |
127 volatile int video_cnt; | |
128 pthread_t video_grabber_thread; | |
10536 | 129 pthread_mutex_t video_buffer_mutex; |
130 | |
131 /* audio */ | |
23151 | 132 char *audio_dev; |
10536 | 133 audio_in_t audio_in; |
134 | |
135 long long audio_start_time; | |
136 int audio_buffer_size; | |
137 int aud_skew_cnt; | |
23151 | 138 unsigned char *audio_ringbuffer; |
139 long long *audio_skew_buffer; | |
140 long long *audio_skew_delta_buffer; | |
141 volatile int audio_head; | |
142 volatile int audio_tail; | |
143 volatile int audio_cnt; | |
10536 | 144 volatile long long audio_skew; |
145 volatile double audio_skew_factor; | |
146 volatile long long audio_skew_measure_time; | |
147 volatile int audio_drop; | |
148 volatile int shutdown; | |
149 | |
25962 | 150 int audio_initialized; |
10536 | 151 double audio_secs_per_block; |
15449 | 152 long long audio_usecs_per_block; |
10536 | 153 long long audio_skew_total; |
10653 | 154 long long audio_skew_delta_total; |
23151 | 155 long audio_recv_blocks_total; |
156 long audio_sent_blocks_total; | |
15449 | 157 pthread_mutex_t audio_mutex; |
158 int audio_insert_null_samples; | |
159 volatile long audio_null_blocks_inserted; | |
160 volatile long long dropped_frames_timeshift; | |
161 long long dropped_frames_compensated; | |
23883 | 162 |
163 tv_param_t *tv_param; | |
10536 | 164 } priv_t; |
165 | |
166 #include "tvi_def.h" | |
167 | |
168 static void *audio_grabber(void *data); | |
169 static void *video_grabber(void *data); | |
170 | |
171 /**********************************************************************\ | |
172 | |
173 Only few of the fourccs are the same in v4l2 and mplayer: | |
174 | |
175 IMGFMT_YVU9 == V4L2_PIX_FMT_YVU410 | |
176 IMGFMT_YV12 == V4L2_PIX_FMT_YVU420 | |
177 IMGFMT_NV12 == V4L2_PIX_FMT_NV12 | |
178 IMGFMT_422P == V4L2_PIX_FMT_YUV422P | |
179 IMGFMT_411P == V4L2_PIX_FMT_YUV411P | |
180 IMGFMT_UYVY == V4L2_PIX_FMT_UYVY | |
181 IMGFMT_Y41P == V4L2_PIX_FMT_Y41P | |
182 | |
183 This may be an useful translation table for some others: | |
184 | |
185 IMGFMT_RGB8 == V4L2_PIX_FMT_RGB332 | |
15449 | 186 IMGFMT_BGR15 == V4L2_PIX_FMT_RGB555 |
187 IMGFMT_BGR16 == V4L2_PIX_FMT_RGB565 | |
10536 | 188 IMGFMT_RGB24 == V4L2_PIX_FMT_RGB24 |
189 IMGFMT_RGB32 == V4L2_PIX_FMT_RGB32 | |
190 IMGFMT_BGR24 == V4L2_PIX_FMT_BGR24 | |
191 IMGFMT_BGR32 == V4L2_PIX_FMT_BGR32 | |
192 IMGFMT_Y800 == V4L2_PIX_FMT_GREY | |
193 IMGFMT_IF09 == V4L2_PIX_FMT_YUV410 | |
194 IMGFMT_I420 == V4L2_PIX_FMT_YUV420 | |
195 IMGFMT_YUY2 == V4L2_PIX_FMT_YUYV | |
196 | |
197 \**********************************************************************/ | |
198 | |
199 /* | |
200 ** Translate a mplayer fourcc to a video4linux2 pixel format. | |
201 */ | |
202 static int fcc_mp2vl(int fcc) | |
203 { | |
204 switch (fcc) { | |
23151 | 205 case IMGFMT_RGB8: return V4L2_PIX_FMT_RGB332; |
206 case IMGFMT_BGR15: return V4L2_PIX_FMT_RGB555; | |
207 case IMGFMT_BGR16: return V4L2_PIX_FMT_RGB565; | |
208 case IMGFMT_RGB24: return V4L2_PIX_FMT_RGB24; | |
209 case IMGFMT_RGB32: return V4L2_PIX_FMT_RGB32; | |
210 case IMGFMT_BGR24: return V4L2_PIX_FMT_BGR24; | |
211 case IMGFMT_BGR32: return V4L2_PIX_FMT_BGR32; | |
212 case IMGFMT_Y800: return V4L2_PIX_FMT_GREY; | |
213 case IMGFMT_IF09: return V4L2_PIX_FMT_YUV410; | |
214 case IMGFMT_I420: return V4L2_PIX_FMT_YUV420; | |
215 case IMGFMT_YUY2: return V4L2_PIX_FMT_YUYV; | |
216 case IMGFMT_YV12: return V4L2_PIX_FMT_YVU420; | |
11657 | 217 case IMGFMT_UYVY: return V4L2_PIX_FMT_UYVY; |
23423 | 218 case IMGFMT_MJPEG: return V4L2_PIX_FMT_MJPEG; |
10536 | 219 } |
220 return fcc; | |
221 } | |
222 | |
223 /* | |
224 ** Translate a video4linux2 fourcc aka pixel format to mplayer. | |
225 */ | |
226 static int fcc_vl2mp(int fcc) | |
227 { | |
228 switch (fcc) { | |
23151 | 229 case V4L2_PIX_FMT_RGB332: return IMGFMT_RGB8; |
230 case V4L2_PIX_FMT_RGB555: return IMGFMT_BGR15; | |
231 case V4L2_PIX_FMT_RGB565: return IMGFMT_BGR16; | |
232 case V4L2_PIX_FMT_RGB24: return IMGFMT_RGB24; | |
233 case V4L2_PIX_FMT_RGB32: return IMGFMT_RGB32; | |
234 case V4L2_PIX_FMT_BGR24: return IMGFMT_BGR24; | |
235 case V4L2_PIX_FMT_BGR32: return IMGFMT_BGR32; | |
236 case V4L2_PIX_FMT_GREY: return IMGFMT_Y800; | |
237 case V4L2_PIX_FMT_YUV410: return IMGFMT_IF09; | |
238 case V4L2_PIX_FMT_YUV420: return IMGFMT_I420; | |
239 case V4L2_PIX_FMT_YVU420: return IMGFMT_YV12; | |
240 case V4L2_PIX_FMT_YUYV: return IMGFMT_YUY2; | |
11657 | 241 case V4L2_PIX_FMT_UYVY: return IMGFMT_UYVY; |
23423 | 242 case V4L2_PIX_FMT_MJPEG: return IMGFMT_MJPEG; |
10536 | 243 } |
244 return fcc; | |
245 } | |
246 | |
247 /* | |
248 ** Translate a video4linux2 fourcc aka pixel format | |
249 ** to a human readable string. | |
250 */ | |
19108
5e767cabf4cd
marks several read-only string parameters and function return-values which can only be used read-only as const. Patch by Stefan Huehner, stefan _AT huener-org
reynaldo
parents:
18958
diff
changeset
|
251 static const char *pixfmt2name(int pixfmt) |
10536 | 252 { |
253 static char unknown[24]; | |
254 | |
255 switch (pixfmt) { | |
23151 | 256 case V4L2_PIX_FMT_RGB332: return "RGB332"; |
257 case V4L2_PIX_FMT_RGB555: return "RGB555"; | |
258 case V4L2_PIX_FMT_RGB565: return "RGB565"; | |
259 case V4L2_PIX_FMT_RGB555X: return "RGB555X"; | |
260 case V4L2_PIX_FMT_RGB565X: return "RGB565X"; | |
261 case V4L2_PIX_FMT_BGR24: return "BGR24"; | |
262 case V4L2_PIX_FMT_RGB24: return "RGB24"; | |
263 case V4L2_PIX_FMT_BGR32: return "BGR32"; | |
264 case V4L2_PIX_FMT_RGB32: return "RGB32"; | |
265 case V4L2_PIX_FMT_GREY: return "GREY"; | |
266 case V4L2_PIX_FMT_YVU410: return "YVU410"; | |
267 case V4L2_PIX_FMT_YVU420: return "YVU420"; | |
268 case V4L2_PIX_FMT_YUYV: return "YUYV"; | |
269 case V4L2_PIX_FMT_UYVY: return "UYVY"; | |
270 /* case V4L2_PIX_FMT_YVU422P: return "YVU422P"; */ | |
271 /* case V4L2_PIX_FMT_YVU411P: return "YVU411P"; */ | |
272 case V4L2_PIX_FMT_YUV422P: return "YUV422P"; | |
273 case V4L2_PIX_FMT_YUV411P: return "YUV411P"; | |
274 case V4L2_PIX_FMT_Y41P: return "Y41P"; | |
275 case V4L2_PIX_FMT_NV12: return "NV12"; | |
276 case V4L2_PIX_FMT_NV21: return "NV21"; | |
277 case V4L2_PIX_FMT_YUV410: return "YUV410"; | |
278 case V4L2_PIX_FMT_YUV420: return "YUV420"; | |
279 case V4L2_PIX_FMT_YYUV: return "YYUV"; | |
280 case V4L2_PIX_FMT_HI240: return "HI240"; | |
281 case V4L2_PIX_FMT_WNVA: return "WNVA"; | |
23423 | 282 case V4L2_PIX_FMT_MJPEG: return "MJPEG"; |
10536 | 283 } |
284 sprintf(unknown, "unknown (0x%x)", pixfmt); | |
285 return unknown; | |
286 } | |
287 | |
288 | |
289 /* | |
290 ** Gives the depth of a video4linux2 fourcc aka pixel format in bits. | |
291 */ | |
292 static int pixfmt2depth(int pixfmt) | |
293 { | |
294 switch (pixfmt) { | |
295 case V4L2_PIX_FMT_RGB332: | |
23151 | 296 return 8; |
10536 | 297 case V4L2_PIX_FMT_RGB555: |
298 case V4L2_PIX_FMT_RGB565: | |
299 case V4L2_PIX_FMT_RGB555X: | |
300 case V4L2_PIX_FMT_RGB565X: | |
23151 | 301 return 16; |
10536 | 302 case V4L2_PIX_FMT_BGR24: |
303 case V4L2_PIX_FMT_RGB24: | |
23151 | 304 return 24; |
10536 | 305 case V4L2_PIX_FMT_BGR32: |
306 case V4L2_PIX_FMT_RGB32: | |
23151 | 307 return 32; |
10536 | 308 case V4L2_PIX_FMT_GREY: |
23151 | 309 return 8; |
10536 | 310 case V4L2_PIX_FMT_YVU410: |
23151 | 311 return 9; |
10536 | 312 case V4L2_PIX_FMT_YVU420: |
23151 | 313 return 12; |
10536 | 314 case V4L2_PIX_FMT_YUYV: |
315 case V4L2_PIX_FMT_UYVY: | |
316 case V4L2_PIX_FMT_YUV422P: | |
317 case V4L2_PIX_FMT_YUV411P: | |
23151 | 318 return 16; |
10536 | 319 case V4L2_PIX_FMT_Y41P: |
320 case V4L2_PIX_FMT_NV12: | |
321 case V4L2_PIX_FMT_NV21: | |
23151 | 322 return 12; |
10536 | 323 case V4L2_PIX_FMT_YUV410: |
23151 | 324 return 9; |
10536 | 325 case V4L2_PIX_FMT_YUV420: |
23151 | 326 return 12; |
10536 | 327 case V4L2_PIX_FMT_YYUV: |
23151 | 328 return 16; |
10536 | 329 case V4L2_PIX_FMT_HI240: |
23151 | 330 return 8; |
10536 | 331 |
332 } | |
333 return 0; | |
334 } | |
335 | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
336 static int amode2v4l(int amode) |
10536 | 337 { |
338 switch (amode) { | |
339 case 0: | |
23151 | 340 return V4L2_TUNER_MODE_MONO; |
10536 | 341 case 1: |
23151 | 342 return V4L2_TUNER_MODE_STEREO; |
10536 | 343 case 2: |
23151 | 344 return V4L2_TUNER_MODE_LANG1; |
10536 | 345 case 3: |
23151 | 346 return V4L2_TUNER_MODE_LANG2; |
10536 | 347 default: |
23151 | 348 return -1; |
10536 | 349 } |
350 } | |
351 | |
352 | |
27138
62916b06a055
Fix division by zero in tvi_v4l2 which occures when capture device
voroshil
parents:
26756
diff
changeset
|
353 /* |
62916b06a055
Fix division by zero in tvi_v4l2 which occures when capture device
voroshil
parents:
26756
diff
changeset
|
354 ** Get current FPS. |
62916b06a055
Fix division by zero in tvi_v4l2 which occures when capture device
voroshil
parents:
26756
diff
changeset
|
355 */ |
62916b06a055
Fix division by zero in tvi_v4l2 which occures when capture device
voroshil
parents:
26756
diff
changeset
|
356 static double getfps(priv_t *priv) |
62916b06a055
Fix division by zero in tvi_v4l2 which occures when capture device
voroshil
parents:
26756
diff
changeset
|
357 { |
62916b06a055
Fix division by zero in tvi_v4l2 which occures when capture device
voroshil
parents:
26756
diff
changeset
|
358 if (priv->tv_param->fps > 0) |
62916b06a055
Fix division by zero in tvi_v4l2 which occures when capture device
voroshil
parents:
26756
diff
changeset
|
359 return priv->tv_param->fps; |
62916b06a055
Fix division by zero in tvi_v4l2 which occures when capture device
voroshil
parents:
26756
diff
changeset
|
360 if (priv->standard.frameperiod.denominator && priv->standard.frameperiod.numerator) |
62916b06a055
Fix division by zero in tvi_v4l2 which occures when capture device
voroshil
parents:
26756
diff
changeset
|
361 return (double)priv->standard.frameperiod.denominator / priv->standard.frameperiod.numerator; |
62916b06a055
Fix division by zero in tvi_v4l2 which occures when capture device
voroshil
parents:
26756
diff
changeset
|
362 return 25.0; |
62916b06a055
Fix division by zero in tvi_v4l2 which occures when capture device
voroshil
parents:
26756
diff
changeset
|
363 } |
62916b06a055
Fix division by zero in tvi_v4l2 which occures when capture device
voroshil
parents:
26756
diff
changeset
|
364 |
10536 | 365 // sets and sanitizes audio buffer/block sizes |
366 static void setup_audio_buffer_sizes(priv_t *priv) | |
367 { | |
368 int bytes_per_sample = priv->audio_in.bytes_per_sample; | |
27138
62916b06a055
Fix division by zero in tvi_v4l2 which occures when capture device
voroshil
parents:
26756
diff
changeset
|
369 int seconds = priv->video_buffer_size_max/getfps(priv); |
10536 | 370 |
371 if (seconds < 5) seconds = 5; | |
372 if (seconds > 500) seconds = 500; | |
373 | |
374 // make the audio buffer at least as the video buffer capacity (or 5 seconds) long | |
375 priv->audio_buffer_size = 1 + seconds*priv->audio_in.samplerate | |
23151 | 376 *priv->audio_in.channels |
377 *bytes_per_sample/priv->audio_in.blocksize; | |
10536 | 378 if (priv->audio_buffer_size < 256) priv->audio_buffer_size = 256; |
379 | |
380 // make the skew buffer at least 1 second long | |
381 priv->aud_skew_cnt = 1 + 1*priv->audio_in.samplerate | |
23151 | 382 *priv->audio_in.channels |
383 *bytes_per_sample/priv->audio_in.blocksize; | |
10536 | 384 if (priv->aud_skew_cnt < 16) priv->aud_skew_cnt = 16; |
385 | |
386 mp_msg(MSGT_TV, MSGL_V, "Audio capture - buffer %d blocks of %d bytes, skew average from %d meas.\n", | |
23151 | 387 priv->audio_buffer_size, priv->audio_in.blocksize, priv->aud_skew_cnt); |
10536 | 388 } |
389 | |
15464 | 390 static void init_audio(priv_t *priv) |
391 { | |
25962 | 392 if (priv->audio_initialized) return; |
15464 | 393 |
23886 | 394 if (!priv->tv_param->noaudio) { |
27390
9d95dc936e66
Introduce CONFIG_ALSA preprocessor directive for ALSA 0.9 and 1.x.
diego
parents:
27387
diff
changeset
|
395 #ifdef CONFIG_ALSA |
23886 | 396 if (priv->tv_param->alsa) |
23151 | 397 audio_in_init(&priv->audio_in, AUDIO_IN_ALSA); |
398 else | |
399 audio_in_init(&priv->audio_in, AUDIO_IN_OSS); | |
15464 | 400 #else |
23151 | 401 audio_in_init(&priv->audio_in, AUDIO_IN_OSS); |
15464 | 402 #endif |
403 | |
23151 | 404 if (priv->audio_dev) { |
405 audio_in_set_device(&priv->audio_in, priv->audio_dev); | |
406 } | |
15464 | 407 |
23151 | 408 audio_in_set_samplerate(&priv->audio_in, 44100); |
409 if (priv->capability.capabilities & V4L2_CAP_TUNER) { | |
410 if (priv->tuner.audmode == V4L2_TUNER_MODE_STEREO) { | |
411 audio_in_set_channels(&priv->audio_in, 2); | |
412 } else { | |
413 audio_in_set_channels(&priv->audio_in, 1); | |
414 } | |
415 } else { | |
23886 | 416 if (priv->tv_param->forcechan >= 0) { |
417 audio_in_set_channels(&priv->audio_in, priv->tv_param->forcechan); | |
23151 | 418 } else { |
419 audio_in_set_channels(&priv->audio_in, 2); | |
420 } | |
421 } | |
15464 | 422 |
23151 | 423 if (audio_in_setup(&priv->audio_in) < 0) return; |
15464 | 424 |
25962 | 425 priv->audio_initialized = 1; |
15464 | 426 } |
427 } | |
428 | |
10536 | 429 #if 0 |
430 /* | |
431 ** the number of milliseconds elapsed between time0 and time1 | |
432 */ | |
433 static size_t difftv(struct timeval time1, struct timeval time0) | |
434 { | |
23151 | 435 return (time1.tv_sec - time0.tv_sec) * 1000 + |
436 (time1.tv_usec - time0.tv_usec) / 1000; | |
10536 | 437 } |
438 #endif | |
439 | |
440 /* | |
441 ** Get current video capture format. | |
442 */ | |
443 static int getfmt(priv_t *priv) | |
444 { | |
445 int i; | |
446 | |
447 priv->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
448 if ((i = ioctl(priv->video_fd, VIDIOC_G_FMT, &priv->format)) < 0) { | |
23151 | 449 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get format failed: %s\n", |
450 info.short_name, strerror(errno)); | |
10536 | 451 } |
452 return i; | |
453 } | |
454 | |
455 | |
456 /* | |
457 ** Get current video capture standard. | |
458 */ | |
459 static int getstd(priv_t *priv) | |
460 { | |
461 v4l2_std_id id; | |
462 int i=0; | |
463 | |
464 if (ioctl(priv->video_fd, VIDIOC_G_STD, &id) < 0) { | |
27139
0917bf2bed6c
Try to get frame rate information through VIDIOC_G_PARM if
voroshil
parents:
27138
diff
changeset
|
465 struct v4l2_streamparm parm; |
0917bf2bed6c
Try to get frame rate information through VIDIOC_G_PARM if
voroshil
parents:
27138
diff
changeset
|
466 |
0917bf2bed6c
Try to get frame rate information through VIDIOC_G_PARM if
voroshil
parents:
27138
diff
changeset
|
467 parm.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; |
0917bf2bed6c
Try to get frame rate information through VIDIOC_G_PARM if
voroshil
parents:
27138
diff
changeset
|
468 if(ioctl(priv->video_fd, VIDIOC_G_PARM, &parm) >= 0) { |
0917bf2bed6c
Try to get frame rate information through VIDIOC_G_PARM if
voroshil
parents:
27138
diff
changeset
|
469 mp_msg(MSGT_TV, MSGL_WARN, "%s: your device driver does not support VIDIOC_G_STD ioctl," |
0917bf2bed6c
Try to get frame rate information through VIDIOC_G_PARM if
voroshil
parents:
27138
diff
changeset
|
470 " VIDIOC_G_PARM was used instead.\n", info.short_name); |
0917bf2bed6c
Try to get frame rate information through VIDIOC_G_PARM if
voroshil
parents:
27138
diff
changeset
|
471 priv->standard.index=0; |
0917bf2bed6c
Try to get frame rate information through VIDIOC_G_PARM if
voroshil
parents:
27138
diff
changeset
|
472 priv->standard.id=0; |
0917bf2bed6c
Try to get frame rate information through VIDIOC_G_PARM if
voroshil
parents:
27138
diff
changeset
|
473 priv->standard.frameperiod=parm.parm.capture.timeperframe; |
0917bf2bed6c
Try to get frame rate information through VIDIOC_G_PARM if
voroshil
parents:
27138
diff
changeset
|
474 return 0; |
0917bf2bed6c
Try to get frame rate information through VIDIOC_G_PARM if
voroshil
parents:
27138
diff
changeset
|
475 } |
0917bf2bed6c
Try to get frame rate information through VIDIOC_G_PARM if
voroshil
parents:
27138
diff
changeset
|
476 |
23151 | 477 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get standard failed: %s\n", |
478 info.short_name, strerror(errno)); | |
479 return -1; | |
10536 | 480 } |
481 do { | |
23151 | 482 priv->standard.index = i++; |
483 if (ioctl(priv->video_fd, VIDIOC_ENUMSTD, &priv->standard) < 0) { | |
484 return -1; | |
485 } | |
10536 | 486 } while (priv->standard.id != id); |
487 return 0; | |
488 } | |
489 | |
490 /***********************************************************************\ | |
23151 | 491 * * |
492 * * | |
493 * Interface to mplayer * | |
494 * * | |
495 * * | |
10536 | 496 \***********************************************************************/ |
497 | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
498 static int set_mute(priv_t *priv, int value) |
10536 | 499 { |
500 struct v4l2_control control; | |
501 control.id = V4L2_CID_AUDIO_MUTE; | |
502 control.value = value; | |
503 if (ioctl(priv->video_fd, VIDIOC_S_CTRL, &control) < 0) { | |
23151 | 504 mp_msg(MSGT_TV,MSGL_ERR,"%s: ioctl set mute failed: %s\n", |
505 info.short_name, strerror(errno)); | |
506 return 0; | |
10536 | 507 } |
508 return 1; | |
509 } | |
510 | |
511 /* | |
12860 | 512 ** MPlayer uses values from -100 up to 100 for controls. |
10536 | 513 ** Here they are scaled to what the tv card needs and applied. |
514 */ | |
515 static int set_control(priv_t *priv, struct v4l2_control *control, int val_signed) { | |
23151 | 516 struct v4l2_queryctrl qctrl; |
10536 | 517 qctrl.id = control->id; |
518 if (ioctl(priv->video_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) { | |
23151 | 519 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query control failed: %s\n", |
520 info.short_name, strerror(errno)); | |
521 return TVI_CONTROL_FALSE; | |
10536 | 522 } |
523 | |
524 if (val_signed) { | |
23151 | 525 if (control->value < 0) { |
526 control->value = qctrl.default_value + control->value * | |
527 (qctrl.default_value - qctrl.minimum) / 100; | |
528 } else { | |
529 control->value = qctrl.default_value + control->value * | |
530 (qctrl.maximum - qctrl.default_value) / 100; | |
531 } | |
10536 | 532 } else { |
23151 | 533 if (control->value < 50) { |
534 control->value = qctrl.default_value + (control->value-50) * | |
535 (qctrl.default_value - qctrl.minimum) / 50; | |
536 } else { | |
537 control->value = qctrl.default_value + (control->value-50) * | |
538 (qctrl.maximum - qctrl.default_value) / 50; | |
539 } | |
10536 | 540 } |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
541 |
10536 | 542 |
543 if (ioctl(priv->video_fd, VIDIOC_S_CTRL, control) < 0) { | |
23151 | 544 mp_msg(MSGT_TV, MSGL_ERR,"%s: ioctl set %s %d failed: %s\n", |
545 info.short_name, qctrl.name, control->value, strerror(errno)); | |
546 return TVI_CONTROL_FALSE; | |
10536 | 547 } |
548 mp_msg(MSGT_TV, MSGL_V, "%s: set %s: %d [%d, %d]\n", info.short_name, | |
549 qctrl.name, control->value, qctrl.minimum, qctrl.maximum); | |
550 | |
551 return TVI_CONTROL_TRUE; | |
552 } | |
553 | |
554 | |
555 /* | |
556 ** Scale the control values back to what mplayer needs. | |
557 */ | |
558 static int get_control(priv_t *priv, struct v4l2_control *control, int val_signed) { | |
23151 | 559 struct v4l2_queryctrl qctrl; |
10536 | 560 |
561 qctrl.id = control->id; | |
562 if (ioctl(priv->video_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) { | |
23151 | 563 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query control failed: %s\n", |
564 info.short_name, strerror(errno)); | |
565 return TVI_CONTROL_FALSE; | |
10536 | 566 } |
567 | |
568 if (ioctl(priv->video_fd, VIDIOC_G_CTRL, control) < 0) { | |
23151 | 569 mp_msg(MSGT_TV, MSGL_ERR,"%s: ioctl get %s failed: %s\n", |
570 info.short_name, qctrl.name, strerror(errno)); | |
571 return TVI_CONTROL_FALSE; | |
10536 | 572 } |
573 mp_msg(MSGT_TV, MSGL_V, "%s: get %s: %d [%d, %d]\n", info.short_name, | |
574 qctrl.name, control->value, qctrl.minimum, qctrl.maximum); | |
575 | |
576 if (val_signed) { | |
23151 | 577 if (control->value < qctrl.default_value) { |
578 control->value = (control->value - qctrl.default_value) * 100 / | |
579 (qctrl.default_value - qctrl.minimum); | |
580 } else { | |
581 control->value = (control->value - qctrl.default_value) * 100 / | |
582 (qctrl.maximum - qctrl.default_value); | |
583 } | |
10536 | 584 } else { |
23151 | 585 if (control->value < qctrl.default_value) { |
586 control->value = (control->value - qctrl.default_value) * 50 / | |
587 (qctrl.default_value - qctrl.minimum) + 50; | |
588 } else { | |
589 control->value = (control->value - qctrl.default_value) * 50 / | |
590 (qctrl.maximum - qctrl.default_value) + 50; | |
591 } | |
10536 | 592 } |
593 | |
594 return TVI_CONTROL_TRUE; | |
595 } | |
596 | |
23901 | 597 static int vbi_init(priv_t* priv,char* device) |
598 { | |
599 int vbi_fd=0; | |
600 struct v4l2_capability cap; | |
601 struct v4l2_format fmt; | |
602 int res; | |
603 | |
604 if(!device) | |
605 return TVI_CONTROL_FALSE; | |
606 | |
607 priv->vbi_dev=strdup(device); | |
608 | |
609 vbi_fd=open(priv->vbi_dev,O_RDWR); | |
610 if(vbi_fd<0){ | |
611 mp_msg(MSGT_TV,MSGL_ERR,"vbi: could not open device %s\n",priv->vbi_dev); | |
612 return TVI_CONTROL_FALSE; | |
613 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
614 |
23901 | 615 if(ioctl(vbi_fd,VIDIOC_QUERYCAP,&cap)<0){ |
31834
64ba1daa147a
various spelling fixes, found by the Debian QA tool 'lintian'
siretart
parents:
31322
diff
changeset
|
616 mp_msg(MSGT_TV,MSGL_ERR,"vbi: Query capabilities failed for %s\n",priv->vbi_dev); |
23901 | 617 close(vbi_fd); |
618 return TVI_CONTROL_FALSE; | |
619 } | |
29949 | 620 if(!(cap.capabilities & V4L2_CAP_VBI_CAPTURE)){ |
23901 | 621 mp_msg(MSGT_TV,MSGL_ERR,"vbi: %s does not support VBI capture\n",priv->vbi_dev); |
622 close(vbi_fd); | |
623 return TVI_CONTROL_FALSE; | |
624 } | |
625 | |
626 memset(&fmt,0,sizeof(struct v4l2_format)); | |
627 fmt.type=V4L2_BUF_TYPE_VBI_CAPTURE; | |
628 if((res=ioctl(vbi_fd,VIDIOC_G_FMT,&fmt))<0){ | |
629 mp_msg(MSGT_TV,MSGL_ERR,"vbi: Query format failed: %x\n",res); | |
630 close(vbi_fd); | |
631 return TVI_CONTROL_FALSE; | |
632 } | |
633 if(fmt.fmt.vbi.sample_format!=V4L2_PIX_FMT_GREY){ | |
634 mp_msg(MSGT_TV,MSGL_ERR,"vbi: format 0x%x is not supported\n",fmt.fmt.vbi.sample_format); | |
635 close(vbi_fd); | |
636 return TVI_CONTROL_FALSE; | |
637 } | |
638 priv->vbi_fd=vbi_fd; | |
639 mp_msg(MSGT_TV,MSGL_DBG3,"vbi: init ok\n"); | |
640 return TVI_CONTROL_TRUE; | |
641 } | |
642 | |
643 static int vbi_get_props(priv_t* priv,tt_stream_props* ptsp) | |
644 { | |
645 struct v4l2_format fmt; | |
646 int res; | |
647 if(!priv || !ptsp) | |
648 return TVI_CONTROL_FALSE; | |
649 | |
650 memset(&fmt,0,sizeof(struct v4l2_format)); | |
651 fmt.type=V4L2_BUF_TYPE_VBI_CAPTURE; | |
652 if((res=ioctl(priv->vbi_fd,VIDIOC_G_FMT,&fmt))<0){ | |
653 mp_msg(MSGT_TV,MSGL_ERR,"vbi_get_props: Query format failed: %x\n",res); | |
654 return TVI_CONTROL_FALSE; | |
655 } | |
656 | |
657 ptsp->interlaced=(fmt.fmt.vbi.flags& V4L2_VBI_INTERLACED?1:0); | |
658 | |
659 ptsp->offset=fmt.fmt.vbi.offset; | |
660 ptsp->sampling_rate=fmt.fmt.vbi.sampling_rate; | |
661 ptsp->samples_per_line=fmt.fmt.vbi.samples_per_line, | |
662 | |
663 ptsp->count[0]=fmt.fmt.vbi.count[0]; | |
664 ptsp->count[1]=fmt.fmt.vbi.count[1]; | |
665 ptsp->bufsize = ptsp->samples_per_line * (ptsp->count[0] + ptsp->count[1]); | |
666 | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
667 mp_msg(MSGT_TV,MSGL_V,"vbi_get_props: sampling_rate=%d,offset:%d,samples_per_line: %d\n interlaced:%s, count=[%d,%d]\n", |
23901 | 668 ptsp->sampling_rate, |
669 ptsp->offset, | |
670 ptsp->samples_per_line, | |
671 ptsp->interlaced?"Yes":"No", | |
672 ptsp->count[0], | |
673 ptsp->count[1]); | |
674 | |
675 return TVI_CONTROL_TRUE; | |
676 } | |
677 | |
678 static void *vbi_grabber(void *data) | |
679 { | |
680 priv_t *priv = (priv_t *) data; | |
681 int bytes,seq,prev_seq; | |
682 unsigned char* buf; | |
683 tt_stream_props tsp; | |
684 | |
685 if(!priv->priv_vbi){ | |
686 mp_msg(MSGT_TV,MSGL_WARN,"vbi: vbi not initialized. stopping thread.\n"); | |
687 return NULL; | |
688 } | |
689 | |
690 if(vbi_get_props(priv,&tsp)!=TVI_CONTROL_TRUE) | |
691 return NULL; | |
692 | |
693 buf=malloc(tsp.bufsize); | |
694 seq=0; | |
695 prev_seq=0; | |
696 mp_msg(MSGT_TV,MSGL_V,"vbi: vbi capture thread started.\n"); | |
697 | |
698 while (!priv->vbi_shutdown){ | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
699 bytes=read(priv->vbi_fd,buf,tsp.bufsize); |
24763
5d7f6e5e0847
After receiving EINTR 'read' syscall should be restarted.
voroshil
parents:
24553
diff
changeset
|
700 if(bytes<0 && errno==EINTR) |
5d7f6e5e0847
After receiving EINTR 'read' syscall should be restarted.
voroshil
parents:
24553
diff
changeset
|
701 continue; |
23901 | 702 if (bytes!=tsp.bufsize){ |
23979 | 703 mp_msg(MSGT_TV,MSGL_WARN,"vbi: expecting bytes: %d, got: %d\n",tsp.bufsize,bytes); |
23901 | 704 break; |
705 } | |
706 seq=*(int*)(buf+bytes-4); | |
707 if(seq<=1) continue; | |
708 if (prev_seq && seq!=prev_seq+1){ | |
709 prev_seq=0; | |
710 seq=0; | |
711 } | |
712 prev_seq=seq; | |
713 teletext_control(priv->priv_vbi,TV_VBI_CONTROL_DECODE_PAGE,&buf); | |
714 mp_msg(MSGT_TV,MSGL_DBG3,"grabber: seq:%d\n",seq); | |
715 } | |
716 free(buf); | |
717 return NULL; | |
718 } | |
719 | |
10536 | 720 static int control(priv_t *priv, int cmd, void *arg) |
721 { | |
722 struct v4l2_control control; | |
723 struct v4l2_frequency frequency; | |
724 | |
725 switch(cmd) { | |
726 case TVI_CONTROL_IS_VIDEO: | |
23151 | 727 return priv->capability.capabilities & V4L2_CAP_VIDEO_CAPTURE? |
728 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
|
729 case TVI_CONTROL_IS_AUDIO: |
23886 | 730 if (priv->tv_param->force_audio) return TVI_CONTROL_TRUE; |
10536 | 731 case TVI_CONTROL_IS_TUNER: |
23151 | 732 return priv->capability.capabilities & V4L2_CAP_TUNER? |
733 TVI_CONTROL_TRUE: TVI_CONTROL_FALSE; | |
10536 | 734 case TVI_CONTROL_IMMEDIATE: |
23151 | 735 priv->immediate_mode = 1; |
736 return TVI_CONTROL_TRUE; | |
10536 | 737 case TVI_CONTROL_VID_GET_FPS: |
32668
cb671a73f3a3
Use getfps helper function everywhere, simplifies code and avoids a possible division by 0.
reimar
parents:
32511
diff
changeset
|
738 *(float *)arg = getfps(priv); |
23151 | 739 mp_msg(MSGT_TV, MSGL_V, "%s: get fps: %f\n", info.short_name, |
740 *(float *)arg); | |
741 return TVI_CONTROL_TRUE; | |
10536 | 742 case TVI_CONTROL_VID_GET_BITS: |
23151 | 743 if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; |
744 *(int *)arg = pixfmt2depth(priv->format.fmt.pix.pixelformat); | |
745 mp_msg(MSGT_TV, MSGL_V, "%s: get depth: %d\n", info.short_name, | |
746 *(int *)arg); | |
747 return TVI_CONTROL_TRUE; | |
10536 | 748 case TVI_CONTROL_VID_GET_FORMAT: |
23151 | 749 if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; |
750 *(int *)arg = fcc_vl2mp(priv->format.fmt.pix.pixelformat); | |
751 mp_msg(MSGT_TV, MSGL_V, "%s: get format: %s\n", info.short_name, | |
752 pixfmt2name(priv->format.fmt.pix.pixelformat)); | |
753 return TVI_CONTROL_TRUE; | |
10536 | 754 case TVI_CONTROL_VID_SET_FORMAT: |
23151 | 755 if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; |
756 priv->format.fmt.pix.pixelformat = fcc_mp2vl(*(int *)arg); | |
757 priv->format.fmt.pix.field = V4L2_FIELD_ANY; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
758 |
23151 | 759 priv->mp_format = *(int *)arg; |
760 mp_msg(MSGT_TV, MSGL_V, "%s: set format: %s\n", info.short_name, | |
761 pixfmt2name(priv->format.fmt.pix.pixelformat)); | |
762 if (ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) { | |
763 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set format failed: %s\n", | |
764 info.short_name, strerror(errno)); | |
765 return TVI_CONTROL_FALSE; | |
766 } | |
767 /* according to the v4l2 specs VIDIOC_S_FMT should not fail, inflexible drivers | |
768 might even always return the default parameters -> update the format here*/ | |
769 priv->mp_format = fcc_vl2mp(priv->format.fmt.pix.pixelformat); | |
770 return TVI_CONTROL_TRUE; | |
10536 | 771 case TVI_CONTROL_VID_GET_WIDTH: |
23151 | 772 if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; |
773 *(int *)arg = priv->format.fmt.pix.width; | |
774 mp_msg(MSGT_TV, MSGL_V, "%s: get width: %d\n", info.short_name, | |
775 *(int *)arg); | |
776 return TVI_CONTROL_TRUE; | |
10536 | 777 case TVI_CONTROL_VID_CHK_WIDTH: |
23151 | 778 return TVI_CONTROL_TRUE; |
28940
7406e7f30d4e
Add TVI_CONTROL_VID_SET_WIDTH_HEIGHT to set width and height together for v4l2,
reimar
parents:
28927
diff
changeset
|
779 case TVI_CONTROL_VID_SET_WIDTH_HEIGHT: |
7406e7f30d4e
Add TVI_CONTROL_VID_SET_WIDTH_HEIGHT to set width and height together for v4l2,
reimar
parents:
28927
diff
changeset
|
780 if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; |
7406e7f30d4e
Add TVI_CONTROL_VID_SET_WIDTH_HEIGHT to set width and height together for v4l2,
reimar
parents:
28927
diff
changeset
|
781 priv->format.fmt.pix.width = ((int *)arg)[0]; |
7406e7f30d4e
Add TVI_CONTROL_VID_SET_WIDTH_HEIGHT to set width and height together for v4l2,
reimar
parents:
28927
diff
changeset
|
782 priv->format.fmt.pix.height = ((int *)arg)[1]; |
7406e7f30d4e
Add TVI_CONTROL_VID_SET_WIDTH_HEIGHT to set width and height together for v4l2,
reimar
parents:
28927
diff
changeset
|
783 priv->format.fmt.pix.field = V4L2_FIELD_ANY; |
7406e7f30d4e
Add TVI_CONTROL_VID_SET_WIDTH_HEIGHT to set width and height together for v4l2,
reimar
parents:
28927
diff
changeset
|
784 if (ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) |
7406e7f30d4e
Add TVI_CONTROL_VID_SET_WIDTH_HEIGHT to set width and height together for v4l2,
reimar
parents:
28927
diff
changeset
|
785 return TVI_CONTROL_FALSE; |
7406e7f30d4e
Add TVI_CONTROL_VID_SET_WIDTH_HEIGHT to set width and height together for v4l2,
reimar
parents:
28927
diff
changeset
|
786 return TVI_CONTROL_TRUE; |
10536 | 787 case TVI_CONTROL_VID_SET_WIDTH: |
23151 | 788 if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; |
789 priv->format.fmt.pix.width = *(int *)arg; | |
790 mp_msg(MSGT_TV, MSGL_V, "%s: set width: %d\n", info.short_name, | |
791 *(int *)arg); | |
792 if (ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) { | |
793 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set width failed: %s\n", | |
794 info.short_name, strerror(errno)); | |
795 return TVI_CONTROL_FALSE; | |
796 } | |
797 return TVI_CONTROL_TRUE; | |
10536 | 798 case TVI_CONTROL_VID_GET_HEIGHT: |
23151 | 799 if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; |
800 *(int *)arg = priv->format.fmt.pix.height; | |
801 mp_msg(MSGT_TV, MSGL_V, "%s: get height: %d\n", info.short_name, | |
802 *(int *)arg); | |
803 return TVI_CONTROL_TRUE; | |
10536 | 804 case TVI_CONTROL_VID_CHK_HEIGHT: |
23151 | 805 return TVI_CONTROL_TRUE; |
10536 | 806 case TVI_CONTROL_VID_SET_HEIGHT: |
23151 | 807 if (getfmt(priv) < 0) return TVI_CONTROL_FALSE; |
808 priv->format.fmt.pix.height = *(int *)arg; | |
809 priv->format.fmt.pix.field = V4L2_FIELD_ANY; | |
810 mp_msg(MSGT_TV, MSGL_V, "%s: set height: %d\n", info.short_name, | |
811 *(int *)arg); | |
812 if (ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) { | |
813 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set height failed: %s\n", | |
814 info.short_name, strerror(errno)); | |
815 return TVI_CONTROL_FALSE; | |
816 } | |
817 return TVI_CONTROL_TRUE; | |
818 case TVI_CONTROL_VID_GET_BRIGHTNESS: | |
819 control.id = V4L2_CID_BRIGHTNESS; | |
820 if (get_control(priv, &control, 1) == TVI_CONTROL_TRUE) { | |
821 *(int *)arg = control.value; | |
822 return TVI_CONTROL_TRUE; | |
823 } | |
824 return TVI_CONTROL_FALSE; | |
825 case TVI_CONTROL_VID_SET_BRIGHTNESS: | |
826 control.id = V4L2_CID_BRIGHTNESS; | |
827 control.value = *(int *)arg; | |
828 return set_control(priv, &control, 1); | |
829 case TVI_CONTROL_VID_GET_HUE: | |
830 control.id = V4L2_CID_HUE; | |
831 if (get_control(priv, &control, 1) == TVI_CONTROL_TRUE) { | |
832 *(int *)arg = control.value; | |
833 return TVI_CONTROL_TRUE; | |
834 } | |
835 return TVI_CONTROL_FALSE; | |
836 case TVI_CONTROL_VID_SET_HUE: | |
837 control.id = V4L2_CID_HUE; | |
838 control.value = *(int *)arg; | |
839 return set_control(priv, &control, 1); | |
840 case TVI_CONTROL_VID_GET_SATURATION: | |
841 control.id = V4L2_CID_SATURATION; | |
842 if (get_control(priv, &control, 1) == TVI_CONTROL_TRUE) { | |
843 *(int *)arg = control.value; | |
844 return TVI_CONTROL_TRUE; | |
845 } | |
846 return TVI_CONTROL_FALSE; | |
847 case TVI_CONTROL_VID_SET_SATURATION: | |
848 control.id = V4L2_CID_SATURATION; | |
849 control.value = *(int *)arg; | |
850 return set_control(priv, &control, 1); | |
24553
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
851 case TVI_CONTROL_VID_GET_GAIN: |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
852 { |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
853 |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
854 control.id = V4L2_CID_AUTOGAIN; |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
855 if(get_control(priv,&control,0)!=TVI_CONTROL_TRUE) |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
856 return TVI_CONTROL_FALSE; |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
857 |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
858 if(control.value){ //Auto Gain control is enabled |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
859 *(int*)arg=0; |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
860 return TVI_CONTROL_TRUE; |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
861 } |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
862 |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
863 //Manual Gain control |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
864 control.id = V4L2_CID_GAIN; |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
865 if(get_control(priv,&control,0)!=TVI_CONTROL_TRUE) |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
866 return TVI_CONTROL_FALSE; |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
867 |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
868 *(int*)arg=control.value?control.value:1; |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
869 |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
870 return TVI_CONTROL_TRUE; |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
871 } |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
872 case TVI_CONTROL_VID_SET_GAIN: |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
873 { |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
874 //value==0 means automatic gain control |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
875 int value=*(int*)arg; |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
876 |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
877 if (value < 0 || value>100) |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
878 return TVI_CONTROL_FALSE; |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
879 |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
880 control.id=value?V4L2_CID_GAIN:V4L2_CID_AUTOGAIN; |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
881 control.value=value?value:1; |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
882 |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
883 return set_control(priv,&control,0); |
d6bba2781d01
Implement setting gain control for video devices (usually webcams)
voroshil
parents:
24346
diff
changeset
|
884 } |
23151 | 885 case TVI_CONTROL_VID_GET_CONTRAST: |
886 control.id = V4L2_CID_CONTRAST; | |
887 if (get_control(priv, &control, 1) == TVI_CONTROL_TRUE) { | |
888 *(int *)arg = control.value; | |
889 return TVI_CONTROL_TRUE; | |
890 } | |
891 return TVI_CONTROL_FALSE; | |
892 case TVI_CONTROL_VID_SET_CONTRAST: | |
893 control.id = V4L2_CID_CONTRAST; | |
894 control.value = *(int *)arg; | |
895 return set_control(priv, &control, 1); | |
10536 | 896 case TVI_CONTROL_TUN_GET_FREQ: |
23151 | 897 frequency.tuner = 0; |
898 frequency.type = V4L2_TUNER_ANALOG_TV; | |
899 if (ioctl(priv->video_fd, VIDIOC_G_FREQUENCY, &frequency) < 0) { | |
900 mp_msg(MSGT_TV,MSGL_ERR,"%s: ioctl get frequency failed: %s\n", | |
901 info.short_name, strerror(errno)); | |
902 return TVI_CONTROL_FALSE; | |
903 } | |
904 *(int *)arg = frequency.frequency; | |
905 return TVI_CONTROL_TRUE; | |
10536 | 906 case TVI_CONTROL_TUN_SET_FREQ: |
907 #if 0 | |
23151 | 908 set_mute(priv, 1); |
909 usleep(100000); // wait to suppress noise during switching | |
10536 | 910 #endif |
23151 | 911 frequency.tuner = 0; |
912 frequency.type = V4L2_TUNER_ANALOG_TV; | |
913 frequency.frequency = *(int *)arg; | |
914 if (ioctl(priv->video_fd, VIDIOC_S_FREQUENCY, &frequency) < 0) { | |
915 mp_msg(MSGT_TV,MSGL_ERR,"%s: ioctl set frequency failed: %s\n", | |
916 info.short_name, strerror(errno)); | |
917 return TVI_CONTROL_FALSE; | |
918 } | |
10536 | 919 #if 0 |
23151 | 920 usleep(100000); // wait to suppress noise during switching |
921 set_mute(priv, 0); | |
10536 | 922 #endif |
23151 | 923 return TVI_CONTROL_TRUE; |
10536 | 924 case TVI_CONTROL_TUN_GET_TUNER: |
23151 | 925 mp_msg(MSGT_TV, MSGL_V, "%s: get tuner\n",info.short_name); |
926 if (ioctl(priv->video_fd, VIDIOC_G_TUNER, &priv->tuner) < 0) { | |
927 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get tuner failed: %s\n", | |
928 info.short_name, strerror(errno)); | |
929 return TVI_CONTROL_FALSE; | |
930 } | |
931 return TVI_CONTROL_TRUE; | |
10536 | 932 case TVI_CONTROL_TUN_SET_TUNER: |
23151 | 933 mp_msg(MSGT_TV, MSGL_V, "%s: set tuner\n",info.short_name); |
934 if (ioctl(priv->video_fd, VIDIOC_S_TUNER, &priv->tuner) < 0) { | |
935 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set tuner failed: %s\n", | |
936 info.short_name, strerror(errno)); | |
937 return TVI_CONTROL_FALSE; | |
938 } | |
939 return TVI_CONTROL_TRUE; | |
10536 | 940 case TVI_CONTROL_TUN_GET_NORM: |
23151 | 941 *(int *)arg = priv->standard.index; |
942 return TVI_CONTROL_TRUE; | |
24105
9e71e0345c35
Automatic TV channels scanning ability for MPlayer.
voroshil
parents:
23979
diff
changeset
|
943 case TVI_CONTROL_TUN_GET_SIGNAL: |
9e71e0345c35
Automatic TV channels scanning ability for MPlayer.
voroshil
parents:
23979
diff
changeset
|
944 if (ioctl(priv->video_fd, VIDIOC_G_TUNER, &priv->tuner) < 0) { |
9e71e0345c35
Automatic TV channels scanning ability for MPlayer.
voroshil
parents:
23979
diff
changeset
|
945 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get tuner failed: %s\n", |
9e71e0345c35
Automatic TV channels scanning ability for MPlayer.
voroshil
parents:
23979
diff
changeset
|
946 info.short_name, strerror(errno)); |
9e71e0345c35
Automatic TV channels scanning ability for MPlayer.
voroshil
parents:
23979
diff
changeset
|
947 return TVI_CONTROL_FALSE; |
9e71e0345c35
Automatic TV channels scanning ability for MPlayer.
voroshil
parents:
23979
diff
changeset
|
948 } |
9e71e0345c35
Automatic TV channels scanning ability for MPlayer.
voroshil
parents:
23979
diff
changeset
|
949 *(int*)arg=100*(priv->tuner.signal>>8)/255; |
9e71e0345c35
Automatic TV channels scanning ability for MPlayer.
voroshil
parents:
23979
diff
changeset
|
950 return TVI_CONTROL_TRUE; |
10536 | 951 case TVI_CONTROL_TUN_SET_NORM: |
23151 | 952 priv->standard.index = *(int *)arg; |
953 if (ioctl(priv->video_fd, VIDIOC_ENUMSTD, &priv->standard) < 0) { | |
954 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl enum norm failed: %s\n", | |
955 info.short_name, strerror(errno)); | |
956 return TVI_CONTROL_FALSE; | |
957 } | |
958 mp_msg(MSGT_TV, MSGL_V, "%s: set norm: %s\n", info.short_name, priv->standard.name); | |
959 if (ioctl(priv->video_fd, VIDIOC_S_STD, &priv->standard.id) < 0) { | |
960 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set norm failed: %s\n", | |
961 info.short_name, strerror(errno)); | |
962 return TVI_CONTROL_FALSE; | |
963 } | |
964 return TVI_CONTROL_TRUE; | |
13978 | 965 case TVI_CONTROL_SPC_GET_NORMID: |
23151 | 966 { |
967 int i; | |
968 for (i = 0;; i++) { | |
969 struct v4l2_standard standard; | |
970 memset(&standard, 0, sizeof(standard)); | |
971 standard.index = i; | |
972 if (-1 == ioctl(priv->video_fd, VIDIOC_ENUMSTD, &standard)) | |
973 return TVI_CONTROL_FALSE; | |
974 if (!strcasecmp(standard.name, (char *)arg)) { | |
975 *(int *)arg = i; | |
976 return TVI_CONTROL_TRUE; | |
977 } | |
978 } | |
979 return TVI_CONTROL_FALSE; | |
980 } | |
10536 | 981 case TVI_CONTROL_SPC_GET_INPUT: |
23151 | 982 if (ioctl(priv->video_fd, VIDIOC_G_INPUT, (int *)arg) < 0) { |
983 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get input failed: %s\n", | |
984 info.short_name, strerror(errno)); | |
985 return TVI_CONTROL_FALSE; | |
986 } | |
987 return TVI_CONTROL_TRUE; | |
10536 | 988 case TVI_CONTROL_SPC_SET_INPUT: |
23151 | 989 mp_msg(MSGT_TV, MSGL_V, "%s: set input: %d\n", info.short_name, *(int *)arg); |
990 priv->input.index = *(int *)arg; | |
991 if (ioctl(priv->video_fd, VIDIOC_ENUMINPUT, &priv->input) < 0) { | |
992 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl enum input failed: %s\n", | |
993 info.short_name, strerror(errno)); | |
994 return TVI_CONTROL_FALSE; | |
995 } | |
996 if (ioctl(priv->video_fd, VIDIOC_S_INPUT, (int *)arg) < 0) { | |
997 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set input failed: %s\n", | |
998 info.short_name, strerror(errno)); | |
999 return TVI_CONTROL_FALSE; | |
1000 } | |
1001 return TVI_CONTROL_TRUE; | |
10536 | 1002 case TVI_CONTROL_AUD_GET_FORMAT: |
23151 | 1003 init_audio(priv); |
25962 | 1004 if (!priv->audio_initialized) return TVI_CONTROL_FALSE; |
23151 | 1005 *(int *)arg = AF_FORMAT_S16_LE; |
1006 mp_msg(MSGT_TV, MSGL_V, "%s: get audio format: %d\n", | |
1007 info.short_name, *(int *)arg); | |
1008 return TVI_CONTROL_TRUE; | |
10536 | 1009 case TVI_CONTROL_AUD_GET_SAMPLERATE: |
23151 | 1010 init_audio(priv); |
25962 | 1011 if (!priv->audio_initialized) return TVI_CONTROL_FALSE; |
23151 | 1012 *(int *)arg = priv->audio_in.samplerate; |
1013 mp_msg(MSGT_TV, MSGL_V, "%s: get audio samplerate: %d\n", | |
1014 info.short_name, *(int *)arg); | |
1015 return TVI_CONTROL_TRUE; | |
10536 | 1016 case TVI_CONTROL_AUD_GET_SAMPLESIZE: |
23151 | 1017 init_audio(priv); |
25962 | 1018 if (!priv->audio_initialized) return TVI_CONTROL_FALSE; |
23151 | 1019 *(int *)arg = priv->audio_in.bytes_per_sample; |
1020 mp_msg(MSGT_TV, MSGL_V, "%s: get audio samplesize: %d\n", | |
1021 info.short_name, *(int *)arg); | |
1022 return TVI_CONTROL_TRUE; | |
10536 | 1023 case TVI_CONTROL_AUD_GET_CHANNELS: |
23151 | 1024 init_audio(priv); |
25962 | 1025 if (!priv->audio_initialized) return TVI_CONTROL_FALSE; |
23151 | 1026 *(int *)arg = priv->audio_in.channels; |
1027 mp_msg(MSGT_TV, MSGL_V, "%s: get audio channels: %d\n", | |
1028 info.short_name, *(int *)arg); | |
1029 return TVI_CONTROL_TRUE; | |
10536 | 1030 case TVI_CONTROL_AUD_SET_SAMPLERATE: |
23151 | 1031 init_audio(priv); |
1032 mp_msg(MSGT_TV, MSGL_V, "%s: set audio samplerate: %d\n", | |
1033 info.short_name, *(int *)arg); | |
1034 if (audio_in_set_samplerate(&priv->audio_in, *(int*)arg) < 0) return TVI_CONTROL_FALSE; | |
1035 // setup_audio_buffer_sizes(priv); | |
1036 return TVI_CONTROL_TRUE; | |
23901 | 1037 case TVI_CONTROL_VBI_INIT: |
1038 { | |
1039 void* ptr; | |
1040 tt_stream_props tsp; | |
1041 | |
1042 if (vbi_init(priv,*(char**)arg)!=TVI_CONTROL_TRUE) | |
1043 return TVI_CONTROL_FALSE; | |
1044 if(vbi_get_props(priv,&tsp)==TVI_CONTROL_TRUE) | |
1045 { | |
1046 ptr=&tsp; | |
29760
1cc8a20520e8
Add MSGT_TELETEXT, rename TVI_CONTROL as VBI_CONTROL and fix some paths
cehoyos
parents:
29759
diff
changeset
|
1047 if(teletext_control(NULL,TV_VBI_CONTROL_START,&ptr)==VBI_CONTROL_TRUE) |
23901 | 1048 priv->priv_vbi=ptr; |
1049 else | |
1050 priv->priv_vbi=NULL; | |
1051 } | |
1052 return TVI_CONTROL_TRUE; | |
1053 } | |
29806 | 1054 case TVI_CONTROL_GET_VBI_PTR: |
1055 *(void **)arg=priv->priv_vbi; | |
1056 return TVI_CONTROL_TRUE; | |
10536 | 1057 } |
1058 mp_msg(MSGT_TV, MSGL_V, "%s: unknown control: %d\n", info.short_name, cmd); | |
26756
c43ce7268677
cosmetics: Remove useless parentheses from return statements.
diego
parents:
25962
diff
changeset
|
1059 return TVI_CONTROL_UNKNOWN; |
10536 | 1060 } |
1061 | |
1062 | |
1063 #define PRIV ((priv_t *) (tvi_handle->priv)) | |
1064 | |
1065 /* handler creator - entry point ! */ | |
23883 | 1066 static tvi_handle_t *tvi_init_v4l2(tv_param_t* tv_param) |
10536 | 1067 { |
1068 tvi_handle_t *tvi_handle; | |
1069 | |
32141
2802b8095bf7
Move TV input new_handle static function to tv.c and make it non-static.
diego
parents:
32090
diff
changeset
|
1070 tvi_handle = tv_new_handle(sizeof(priv_t), &functions); |
10536 | 1071 if (!tvi_handle) { |
23151 | 1072 return NULL; |
10536 | 1073 } |
1074 PRIV->video_fd = -1; | |
1075 | |
23883 | 1076 PRIV->video_dev = strdup(tv_param->device? tv_param->device: "/dev/video0"); |
10536 | 1077 if (!PRIV->video_dev) { |
32090
535ebcd085e4
Move TV input free_handle static function to tv.c and make it non-static.
diego
parents:
31834
diff
changeset
|
1078 tv_free_handle(tvi_handle); |
23151 | 1079 return NULL; |
10536 | 1080 } |
1081 | |
23883 | 1082 if (tv_param->adevice) { |
1083 PRIV->audio_dev = strdup(tv_param->adevice); | |
23151 | 1084 if (!PRIV->audio_dev) { |
1085 free(PRIV->video_dev); | |
32090
535ebcd085e4
Move TV input free_handle static function to tv.c and make it non-static.
diego
parents:
31834
diff
changeset
|
1086 tv_free_handle(tvi_handle); |
23151 | 1087 return NULL; |
1088 } | |
10536 | 1089 } |
1090 | |
23883 | 1091 PRIV->tv_param=tv_param; |
10536 | 1092 return tvi_handle; |
1093 } | |
1094 | |
1095 #undef PRIV | |
1096 | |
1097 | |
1098 static int uninit(priv_t *priv) | |
1099 { | |
1100 int i, frames, dropped = 0; | |
1101 | |
23901 | 1102 priv->vbi_shutdown=1; |
1103 if(priv->vbi_grabber_thread) | |
1104 pthread_join(priv->vbi_grabber_thread, NULL); | |
1105 | |
1106 teletext_control(priv->priv_vbi,TV_VBI_CONTROL_STOP,(void*)1); | |
1107 priv->priv_vbi=NULL; | |
1108 | |
1109 if(priv->vbi_fd){ | |
1110 close(priv->vbi_fd); | |
1111 priv->vbi_fd=0; | |
1112 } | |
1113 | |
32511
b39155e98ac3
Remove some useless NULL pointer checks before invoking free() on the pointer.
diego
parents:
32352
diff
changeset
|
1114 free(priv->vbi_dev); |
b39155e98ac3
Remove some useless NULL pointer checks before invoking free() on the pointer.
diego
parents:
32352
diff
changeset
|
1115 priv->vbi_dev = NULL; |
10536 | 1116 priv->shutdown = 1; |
16185 | 1117 if(priv->video_grabber_thread) |
23151 | 1118 pthread_join(priv->video_grabber_thread, NULL); |
10536 | 1119 pthread_mutex_destroy(&priv->video_buffer_mutex); |
1120 | |
1121 if (priv->streamon) { | |
23151 | 1122 struct v4l2_buffer buf; |
10536 | 1123 |
23151 | 1124 /* get performance */ |
28927
8f7c8a1cb8b7
100l fix calculation of dropped frames, number of frames is time * fps, not time / fps.
reimar
parents:
28106
diff
changeset
|
1125 frames = 1 + lrintf((double)(priv->curr_frame - priv->first_frame) / 1e6 * getfps(priv)); |
23151 | 1126 dropped = frames - priv->frames; |
10536 | 1127 |
23151 | 1128 /* turn off streaming */ |
1129 if (ioctl(priv->video_fd, VIDIOC_STREAMOFF, &(priv->map[0].buf.type)) < 0) { | |
1130 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl streamoff failed: %s\n", | |
1131 info.short_name, strerror(errno)); | |
1132 } | |
1133 priv->streamon = 0; | |
10536 | 1134 |
23151 | 1135 /* unqueue all remaining buffers */ |
1136 memset(&buf,0,sizeof(buf)); | |
1137 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
1138 buf.memory = V4L2_MEMORY_MMAP; | |
1139 while (!ioctl(priv->video_fd, VIDIOC_DQBUF, &buf)); | |
10536 | 1140 } |
1141 | |
1142 /* unmap all buffers */ | |
1143 for (i = 0; i < priv->mapcount; i++) { | |
23151 | 1144 if (munmap(priv->map[i].addr, priv->map[i].len) < 0) { |
1145 mp_msg(MSGT_TV, MSGL_ERR, "%s: munmap capture buffer failed: %s\n", | |
1146 info.short_name, strerror(errno)); | |
1147 } | |
10536 | 1148 } |
1149 | |
1150 /* stop audio thread */ | |
23886 | 1151 if (!priv->tv_param->noaudio && priv->audio_grabber_thread) { |
23151 | 1152 pthread_join(priv->audio_grabber_thread, NULL); |
1153 pthread_mutex_destroy(&priv->skew_mutex); | |
1154 pthread_mutex_destroy(&priv->audio_mutex); | |
10536 | 1155 } |
1156 | |
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
|
1157 set_mute(priv, 1); |
10536 | 1158 |
1159 /* free memory and close device */ | |
23151 | 1160 free(priv->map); priv->map = NULL; |
10536 | 1161 priv->mapcount = 0; |
23151 | 1162 if(priv->video_fd!=-1)close(priv->video_fd); priv->video_fd = -1; |
1163 free(priv->video_dev); priv->video_dev = NULL; | |
10536 | 1164 |
1165 if (priv->video_ringbuffer) { | |
23151 | 1166 int i; |
1167 for (i = 0; i < priv->video_buffer_size_current; i++) { | |
23423 | 1168 free(priv->video_ringbuffer[i].data); |
23151 | 1169 } |
1170 free(priv->video_ringbuffer); | |
10536 | 1171 } |
23886 | 1172 if (!priv->tv_param->noaudio) { |
32511
b39155e98ac3
Remove some useless NULL pointer checks before invoking free() on the pointer.
diego
parents:
32352
diff
changeset
|
1173 free(priv->audio_ringbuffer); |
b39155e98ac3
Remove some useless NULL pointer checks before invoking free() on the pointer.
diego
parents:
32352
diff
changeset
|
1174 free(priv->audio_skew_buffer); |
b39155e98ac3
Remove some useless NULL pointer checks before invoking free() on the pointer.
diego
parents:
32352
diff
changeset
|
1175 free(priv->audio_skew_delta_buffer); |
25005
1635b2b31bdd
Add missing call to audio_in_uninit in v4l2 tv driver.
voroshil
parents:
24763
diff
changeset
|
1176 |
1635b2b31bdd
Add missing call to audio_in_uninit in v4l2 tv driver.
voroshil
parents:
24763
diff
changeset
|
1177 audio_in_uninit(&priv->audio_in); |
10536 | 1178 } |
1179 | |
1180 /* show some nice statistics ;-) */ | |
1181 mp_msg(MSGT_TV, MSGL_INFO, | |
23151 | 1182 "%s: %d frames successfully processed, %d frames dropped.\n", |
1183 info.short_name, priv->frames, dropped); | |
10536 | 1184 mp_msg(MSGT_TV, MSGL_V, "%s: up to %u video frames buffered.\n", |
23151 | 1185 info.short_name, priv->video_buffer_size_current); |
10536 | 1186 return 1; |
1187 } | |
1188 | |
1189 | |
1190 /* initialisation */ | |
1191 static int init(priv_t *priv) | |
1192 { | |
1193 int i; | |
1194 | |
1195 priv->audio_ringbuffer = NULL; | |
1196 priv->audio_skew_buffer = NULL; | |
10653 | 1197 priv->audio_skew_delta_buffer = NULL; |
10536 | 1198 |
25962 | 1199 priv->audio_initialized = 0; |
15464 | 1200 |
10536 | 1201 /* Open the video device. */ |
1202 priv->video_fd = open(priv->video_dev, O_RDWR); | |
1203 if (priv->video_fd < 0) { | |
23151 | 1204 mp_msg(MSGT_TV, MSGL_ERR, "%s: unable to open '%s': %s\n", |
1205 info.short_name, priv->video_dev, strerror(errno)); | |
1206 uninit(priv); | |
1207 return 0; | |
10536 | 1208 } |
1209 mp_msg(MSGT_TV, MSGL_DBG2, "%s: video fd: %s: %d\n", | |
23151 | 1210 info.short_name, priv->video_dev, priv->video_fd); |
10536 | 1211 |
1212 /* | |
1213 ** Query the video capabilities and current settings | |
1214 ** for further control calls. | |
1215 */ | |
1216 if (ioctl(priv->video_fd, VIDIOC_QUERYCAP, &priv->capability) < 0) { | |
23151 | 1217 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query capabilities failed: %s\n", |
1218 info.short_name, strerror(errno)); | |
1219 uninit(priv); | |
1220 return 0; | |
10536 | 1221 } |
1222 | |
1223 if (!(priv->capability.capabilities & V4L2_CAP_VIDEO_CAPTURE)) | |
1224 { | |
23151 | 1225 mp_msg(MSGT_TV, MSGL_ERR, "Device %s is not a video capture device.\n", |
1226 priv->video_dev); | |
1227 return 0; | |
10536 | 1228 } |
1229 | |
18073
8ceb31f028ee
make failures during e.g. setting the TV norm non-fatal.
reimar
parents:
17765
diff
changeset
|
1230 if (getfmt(priv) < 0) { |
23151 | 1231 uninit(priv); |
1232 return 0; | |
10536 | 1233 } |
18073
8ceb31f028ee
make failures during e.g. setting the TV norm non-fatal.
reimar
parents:
17765
diff
changeset
|
1234 getstd(priv); |
10536 | 1235 /* |
1236 ** if this device has got a tuner query it's settings | |
1237 ** otherwise set some nice defaults | |
1238 */ | |
1239 if (priv->capability.capabilities & V4L2_CAP_TUNER) { | |
23151 | 1240 if (ioctl(priv->video_fd, VIDIOC_G_TUNER, &priv->tuner) < 0) { |
1241 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get tuner failed: %s\n", | |
1242 info.short_name, strerror(errno)); | |
1243 uninit(priv); | |
1244 return 0; | |
1245 } | |
10536 | 1246 } |
1247 mp_msg(MSGT_TV, MSGL_INFO, "Selected device: %s\n", priv->capability.card); | |
1248 if (priv->capability.capabilities & V4L2_CAP_TUNER) { | |
23151 | 1249 mp_msg(MSGT_TV, MSGL_INFO, " Tuner cap:%s%s%s\n", |
1250 (priv->tuner.capability & V4L2_TUNER_CAP_STEREO) ? " STEREO" : "", | |
1251 (priv->tuner.capability & V4L2_TUNER_CAP_LANG1) ? " LANG1" : "", | |
1252 (priv->tuner.capability & V4L2_TUNER_CAP_LANG2) ? " LANG2" : ""); | |
1253 mp_msg(MSGT_TV, MSGL_INFO, " Tuner rxs:%s%s%s%s\n", | |
1254 (priv->tuner.rxsubchans & V4L2_TUNER_SUB_MONO) ? " MONO" : "", | |
1255 (priv->tuner.rxsubchans & V4L2_TUNER_SUB_STEREO) ? " STEREO" : "", | |
1256 (priv->tuner.rxsubchans & V4L2_TUNER_SUB_LANG1) ? " LANG1" : "", | |
1257 (priv->tuner.rxsubchans & V4L2_TUNER_SUB_LANG2) ? " LANG2" : ""); | |
10536 | 1258 } |
31834
64ba1daa147a
various spelling fixes, found by the Debian QA tool 'lintian'
siretart
parents:
31322
diff
changeset
|
1259 mp_msg(MSGT_TV, MSGL_INFO, " Capabilities:%s%s%s%s%s%s%s%s%s%s%s\n", |
23151 | 1260 priv->capability.capabilities & V4L2_CAP_VIDEO_CAPTURE? |
1261 " video capture": "", | |
1262 priv->capability.capabilities & V4L2_CAP_VIDEO_OUTPUT? | |
1263 " video output": "", | |
1264 priv->capability.capabilities & V4L2_CAP_VIDEO_OVERLAY? | |
1265 " video overlay": "", | |
1266 priv->capability.capabilities & V4L2_CAP_VBI_CAPTURE? | |
1267 " VBI capture device": "", | |
1268 priv->capability.capabilities & V4L2_CAP_VBI_OUTPUT? | |
1269 " VBI output": "", | |
1270 priv->capability.capabilities & V4L2_CAP_RDS_CAPTURE? | |
1271 " RDS data capture": "", | |
1272 priv->capability.capabilities & V4L2_CAP_TUNER? | |
1273 " tuner": "", | |
1274 priv->capability.capabilities & V4L2_CAP_AUDIO? | |
1275 " audio": "", | |
1276 priv->capability.capabilities & V4L2_CAP_READWRITE? | |
1277 " read/write": "", | |
1278 priv->capability.capabilities & V4L2_CAP_ASYNCIO? | |
1279 " async i/o": "", | |
1280 priv->capability.capabilities & V4L2_CAP_STREAMING? | |
1281 " streaming": ""); | |
10536 | 1282 mp_msg(MSGT_TV, MSGL_INFO, " supported norms:"); |
1283 for (i = 0;; i++) { | |
23151 | 1284 struct v4l2_standard standard; |
1285 memset(&standard, 0, sizeof(standard)); | |
1286 standard.index = i; | |
1287 if (-1 == ioctl(priv->video_fd, VIDIOC_ENUMSTD, &standard)) | |
1288 break; | |
1289 mp_msg(MSGT_TV, MSGL_INFO, " %d = %s;", i, standard.name); | |
10536 | 1290 } |
1291 mp_msg(MSGT_TV, MSGL_INFO, "\n inputs:"); | |
1292 for (i = 0; 1; i++) { | |
23151 | 1293 struct v4l2_input input; |
10536 | 1294 |
23151 | 1295 input.index = i; |
1296 if (ioctl(priv->video_fd, VIDIOC_ENUMINPUT, &input) < 0) { | |
1297 break; | |
1298 } | |
1299 mp_msg(MSGT_TV, MSGL_INFO, " %d = %s;", i, input.name); | |
10536 | 1300 } |
29121
bae666342ba9
Make tvi_v4l2 print -1 as "Current input" if the ioctl to read it failed.
reimar
parents:
28940
diff
changeset
|
1301 i = -1; |
10536 | 1302 if (ioctl(priv->video_fd, VIDIOC_G_INPUT, &i) < 0) { |
23151 | 1303 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl get input failed: %s\n", |
1304 info.short_name, strerror(errno)); | |
10536 | 1305 } |
1306 mp_msg(MSGT_TV, MSGL_INFO, "\n Current input: %d\n", i); | |
1307 for (i = 0; ; i++) { | |
23151 | 1308 struct v4l2_fmtdesc fmtdesc; |
10536 | 1309 |
23151 | 1310 fmtdesc.index = i; |
1311 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
1312 if (ioctl(priv->video_fd, VIDIOC_ENUM_FMT, &fmtdesc) < 0) { | |
1313 break; | |
1314 } | |
1315 mp_msg(MSGT_TV, MSGL_V, " Format %-6s (%2d bits, %s): %s\n", | |
1316 pixfmt2name(fmtdesc.pixelformat), pixfmt2depth(fmtdesc.pixelformat), | |
1317 fmtdesc.description, vo_format_name(fcc_vl2mp(fmtdesc.pixelformat))); | |
10536 | 1318 } |
1319 mp_msg(MSGT_TV, MSGL_INFO, " Current format: %s\n", | |
23151 | 1320 pixfmt2name(priv->format.fmt.pix.pixelformat)); |
10536 | 1321 |
1322 /* set some nice defaults */ | |
1323 if (getfmt(priv) < 0) return 0; | |
1324 priv->format.fmt.pix.width = 640; | |
1325 priv->format.fmt.pix.height = 480; | |
1326 if (ioctl(priv->video_fd, VIDIOC_S_FMT, &priv->format) < 0) { | |
23151 | 1327 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set format failed: %s\n", |
1328 info.short_name, strerror(errno)); | |
1329 uninit(priv); | |
1330 return 0; | |
10536 | 1331 } |
1332 | |
23886 | 1333 // if (!(priv->capability.capabilities & V4L2_CAP_AUDIO) && !priv->tv_param->force_audio) priv->tv_param->noaudio = 1; |
10536 | 1334 |
1335 if (priv->capability.capabilities & V4L2_CAP_TUNER) { | |
23151 | 1336 struct v4l2_control control; |
23886 | 1337 if (priv->tv_param->amode >= 0) { |
23151 | 1338 mp_msg(MSGT_TV, MSGL_V, "%s: setting audio mode\n", info.short_name); |
23886 | 1339 priv->tuner.audmode = amode2v4l(priv->tv_param->amode); |
23151 | 1340 if (ioctl(priv->video_fd, VIDIOC_S_TUNER, &priv->tuner) < 0) { |
1341 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl set tuner failed: %s\n", | |
1342 info.short_name, strerror(errno)); | |
1343 return TVI_CONTROL_FALSE; | |
1344 } | |
1345 } | |
1346 mp_msg(MSGT_TV, MSGL_INFO, "%s: current audio mode is :%s%s%s%s\n", info.short_name, | |
1347 (priv->tuner.audmode == V4L2_TUNER_MODE_MONO) ? " MONO" : "", | |
1348 (priv->tuner.audmode == V4L2_TUNER_MODE_STEREO) ? " STEREO" : "", | |
1349 (priv->tuner.audmode == V4L2_TUNER_MODE_LANG1) ? " LANG1" : "", | |
1350 (priv->tuner.audmode == V4L2_TUNER_MODE_LANG2) ? " LANG2" : ""); | |
10536 | 1351 |
23886 | 1352 if (priv->tv_param->volume >= 0) { |
23151 | 1353 control.id = V4L2_CID_AUDIO_VOLUME; |
23886 | 1354 control.value = priv->tv_param->volume; |
23151 | 1355 set_control(priv, &control, 0); |
1356 } | |
23886 | 1357 if (priv->tv_param->bass >= 0) { |
23151 | 1358 control.id = V4L2_CID_AUDIO_BASS; |
23886 | 1359 control.value = priv->tv_param->bass; |
23151 | 1360 set_control(priv, &control, 0); |
1361 } | |
23886 | 1362 if (priv->tv_param->treble >= 0) { |
23151 | 1363 control.id = V4L2_CID_AUDIO_TREBLE; |
23886 | 1364 control.value = priv->tv_param->treble; |
23151 | 1365 set_control(priv, &control, 0); |
1366 } | |
23886 | 1367 if (priv->tv_param->balance >= 0) { |
23151 | 1368 control.id = V4L2_CID_AUDIO_BALANCE; |
23886 | 1369 control.value = priv->tv_param->balance; |
23151 | 1370 set_control(priv, &control, 0); |
1371 } | |
10536 | 1372 } |
1373 | |
1374 return 1; | |
1375 } | |
1376 | |
1377 static int get_capture_buffer_size(priv_t *priv) | |
1378 { | |
33644
c15dabfa2380
Do a proper calculation of free RAM to be used as V4L buffers.
iive
parents:
33163
diff
changeset
|
1379 uint64_t bufsize; |
c15dabfa2380
Do a proper calculation of free RAM to be used as V4L buffers.
iive
parents:
33163
diff
changeset
|
1380 int cnt; |
10536 | 1381 |
23886 | 1382 if (priv->tv_param->buffer_size >= 0) { |
1383 bufsize = priv->tv_param->buffer_size*1024*1024; | |
10536 | 1384 } else { |
1385 #ifdef HAVE_SYS_SYSINFO_H | |
23151 | 1386 struct sysinfo si; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1387 |
23151 | 1388 sysinfo(&si); |
33644
c15dabfa2380
Do a proper calculation of free RAM to be used as V4L buffers.
iive
parents:
33163
diff
changeset
|
1389 bufsize = (si.freeram/2)*si.mem_unit; |
c15dabfa2380
Do a proper calculation of free RAM to be used as V4L buffers.
iive
parents:
33163
diff
changeset
|
1390 if ( bufsize < 16*1024*1024) |
c15dabfa2380
Do a proper calculation of free RAM to be used as V4L buffers.
iive
parents:
33163
diff
changeset
|
1391 #endif |
23151 | 1392 bufsize = 16*1024*1024; |
10536 | 1393 } |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1394 |
23423 | 1395 cnt = bufsize/priv->format.fmt.pix.sizeimage; |
10536 | 1396 if (cnt < 2) cnt = 2; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1397 |
10536 | 1398 return cnt; |
1399 } | |
1400 | |
1401 /* that's the real start, we'got the format parameters (checked with control) */ | |
1402 static int start(priv_t *priv) | |
1403 { | |
1404 struct v4l2_requestbuffers request; | |
24346 | 1405 unsigned int i; |
10536 | 1406 |
1407 /* setup audio parameters */ | |
1408 | |
15464 | 1409 init_audio(priv); |
25962 | 1410 if (!priv->tv_param->noaudio && !priv->audio_initialized) return 0; |
15464 | 1411 |
10536 | 1412 /* we need this to size the audio buffer properly */ |
1413 if (priv->immediate_mode) { | |
23151 | 1414 priv->video_buffer_size_max = 2; |
10536 | 1415 } else { |
23151 | 1416 priv->video_buffer_size_max = get_capture_buffer_size(priv); |
10536 | 1417 } |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1418 |
23886 | 1419 if (!priv->tv_param->noaudio) { |
23151 | 1420 setup_audio_buffer_sizes(priv); |
1421 priv->audio_skew_buffer = calloc(priv->aud_skew_cnt, sizeof(long long)); | |
1422 if (!priv->audio_skew_buffer) { | |
1423 mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate skew buffer: %s\n", strerror(errno)); | |
1424 return 0; | |
1425 } | |
1426 priv->audio_skew_delta_buffer = calloc(priv->aud_skew_cnt, sizeof(long long)); | |
1427 if (!priv->audio_skew_delta_buffer) { | |
1428 mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate skew buffer: %s\n", strerror(errno)); | |
1429 return 0; | |
1430 } | |
10536 | 1431 |
23151 | 1432 priv->audio_ringbuffer = calloc(priv->audio_in.blocksize, priv->audio_buffer_size); |
1433 if (!priv->audio_ringbuffer) { | |
1434 mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate audio buffer: %s\n", strerror(errno)); | |
1435 return 0; | |
1436 } | |
10536 | 1437 |
23151 | 1438 priv->audio_secs_per_block = (double)priv->audio_in.blocksize/(priv->audio_in.samplerate |
1439 *priv->audio_in.channels | |
1440 *priv->audio_in.bytes_per_sample); | |
1441 priv->audio_usecs_per_block = 1e6*priv->audio_secs_per_block; | |
1442 priv->audio_head = 0; | |
1443 priv->audio_tail = 0; | |
1444 priv->audio_cnt = 0; | |
1445 priv->audio_drop = 0; | |
1446 priv->audio_skew = 0; | |
1447 priv->audio_skew_total = 0; | |
1448 priv->audio_skew_delta_total = 0; | |
1449 priv->audio_recv_blocks_total = 0; | |
1450 priv->audio_sent_blocks_total = 0; | |
1451 priv->audio_null_blocks_inserted = 0; | |
1452 priv->audio_insert_null_samples = 0; | |
1453 priv->dropped_frames_timeshift = 0; | |
1454 priv->dropped_frames_compensated = 0; | |
15449 | 1455 |
23151 | 1456 pthread_mutex_init(&priv->skew_mutex, NULL); |
1457 pthread_mutex_init(&priv->audio_mutex, NULL); | |
10536 | 1458 } |
1459 | |
1460 /* setup video parameters */ | |
23886 | 1461 if (!priv->tv_param->noaudio) { |
32668
cb671a73f3a3
Use getfps helper function everywhere, simplifies code and avoids a possible division by 0.
reimar
parents:
32511
diff
changeset
|
1462 if (priv->video_buffer_size_max < 3*getfps(priv)*priv->audio_secs_per_block) { |
23151 | 1463 mp_msg(MSGT_TV, MSGL_ERR, "Video buffer shorter than 3 times audio frame duration.\n" |
1464 "You will probably experience heavy framedrops.\n"); | |
1465 } | |
10536 | 1466 } |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1467 |
10536 | 1468 { |
23151 | 1469 int bytesperline = priv->format.fmt.pix.width*pixfmt2depth(priv->format.fmt.pix.pixelformat)/8; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1470 |
23151 | 1471 mp_msg(MSGT_TV, MSGL_V, "Using a ring buffer for maximum %d frames, %d MB total size.\n", |
1472 priv->video_buffer_size_max, | |
1473 priv->video_buffer_size_max*priv->format.fmt.pix.height*bytesperline/(1024*1024)); | |
10536 | 1474 } |
1475 | |
23423 | 1476 priv->video_ringbuffer = calloc(priv->video_buffer_size_max, sizeof(video_buffer_entry)); |
10536 | 1477 if (!priv->video_ringbuffer) { |
23151 | 1478 mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate video buffer: %s\n", strerror(errno)); |
1479 return 0; | |
10536 | 1480 } |
23423 | 1481 memset(priv->video_ringbuffer,0,priv->video_buffer_size_max * sizeof(video_buffer_entry)); |
10536 | 1482 |
15449 | 1483 pthread_mutex_init(&priv->video_buffer_mutex, NULL); |
1484 | |
10536 | 1485 priv->video_head = 0; |
1486 priv->video_tail = 0; | |
1487 priv->video_cnt = 0; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1488 |
10536 | 1489 /* request buffers */ |
1490 if (priv->immediate_mode) { | |
23151 | 1491 request.count = 2; |
10536 | 1492 } else { |
23151 | 1493 request.count = BUFFER_COUNT; |
10536 | 1494 } |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1495 |
10536 | 1496 request.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
1497 request.memory = V4L2_MEMORY_MMAP; | |
1498 if (ioctl(priv->video_fd, VIDIOC_REQBUFS, &request) < 0) { | |
23151 | 1499 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl request buffers failed: %s\n", |
1500 info.short_name, strerror(errno)); | |
1501 return 0; | |
10536 | 1502 } |
1503 | |
1504 /* query buffers */ | |
18558
4928dd61f136
Fix potential integer overflows in memory allocation.
rtogni
parents:
18176
diff
changeset
|
1505 if (!(priv->map = calloc(request.count, sizeof(struct map)))) { |
23151 | 1506 mp_msg(MSGT_TV, MSGL_ERR, "%s: malloc capture buffers failed: %s\n", |
1507 info.short_name, strerror(errno)); | |
1508 return 0; | |
10536 | 1509 } |
1510 | |
1511 /* map and queue buffers */ | |
1512 for (i = 0; i < request.count; i++) { | |
23151 | 1513 memset(&priv->map[i].buf,0,sizeof(priv->map[i].buf)); |
1514 priv->map[i].buf.index = i; | |
1515 priv->map[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
1516 priv->map[i].buf.memory = V4L2_MEMORY_MMAP; | |
1517 if (ioctl(priv->video_fd, VIDIOC_QUERYBUF, &(priv->map[i].buf)) < 0) { | |
1518 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query buffer failed: %s\n", | |
1519 info.short_name, strerror(errno)); | |
1520 free(priv->map); | |
1521 priv->map = NULL; | |
1522 return 0; | |
1523 } | |
1524 priv->map[i].addr = mmap (0, priv->map[i].buf.length, PROT_READ | | |
1525 PROT_WRITE, MAP_SHARED, priv->video_fd, priv->map[i].buf.m.offset); | |
1526 if (priv->map[i].addr == MAP_FAILED) { | |
1527 mp_msg(MSGT_TV, MSGL_ERR, "%s: mmap capture buffer failed: %s\n", | |
1528 info.short_name, strerror(errno)); | |
1529 priv->map[i].len = 0; | |
1530 return 0; | |
1531 } | |
1532 priv->map[i].len = priv->map[i].buf.length; | |
1533 /* count up to make sure this is correct everytime */ | |
1534 priv->mapcount++; | |
10536 | 1535 |
23151 | 1536 if (ioctl(priv->video_fd, VIDIOC_QBUF, &(priv->map[i].buf)) < 0) { |
1537 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl queue buffer failed: %s\n", | |
1538 info.short_name, strerror(errno)); | |
1539 return 0; | |
1540 } | |
10536 | 1541 } |
1542 | |
23901 | 1543 /* start vbi thread */ |
1544 if(priv->priv_vbi){ | |
1545 priv->vbi_shutdown = 0; | |
1546 pthread_create(&priv->vbi_grabber_thread, NULL, vbi_grabber, priv); | |
1547 } | |
10536 | 1548 /* start audio thread */ |
1549 priv->shutdown = 0; | |
1550 priv->audio_skew_measure_time = 0; | |
1551 priv->first_frame = 0; | |
1552 priv->audio_skew = 0; | |
1553 priv->first = 1; | |
1554 | |
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
|
1555 set_mute(priv, 0); |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1556 |
10536 | 1557 return 1; |
1558 } | |
1559 | |
1560 // copies a video frame | |
23423 | 1561 static inline void copy_frame(priv_t *priv, video_buffer_entry *dest, unsigned char *source,int len) |
10536 | 1562 { |
23423 | 1563 dest->framesize=len; |
23886 | 1564 if(priv->tv_param->automute>0){ |
23422 | 1565 if (ioctl(priv->video_fd, VIDIOC_G_TUNER, &priv->tuner) >= 0) { |
23886 | 1566 if(priv->tv_param->automute<<8>priv->tuner.signal){ |
23423 | 1567 fill_blank_frame(dest->data,dest->framesize,fcc_vl2mp(priv->format.fmt.pix.pixelformat)); |
23422 | 1568 set_mute(priv,1); |
1569 return; | |
1570 } | |
1571 } | |
1572 set_mute(priv,0); | |
1573 } | |
23423 | 1574 memcpy(dest->data, source, len); |
10536 | 1575 } |
1576 | |
1577 // maximum skew change, in frames | |
1578 #define MAX_SKEW_DELTA 0.6 | |
1579 static void *video_grabber(void *data) | |
1580 { | |
1581 priv_t *priv = (priv_t*)data; | |
15449 | 1582 long long skew, prev_skew, xskew, interval, prev_interval, delta; |
10536 | 1583 int i; |
23423 | 1584 int framesize = priv->format.fmt.pix.sizeimage; |
10536 | 1585 fd_set rdset; |
1586 struct timeval timeout; | |
1587 struct v4l2_buffer buf; | |
1588 | |
1589 xskew = 0; | |
1590 skew = 0; | |
1591 interval = 0; | |
1592 prev_interval = 0; | |
1593 prev_skew = 0; | |
1594 | |
1595 mp_msg(MSGT_TV, MSGL_V, "%s: going to capture\n", info.short_name); | |
1596 if (ioctl(priv->video_fd, VIDIOC_STREAMON, &(priv->format.type)) < 0) { | |
23151 | 1597 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl streamon failed: %s\n", |
1598 info.short_name, strerror(errno)); | |
1599 return 0; | |
10536 | 1600 } |
1601 priv->streamon = 1; | |
1602 | |
23886 | 1603 if (!priv->tv_param->noaudio) { |
23151 | 1604 pthread_create(&priv->audio_grabber_thread, NULL, audio_grabber, priv); |
10536 | 1605 } |
1606 | |
1607 for (priv->frames = 0; !priv->shutdown;) | |
1608 { | |
23151 | 1609 int ret; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1610 |
23151 | 1611 if (priv->immediate_mode) { |
1612 while (priv->video_cnt == priv->video_buffer_size_max) { | |
1613 usleep(10000); | |
1614 if (priv->shutdown) { | |
1615 return NULL; | |
1616 } | |
1617 } | |
1618 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1619 |
23151 | 1620 FD_ZERO (&rdset); |
1621 FD_SET (priv->video_fd, &rdset); | |
10536 | 1622 |
23151 | 1623 timeout.tv_sec = 1; |
1624 timeout.tv_usec = 0; | |
10536 | 1625 |
23151 | 1626 i = select(priv->video_fd + 1, &rdset, NULL, NULL, &timeout); |
1627 if (i < 0) { | |
1628 mp_msg(MSGT_TV, MSGL_ERR, "%s: select failed: %s\n", | |
1629 info.short_name, strerror(errno)); | |
1630 continue; | |
1631 } | |
1632 else if (i == 0) { | |
1633 mp_msg(MSGT_TV, MSGL_ERR, "%s: select timeout\n", info.short_name); | |
1634 continue; | |
1635 } | |
1636 else if (!FD_ISSET(priv->video_fd, &rdset)) { | |
1637 continue; | |
1638 } | |
10536 | 1639 |
23151 | 1640 memset(&buf,0,sizeof(buf)); |
1641 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
1642 buf.memory = V4L2_MEMORY_MMAP; | |
1643 ret = ioctl(priv->video_fd, VIDIOC_DQBUF, &buf); | |
10536 | 1644 |
23151 | 1645 if (ret < 0) { |
1646 /* | |
1647 if there's no signal, the buffer might me dequeued | |
1648 so we query all the buffers to see which one we should | |
1649 put back to queue | |
10536 | 1650 |
23151 | 1651 observed with saa7134 0.2.8 |
1652 don't know if is it a bug or (mis)feature | |
1653 */ | |
1654 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl dequeue buffer failed: %s, idx = %d\n", | |
1655 info.short_name, strerror(errno), buf.index); | |
1656 for (i = 0; i < priv->mapcount; i++) { | |
1657 memset(&buf,0,sizeof(buf)); | |
1658 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
1659 buf.memory = V4L2_MEMORY_MMAP; | |
1660 buf.index = i; | |
1661 ret = ioctl(priv->video_fd, VIDIOC_QUERYBUF, &buf); | |
1662 if (ret < 0) { | |
1663 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query buffer failed: %s, idx = %d\n", | |
1664 info.short_name, strerror(errno), buf.index); | |
1665 return 0; | |
1666 } | |
1667 if ((buf.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE)) == V4L2_BUF_FLAG_MAPPED) { | |
1668 if (ioctl(priv->video_fd, VIDIOC_QBUF, &(priv->map[i].buf)) < 0) { | |
1669 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl queue buffer failed: %s\n", | |
1670 info.short_name, strerror(errno)); | |
1671 return 0; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1672 } |
23151 | 1673 } |
1674 } | |
1675 continue; | |
1676 } | |
10536 | 1677 |
23151 | 1678 /* store the timestamp of the very first frame as reference */ |
1679 if (!priv->frames++) { | |
23886 | 1680 if (!priv->tv_param->noaudio) pthread_mutex_lock(&priv->skew_mutex); |
23151 | 1681 priv->first_frame = (long long)1e6*buf.timestamp.tv_sec + buf.timestamp.tv_usec; |
23886 | 1682 if (!priv->tv_param->noaudio) pthread_mutex_unlock(&priv->skew_mutex); |
23151 | 1683 } |
1684 priv->curr_frame = (long long)buf.timestamp.tv_sec*1e6+buf.timestamp.tv_usec; | |
32352
76f94c00a69f
1000l, %lf is not valid format string for printf (only for scanf) and actually
reimar
parents:
32141
diff
changeset
|
1685 // fprintf(stderr, "idx = %d, ts = %f\n", buf.index, (double)(priv->curr_frame) / 1e6); |
10536 | 1686 |
23151 | 1687 interval = priv->curr_frame - priv->first_frame; |
1688 delta = interval - prev_interval; | |
10536 | 1689 |
23151 | 1690 if (!priv->immediate_mode) { |
1691 // interpolate the skew in time | |
23886 | 1692 if (!priv->tv_param->noaudio) pthread_mutex_lock(&priv->skew_mutex); |
23151 | 1693 xskew = priv->audio_skew + (interval - priv->audio_skew_measure_time)*priv->audio_skew_factor; |
23886 | 1694 if (!priv->tv_param->noaudio) pthread_mutex_unlock(&priv->skew_mutex); |
23151 | 1695 // correct extreme skew changes to avoid (especially) moving backwards in time |
1696 if (xskew - prev_skew > delta*MAX_SKEW_DELTA) { | |
1697 skew = prev_skew + delta*MAX_SKEW_DELTA; | |
1698 } else if (xskew - prev_skew < -delta*MAX_SKEW_DELTA) { | |
1699 skew = prev_skew - delta*MAX_SKEW_DELTA; | |
1700 } else { | |
1701 skew = xskew; | |
1702 } | |
1703 } | |
10536 | 1704 |
32352
76f94c00a69f
1000l, %lf is not valid format string for printf (only for scanf) and actually
reimar
parents:
32141
diff
changeset
|
1705 mp_msg(MSGT_TV, MSGL_DBG3, "\nfps = %f, interval = %f, a_skew = %f, corr_skew = %f\n", |
23151 | 1706 delta ? (double)1e6/delta : -1, |
1707 (double)1e-6*interval, (double)1e-6*xskew, (double)1e-6*skew); | |
1708 mp_msg(MSGT_TV, MSGL_DBG3, "vcnt = %d, acnt = %d\n", priv->video_cnt, priv->audio_cnt); | |
10536 | 1709 |
23151 | 1710 prev_skew = skew; |
1711 prev_interval = interval; | |
10536 | 1712 |
23151 | 1713 /* allocate a new buffer, if needed */ |
1714 pthread_mutex_lock(&priv->video_buffer_mutex); | |
1715 if (priv->video_buffer_size_current < priv->video_buffer_size_max) { | |
1716 if (priv->video_cnt == priv->video_buffer_size_current) { | |
1717 unsigned char *newbuf = malloc(framesize); | |
1718 if (newbuf) { | |
1719 memmove(priv->video_ringbuffer+priv->video_tail+1, priv->video_ringbuffer+priv->video_tail, | |
23423 | 1720 (priv->video_buffer_size_current-priv->video_tail)*sizeof(video_buffer_entry)); |
1721 priv->video_ringbuffer[priv->video_tail].data = newbuf; | |
23151 | 1722 if ((priv->video_head >= priv->video_tail) && (priv->video_cnt > 0)) priv->video_head++; |
1723 priv->video_buffer_size_current++; | |
1724 } | |
1725 } | |
1726 } | |
1727 pthread_mutex_unlock(&priv->video_buffer_mutex); | |
10536 | 1728 |
23151 | 1729 if (priv->video_cnt == priv->video_buffer_size_current) { |
1730 if (!priv->immediate_mode) { | |
1731 mp_msg(MSGT_TV, MSGL_ERR, "\nvideo buffer full - dropping frame\n"); | |
1732 if (priv->audio_insert_null_samples) { | |
1733 pthread_mutex_lock(&priv->audio_mutex); | |
1734 priv->dropped_frames_timeshift += delta; | |
1735 pthread_mutex_unlock(&priv->audio_mutex); | |
1736 } | |
1737 } | |
1738 } else { | |
1739 if (priv->immediate_mode) { | |
23423 | 1740 priv->video_ringbuffer[priv->video_tail].timestamp = 0; |
23151 | 1741 } else { |
1742 // compensate for audio skew | |
1743 // negative skew => there are more audio samples, increase interval | |
1744 // positive skew => less samples, shorten the interval | |
23423 | 1745 priv->video_ringbuffer[priv->video_tail].timestamp = interval - skew; |
1746 if (priv->audio_insert_null_samples && priv->video_ringbuffer[priv->video_tail].timestamp > 0) { | |
23151 | 1747 pthread_mutex_lock(&priv->audio_mutex); |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1748 priv->video_ringbuffer[priv->video_tail].timestamp += |
23151 | 1749 (priv->audio_null_blocks_inserted |
1750 - priv->dropped_frames_timeshift/priv->audio_usecs_per_block) | |
1751 *priv->audio_usecs_per_block; | |
1752 pthread_mutex_unlock(&priv->audio_mutex); | |
1753 } | |
1754 } | |
23423 | 1755 copy_frame(priv, priv->video_ringbuffer+priv->video_tail, priv->map[buf.index].addr,buf.bytesused); |
23151 | 1756 priv->video_tail = (priv->video_tail+1)%priv->video_buffer_size_current; |
1757 priv->video_cnt++; | |
1758 } | |
1759 if (ioctl(priv->video_fd, VIDIOC_QBUF, &buf) < 0) { | |
1760 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl queue buffer failed: %s\n", | |
1761 info.short_name, strerror(errno)); | |
1762 return 0; | |
1763 } | |
10536 | 1764 } |
1765 return NULL; | |
1766 } | |
1767 | |
16962
bdc218b5a49a
Do not hang forever when the card delivers no new data.
reimar
parents:
16536
diff
changeset
|
1768 #define MAX_LOOP 50 |
10536 | 1769 static double grab_video_frame(priv_t *priv, char *buffer, int len) |
1770 { | |
1771 double interval; | |
16962
bdc218b5a49a
Do not hang forever when the card delivers no new data.
reimar
parents:
16536
diff
changeset
|
1772 int loop_cnt = 0; |
10536 | 1773 |
1774 if (priv->first) { | |
23151 | 1775 pthread_create(&priv->video_grabber_thread, NULL, video_grabber, priv); |
1776 priv->first = 0; | |
10536 | 1777 } |
1778 | |
1779 while (priv->video_cnt == 0) { | |
23151 | 1780 usleep(10000); |
1781 if (loop_cnt++ > MAX_LOOP) return 0; | |
10536 | 1782 } |
1783 | |
1784 pthread_mutex_lock(&priv->video_buffer_mutex); | |
23423 | 1785 interval = (double)priv->video_ringbuffer[priv->video_head].timestamp*1e-6; |
1786 memcpy(buffer, priv->video_ringbuffer[priv->video_head].data, len); | |
10536 | 1787 priv->video_cnt--; |
1788 priv->video_head = (priv->video_head+1)%priv->video_buffer_size_current; | |
1789 pthread_mutex_unlock(&priv->video_buffer_mutex); | |
1790 | |
1791 return interval; | |
1792 } | |
1793 | |
1794 static int get_video_framesize(priv_t *priv) | |
1795 { | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1796 /* |
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1797 this routine will be called before grab_video_frame |
23423 | 1798 thus let's return topmost frame's size |
1799 */ | |
1800 if (priv->video_cnt) | |
1801 return priv->video_ringbuffer[priv->video_head].framesize; | |
1802 /* | |
1803 no video frames yet available. i don't know what to do in this case, | |
1804 thus let's return some fallback result (for compressed format this will be | |
1805 maximum allowed frame size. | |
1806 */ | |
10536 | 1807 return priv->format.fmt.pix.sizeimage; |
1808 } | |
1809 | |
10704 | 1810 //#define DOUBLESPEED |
1811 #ifdef DOUBLESPEED | |
10536 | 1812 // for testing purposes only |
1813 static void read_doublespeed(priv_t *priv) | |
1814 { | |
18885 | 1815 char *bufx = calloc(priv->audio_in.blocksize, 2); |
10536 | 1816 short *s; |
1817 short *d; | |
1818 int i; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1819 |
10536 | 1820 audio_in_read_chunk(&priv->audio_in, bufx); |
1821 audio_in_read_chunk(&priv->audio_in, bufx+priv->audio_in.blocksize); | |
1822 | |
1823 s = bufx; | |
1824 d = priv->audio_ringbuffer+priv->audio_tail*priv->audio_in.blocksize; | |
1825 for (i = 0; i < priv->audio_in.blocksize/2; i++) { | |
23151 | 1826 *d++ = *s++; |
1827 *s++; | |
10536 | 1828 } |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1829 |
10536 | 1830 } |
10704 | 1831 #endif |
10536 | 1832 |
1833 static void *audio_grabber(void *data) | |
1834 { | |
1835 priv_t *priv = (priv_t*)data; | |
1836 struct timeval tv; | |
1837 int i, audio_skew_ptr = 0; | |
10653 | 1838 long long current_time, prev_skew = 0, prev_skew_uncorr = 0; |
10852 | 1839 long long start_time_avg; |
10536 | 1840 |
1841 gettimeofday(&tv, NULL); | |
10852 | 1842 start_time_avg = priv->audio_start_time = (long long)1e6*tv.tv_sec + tv.tv_usec; |
10536 | 1843 audio_in_start_capture(&priv->audio_in); |
1844 for (i = 0; i < priv->aud_skew_cnt; i++) | |
23151 | 1845 priv->audio_skew_buffer[i] = 0; |
10653 | 1846 for (i = 0; i < priv->aud_skew_cnt; i++) |
23151 | 1847 priv->audio_skew_delta_buffer[i] = 0; |
10536 | 1848 |
1849 for (; !priv->shutdown;) | |
1850 { | |
10704 | 1851 #ifdef DOUBLESPEED |
23151 | 1852 read_doublespeed(priv); |
10704 | 1853 #else |
23151 | 1854 if (audio_in_read_chunk(&priv->audio_in, priv->audio_ringbuffer+priv->audio_tail*priv->audio_in.blocksize) < 0) |
1855 continue; | |
10704 | 1856 #endif |
23151 | 1857 pthread_mutex_lock(&priv->skew_mutex); |
1858 if (priv->first_frame == 0) { | |
1859 // there is no first frame yet (unlikely to happen) | |
1860 gettimeofday(&tv, NULL); | |
1861 start_time_avg = priv->audio_start_time = (long long)1e6*tv.tv_sec + tv.tv_usec; | |
1862 // fprintf(stderr, "warning - first frame not yet available!\n"); | |
1863 pthread_mutex_unlock(&priv->skew_mutex); | |
1864 continue; | |
1865 } | |
1866 pthread_mutex_unlock(&priv->skew_mutex); | |
10536 | 1867 |
23151 | 1868 gettimeofday(&tv, NULL); |
10536 | 1869 |
23151 | 1870 priv->audio_recv_blocks_total++; |
1871 current_time = (long long)1e6*tv.tv_sec + tv.tv_usec - priv->audio_start_time; | |
10536 | 1872 |
23151 | 1873 if (priv->audio_recv_blocks_total < priv->aud_skew_cnt*2) { |
1874 start_time_avg += (long long)1e6*tv.tv_sec + tv.tv_usec - priv->audio_usecs_per_block*priv->audio_recv_blocks_total; | |
1875 priv->audio_start_time = start_time_avg/(priv->audio_recv_blocks_total+1); | |
1876 } | |
10852 | 1877 |
32352
76f94c00a69f
1000l, %lf is not valid format string for printf (only for scanf) and actually
reimar
parents:
32141
diff
changeset
|
1878 // fprintf(stderr, "spb = %f, bs = %d, skew = %f\n", priv->audio_secs_per_block, priv->audio_in.blocksize, |
23151 | 1879 // (double)(current_time - 1e6*priv->audio_secs_per_block*priv->audio_recv_blocks_total)/1e6); |
10536 | 1880 |
23151 | 1881 // put the current skew into the ring buffer |
1882 priv->audio_skew_total -= priv->audio_skew_buffer[audio_skew_ptr]; | |
1883 priv->audio_skew_buffer[audio_skew_ptr] = current_time | |
1884 - priv->audio_usecs_per_block*priv->audio_recv_blocks_total; | |
1885 priv->audio_skew_total += priv->audio_skew_buffer[audio_skew_ptr]; | |
10536 | 1886 |
23151 | 1887 pthread_mutex_lock(&priv->skew_mutex); |
10704 | 1888 |
23151 | 1889 // skew calculation |
10704 | 1890 |
23151 | 1891 // compute the sliding average of the skews |
1892 if (priv->audio_recv_blocks_total > priv->aud_skew_cnt) { | |
1893 priv->audio_skew = priv->audio_skew_total/priv->aud_skew_cnt; | |
1894 } else { | |
1895 priv->audio_skew = priv->audio_skew_total/priv->audio_recv_blocks_total; | |
1896 } | |
10653 | 1897 |
23151 | 1898 // put the current skew change (skew-prev_skew) into the ring buffer |
1899 priv->audio_skew_delta_total -= priv->audio_skew_delta_buffer[audio_skew_ptr]; | |
1900 priv->audio_skew_delta_buffer[audio_skew_ptr] = priv->audio_skew - prev_skew_uncorr; | |
1901 priv->audio_skew_delta_total += priv->audio_skew_delta_buffer[audio_skew_ptr]; | |
1902 prev_skew_uncorr = priv->audio_skew; // remember the _uncorrected_ average value | |
10704 | 1903 |
23151 | 1904 audio_skew_ptr = (audio_skew_ptr+1) % priv->aud_skew_cnt; // rotate the buffer pointer |
10653 | 1905 |
23151 | 1906 // sliding average approximates the value in the middle of the interval |
1907 // so interpolate the skew value further to the current time | |
1908 priv->audio_skew += priv->audio_skew_delta_total/2; | |
10653 | 1909 |
23151 | 1910 // now finally, priv->audio_skew contains fairly good approximation |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1911 // of the current value |
10653 | 1912 |
23151 | 1913 // current skew factor (assuming linearity) |
1914 // used for further interpolation in video_grabber | |
1915 // probably overkill but seems to be necessary for | |
1916 // stress testing by dropping half of the audio frames ;) | |
1917 // especially when using ALSA with large block sizes | |
1918 // where audio_skew remains a long while behind | |
1919 if ((priv->audio_skew_measure_time != 0) && (current_time - priv->audio_skew_measure_time != 0)) { | |
1920 priv->audio_skew_factor = (double)(priv->audio_skew-prev_skew)/(current_time - priv->audio_skew_measure_time); | |
1921 } else { | |
1922 priv->audio_skew_factor = 0.0; | |
1923 } | |
10852 | 1924 |
23151 | 1925 priv->audio_skew_measure_time = current_time; |
1926 prev_skew = priv->audio_skew; | |
1927 priv->audio_skew += priv->audio_start_time - priv->first_frame; | |
1928 pthread_mutex_unlock(&priv->skew_mutex); | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1929 |
32352
76f94c00a69f
1000l, %lf is not valid format string for printf (only for scanf) and actually
reimar
parents:
32141
diff
changeset
|
1930 // fprintf(stderr, "audio_skew = %f, delta = %f\n", (double)priv->audio_skew/1e6, (double)priv->audio_skew_delta_total/1e6); |
10851 | 1931 |
23151 | 1932 pthread_mutex_lock(&priv->audio_mutex); |
1933 if ((priv->audio_tail+1) % priv->audio_buffer_size == priv->audio_head) { | |
1934 mp_msg(MSGT_TV, MSGL_ERR, "\ntoo bad - dropping audio frame !\n"); | |
1935 priv->audio_drop++; | |
1936 } else { | |
1937 priv->audio_tail = (priv->audio_tail+1) % priv->audio_buffer_size; | |
1938 priv->audio_cnt++; | |
1939 } | |
1940 pthread_mutex_unlock(&priv->audio_mutex); | |
10536 | 1941 } |
1942 return NULL; | |
1943 } | |
1944 | |
1945 static double grab_audio_frame(priv_t *priv, char *buffer, int len) | |
1946 { | |
1947 mp_dbg(MSGT_TV, MSGL_DBG2, "grab_audio_frame(priv=%p, buffer=%p, len=%d)\n", | |
23151 | 1948 priv, buffer, len); |
10536 | 1949 |
15449 | 1950 // hack: if grab_audio_frame is called first, it means we are used by mplayer |
1951 // => switch to the mode which outputs audio immediately, even if | |
1952 // it should be silence | |
1953 if (priv->first) priv->audio_insert_null_samples = 1; | |
1954 | |
1955 pthread_mutex_lock(&priv->audio_mutex); | |
1956 while (priv->audio_insert_null_samples | |
23151 | 1957 && priv->dropped_frames_timeshift - priv->dropped_frames_compensated >= priv->audio_usecs_per_block) { |
1958 // some frames were dropped - drop the corresponding number of audio blocks | |
1959 if (priv->audio_drop) { | |
1960 priv->audio_drop--; | |
1961 } else { | |
1962 if (priv->audio_head == priv->audio_tail) break; | |
1963 priv->audio_head = (priv->audio_head+1) % priv->audio_buffer_size; | |
1964 } | |
1965 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
|
1966 } |
80402283a017
Fix immediatemode with mplayer (ie playing both sound and video)
albeu
parents:
10735
diff
changeset
|
1967 |
10536 | 1968 // compensate for dropped audio frames |
1969 if (priv->audio_drop && (priv->audio_head == priv->audio_tail)) { | |
23151 | 1970 priv->audio_drop--; |
1971 memset(buffer, 0, len); | |
1972 goto out; | |
10536 | 1973 } |
1974 | |
15449 | 1975 if (priv->audio_insert_null_samples && (priv->audio_head == priv->audio_tail)) { |
23151 | 1976 // return silence to avoid desync and stuttering |
1977 memset(buffer, 0, len); | |
1978 priv->audio_null_blocks_inserted++; | |
1979 goto out; | |
15449 | 1980 } |
1981 | |
1982 pthread_mutex_unlock(&priv->audio_mutex); | |
10536 | 1983 while (priv->audio_head == priv->audio_tail) { |
23151 | 1984 // this is mencoder => just wait until some audio is available |
1985 usleep(10000); | |
10536 | 1986 } |
15451 | 1987 pthread_mutex_lock(&priv->audio_mutex); |
10536 | 1988 memcpy(buffer, priv->audio_ringbuffer+priv->audio_head*priv->audio_in.blocksize, len); |
1989 priv->audio_head = (priv->audio_head+1) % priv->audio_buffer_size; | |
1990 priv->audio_cnt--; | |
15449 | 1991 out: |
1992 pthread_mutex_unlock(&priv->audio_mutex); | |
10536 | 1993 priv->audio_sent_blocks_total++; |
1994 return (double)priv->audio_sent_blocks_total*priv->audio_secs_per_block; | |
1995 } | |
1996 | |
1997 static int get_audio_framesize(priv_t *priv) | |
1998 { | |
26756
c43ce7268677
cosmetics: Remove useless parentheses from return statements.
diego
parents:
25962
diff
changeset
|
1999 return priv->audio_in.blocksize; |
10536 | 2000 } |