Mercurial > mplayer.hg
annotate stream/tvi_v4l2.c @ 33526:140525bcc32f
Fix GUI icon bug.
The GUI icon did not display properly but showed up with various distortions.
The reason was the icon mask which hadn't been put to the X server yet when
used.
The icon itself was okay, but is rendered now in a way that doesn't need a
drawable which spares creating a GTK window and destroying it right after.
The locally used GDK variables have been moved inside the function where
they are needed.
Patch with grateful support by Steaphan Greene, sgreene cs.binghamton edu.
This closes Bugzilla #582.
author | ib |
---|---|
date | Tue, 14 Jun 2011 17:51:17 +0000 |
parents | d941d34d5b0f |
children | c15dabfa2380 |
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 { | |
1379 int bufsize, cnt; | |
1380 | |
23886 | 1381 if (priv->tv_param->buffer_size >= 0) { |
1382 bufsize = priv->tv_param->buffer_size*1024*1024; | |
10536 | 1383 } else { |
1384 #ifdef HAVE_SYS_SYSINFO_H | |
23151 | 1385 struct sysinfo si; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1386 |
23151 | 1387 sysinfo(&si); |
1388 if (si.totalram<2*1024*1024) { | |
1389 bufsize = 1024*1024; | |
1390 } else { | |
1391 bufsize = si.totalram/2; | |
1392 } | |
10536 | 1393 #else |
23151 | 1394 bufsize = 16*1024*1024; |
10536 | 1395 #endif |
1396 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1397 |
23423 | 1398 cnt = bufsize/priv->format.fmt.pix.sizeimage; |
10536 | 1399 if (cnt < 2) cnt = 2; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1400 |
10536 | 1401 return cnt; |
1402 } | |
1403 | |
1404 /* that's the real start, we'got the format parameters (checked with control) */ | |
1405 static int start(priv_t *priv) | |
1406 { | |
1407 struct v4l2_requestbuffers request; | |
24346 | 1408 unsigned int i; |
10536 | 1409 |
1410 /* setup audio parameters */ | |
1411 | |
15464 | 1412 init_audio(priv); |
25962 | 1413 if (!priv->tv_param->noaudio && !priv->audio_initialized) return 0; |
15464 | 1414 |
10536 | 1415 /* we need this to size the audio buffer properly */ |
1416 if (priv->immediate_mode) { | |
23151 | 1417 priv->video_buffer_size_max = 2; |
10536 | 1418 } else { |
23151 | 1419 priv->video_buffer_size_max = get_capture_buffer_size(priv); |
10536 | 1420 } |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1421 |
23886 | 1422 if (!priv->tv_param->noaudio) { |
23151 | 1423 setup_audio_buffer_sizes(priv); |
1424 priv->audio_skew_buffer = calloc(priv->aud_skew_cnt, sizeof(long long)); | |
1425 if (!priv->audio_skew_buffer) { | |
1426 mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate skew buffer: %s\n", strerror(errno)); | |
1427 return 0; | |
1428 } | |
1429 priv->audio_skew_delta_buffer = calloc(priv->aud_skew_cnt, sizeof(long long)); | |
1430 if (!priv->audio_skew_delta_buffer) { | |
1431 mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate skew buffer: %s\n", strerror(errno)); | |
1432 return 0; | |
1433 } | |
10536 | 1434 |
23151 | 1435 priv->audio_ringbuffer = calloc(priv->audio_in.blocksize, priv->audio_buffer_size); |
1436 if (!priv->audio_ringbuffer) { | |
1437 mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate audio buffer: %s\n", strerror(errno)); | |
1438 return 0; | |
1439 } | |
10536 | 1440 |
23151 | 1441 priv->audio_secs_per_block = (double)priv->audio_in.blocksize/(priv->audio_in.samplerate |
1442 *priv->audio_in.channels | |
1443 *priv->audio_in.bytes_per_sample); | |
1444 priv->audio_usecs_per_block = 1e6*priv->audio_secs_per_block; | |
1445 priv->audio_head = 0; | |
1446 priv->audio_tail = 0; | |
1447 priv->audio_cnt = 0; | |
1448 priv->audio_drop = 0; | |
1449 priv->audio_skew = 0; | |
1450 priv->audio_skew_total = 0; | |
1451 priv->audio_skew_delta_total = 0; | |
1452 priv->audio_recv_blocks_total = 0; | |
1453 priv->audio_sent_blocks_total = 0; | |
1454 priv->audio_null_blocks_inserted = 0; | |
1455 priv->audio_insert_null_samples = 0; | |
1456 priv->dropped_frames_timeshift = 0; | |
1457 priv->dropped_frames_compensated = 0; | |
15449 | 1458 |
23151 | 1459 pthread_mutex_init(&priv->skew_mutex, NULL); |
1460 pthread_mutex_init(&priv->audio_mutex, NULL); | |
10536 | 1461 } |
1462 | |
1463 /* setup video parameters */ | |
23886 | 1464 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
|
1465 if (priv->video_buffer_size_max < 3*getfps(priv)*priv->audio_secs_per_block) { |
23151 | 1466 mp_msg(MSGT_TV, MSGL_ERR, "Video buffer shorter than 3 times audio frame duration.\n" |
1467 "You will probably experience heavy framedrops.\n"); | |
1468 } | |
10536 | 1469 } |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1470 |
10536 | 1471 { |
23151 | 1472 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
|
1473 |
23151 | 1474 mp_msg(MSGT_TV, MSGL_V, "Using a ring buffer for maximum %d frames, %d MB total size.\n", |
1475 priv->video_buffer_size_max, | |
1476 priv->video_buffer_size_max*priv->format.fmt.pix.height*bytesperline/(1024*1024)); | |
10536 | 1477 } |
1478 | |
23423 | 1479 priv->video_ringbuffer = calloc(priv->video_buffer_size_max, sizeof(video_buffer_entry)); |
10536 | 1480 if (!priv->video_ringbuffer) { |
23151 | 1481 mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate video buffer: %s\n", strerror(errno)); |
1482 return 0; | |
10536 | 1483 } |
23423 | 1484 memset(priv->video_ringbuffer,0,priv->video_buffer_size_max * sizeof(video_buffer_entry)); |
10536 | 1485 |
15449 | 1486 pthread_mutex_init(&priv->video_buffer_mutex, NULL); |
1487 | |
10536 | 1488 priv->video_head = 0; |
1489 priv->video_tail = 0; | |
1490 priv->video_cnt = 0; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1491 |
10536 | 1492 /* request buffers */ |
1493 if (priv->immediate_mode) { | |
23151 | 1494 request.count = 2; |
10536 | 1495 } else { |
23151 | 1496 request.count = BUFFER_COUNT; |
10536 | 1497 } |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1498 |
10536 | 1499 request.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
1500 request.memory = V4L2_MEMORY_MMAP; | |
1501 if (ioctl(priv->video_fd, VIDIOC_REQBUFS, &request) < 0) { | |
23151 | 1502 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl request buffers failed: %s\n", |
1503 info.short_name, strerror(errno)); | |
1504 return 0; | |
10536 | 1505 } |
1506 | |
1507 /* query buffers */ | |
18558
4928dd61f136
Fix potential integer overflows in memory allocation.
rtogni
parents:
18176
diff
changeset
|
1508 if (!(priv->map = calloc(request.count, sizeof(struct map)))) { |
23151 | 1509 mp_msg(MSGT_TV, MSGL_ERR, "%s: malloc capture buffers failed: %s\n", |
1510 info.short_name, strerror(errno)); | |
1511 return 0; | |
10536 | 1512 } |
1513 | |
1514 /* map and queue buffers */ | |
1515 for (i = 0; i < request.count; i++) { | |
23151 | 1516 memset(&priv->map[i].buf,0,sizeof(priv->map[i].buf)); |
1517 priv->map[i].buf.index = i; | |
1518 priv->map[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
1519 priv->map[i].buf.memory = V4L2_MEMORY_MMAP; | |
1520 if (ioctl(priv->video_fd, VIDIOC_QUERYBUF, &(priv->map[i].buf)) < 0) { | |
1521 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query buffer failed: %s\n", | |
1522 info.short_name, strerror(errno)); | |
1523 free(priv->map); | |
1524 priv->map = NULL; | |
1525 return 0; | |
1526 } | |
1527 priv->map[i].addr = mmap (0, priv->map[i].buf.length, PROT_READ | | |
1528 PROT_WRITE, MAP_SHARED, priv->video_fd, priv->map[i].buf.m.offset); | |
1529 if (priv->map[i].addr == MAP_FAILED) { | |
1530 mp_msg(MSGT_TV, MSGL_ERR, "%s: mmap capture buffer failed: %s\n", | |
1531 info.short_name, strerror(errno)); | |
1532 priv->map[i].len = 0; | |
1533 return 0; | |
1534 } | |
1535 priv->map[i].len = priv->map[i].buf.length; | |
1536 /* count up to make sure this is correct everytime */ | |
1537 priv->mapcount++; | |
10536 | 1538 |
23151 | 1539 if (ioctl(priv->video_fd, VIDIOC_QBUF, &(priv->map[i].buf)) < 0) { |
1540 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl queue buffer failed: %s\n", | |
1541 info.short_name, strerror(errno)); | |
1542 return 0; | |
1543 } | |
10536 | 1544 } |
1545 | |
23901 | 1546 /* start vbi thread */ |
1547 if(priv->priv_vbi){ | |
1548 priv->vbi_shutdown = 0; | |
1549 pthread_create(&priv->vbi_grabber_thread, NULL, vbi_grabber, priv); | |
1550 } | |
10536 | 1551 /* start audio thread */ |
1552 priv->shutdown = 0; | |
1553 priv->audio_skew_measure_time = 0; | |
1554 priv->first_frame = 0; | |
1555 priv->audio_skew = 0; | |
1556 priv->first = 1; | |
1557 | |
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
|
1558 set_mute(priv, 0); |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1559 |
10536 | 1560 return 1; |
1561 } | |
1562 | |
1563 // copies a video frame | |
23423 | 1564 static inline void copy_frame(priv_t *priv, video_buffer_entry *dest, unsigned char *source,int len) |
10536 | 1565 { |
23423 | 1566 dest->framesize=len; |
23886 | 1567 if(priv->tv_param->automute>0){ |
23422 | 1568 if (ioctl(priv->video_fd, VIDIOC_G_TUNER, &priv->tuner) >= 0) { |
23886 | 1569 if(priv->tv_param->automute<<8>priv->tuner.signal){ |
23423 | 1570 fill_blank_frame(dest->data,dest->framesize,fcc_vl2mp(priv->format.fmt.pix.pixelformat)); |
23422 | 1571 set_mute(priv,1); |
1572 return; | |
1573 } | |
1574 } | |
1575 set_mute(priv,0); | |
1576 } | |
23423 | 1577 memcpy(dest->data, source, len); |
10536 | 1578 } |
1579 | |
1580 // maximum skew change, in frames | |
1581 #define MAX_SKEW_DELTA 0.6 | |
1582 static void *video_grabber(void *data) | |
1583 { | |
1584 priv_t *priv = (priv_t*)data; | |
15449 | 1585 long long skew, prev_skew, xskew, interval, prev_interval, delta; |
10536 | 1586 int i; |
23423 | 1587 int framesize = priv->format.fmt.pix.sizeimage; |
10536 | 1588 fd_set rdset; |
1589 struct timeval timeout; | |
1590 struct v4l2_buffer buf; | |
1591 | |
1592 xskew = 0; | |
1593 skew = 0; | |
1594 interval = 0; | |
1595 prev_interval = 0; | |
1596 prev_skew = 0; | |
1597 | |
1598 mp_msg(MSGT_TV, MSGL_V, "%s: going to capture\n", info.short_name); | |
1599 if (ioctl(priv->video_fd, VIDIOC_STREAMON, &(priv->format.type)) < 0) { | |
23151 | 1600 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl streamon failed: %s\n", |
1601 info.short_name, strerror(errno)); | |
1602 return 0; | |
10536 | 1603 } |
1604 priv->streamon = 1; | |
1605 | |
23886 | 1606 if (!priv->tv_param->noaudio) { |
23151 | 1607 pthread_create(&priv->audio_grabber_thread, NULL, audio_grabber, priv); |
10536 | 1608 } |
1609 | |
1610 for (priv->frames = 0; !priv->shutdown;) | |
1611 { | |
23151 | 1612 int ret; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1613 |
23151 | 1614 if (priv->immediate_mode) { |
1615 while (priv->video_cnt == priv->video_buffer_size_max) { | |
1616 usleep(10000); | |
1617 if (priv->shutdown) { | |
1618 return NULL; | |
1619 } | |
1620 } | |
1621 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1622 |
23151 | 1623 FD_ZERO (&rdset); |
1624 FD_SET (priv->video_fd, &rdset); | |
10536 | 1625 |
23151 | 1626 timeout.tv_sec = 1; |
1627 timeout.tv_usec = 0; | |
10536 | 1628 |
23151 | 1629 i = select(priv->video_fd + 1, &rdset, NULL, NULL, &timeout); |
1630 if (i < 0) { | |
1631 mp_msg(MSGT_TV, MSGL_ERR, "%s: select failed: %s\n", | |
1632 info.short_name, strerror(errno)); | |
1633 continue; | |
1634 } | |
1635 else if (i == 0) { | |
1636 mp_msg(MSGT_TV, MSGL_ERR, "%s: select timeout\n", info.short_name); | |
1637 continue; | |
1638 } | |
1639 else if (!FD_ISSET(priv->video_fd, &rdset)) { | |
1640 continue; | |
1641 } | |
10536 | 1642 |
23151 | 1643 memset(&buf,0,sizeof(buf)); |
1644 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
1645 buf.memory = V4L2_MEMORY_MMAP; | |
1646 ret = ioctl(priv->video_fd, VIDIOC_DQBUF, &buf); | |
10536 | 1647 |
23151 | 1648 if (ret < 0) { |
1649 /* | |
1650 if there's no signal, the buffer might me dequeued | |
1651 so we query all the buffers to see which one we should | |
1652 put back to queue | |
10536 | 1653 |
23151 | 1654 observed with saa7134 0.2.8 |
1655 don't know if is it a bug or (mis)feature | |
1656 */ | |
1657 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl dequeue buffer failed: %s, idx = %d\n", | |
1658 info.short_name, strerror(errno), buf.index); | |
1659 for (i = 0; i < priv->mapcount; i++) { | |
1660 memset(&buf,0,sizeof(buf)); | |
1661 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
1662 buf.memory = V4L2_MEMORY_MMAP; | |
1663 buf.index = i; | |
1664 ret = ioctl(priv->video_fd, VIDIOC_QUERYBUF, &buf); | |
1665 if (ret < 0) { | |
1666 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query buffer failed: %s, idx = %d\n", | |
1667 info.short_name, strerror(errno), buf.index); | |
1668 return 0; | |
1669 } | |
1670 if ((buf.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE)) == V4L2_BUF_FLAG_MAPPED) { | |
1671 if (ioctl(priv->video_fd, VIDIOC_QBUF, &(priv->map[i].buf)) < 0) { | |
1672 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl queue buffer failed: %s\n", | |
1673 info.short_name, strerror(errno)); | |
1674 return 0; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1675 } |
23151 | 1676 } |
1677 } | |
1678 continue; | |
1679 } | |
10536 | 1680 |
23151 | 1681 /* store the timestamp of the very first frame as reference */ |
1682 if (!priv->frames++) { | |
23886 | 1683 if (!priv->tv_param->noaudio) pthread_mutex_lock(&priv->skew_mutex); |
23151 | 1684 priv->first_frame = (long long)1e6*buf.timestamp.tv_sec + buf.timestamp.tv_usec; |
23886 | 1685 if (!priv->tv_param->noaudio) pthread_mutex_unlock(&priv->skew_mutex); |
23151 | 1686 } |
1687 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
|
1688 // fprintf(stderr, "idx = %d, ts = %f\n", buf.index, (double)(priv->curr_frame) / 1e6); |
10536 | 1689 |
23151 | 1690 interval = priv->curr_frame - priv->first_frame; |
1691 delta = interval - prev_interval; | |
10536 | 1692 |
23151 | 1693 if (!priv->immediate_mode) { |
1694 // interpolate the skew in time | |
23886 | 1695 if (!priv->tv_param->noaudio) pthread_mutex_lock(&priv->skew_mutex); |
23151 | 1696 xskew = priv->audio_skew + (interval - priv->audio_skew_measure_time)*priv->audio_skew_factor; |
23886 | 1697 if (!priv->tv_param->noaudio) pthread_mutex_unlock(&priv->skew_mutex); |
23151 | 1698 // correct extreme skew changes to avoid (especially) moving backwards in time |
1699 if (xskew - prev_skew > delta*MAX_SKEW_DELTA) { | |
1700 skew = prev_skew + delta*MAX_SKEW_DELTA; | |
1701 } else if (xskew - prev_skew < -delta*MAX_SKEW_DELTA) { | |
1702 skew = prev_skew - delta*MAX_SKEW_DELTA; | |
1703 } else { | |
1704 skew = xskew; | |
1705 } | |
1706 } | |
10536 | 1707 |
32352
76f94c00a69f
1000l, %lf is not valid format string for printf (only for scanf) and actually
reimar
parents:
32141
diff
changeset
|
1708 mp_msg(MSGT_TV, MSGL_DBG3, "\nfps = %f, interval = %f, a_skew = %f, corr_skew = %f\n", |
23151 | 1709 delta ? (double)1e6/delta : -1, |
1710 (double)1e-6*interval, (double)1e-6*xskew, (double)1e-6*skew); | |
1711 mp_msg(MSGT_TV, MSGL_DBG3, "vcnt = %d, acnt = %d\n", priv->video_cnt, priv->audio_cnt); | |
10536 | 1712 |
23151 | 1713 prev_skew = skew; |
1714 prev_interval = interval; | |
10536 | 1715 |
23151 | 1716 /* allocate a new buffer, if needed */ |
1717 pthread_mutex_lock(&priv->video_buffer_mutex); | |
1718 if (priv->video_buffer_size_current < priv->video_buffer_size_max) { | |
1719 if (priv->video_cnt == priv->video_buffer_size_current) { | |
1720 unsigned char *newbuf = malloc(framesize); | |
1721 if (newbuf) { | |
1722 memmove(priv->video_ringbuffer+priv->video_tail+1, priv->video_ringbuffer+priv->video_tail, | |
23423 | 1723 (priv->video_buffer_size_current-priv->video_tail)*sizeof(video_buffer_entry)); |
1724 priv->video_ringbuffer[priv->video_tail].data = newbuf; | |
23151 | 1725 if ((priv->video_head >= priv->video_tail) && (priv->video_cnt > 0)) priv->video_head++; |
1726 priv->video_buffer_size_current++; | |
1727 } | |
1728 } | |
1729 } | |
1730 pthread_mutex_unlock(&priv->video_buffer_mutex); | |
10536 | 1731 |
23151 | 1732 if (priv->video_cnt == priv->video_buffer_size_current) { |
1733 if (!priv->immediate_mode) { | |
1734 mp_msg(MSGT_TV, MSGL_ERR, "\nvideo buffer full - dropping frame\n"); | |
1735 if (priv->audio_insert_null_samples) { | |
1736 pthread_mutex_lock(&priv->audio_mutex); | |
1737 priv->dropped_frames_timeshift += delta; | |
1738 pthread_mutex_unlock(&priv->audio_mutex); | |
1739 } | |
1740 } | |
1741 } else { | |
1742 if (priv->immediate_mode) { | |
23423 | 1743 priv->video_ringbuffer[priv->video_tail].timestamp = 0; |
23151 | 1744 } else { |
1745 // compensate for audio skew | |
1746 // negative skew => there are more audio samples, increase interval | |
1747 // positive skew => less samples, shorten the interval | |
23423 | 1748 priv->video_ringbuffer[priv->video_tail].timestamp = interval - skew; |
1749 if (priv->audio_insert_null_samples && priv->video_ringbuffer[priv->video_tail].timestamp > 0) { | |
23151 | 1750 pthread_mutex_lock(&priv->audio_mutex); |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1751 priv->video_ringbuffer[priv->video_tail].timestamp += |
23151 | 1752 (priv->audio_null_blocks_inserted |
1753 - priv->dropped_frames_timeshift/priv->audio_usecs_per_block) | |
1754 *priv->audio_usecs_per_block; | |
1755 pthread_mutex_unlock(&priv->audio_mutex); | |
1756 } | |
1757 } | |
23423 | 1758 copy_frame(priv, priv->video_ringbuffer+priv->video_tail, priv->map[buf.index].addr,buf.bytesused); |
23151 | 1759 priv->video_tail = (priv->video_tail+1)%priv->video_buffer_size_current; |
1760 priv->video_cnt++; | |
1761 } | |
1762 if (ioctl(priv->video_fd, VIDIOC_QBUF, &buf) < 0) { | |
1763 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl queue buffer failed: %s\n", | |
1764 info.short_name, strerror(errno)); | |
1765 return 0; | |
1766 } | |
10536 | 1767 } |
1768 return NULL; | |
1769 } | |
1770 | |
16962
bdc218b5a49a
Do not hang forever when the card delivers no new data.
reimar
parents:
16536
diff
changeset
|
1771 #define MAX_LOOP 50 |
10536 | 1772 static double grab_video_frame(priv_t *priv, char *buffer, int len) |
1773 { | |
1774 double interval; | |
16962
bdc218b5a49a
Do not hang forever when the card delivers no new data.
reimar
parents:
16536
diff
changeset
|
1775 int loop_cnt = 0; |
10536 | 1776 |
1777 if (priv->first) { | |
23151 | 1778 pthread_create(&priv->video_grabber_thread, NULL, video_grabber, priv); |
1779 priv->first = 0; | |
10536 | 1780 } |
1781 | |
1782 while (priv->video_cnt == 0) { | |
23151 | 1783 usleep(10000); |
1784 if (loop_cnt++ > MAX_LOOP) return 0; | |
10536 | 1785 } |
1786 | |
1787 pthread_mutex_lock(&priv->video_buffer_mutex); | |
23423 | 1788 interval = (double)priv->video_ringbuffer[priv->video_head].timestamp*1e-6; |
1789 memcpy(buffer, priv->video_ringbuffer[priv->video_head].data, len); | |
10536 | 1790 priv->video_cnt--; |
1791 priv->video_head = (priv->video_head+1)%priv->video_buffer_size_current; | |
1792 pthread_mutex_unlock(&priv->video_buffer_mutex); | |
1793 | |
1794 return interval; | |
1795 } | |
1796 | |
1797 static int get_video_framesize(priv_t *priv) | |
1798 { | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1799 /* |
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1800 this routine will be called before grab_video_frame |
23423 | 1801 thus let's return topmost frame's size |
1802 */ | |
1803 if (priv->video_cnt) | |
1804 return priv->video_ringbuffer[priv->video_head].framesize; | |
1805 /* | |
1806 no video frames yet available. i don't know what to do in this case, | |
1807 thus let's return some fallback result (for compressed format this will be | |
1808 maximum allowed frame size. | |
1809 */ | |
10536 | 1810 return priv->format.fmt.pix.sizeimage; |
1811 } | |
1812 | |
10704 | 1813 //#define DOUBLESPEED |
1814 #ifdef DOUBLESPEED | |
10536 | 1815 // for testing purposes only |
1816 static void read_doublespeed(priv_t *priv) | |
1817 { | |
18885 | 1818 char *bufx = calloc(priv->audio_in.blocksize, 2); |
10536 | 1819 short *s; |
1820 short *d; | |
1821 int i; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1822 |
10536 | 1823 audio_in_read_chunk(&priv->audio_in, bufx); |
1824 audio_in_read_chunk(&priv->audio_in, bufx+priv->audio_in.blocksize); | |
1825 | |
1826 s = bufx; | |
1827 d = priv->audio_ringbuffer+priv->audio_tail*priv->audio_in.blocksize; | |
1828 for (i = 0; i < priv->audio_in.blocksize/2; i++) { | |
23151 | 1829 *d++ = *s++; |
1830 *s++; | |
10536 | 1831 } |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1832 |
10536 | 1833 } |
10704 | 1834 #endif |
10536 | 1835 |
1836 static void *audio_grabber(void *data) | |
1837 { | |
1838 priv_t *priv = (priv_t*)data; | |
1839 struct timeval tv; | |
1840 int i, audio_skew_ptr = 0; | |
10653 | 1841 long long current_time, prev_skew = 0, prev_skew_uncorr = 0; |
10852 | 1842 long long start_time_avg; |
10536 | 1843 |
1844 gettimeofday(&tv, NULL); | |
10852 | 1845 start_time_avg = priv->audio_start_time = (long long)1e6*tv.tv_sec + tv.tv_usec; |
10536 | 1846 audio_in_start_capture(&priv->audio_in); |
1847 for (i = 0; i < priv->aud_skew_cnt; i++) | |
23151 | 1848 priv->audio_skew_buffer[i] = 0; |
10653 | 1849 for (i = 0; i < priv->aud_skew_cnt; i++) |
23151 | 1850 priv->audio_skew_delta_buffer[i] = 0; |
10536 | 1851 |
1852 for (; !priv->shutdown;) | |
1853 { | |
10704 | 1854 #ifdef DOUBLESPEED |
23151 | 1855 read_doublespeed(priv); |
10704 | 1856 #else |
23151 | 1857 if (audio_in_read_chunk(&priv->audio_in, priv->audio_ringbuffer+priv->audio_tail*priv->audio_in.blocksize) < 0) |
1858 continue; | |
10704 | 1859 #endif |
23151 | 1860 pthread_mutex_lock(&priv->skew_mutex); |
1861 if (priv->first_frame == 0) { | |
1862 // there is no first frame yet (unlikely to happen) | |
1863 gettimeofday(&tv, NULL); | |
1864 start_time_avg = priv->audio_start_time = (long long)1e6*tv.tv_sec + tv.tv_usec; | |
1865 // fprintf(stderr, "warning - first frame not yet available!\n"); | |
1866 pthread_mutex_unlock(&priv->skew_mutex); | |
1867 continue; | |
1868 } | |
1869 pthread_mutex_unlock(&priv->skew_mutex); | |
10536 | 1870 |
23151 | 1871 gettimeofday(&tv, NULL); |
10536 | 1872 |
23151 | 1873 priv->audio_recv_blocks_total++; |
1874 current_time = (long long)1e6*tv.tv_sec + tv.tv_usec - priv->audio_start_time; | |
10536 | 1875 |
23151 | 1876 if (priv->audio_recv_blocks_total < priv->aud_skew_cnt*2) { |
1877 start_time_avg += (long long)1e6*tv.tv_sec + tv.tv_usec - priv->audio_usecs_per_block*priv->audio_recv_blocks_total; | |
1878 priv->audio_start_time = start_time_avg/(priv->audio_recv_blocks_total+1); | |
1879 } | |
10852 | 1880 |
32352
76f94c00a69f
1000l, %lf is not valid format string for printf (only for scanf) and actually
reimar
parents:
32141
diff
changeset
|
1881 // fprintf(stderr, "spb = %f, bs = %d, skew = %f\n", priv->audio_secs_per_block, priv->audio_in.blocksize, |
23151 | 1882 // (double)(current_time - 1e6*priv->audio_secs_per_block*priv->audio_recv_blocks_total)/1e6); |
10536 | 1883 |
23151 | 1884 // put the current skew into the ring buffer |
1885 priv->audio_skew_total -= priv->audio_skew_buffer[audio_skew_ptr]; | |
1886 priv->audio_skew_buffer[audio_skew_ptr] = current_time | |
1887 - priv->audio_usecs_per_block*priv->audio_recv_blocks_total; | |
1888 priv->audio_skew_total += priv->audio_skew_buffer[audio_skew_ptr]; | |
10536 | 1889 |
23151 | 1890 pthread_mutex_lock(&priv->skew_mutex); |
10704 | 1891 |
23151 | 1892 // skew calculation |
10704 | 1893 |
23151 | 1894 // compute the sliding average of the skews |
1895 if (priv->audio_recv_blocks_total > priv->aud_skew_cnt) { | |
1896 priv->audio_skew = priv->audio_skew_total/priv->aud_skew_cnt; | |
1897 } else { | |
1898 priv->audio_skew = priv->audio_skew_total/priv->audio_recv_blocks_total; | |
1899 } | |
10653 | 1900 |
23151 | 1901 // put the current skew change (skew-prev_skew) into the ring buffer |
1902 priv->audio_skew_delta_total -= priv->audio_skew_delta_buffer[audio_skew_ptr]; | |
1903 priv->audio_skew_delta_buffer[audio_skew_ptr] = priv->audio_skew - prev_skew_uncorr; | |
1904 priv->audio_skew_delta_total += priv->audio_skew_delta_buffer[audio_skew_ptr]; | |
1905 prev_skew_uncorr = priv->audio_skew; // remember the _uncorrected_ average value | |
10704 | 1906 |
23151 | 1907 audio_skew_ptr = (audio_skew_ptr+1) % priv->aud_skew_cnt; // rotate the buffer pointer |
10653 | 1908 |
23151 | 1909 // sliding average approximates the value in the middle of the interval |
1910 // so interpolate the skew value further to the current time | |
1911 priv->audio_skew += priv->audio_skew_delta_total/2; | |
10653 | 1912 |
23151 | 1913 // now finally, priv->audio_skew contains fairly good approximation |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1914 // of the current value |
10653 | 1915 |
23151 | 1916 // current skew factor (assuming linearity) |
1917 // used for further interpolation in video_grabber | |
1918 // probably overkill but seems to be necessary for | |
1919 // stress testing by dropping half of the audio frames ;) | |
1920 // especially when using ALSA with large block sizes | |
1921 // where audio_skew remains a long while behind | |
1922 if ((priv->audio_skew_measure_time != 0) && (current_time - priv->audio_skew_measure_time != 0)) { | |
1923 priv->audio_skew_factor = (double)(priv->audio_skew-prev_skew)/(current_time - priv->audio_skew_measure_time); | |
1924 } else { | |
1925 priv->audio_skew_factor = 0.0; | |
1926 } | |
10852 | 1927 |
23151 | 1928 priv->audio_skew_measure_time = current_time; |
1929 prev_skew = priv->audio_skew; | |
1930 priv->audio_skew += priv->audio_start_time - priv->first_frame; | |
1931 pthread_mutex_unlock(&priv->skew_mutex); | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29121
diff
changeset
|
1932 |
32352
76f94c00a69f
1000l, %lf is not valid format string for printf (only for scanf) and actually
reimar
parents:
32141
diff
changeset
|
1933 // fprintf(stderr, "audio_skew = %f, delta = %f\n", (double)priv->audio_skew/1e6, (double)priv->audio_skew_delta_total/1e6); |
10851 | 1934 |
23151 | 1935 pthread_mutex_lock(&priv->audio_mutex); |
1936 if ((priv->audio_tail+1) % priv->audio_buffer_size == priv->audio_head) { | |
1937 mp_msg(MSGT_TV, MSGL_ERR, "\ntoo bad - dropping audio frame !\n"); | |
1938 priv->audio_drop++; | |
1939 } else { | |
1940 priv->audio_tail = (priv->audio_tail+1) % priv->audio_buffer_size; | |
1941 priv->audio_cnt++; | |
1942 } | |
1943 pthread_mutex_unlock(&priv->audio_mutex); | |
10536 | 1944 } |
1945 return NULL; | |
1946 } | |
1947 | |
1948 static double grab_audio_frame(priv_t *priv, char *buffer, int len) | |
1949 { | |
1950 mp_dbg(MSGT_TV, MSGL_DBG2, "grab_audio_frame(priv=%p, buffer=%p, len=%d)\n", | |
23151 | 1951 priv, buffer, len); |
10536 | 1952 |
15449 | 1953 // hack: if grab_audio_frame is called first, it means we are used by mplayer |
1954 // => switch to the mode which outputs audio immediately, even if | |
1955 // it should be silence | |
1956 if (priv->first) priv->audio_insert_null_samples = 1; | |
1957 | |
1958 pthread_mutex_lock(&priv->audio_mutex); | |
1959 while (priv->audio_insert_null_samples | |
23151 | 1960 && priv->dropped_frames_timeshift - priv->dropped_frames_compensated >= priv->audio_usecs_per_block) { |
1961 // some frames were dropped - drop the corresponding number of audio blocks | |
1962 if (priv->audio_drop) { | |
1963 priv->audio_drop--; | |
1964 } else { | |
1965 if (priv->audio_head == priv->audio_tail) break; | |
1966 priv->audio_head = (priv->audio_head+1) % priv->audio_buffer_size; | |
1967 } | |
1968 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
|
1969 } |
80402283a017
Fix immediatemode with mplayer (ie playing both sound and video)
albeu
parents:
10735
diff
changeset
|
1970 |
10536 | 1971 // compensate for dropped audio frames |
1972 if (priv->audio_drop && (priv->audio_head == priv->audio_tail)) { | |
23151 | 1973 priv->audio_drop--; |
1974 memset(buffer, 0, len); | |
1975 goto out; | |
10536 | 1976 } |
1977 | |
15449 | 1978 if (priv->audio_insert_null_samples && (priv->audio_head == priv->audio_tail)) { |
23151 | 1979 // return silence to avoid desync and stuttering |
1980 memset(buffer, 0, len); | |
1981 priv->audio_null_blocks_inserted++; | |
1982 goto out; | |
15449 | 1983 } |
1984 | |
1985 pthread_mutex_unlock(&priv->audio_mutex); | |
10536 | 1986 while (priv->audio_head == priv->audio_tail) { |
23151 | 1987 // this is mencoder => just wait until some audio is available |
1988 usleep(10000); | |
10536 | 1989 } |
15451 | 1990 pthread_mutex_lock(&priv->audio_mutex); |
10536 | 1991 memcpy(buffer, priv->audio_ringbuffer+priv->audio_head*priv->audio_in.blocksize, len); |
1992 priv->audio_head = (priv->audio_head+1) % priv->audio_buffer_size; | |
1993 priv->audio_cnt--; | |
15449 | 1994 out: |
1995 pthread_mutex_unlock(&priv->audio_mutex); | |
10536 | 1996 priv->audio_sent_blocks_total++; |
1997 return (double)priv->audio_sent_blocks_total*priv->audio_secs_per_block; | |
1998 } | |
1999 | |
2000 static int get_audio_framesize(priv_t *priv) | |
2001 { | |
26756
c43ce7268677
cosmetics: Remove useless parentheses from return statements.
diego
parents:
25962
diff
changeset
|
2002 return priv->audio_in.blocksize; |
10536 | 2003 } |