contrib: soxr: enable by default
[vlc.git] / modules / access / linsys / linsys_hdsdi.c
bloba9573ba7149b09ea88c14c7701dccf3de7a61f6e
1 /*****************************************************************************
2 * linsys_hdsdi.c: HDSDI capture for Linear Systems/Computer Modules cards
3 *****************************************************************************
4 * Copyright (C) 2010-2011 VideoLAN
6 * Authors: Christophe Massiot <massiot@via.ecp.fr>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
27 /*****************************************************************************
28 * Preamble
29 *****************************************************************************/
30 #include <poll.h>
31 #include <sys/mman.h>
32 #include <sys/ioctl.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <sys/eventfd.h>
36 #include <fcntl.h>
37 #include <errno.h>
39 #include <vlc_common.h>
40 #include <vlc_plugin.h>
42 #include <vlc_input.h>
43 #include <vlc_access.h>
44 #include <vlc_demux.h>
46 #include <vlc_fs.h>
48 #include "linsys_sdivideo.h"
49 #include "linsys_sdiaudio.h"
51 #undef HAVE_MMAP_SDIVIDEO
52 #undef HAVE_MMAP_SDIAUDIO
54 #define SDIVIDEO_DEVICE "/dev/sdivideorx%u"
55 #define SDIVIDEO_BUFFERS_FILE "/sys/class/sdivideo/sdivideorx%u/buffers"
56 #define SDIVIDEO_BUFSIZE_FILE "/sys/class/sdivideo/sdivideorx%u/bufsize"
57 #define SDIVIDEO_MODE_FILE "/sys/class/sdivideo/sdivideorx%u/mode"
58 #define SDIAUDIO_DEVICE "/dev/sdiaudiorx%u"
59 #define SDIAUDIO_BUFFERS_FILE "/sys/class/sdiaudio/sdiaudiorx%u/buffers"
60 #define SDIAUDIO_BUFSIZE_FILE "/sys/class/sdiaudio/sdiaudiorx%u/bufsize"
61 #define SDIAUDIO_SAMPLESIZE_FILE "/sys/class/sdiaudio/sdiaudiorx%u/sample_size"
62 #define SDIAUDIO_CHANNELS_FILE "/sys/class/sdiaudio/sdiaudiorx%u/channels"
63 #define NB_VBUFFERS 2
64 #define CLOCK_GAP INT64_C(500000)
65 #define START_DATE INT64_C(4294967296)
67 #define MAX_AUDIOS 4
69 /*****************************************************************************
70 * Module descriptor
71 *****************************************************************************/
72 #define LINK_TEXT N_("Link #")
73 #define LINK_LONGTEXT N_( \
74 "Allows you to set the desired link of the board for the capture (starting at 0)." )
75 #define VIDEO_TEXT N_("Video ID")
76 #define VIDEO_LONGTEXT N_( \
77 "Allows you to set the ES ID of the video." )
78 #define VIDEO_ASPECT_TEXT N_("Aspect ratio")
79 #define VIDEO_ASPECT_LONGTEXT N_( \
80 "Allows you to force the aspect ratio of the video." )
81 #define AUDIO_TEXT N_("Audio configuration")
82 #define AUDIO_LONGTEXT N_( \
83 "Allows you to set audio configuration (id=group,pair:id=group,pair...)." )
85 static int Open ( vlc_object_t * );
86 static void Close( vlc_object_t * );
88 vlc_module_begin()
89 set_description( N_("HD-SDI Input") )
90 set_shortname( N_("HD-SDI") )
91 set_category( CAT_INPUT )
92 set_subcategory( SUBCAT_INPUT_ACCESS )
94 add_integer( "linsys-hdsdi-link", 0,
95 LINK_TEXT, LINK_LONGTEXT, true )
97 add_integer( "linsys-hdsdi-id-video", 0,
98 VIDEO_TEXT, VIDEO_LONGTEXT, true )
99 add_string( "linsys-hdsdi-aspect-ratio", "",
100 VIDEO_ASPECT_TEXT, VIDEO_ASPECT_LONGTEXT, true )
101 add_string( "linsys-hdsdi-audio", "0=1,1",
102 AUDIO_TEXT, AUDIO_LONGTEXT, true )
104 set_capability( "access_demux", 0 )
105 add_shortcut( "linsys-hdsdi" )
106 set_callbacks( Open, Close )
107 vlc_module_end()
109 /*****************************************************************************
110 * Local prototypes
111 *****************************************************************************/
112 typedef struct hdsdi_audio_t
114 int i_channel; /* i_group * 2 + i_pair */
116 /* HDSDI parser */
117 int32_t i_delay;
119 /* ES stuff */
120 int i_id;
121 es_out_id_t *p_es;
122 } hdsdi_audio_t;
124 struct demux_sys_t
126 /* video device reader */
127 int i_vfd;
128 unsigned int i_link;
129 unsigned int i_standard;
130 #ifdef HAVE_MMAP_SDIVIDEO
131 uint8_t **pp_vbuffers;
132 unsigned int i_vbuffers, i_current_vbuffer;
133 #endif
134 unsigned int i_vbuffer_size;
136 /* audio device reader */
137 int i_afd;
138 int i_max_channel;
139 unsigned int i_sample_rate;
140 #ifdef HAVE_MMAP_SDIAUDIO
141 uint8_t **pp_abuffers;
142 unsigned int i_abuffers, i_current_abuffer;
143 #endif
144 unsigned int i_abuffer_size;
146 /* picture decoding */
147 unsigned int i_frame_rate, i_frame_rate_base;
148 unsigned int i_width, i_height, i_aspect, i_forced_aspect;
149 unsigned int i_vblock_size, i_ablock_size;
150 mtime_t i_next_vdate, i_next_adate;
151 int i_incr, i_aincr;
153 /* ES stuff */
154 int i_id_video;
155 es_out_id_t *p_es_video;
156 hdsdi_audio_t p_audios[MAX_AUDIOS];
158 pthread_t thread;
159 int evfd;
162 static int Control( demux_t *, int, va_list );
163 static void *Demux( void * );
165 static int InitCapture( demux_t *p_demux );
166 static void CloseCapture( demux_t *p_demux );
167 static int Capture( demux_t *p_demux );
169 /*****************************************************************************
170 * DemuxOpen:
171 *****************************************************************************/
172 static int Open( vlc_object_t *p_this )
174 demux_t *p_demux = (demux_t *)p_this;
175 demux_sys_t *p_sys;
176 char *psz_parser;
178 /* Fill p_demux field */
179 p_demux->p_sys = p_sys = calloc( 1, sizeof( demux_sys_t ) );
180 if( unlikely(!p_sys) )
181 return VLC_ENOMEM;
183 /* HDSDI AR */
184 unsigned int i_num, i_den;
185 if ( !var_InheritURational( p_demux, &i_num, &i_den,
186 "linsys-hdsdi-aspect-ratio" ) && i_den != 0 )
187 p_sys->i_forced_aspect = p_sys->i_aspect =
188 i_num * VOUT_ASPECT_FACTOR / i_den;
189 else
190 p_sys->i_forced_aspect = 0;
192 /* */
193 p_sys->i_id_video = var_InheritInteger( p_demux, "linsys-hdsdi-id-video" );
195 /* Audio ES */
196 char *psz_string = psz_parser = var_InheritString( p_demux,
197 "linsys-hdsdi-audio" );
198 int i = 0;
199 p_sys->i_max_channel = -1;
201 while ( psz_parser != NULL && *psz_parser )
203 int i_id, i_group, i_pair;
204 char *psz_next = strchr( psz_parser, '=' );
205 if ( psz_next != NULL )
207 *psz_next = '\0';
208 i_id = strtol( psz_parser, NULL, 0 );
209 psz_parser = psz_next + 1;
211 else
212 i_id = 0;
214 psz_next = strchr( psz_parser, ':' );
215 if ( psz_next != NULL )
217 *psz_next = '\0';
218 psz_next++;
221 if ( sscanf( psz_parser, "%d,%d", &i_group, &i_pair ) == 2 )
223 p_sys->p_audios[i].i_channel = (i_group - 1) * 2 + (i_pair - 1);
224 if ( p_sys->p_audios[i].i_channel > p_sys->i_max_channel )
225 p_sys->i_max_channel = p_sys->p_audios[i].i_channel;
226 p_sys->p_audios[i].i_id = i_id;
227 i++;
229 else
230 msg_Warn( p_demux, "malformed audio configuration (%s)",
231 psz_parser );
233 psz_parser = psz_next;
235 free( psz_string );
236 for ( ; i < MAX_AUDIOS; i++ )
237 p_sys->p_audios[i].i_channel = -1;
240 p_sys->i_link = var_InheritInteger( p_demux, "linsys-hdsdi-link" );
242 p_sys->evfd = eventfd( 0, EFD_CLOEXEC );
243 if( p_sys->evfd == -1 )
244 goto error;
246 if( pthread_create( &p_sys->thread, NULL, Demux, p_demux ) )
248 vlc_close( p_sys->evfd );
249 goto error;
252 p_demux->pf_demux = NULL;
253 p_demux->pf_control = Control;
254 return VLC_SUCCESS;
255 error:
256 free( p_sys );
257 return VLC_EGENERIC;
260 /*****************************************************************************
261 * DemuxClose:
262 *****************************************************************************/
263 static void Close( vlc_object_t *p_this )
265 demux_t *p_demux = (demux_t *)p_this;
266 demux_sys_t *p_sys = p_demux->p_sys;
268 write( p_sys->evfd, &(uint64_t){ 1 }, sizeof (uint64_t));
269 pthread_join( p_sys->thread, NULL );
270 vlc_close( p_sys->evfd );
271 free( p_sys );
274 /*****************************************************************************
275 * DemuxDemux:
276 *****************************************************************************/
277 static void *Demux( void *opaque )
279 demux_t *p_demux = opaque;
281 if( InitCapture( p_demux ) != VLC_SUCCESS )
282 return NULL;
284 while( Capture( p_demux ) == VLC_SUCCESS );
286 CloseCapture( p_demux );
287 return NULL;
290 /*****************************************************************************
291 * Control:
292 *****************************************************************************/
293 static int Control( demux_t *p_demux, int i_query, va_list args )
295 bool *pb;
296 int64_t *pi64;
298 switch( i_query )
300 /* Special for access_demux */
301 case DEMUX_CAN_PAUSE:
302 case DEMUX_CAN_CONTROL_PACE:
303 /* TODO */
304 pb = va_arg( args, bool * );
305 *pb = false;
306 return VLC_SUCCESS;
308 case DEMUX_GET_PTS_DELAY:
309 pi64 = va_arg( args, int64_t * );
310 *pi64 = INT64_C(1000)
311 * var_InheritInteger( p_demux, "live-caching" );
312 return VLC_SUCCESS;
314 /* TODO implement others */
315 default:
316 return VLC_EGENERIC;
320 /*****************************************************************************
321 * HDSDI syntax parsing stuff
322 *****************************************************************************/
323 #define U (uint16_t)(p_line[0])
324 #define Y1 (uint16_t)(p_line[1])
325 #define V (uint16_t)(p_line[2])
326 #define Y2 (uint16_t)(p_line[3])
328 /* For lines 0 [4] or 1 [4] */
329 static void Unpack01( const uint8_t *p_line, unsigned int i_size,
330 uint8_t *p_y, uint8_t *p_u, uint8_t *p_v )
332 const uint8_t *p_end = p_line + i_size;
334 while ( p_line < p_end )
336 *p_u++ = U;
337 *p_y++ = Y1;
338 *p_v++ = V;
339 *p_y++ = Y2;
340 p_line += 4;
344 /* For lines 2 [4] */
345 static void Unpack2( const uint8_t *p_line, unsigned int i_size,
346 uint8_t *p_y, uint8_t *p_u, uint8_t *p_v )
348 const uint8_t *p_end = p_line + i_size;
350 while ( p_line < p_end )
352 uint16_t tmp;
353 tmp = 3 * *p_u;
354 tmp += U;
355 *p_u++ = tmp / 4;
356 *p_y++ = Y1;
357 tmp = 3 * *p_v;
358 tmp += V;
359 *p_v++ = tmp / 4;
360 *p_y++ = Y2;
361 p_line += 4;
365 /* For lines 3 [4] */
366 static void Unpack3( const uint8_t *p_line, unsigned int i_size,
367 uint8_t *p_y, uint8_t *p_u, uint8_t *p_v )
369 const uint8_t *p_end = p_line + i_size;
371 while ( p_line < p_end )
373 uint16_t tmp;
374 tmp = *p_u;
375 tmp += 3 * U;
376 *p_u++ = tmp / 4;
377 *p_y++ = Y1;
378 tmp = *p_v;
379 tmp += 3 * V;
380 *p_v++ = tmp / 4;
381 *p_y++ = Y2;
382 p_line += 4;
386 #undef U
387 #undef Y1
388 #undef V
389 #undef Y2
391 static void SparseCopy( int16_t *p_dest, const int16_t *p_src,
392 size_t i_nb_samples, size_t i_offset, size_t i_stride )
394 for ( size_t i = 0; i < i_nb_samples; i++ )
396 p_dest[2 * i] = p_src[i_offset];
397 p_dest[2 * i + 1] = p_src[i_offset + 1];
398 i_offset += 2 * i_stride;
402 /*****************************************************************************
403 * Video & audio decoding
404 *****************************************************************************/
405 struct block_extension_t
407 bool b_progressive; /**< is it a progressive frame ? */
408 bool b_top_field_first; /**< which field is first */
409 unsigned int i_nb_fields; /**< # of displayed fields */
410 unsigned int i_aspect; /**< aspect ratio of frame */
413 static void StopDecode( demux_t *p_demux )
415 demux_sys_t *p_sys = p_demux->p_sys;
417 es_out_Del( p_demux->out, p_sys->p_es_video );
419 for ( int i = 0; i < MAX_AUDIOS; i++ )
421 hdsdi_audio_t *p_audio = &p_sys->p_audios[i];
422 if ( p_audio->i_channel != -1 && p_audio->p_es != NULL )
424 es_out_Del( p_demux->out, p_audio->p_es );
425 p_audio->p_es = NULL;
430 static int InitVideo( demux_t *p_demux )
432 demux_sys_t *p_sys = p_demux->p_sys;
433 es_format_t fmt;
435 msg_Dbg( p_demux, "found standard %d", p_sys->i_standard );
436 switch ( p_sys->i_standard )
438 case SDIVIDEO_CTL_BT_601_576I_50HZ:
439 /* PAL */
440 p_sys->i_frame_rate = 25;
441 p_sys->i_frame_rate_base = 1;
442 p_sys->i_width = 720;
443 p_sys->i_height = 576;
444 p_sys->i_aspect = 4 * VOUT_ASPECT_FACTOR / 3;
445 break;
447 case SDIVIDEO_CTL_SMPTE_296M_720P_50HZ:
448 p_sys->i_frame_rate = 50;
449 p_sys->i_frame_rate_base = 1;
450 p_sys->i_width = 1280;
451 p_sys->i_height = 720;
452 p_sys->i_aspect = 16 * VOUT_ASPECT_FACTOR / 9;
453 break;
455 case SDIVIDEO_CTL_SMPTE_296M_720P_60HZ:
456 p_sys->i_frame_rate = 60;
457 p_sys->i_frame_rate_base = 1;
458 p_sys->i_width = 1280;
459 p_sys->i_height = 720;
460 p_sys->i_aspect = 16 * VOUT_ASPECT_FACTOR / 9;
461 break;
463 case SDIVIDEO_CTL_SMPTE_295M_1080I_50HZ:
464 case SDIVIDEO_CTL_SMPTE_274M_1080I_50HZ:
465 case SDIVIDEO_CTL_SMPTE_274M_1080PSF_25HZ:
466 /* 1080i50 or 1080p25 */
467 p_sys->i_frame_rate = 25;
468 p_sys->i_frame_rate_base = 1;
469 p_sys->i_width = 1920;
470 p_sys->i_height = 1080;
471 p_sys->i_aspect = 16 * VOUT_ASPECT_FACTOR / 9;
472 break;
474 case SDIVIDEO_CTL_SMPTE_274M_1080I_59_94HZ:
475 p_sys->i_frame_rate = 30000;
476 p_sys->i_frame_rate_base = 1001;
477 p_sys->i_width = 1920;
478 p_sys->i_height = 1080;
479 p_sys->i_aspect = 16 * VOUT_ASPECT_FACTOR / 9;
480 break;
482 case SDIVIDEO_CTL_SMPTE_274M_1080I_60HZ:
483 p_sys->i_frame_rate = 30;
484 p_sys->i_frame_rate_base = 1;
485 p_sys->i_width = 1920;
486 p_sys->i_height = 1080;
487 p_sys->i_aspect = 16 * VOUT_ASPECT_FACTOR / 9;
488 break;
490 default:
491 msg_Err( p_demux, "unsupported standard %d", p_sys->i_standard );
492 return VLC_EGENERIC;
495 p_sys->i_next_vdate = START_DATE;
496 p_sys->i_incr = 1000000 * p_sys->i_frame_rate_base / p_sys->i_frame_rate;
497 p_sys->i_vblock_size = p_sys->i_width * p_sys->i_height * 3 / 2
498 + sizeof(struct block_extension_t);
500 /* Video ES */
501 es_format_Init( &fmt, VIDEO_ES, VLC_CODEC_I420 );
502 fmt.i_id = p_sys->i_id_video;
503 fmt.video.i_frame_rate = p_sys->i_frame_rate;
504 fmt.video.i_frame_rate_base = p_sys->i_frame_rate_base;
505 fmt.video.i_width = fmt.video.i_visible_width = p_sys->i_width;
506 fmt.video.i_height = fmt.video.i_visible_height = p_sys->i_height;
507 fmt.video.i_sar_num = p_sys->i_aspect * fmt.video.i_height
508 / fmt.video.i_width;
509 fmt.video.i_sar_den = VOUT_ASPECT_FACTOR;
510 p_sys->p_es_video = es_out_Add( p_demux->out, &fmt );
512 return VLC_SUCCESS;
515 static int InitAudio( demux_t *p_demux )
517 demux_sys_t *p_sys = p_demux->p_sys;
518 es_format_t fmt;
520 for ( int i = 0; i < MAX_AUDIOS; i++ )
522 hdsdi_audio_t *p_audio = &p_sys->p_audios[i];
524 if ( p_audio->i_channel == -1 ) continue;
526 msg_Dbg( p_demux, "starting audio %u/%u rate:%u delay:%d",
527 1 + p_audio->i_channel / 2, 1 + (p_audio->i_channel % 2),
528 p_sys->i_sample_rate, p_audio->i_delay );
530 es_format_Init( &fmt, AUDIO_ES, VLC_CODEC_S16L );
531 fmt.i_id = p_audio->i_id;
532 fmt.audio.i_channels = 2;
533 fmt.audio.i_physical_channels = AOUT_CHANS_STEREO;
534 fmt.audio.i_rate = p_sys->i_sample_rate;
535 fmt.audio.i_bitspersample = 16;
536 fmt.audio.i_blockalign = fmt.audio.i_channels *
537 fmt.audio.i_bitspersample / 8;
538 fmt.i_bitrate = fmt.audio.i_channels * fmt.audio.i_rate *
539 fmt.audio.i_bitspersample;
540 p_audio->p_es = es_out_Add( p_demux->out, &fmt );
543 p_sys->i_next_adate = START_DATE;
544 p_sys->i_ablock_size = p_sys->i_sample_rate * 4 * p_sys->i_frame_rate_base / p_sys->i_frame_rate;
545 p_sys->i_aincr = 1000000. * p_sys->i_ablock_size / p_sys->i_sample_rate / 4;
547 return VLC_SUCCESS;
550 static int HandleVideo( demux_t *p_demux, const uint8_t *p_buffer )
552 demux_sys_t *p_sys = p_demux->p_sys;
553 block_t *p_current_picture = block_Alloc( p_sys->i_vblock_size );
554 if( unlikely( !p_current_picture ) )
555 return VLC_ENOMEM;
556 uint8_t *p_y = p_current_picture->p_buffer;
557 uint8_t *p_u = p_y + p_sys->i_width * p_sys->i_height;
558 uint8_t *p_v = p_u + p_sys->i_width * p_sys->i_height / 4;
559 unsigned int i_total_size = p_sys->i_width * 2;
560 unsigned int i_current_line;
561 struct block_extension_t ext;
563 for ( i_current_line = 0; i_current_line < p_sys->i_height;
564 i_current_line++ )
566 bool b_field = (i_current_line >= p_sys->i_height / 2);
567 unsigned int i_field_line = b_field ?
568 i_current_line - (p_sys->i_height + 1) / 2 :
569 i_current_line;
570 unsigned int i_real_line = b_field + i_field_line * 2;
571 const uint8_t *p_line = p_buffer + i_current_line * p_sys->i_width * 2;
573 if ( !(i_field_line % 2) && !b_field )
574 Unpack01( p_line, i_total_size,
575 p_y + p_sys->i_width * i_real_line,
576 p_u + (p_sys->i_width / 2) * (i_real_line / 2),
577 p_v + (p_sys->i_width / 2) * (i_real_line / 2) );
578 else if ( !(i_field_line % 2) )
579 Unpack01( p_line, i_total_size,
580 p_y + p_sys->i_width * i_real_line,
581 p_u + (p_sys->i_width / 2) * (i_real_line / 2 + 1),
582 p_v + (p_sys->i_width / 2) * (i_real_line / 2 + 1) );
583 else if ( !b_field )
584 Unpack2( p_line, i_total_size,
585 p_y + p_sys->i_width * i_real_line,
586 p_u + (p_sys->i_width / 2) * (i_real_line / 2 - 1),
587 p_v + (p_sys->i_width / 2) * (i_real_line / 2 - 1) );
588 else
589 Unpack3( p_line, i_total_size,
590 p_y + p_sys->i_width * i_real_line,
591 p_u + (p_sys->i_width / 2) * (i_real_line / 2),
592 p_v + (p_sys->i_width / 2) * (i_real_line / 2) );
595 /* FIXME: progressive formats ? */
596 ext.b_progressive = false;
597 ext.i_nb_fields = 2;
598 ext.b_top_field_first = true;
599 ext.i_aspect = p_sys->i_forced_aspect ? p_sys->i_forced_aspect :
600 p_sys->i_aspect;
602 memcpy( &p_current_picture->p_buffer[p_sys->i_vblock_size
603 - sizeof(struct block_extension_t)],
604 &ext, sizeof(struct block_extension_t) );
606 p_current_picture->i_dts = p_current_picture->i_pts = p_sys->i_next_vdate;
607 es_out_Send( p_demux->out, p_sys->p_es_video, p_current_picture );
609 es_out_SetPCR( p_demux->out, p_sys->i_next_vdate );
610 p_sys->i_next_vdate += p_sys->i_incr;
611 return VLC_SUCCESS;
614 static int HandleAudio( demux_t *p_demux, const uint8_t *p_buffer )
616 demux_sys_t *p_sys = p_demux->p_sys;
618 for ( int i = 0; i < MAX_AUDIOS; i++ )
620 hdsdi_audio_t *p_audio = &p_sys->p_audios[i];
621 if ( p_audio->i_channel != -1 && p_audio->p_es != NULL )
623 block_t *p_block = block_Alloc( p_sys->i_ablock_size );
624 if( unlikely( !p_block ) )
625 return VLC_ENOMEM;
626 SparseCopy( (int16_t *)p_block->p_buffer, (const int16_t *)p_buffer,
627 p_sys->i_ablock_size / 4,
628 p_audio->i_channel * 2, p_sys->i_max_channel + 1 );
630 p_block->i_dts = p_block->i_pts
631 = p_sys->i_next_adate + (mtime_t)p_audio->i_delay
632 * INT64_C(1000000) / p_sys->i_sample_rate;
633 p_block->i_length = p_sys->i_aincr;
634 es_out_Send( p_demux->out, p_audio->p_es, p_block );
637 p_sys->i_next_adate += p_sys->i_aincr;
638 return VLC_SUCCESS;
641 /*****************************************************************************
642 * Low-level device stuff
643 *****************************************************************************/
644 #define MAXLEN 256
646 static ssize_t WriteULSysfs( const char *psz_fmt, unsigned int i_link,
647 unsigned int i_buf )
649 char psz_file[MAXLEN], psz_data[MAXLEN];
650 int i_fd;
651 ssize_t i_ret;
653 snprintf( psz_file, sizeof(psz_file) -1, psz_fmt, i_link );
655 snprintf( psz_data, sizeof(psz_data) -1, "%u\n", i_buf );
657 if ( (i_fd = vlc_open( psz_file, O_WRONLY )) < 0 )
658 return i_fd;
660 i_ret = write( i_fd, psz_data, strlen(psz_data) + 1 );
661 vlc_close( i_fd );
662 return i_ret;
665 static int InitCapture( demux_t *p_demux )
667 demux_sys_t *p_sys = p_demux->p_sys;
668 #ifdef HAVE_MMAP_SDIVIDEO
669 const int i_page_size = getpagesize();
670 unsigned int i_bufmemsize;
671 #endif
672 char psz_vdev[MAXLEN];
674 snprintf( psz_vdev, sizeof(psz_vdev), SDIVIDEO_DEVICE, p_sys->i_link );
675 if ( (p_sys->i_vfd = vlc_open( psz_vdev, O_RDONLY ) ) < 0 )
677 msg_Err( p_demux, "couldn't open device %s", psz_vdev );
678 return VLC_EGENERIC;
681 /* Wait for standard to settle down */
682 struct pollfd pfd[2];
684 pfd[0].fd = p_sys->i_vfd;
685 pfd[0].events = POLLPRI;
686 pfd[1].fd = p_sys->evfd;
687 pfd[1].events = POLLIN;
689 for( ;; )
691 if( poll( pfd, 2, -1 ) < 0 )
692 continue;
694 if ( pfd[0].revents & POLLPRI )
696 unsigned int i_val;
698 if ( ioctl( p_sys->i_vfd, SDIVIDEO_IOC_RXGETEVENTS, &i_val ) < 0 )
699 msg_Warn( p_demux, "couldn't SDIVIDEO_IOC_RXGETEVENTS: %s",
700 vlc_strerror_c(errno) );
701 else
703 if ( i_val & SDIVIDEO_EVENT_RX_BUFFER )
704 msg_Warn( p_demux, "driver receive buffer queue overrun" );
705 if ( i_val & SDIVIDEO_EVENT_RX_FIFO )
706 msg_Warn( p_demux, "onboard receive FIFO overrun");
707 if ( i_val & SDIVIDEO_EVENT_RX_CARRIER )
708 msg_Warn( p_demux, "carrier status change");
709 if ( i_val & SDIVIDEO_EVENT_RX_DATA )
710 msg_Warn( p_demux, "data status change");
711 if ( i_val & SDIVIDEO_EVENT_RX_STD )
713 msg_Warn( p_demux, "standard status change");
714 break;
719 if( pfd[1].revents )
721 vlc_close( p_sys->i_vfd );
722 return VLC_EGENERIC;
726 if ( ioctl( p_sys->i_vfd, SDIVIDEO_IOC_RXGETVIDSTATUS, &p_sys->i_standard )
727 < 0 )
729 msg_Warn( p_demux, "couldn't SDIVIDEO_IOC_RXGETVIDSTATUS: %s",
730 vlc_strerror_c(errno) );
731 vlc_close( p_sys->i_vfd );
732 return VLC_EGENERIC;
734 vlc_close( p_sys->i_vfd );
736 if ( InitVideo( p_demux ) != VLC_SUCCESS )
737 return VLC_EGENERIC;
738 p_sys->i_vbuffer_size = p_sys->i_height * p_sys->i_width * 2;
740 /* First open the audio for synchronization reasons */
741 if ( p_sys->i_max_channel != -1 )
743 unsigned int i_rate;
744 char psz_adev[MAXLEN];
746 snprintf( psz_adev, sizeof(psz_adev), SDIAUDIO_DEVICE, p_sys->i_link );
747 if ( (p_sys->i_afd = vlc_open( psz_adev, O_RDONLY ) ) < 0 )
749 msg_Err( p_demux, "couldn't open device %s", psz_adev );
750 return VLC_EGENERIC;
753 if ( ioctl( p_sys->i_afd, SDIAUDIO_IOC_RXGETAUDRATE, &i_rate ) < 0 )
755 msg_Warn( p_demux, "couldn't SDIAUDIO_IOC_RXGETAUDRATE: %s",
756 vlc_strerror_c(errno) );
757 return VLC_EGENERIC;
759 switch ( i_rate )
761 case SDIAUDIO_CTL_ASYNC_48_KHZ:
762 case SDIAUDIO_CTL_SYNC_48_KHZ:
763 p_sys->i_sample_rate = 48000;
764 break;
765 case SDIAUDIO_CTL_ASYNC_44_1_KHZ:
766 case SDIAUDIO_CTL_SYNC_44_1_KHZ:
767 p_sys->i_sample_rate = 44100;
768 break;
769 case SDIAUDIO_CTL_ASYNC_32_KHZ:
770 case SDIAUDIO_CTL_SYNC_32_KHZ:
771 p_sys->i_sample_rate = 32000;
772 break;
773 case SDIAUDIO_CTL_ASYNC_96_KHZ:
774 case SDIAUDIO_CTL_SYNC_96_KHZ:
775 p_sys->i_sample_rate = 96000;
776 break;
777 case SDIAUDIO_CTL_ASYNC_FREE_RUNNING:
778 case SDIAUDIO_CTL_SYNC_FREE_RUNNING:
779 default:
780 msg_Err( p_demux, "unknown sample rate %u", i_rate );
781 return VLC_EGENERIC;
783 vlc_close( p_sys->i_afd );
785 if ( InitAudio( p_demux ) != VLC_SUCCESS )
786 return VLC_EGENERIC;
787 p_sys->i_abuffer_size = p_sys->i_ablock_size
788 * (1 + p_sys->i_max_channel);
790 /* Use 16-bit audio */
791 if ( WriteULSysfs( SDIAUDIO_SAMPLESIZE_FILE, p_sys->i_link,
792 SDIAUDIO_CTL_AUDSAMP_SZ_16 ) < 0 )
794 msg_Err( p_demux, "couldn't write file " SDIAUDIO_SAMPLESIZE_FILE,
795 p_sys->i_link );
796 return VLC_EGENERIC;
799 if ( WriteULSysfs( SDIAUDIO_CHANNELS_FILE, p_sys->i_link,
800 (p_sys->i_max_channel + 1) * 2 ) < 0 )
802 msg_Err( p_demux, "couldn't write file " SDIAUDIO_CHANNELS_FILE,
803 p_sys->i_link );
804 return VLC_EGENERIC;
807 #ifdef HAVE_MMAP_SDIAUDIO
808 if ( (p_sys->i_abuffers = ReadULSysfs( SDIAUDIO_BUFFERS_FILE,
809 p_sys->i_link )) < 0 )
811 msg_Err( p_demux, "couldn't read file " SDIAUDIO_BUFFERS_FILE,
812 p_sys->i_link );
813 return VLC_EGENERIC;
815 p_sys->i_current_abuffer = 0;
816 #endif
818 if ( WriteULSysfs( SDIAUDIO_BUFSIZE_FILE, p_sys->i_link,
819 p_sys->i_abuffer_size ) < 0 )
821 msg_Err( p_demux, "couldn't write file " SDIAUDIO_BUFSIZE_FILE,
822 p_sys->i_link );
823 return VLC_EGENERIC;
826 if ( (p_sys->i_afd = open( psz_adev, O_RDONLY ) ) < 0 )
828 msg_Err( p_demux, "couldn't open device %s", psz_adev );
829 return VLC_EGENERIC;
832 #ifdef HAVE_MMAP_SDIAUDIO
833 i_bufmemsize = ((p_sys->i_abuffer_size + i_page_size - 1) / i_page_size)
834 * i_page_size;
835 p_sys->pp_abuffers = vlc_alloc( p_sys->i_abuffers, sizeof(uint8_t *) );
836 if( unlikely( !p_sys->pp_abuffers ) )
837 return VLC_ENOMEM;
838 for ( unsigned int i = 0; i < p_sys->i_abuffers; i++ )
840 if ( (p_sys->pp_abuffers[i] = mmap( NULL, p_sys->i_abuffer_size,
841 PROT_READ, MAP_SHARED, p_sys->i_afd,
842 i * i_bufmemsize )) == MAP_FAILED )
844 msg_Err( p_demux, "couldn't mmap(%d): %s", i,
845 vlc_strerror_c(errno) );
846 return VLC_EGENERIC;
849 #endif
852 /* Use 8-bit video */
853 if ( WriteULSysfs( SDIVIDEO_MODE_FILE, p_sys->i_link,
854 SDIVIDEO_CTL_MODE_UYVY ) < 0 )
856 msg_Err( p_demux, "couldn't write file " SDIVIDEO_MODE_FILE,
857 p_sys->i_link );
858 return VLC_EGENERIC;
861 if ( WriteULSysfs( SDIVIDEO_BUFFERS_FILE, p_sys->i_link,
862 NB_VBUFFERS ) < 0 )
864 msg_Err( p_demux, "couldn't write file " SDIVIDEO_BUFFERS_FILE,
865 p_sys->i_link );
866 return VLC_EGENERIC;
868 #ifdef HAVE_MMAP_SDIVIDEO
869 p_sys->i_vbuffers = NB_VBUFFERS;
870 #endif
872 if ( WriteULSysfs( SDIVIDEO_BUFSIZE_FILE, p_sys->i_link,
873 p_sys->i_vbuffer_size ) < 0 )
875 msg_Err( p_demux, "couldn't write file " SDIVIDEO_BUFSIZE_FILE,
876 p_sys->i_link );
877 return VLC_EGENERIC;
880 if ( (p_sys->i_vfd = open( psz_vdev, O_RDONLY ) ) < 0 )
882 msg_Err( p_demux, "couldn't open device %s", psz_vdev );
883 return VLC_EGENERIC;
886 #ifdef HAVE_MMAP_SDIVIDEO
887 p_sys->i_current_vbuffer = 0;
888 i_bufmemsize = ((p_sys->i_vbuffer_size + i_page_size - 1) / i_page_size)
889 * i_page_size;
890 p_sys->pp_vbuffers = vlc_alloc( p_sys->i_vbuffers, sizeof(uint8_t *) );
891 if( unlikely( !p_sys->pp_vbuffers ) )
892 return VLC_ENOMEM;
893 for ( unsigned int i = 0; i < p_sys->i_vbuffers; i++ )
895 if ( (p_sys->pp_vbuffers[i] = mmap( NULL, p_sys->i_vbuffer_size,
896 PROT_READ, MAP_SHARED, p_sys->i_vfd,
897 i * i_bufmemsize )) == MAP_FAILED )
899 msg_Err( p_demux, "couldn't mmap(%d): %s", i,
900 vlc_strerror_c(errno) );
901 return VLC_EGENERIC;
904 #endif
906 return VLC_SUCCESS;
909 static void CloseCapture( demux_t *p_demux )
911 demux_sys_t *p_sys = p_demux->p_sys;
913 StopDecode( p_demux );
914 #ifdef HAVE_MMAP_SDIVIDEO
915 for ( unsigned int i = 0; i < p_sys->i_vbuffers; i++ )
916 munmap( p_sys->pp_vbuffers[i], p_sys->i_vbuffer_size );
917 free( p_sys->pp_vbuffers );
918 #endif
919 vlc_close( p_sys->i_vfd );
920 if ( p_sys->i_max_channel != -1 )
922 #ifdef HAVE_MMAP_SDIAUDIO
923 for ( unsigned int i = 0; i < p_sys->i_abuffers; i++ )
924 munmap( p_sys->pp_abuffers[i], p_sys->i_abuffer_size );
925 free( p_sys->pp_abuffers );
926 #endif
927 vlc_close( p_sys->i_afd );
931 static int Capture( demux_t *p_demux )
933 demux_sys_t *p_sys = p_demux->p_sys;
934 struct pollfd pfd[3];
936 pfd[0].fd = p_sys->evfd;
937 pfd[0].events = POLLIN;
938 pfd[1].fd = p_sys->i_vfd;
939 pfd[1].events = POLLIN | POLLPRI;
940 if ( p_sys->i_max_channel != -1 )
942 pfd[2].fd = p_sys->i_afd;
943 pfd[2].events = POLLIN | POLLPRI;
946 if( poll( pfd, 2 + (p_sys->i_max_channel != -1), -1 ) < 0 )
947 return VLC_SUCCESS;
949 if( pfd[0].revents )
950 return VLC_EGENERIC; /* Stop! */
952 if( pfd[1].revents & POLLPRI )
954 unsigned int i_val;
956 if ( ioctl( p_sys->i_vfd, SDIVIDEO_IOC_RXGETEVENTS, &i_val ) < 0 )
957 msg_Warn( p_demux, "couldn't SDIVIDEO_IOC_RXGETEVENTS: %s",
958 vlc_strerror_c(errno) );
959 else
961 if ( i_val & SDIVIDEO_EVENT_RX_BUFFER )
962 msg_Warn( p_demux, "driver receive buffer queue overrun" );
963 if ( i_val & SDIVIDEO_EVENT_RX_FIFO )
964 msg_Warn( p_demux, "onboard receive FIFO overrun");
965 if ( i_val & SDIVIDEO_EVENT_RX_CARRIER )
966 msg_Warn( p_demux, "carrier status change");
967 if ( i_val & SDIVIDEO_EVENT_RX_DATA )
968 msg_Warn( p_demux, "data status change");
969 if ( i_val & SDIVIDEO_EVENT_RX_STD )
970 msg_Warn( p_demux, "standard status change");
973 p_sys->i_next_adate += CLOCK_GAP;
974 p_sys->i_next_vdate += CLOCK_GAP;
977 if( p_sys->i_max_channel != -1 && (pfd[2].revents & POLLPRI) )
979 unsigned int i_val;
981 if ( ioctl( p_sys->i_afd, SDIAUDIO_IOC_RXGETEVENTS, &i_val ) < 0 )
982 msg_Warn( p_demux, "couldn't SDIAUDIO_IOC_RXGETEVENTS: %s",
983 vlc_strerror_c(errno) );
984 else
986 if ( i_val & SDIAUDIO_EVENT_RX_BUFFER )
987 msg_Warn( p_demux, "driver receive buffer queue overrun" );
988 if ( i_val & SDIAUDIO_EVENT_RX_FIFO )
989 msg_Warn( p_demux, "onboard receive FIFO overrun");
990 if ( i_val & SDIAUDIO_EVENT_RX_CARRIER )
991 msg_Warn( p_demux, "carrier status change");
992 if ( i_val & SDIAUDIO_EVENT_RX_DATA )
993 msg_Warn( p_demux, "data status change");
996 p_sys->i_next_adate += CLOCK_GAP;
997 p_sys->i_next_vdate += CLOCK_GAP;
1000 if( pfd[1].revents & POLLIN )
1002 #ifdef HAVE_MMAP_SDIVIDEO
1003 if ( ioctl( p_sys->i_vfd, SDIVIDEO_IOC_DQBUF, p_sys->i_current_vbuffer )
1004 < 0 )
1006 msg_Warn( p_demux, "couldn't SDIVIDEO_IOC_DQBUF: %s",
1007 vlc_strerror_c(errno) );
1008 return VLC_EGENERIC;
1011 if( HandleVideo( p_demux, p_sys->pp_vbuffers[p_sys->i_current_vbuffer] ) != VLC_SUCCESS )
1012 return VLC_ENOMEM;
1014 if ( ioctl( p_sys->i_vfd, SDIVIDEO_IOC_QBUF, p_sys->i_current_vbuffer )
1015 < 0 )
1017 msg_Warn( p_demux, "couldn't SDIVIDEO_IOC_QBUF: %s",
1018 vlc_strerror_c(errno) );
1019 return VLC_EGENERIC;
1022 p_sys->i_current_vbuffer++;
1023 p_sys->i_current_vbuffer %= p_sys->i_vbuffers;
1024 #else
1025 uint8_t *p_buffer = malloc( p_sys->i_vbuffer_size );
1026 if( unlikely( !p_buffer ) )
1027 return VLC_ENOMEM;
1029 if ( read( p_sys->i_vfd, p_buffer, p_sys->i_vbuffer_size ) < 0 )
1031 msg_Warn( p_demux, "couldn't read: %s", vlc_strerror_c(errno) );
1032 free( p_buffer );
1033 return VLC_EGENERIC;
1036 if( HandleVideo( p_demux, p_buffer ) != VLC_SUCCESS )
1038 free( p_buffer );
1039 return VLC_ENOMEM;
1041 free( p_buffer );
1042 #endif
1045 if( p_sys->i_max_channel != -1 && (pfd[2].revents & POLLIN) )
1047 #ifdef HAVE_MMAP_SDIAUDIO
1048 if ( ioctl( p_sys->i_afd, SDIAUDIO_IOC_DQBUF, p_sys->i_current_abuffer )
1049 < 0 )
1051 msg_Warn( p_demux, "couldn't SDIAUDIO_IOC_DQBUF: %s",
1052 vlc_strerror_c(errno) );
1053 return VLC_EGENERIC;
1056 if( HandleAudio( p_demux, p_sys->pp_abuffers[p_sys->i_current_abuffer] ) != VLC_SUCCESS )
1057 return VLC_ENOMEM;
1059 if ( ioctl( p_sys->i_afd, SDIAUDIO_IOC_QBUF, p_sys->i_current_abuffer )
1060 < 0 )
1062 msg_Warn( p_demux, "couldn't SDIAUDIO_IOC_QBUF: %s",
1063 vlc_strerror_c(errno) );
1064 return VLC_EGENERIC;
1067 p_sys->i_current_abuffer++;
1068 p_sys->i_current_abuffer %= p_sys->i_abuffers;
1069 #else
1070 uint8_t *p_buffer = malloc( p_sys->i_abuffer_size );
1071 if( unlikely( !p_buffer ) )
1072 return VLC_ENOMEM;
1074 if ( read( p_sys->i_afd, p_buffer, p_sys->i_abuffer_size ) < 0 )
1076 msg_Warn( p_demux, "couldn't read: %s", vlc_strerror_c(errno) );
1077 free( p_buffer );
1078 return VLC_EGENERIC;
1081 if( HandleAudio( p_demux, p_buffer ) != VLC_SUCCESS )
1083 free( p_buffer );
1084 return VLC_ENOMEM;
1086 free( p_buffer );
1087 #endif
1090 return VLC_SUCCESS;