]> git.sesse.net Git - vlc/blob - modules/access/linsys/linsys_hdsdi.c
36d9a1af58cf27f974bc9491960c1d0ec1c9329a
[vlc] / modules / access / linsys / linsys_hdsdi.c
1 /*****************************************************************************
2  * linsys_hdsdi.c: HDSDI capture for Linear Systems/Computer Modules cards
3  *****************************************************************************
4  * Copyright (C) 2010-2011 VideoLAN
5  *
6  * Authors: Christophe Massiot <massiot@via.ecp.fr>
7  *
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.
12  *
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.
17  *
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  *****************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
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 <fcntl.h>
36 #include <errno.h>
37
38 #include <vlc_common.h>
39 #include <vlc_plugin.h>
40
41 #include <vlc_input.h>
42 #include <vlc_access.h>
43 #include <vlc_demux.h>
44
45 #include <vlc_fs.h>
46
47 #include "linsys_sdivideo.h"
48 #include "linsys_sdiaudio.h"
49
50 #undef HAVE_MMAP_SDIVIDEO
51 #undef HAVE_MMAP_SDIAUDIO
52
53 #define SDIVIDEO_DEVICE         "/dev/sdivideorx%u"
54 #define SDIVIDEO_BUFFERS_FILE   "/sys/class/sdivideo/sdivideorx%u/buffers"
55 #define SDIVIDEO_BUFSIZE_FILE   "/sys/class/sdivideo/sdivideorx%u/bufsize"
56 #define SDIVIDEO_MODE_FILE      "/sys/class/sdivideo/sdivideorx%u/mode"
57 #define SDIAUDIO_DEVICE         "/dev/sdiaudiorx%u"
58 #define SDIAUDIO_BUFFERS_FILE   "/sys/class/sdiaudio/sdiaudiorx%u/buffers"
59 #define SDIAUDIO_BUFSIZE_FILE   "/sys/class/sdiaudio/sdiaudiorx%u/bufsize"
60 #define SDIAUDIO_SAMPLESIZE_FILE "/sys/class/sdiaudio/sdiaudiorx%u/sample_size"
61 #define SDIAUDIO_CHANNELS_FILE  "/sys/class/sdiaudio/sdiaudiorx%u/channels"
62 #define NB_VBUFFERS             2
63 #define READ_TIMEOUT            80000
64 #define CLOCK_GAP               INT64_C(500000)
65 #define START_DATE              INT64_C(4294967296)
66
67 #define MAX_AUDIOS              4
68
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...)." )
84
85 static int  Open ( vlc_object_t * );
86 static void Close( vlc_object_t * );
87
88 vlc_module_begin()
89     set_description( _("HD-SDI Input") )
90     set_shortname( N_("HD-SDI") )
91     set_category( CAT_INPUT )
92     set_subcategory( SUBCAT_INPUT_ACCESS )
93
94     add_integer( "linsys-hdsdi-link", 0,
95         LINK_TEXT, LINK_LONGTEXT, true )
96
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 )
103
104     set_capability( "access_demux", 0 )
105     add_shortcut( "linsys-hdsdi" )
106     set_callbacks( Open, Close )
107 vlc_module_end()
108
109 /*****************************************************************************
110  * Local prototypes
111  *****************************************************************************/
112 typedef struct hdsdi_audio_t
113 {
114     int         i_channel; /* i_group * 2 + i_pair */
115
116     /* HDSDI parser */
117     int32_t     i_delay;
118
119     /* ES stuff */
120     int         i_id;
121     es_out_id_t *p_es;
122 } hdsdi_audio_t;
123
124 struct demux_sys_t
125 {
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;
135
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;
145
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;
152
153     /* ES stuff */
154     int          i_id_video;
155     es_out_id_t  *p_es_video;
156     hdsdi_audio_t p_audios[MAX_AUDIOS];
157 };
158
159 static int Control( demux_t *, int, va_list );
160 static int Demux( demux_t * );
161
162 static int InitCapture( demux_t *p_demux );
163 static void CloseCapture( demux_t *p_demux );
164 static int Capture( demux_t *p_demux );
165
166 /*****************************************************************************
167  * DemuxOpen:
168  *****************************************************************************/
169 static int Open( vlc_object_t *p_this )
170 {
171     demux_t     *p_demux = (demux_t *)p_this;
172     demux_sys_t *p_sys;
173     char        *psz_parser;
174
175     /* Fill p_demux field */
176     p_demux->pf_demux = Demux;
177     p_demux->pf_control = Control;
178     p_demux->p_sys = p_sys = calloc( 1, sizeof( demux_sys_t ) );
179     if( unlikely(!p_sys) )
180         return VLC_ENOMEM;
181
182     /* HDSDI AR */
183     char *psz_ar = var_InheritString( p_demux, "linsys-hdsdi-aspect-ratio" );
184     if ( psz_ar != NULL )
185     {
186         psz_parser = strchr( psz_ar, ':' );
187         if ( psz_parser )
188         {
189             *psz_parser++ = '\0';
190             p_sys->i_forced_aspect = p_sys->i_aspect =
191                  strtol( psz_ar, NULL, 0 ) * VOUT_ASPECT_FACTOR
192                  / strtol( psz_parser, NULL, 0 );
193         }
194         else
195             p_sys->i_forced_aspect = 0;
196         free( psz_ar );
197     }
198
199     /* */
200     p_sys->i_id_video = var_InheritInteger( p_demux, "linsys-hdsdi-id-video" );
201
202     /* Audio ES */
203     char *psz_string = psz_parser = var_InheritString( p_demux,
204                                                        "linsys-hdsdi-audio" );
205     int i = 0;
206     p_sys->i_max_channel = -1;
207
208     while ( psz_parser != NULL && *psz_parser )
209     {
210         int i_id, i_group, i_pair;
211         char *psz_next = strchr( psz_parser, '=' );
212         if ( psz_next != NULL )
213         {
214             *psz_next = '\0';
215             i_id = strtol( psz_parser, NULL, 0 );
216             psz_parser = psz_next + 1;
217         }
218         else
219             i_id = 0;
220
221         psz_next = strchr( psz_parser, ':' );
222         if ( psz_next != NULL )
223         {
224             *psz_next = '\0';
225             psz_next++;
226         }
227
228         if ( sscanf( psz_parser, "%d,%d", &i_group, &i_pair ) == 2 )
229         {
230             p_sys->p_audios[i].i_channel = (i_group - 1) * 2 + (i_pair - 1);
231             if ( p_sys->p_audios[i].i_channel > p_sys->i_max_channel )
232                 p_sys->i_max_channel = p_sys->p_audios[i].i_channel;
233             p_sys->p_audios[i].i_id = i_id;
234             i++;
235         }
236         else
237             msg_Warn( p_demux, "malformed audio configuration (%s)",
238                       psz_parser );
239
240         psz_parser = psz_next;
241     }
242     free( psz_string );
243     for ( ; i < MAX_AUDIOS; i++ )
244         p_sys->p_audios[i].i_channel = -1;
245
246
247     p_sys->i_link = var_InheritInteger( p_demux, "linsys-hdsdi-link" );
248
249     if( InitCapture( p_demux ) != VLC_SUCCESS )
250     {
251         free( p_sys );
252         return VLC_EGENERIC;
253     }
254
255     return VLC_SUCCESS;
256 }
257
258 /*****************************************************************************
259  * DemuxClose:
260  *****************************************************************************/
261 static void Close( vlc_object_t *p_this )
262 {
263     demux_t     *p_demux = (demux_t *)p_this;
264     demux_sys_t *p_sys = p_demux->p_sys;
265
266     CloseCapture( p_demux );
267     free( p_sys );
268 }
269
270 /*****************************************************************************
271  * DemuxDemux:
272  *****************************************************************************/
273 static int Demux( demux_t *p_demux )
274 {
275     return ( Capture( p_demux ) == VLC_SUCCESS );
276 }
277
278 /*****************************************************************************
279  * Control:
280  *****************************************************************************/
281 static int Control( demux_t *p_demux, int i_query, va_list args )
282 {
283     bool *pb;
284     int64_t *pi64;
285
286     switch( i_query )
287     {
288         /* Special for access_demux */
289         case DEMUX_CAN_PAUSE:
290         case DEMUX_CAN_CONTROL_PACE:
291             /* TODO */
292             pb = (bool*)va_arg( args, bool * );
293             *pb = false;
294             return VLC_SUCCESS;
295
296         case DEMUX_GET_PTS_DELAY:
297             pi64 = (int64_t*)va_arg( args, int64_t * );
298             *pi64 = INT64_C(1000)
299                   * var_InheritInteger( p_demux, "live-caching" );
300             return VLC_SUCCESS;
301
302         /* TODO implement others */
303         default:
304             return VLC_EGENERIC;
305     }
306 }
307
308 /*****************************************************************************
309  * HDSDI syntax parsing stuff
310  *****************************************************************************/
311 #define U   (uint16_t)(p_line[0])
312 #define Y1  (uint16_t)(p_line[1])
313 #define V   (uint16_t)(p_line[2])
314 #define Y2  (uint16_t)(p_line[3])
315
316 /* For lines 0 [4] or 1 [4] */
317 static void Unpack01( const uint8_t *p_line, unsigned int i_size,
318                       uint8_t *p_y, uint8_t *p_u, uint8_t *p_v )
319 {
320     const uint8_t *p_end = p_line + i_size;
321
322     while ( p_line < p_end )
323     {
324         *p_u++ = U;
325         *p_y++ = Y1;
326         *p_v++ = V;
327         *p_y++ = Y2;
328         p_line += 4;
329     }
330 }
331
332 /* For lines 2 [4] */
333 static void Unpack2( const uint8_t *p_line, unsigned int i_size,
334                      uint8_t *p_y, uint8_t *p_u, uint8_t *p_v )
335 {
336     const uint8_t *p_end = p_line + i_size;
337
338     while ( p_line < p_end )
339     {
340         uint16_t tmp;
341         tmp = 3 * *p_u;
342         tmp += U;
343         *p_u++ = tmp / 4;
344         *p_y++ = Y1;
345         tmp = 3 * *p_v;
346         tmp += V;
347         *p_v++ = tmp / 4;
348         *p_y++ = Y2;
349         p_line += 4;
350     }
351 }
352
353 /* For lines 3 [4] */
354 static void Unpack3( const uint8_t *p_line, unsigned int i_size,
355                      uint8_t *p_y, uint8_t *p_u, uint8_t *p_v )
356 {
357     const uint8_t *p_end = p_line + i_size;
358
359     while ( p_line < p_end )
360     {
361         uint16_t tmp;
362         tmp = *p_u;
363         tmp += 3 * U;
364         *p_u++ = tmp / 4;
365         *p_y++ = Y1;
366         tmp = *p_v;
367         tmp += 3 * V;
368         *p_v++ = tmp / 4;
369         *p_y++ = Y2;
370         p_line += 4;
371     }
372 }
373
374 #undef U
375 #undef Y1
376 #undef V
377 #undef Y2
378
379 static void SparseCopy( int16_t *p_dest, const int16_t *p_src,
380                         size_t i_nb_samples, size_t i_offset, size_t i_stride )
381 {
382     for ( size_t i = 0; i < i_nb_samples; i++ )
383     {
384         p_dest[2 * i] = p_src[i_offset];
385         p_dest[2 * i + 1] = p_src[i_offset + 1];
386         i_offset += 2 * i_stride;
387     }
388 }
389
390 /*****************************************************************************
391  * Video & audio decoding
392  *****************************************************************************/
393 struct block_extension_t
394 {
395     bool            b_progressive;          /**< is it a progressive frame ? */
396     bool            b_top_field_first;             /**< which field is first */
397     unsigned int    i_nb_fields;                  /**< # of displayed fields */
398     unsigned int    i_aspect;                     /**< aspect ratio of frame */
399 };
400
401 static void StopDecode( demux_t *p_demux )
402 {
403     demux_sys_t *p_sys = p_demux->p_sys;
404
405     es_out_Del( p_demux->out, p_sys->p_es_video );
406
407     for ( int i = 0; i < MAX_AUDIOS; i++ )
408     {
409         hdsdi_audio_t *p_audio = &p_sys->p_audios[i];
410         if ( p_audio->i_channel != -1 && p_audio->p_es != NULL )
411         {
412             es_out_Del( p_demux->out, p_audio->p_es );
413             p_audio->p_es = NULL;
414         }
415     }
416 }
417
418 static int InitVideo( demux_t *p_demux )
419 {
420     demux_sys_t *p_sys = p_demux->p_sys;
421     es_format_t fmt;
422
423     msg_Dbg( p_demux, "found standard %d", p_sys->i_standard );
424     switch ( p_sys->i_standard )
425     {
426     case SDIVIDEO_CTL_BT_601_576I_50HZ:
427         /* PAL */
428         p_sys->i_frame_rate      = 25;
429         p_sys->i_frame_rate_base = 1;
430         p_sys->i_width           = 720;
431         p_sys->i_height          = 576;
432         p_sys->i_aspect          = 4 * VOUT_ASPECT_FACTOR / 3;
433         break;
434
435     case SDIVIDEO_CTL_SMPTE_296M_720P_50HZ:
436         p_sys->i_frame_rate      = 50;
437         p_sys->i_frame_rate_base = 1;
438         p_sys->i_width           = 1280;
439         p_sys->i_height          = 720;
440         p_sys->i_aspect          = 16 * VOUT_ASPECT_FACTOR / 9;
441         break;
442
443     case SDIVIDEO_CTL_SMPTE_296M_720P_60HZ:
444         p_sys->i_frame_rate      = 60;
445         p_sys->i_frame_rate_base = 1;
446         p_sys->i_width           = 1280;
447         p_sys->i_height          = 720;
448         p_sys->i_aspect          = 16 * VOUT_ASPECT_FACTOR / 9;
449         break;
450
451     case SDIVIDEO_CTL_SMPTE_295M_1080I_50HZ:
452     case SDIVIDEO_CTL_SMPTE_274M_1080I_50HZ:
453     case SDIVIDEO_CTL_SMPTE_274M_1080PSF_25HZ:
454         /* 1080i50 or 1080p25 */
455         p_sys->i_frame_rate      = 25;
456         p_sys->i_frame_rate_base = 1;
457         p_sys->i_width           = 1920;
458         p_sys->i_height          = 1080;
459         p_sys->i_aspect          = 16 * VOUT_ASPECT_FACTOR / 9;
460         break;
461
462     case SDIVIDEO_CTL_SMPTE_274M_1080I_59_94HZ:
463         p_sys->i_frame_rate      = 30000;
464         p_sys->i_frame_rate_base = 1001;
465         p_sys->i_width           = 1920;
466         p_sys->i_height          = 1080;
467         p_sys->i_aspect          = 16 * VOUT_ASPECT_FACTOR / 9;
468         break;
469
470     case SDIVIDEO_CTL_SMPTE_274M_1080I_60HZ:
471         p_sys->i_frame_rate      = 30;
472         p_sys->i_frame_rate_base = 1;
473         p_sys->i_width           = 1920;
474         p_sys->i_height          = 1080;
475         p_sys->i_aspect          = 16 * VOUT_ASPECT_FACTOR / 9;
476         break;
477
478     default:
479         msg_Err( p_demux, "unsupported standard %d", p_sys->i_standard );
480         return VLC_EGENERIC;
481     }
482
483     p_sys->i_next_vdate = START_DATE;
484     p_sys->i_incr = 1000000 * p_sys->i_frame_rate_base / p_sys->i_frame_rate;
485     p_sys->i_vblock_size = p_sys->i_width * p_sys->i_height * 3 / 2
486                             + sizeof(struct block_extension_t);
487
488     /* Video ES */
489     es_format_Init( &fmt, VIDEO_ES, VLC_FOURCC('I','4','2','0') );
490     fmt.i_id                    = p_sys->i_id_video;
491     fmt.video.i_frame_rate      = p_sys->i_frame_rate;
492     fmt.video.i_frame_rate_base = p_sys->i_frame_rate_base;
493     fmt.video.i_width           = fmt.video.i_visible_width = p_sys->i_width;
494     fmt.video.i_height          = fmt.video.i_visible_height = p_sys->i_height;
495     fmt.video.i_sar_num         = p_sys->i_aspect * fmt.video.i_height
496                                   / fmt.video.i_width;
497     fmt.video.i_sar_den         = VOUT_ASPECT_FACTOR;
498     p_sys->p_es_video           = es_out_Add( p_demux->out, &fmt );
499
500     return VLC_SUCCESS;
501 }
502
503 static int InitAudio( demux_t *p_demux )
504 {
505     demux_sys_t *p_sys = p_demux->p_sys;
506     es_format_t fmt;
507
508     for ( int i = 0; i < MAX_AUDIOS; i++ )
509     {
510         hdsdi_audio_t *p_audio = &p_sys->p_audios[i];
511
512         if ( p_audio->i_channel == -1 ) continue;
513
514         msg_Dbg( p_demux, "starting audio %u/%u rate:%u delay:%d",
515                  1 + p_audio->i_channel / 2, 1 + (p_audio->i_channel % 2),
516                  p_sys->i_sample_rate, p_audio->i_delay );
517
518         es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC('a','r','a','w') );
519         fmt.i_id = p_audio->i_id;
520         fmt.audio.i_channels          = 2;
521         fmt.audio.i_original_channels =
522         fmt.audio.i_physical_channels = AOUT_CHANS_STEREO;
523         fmt.audio.i_rate              = p_sys->i_sample_rate;
524         fmt.audio.i_bitspersample     = 16;
525         fmt.audio.i_blockalign = fmt.audio.i_channels *
526             fmt.audio.i_bitspersample / 8;
527         fmt.i_bitrate = fmt.audio.i_channels * fmt.audio.i_rate *
528             fmt.audio.i_bitspersample;
529         p_audio->p_es = es_out_Add( p_demux->out, &fmt );
530     }
531
532     p_sys->i_next_adate = START_DATE;
533     p_sys->i_ablock_size = p_sys->i_sample_rate * 4 * p_sys->i_frame_rate_base / p_sys->i_frame_rate;
534     p_sys->i_aincr = 1000000. * p_sys->i_ablock_size / p_sys->i_sample_rate / 4;
535
536     return VLC_SUCCESS;
537 }
538
539 static int HandleVideo( demux_t *p_demux, const uint8_t *p_buffer )
540 {
541     demux_sys_t *p_sys = p_demux->p_sys;
542     block_t *p_current_picture = block_Alloc( p_sys->i_vblock_size );
543     if( unlikely( !p_current_picture ) )
544         return VLC_ENOMEM;
545     uint8_t *p_y = p_current_picture->p_buffer;
546     uint8_t *p_u = p_y + p_sys->i_width * p_sys->i_height;
547     uint8_t *p_v = p_u + p_sys->i_width * p_sys->i_height / 4;
548     unsigned int i_total_size = p_sys->i_width * 2;
549     unsigned int i_current_line;
550     struct block_extension_t ext;
551
552     for ( i_current_line = 0; i_current_line < p_sys->i_height;
553           i_current_line++ )
554     {
555         bool b_field = (i_current_line >= p_sys->i_height / 2);
556         unsigned int i_field_line = b_field ?
557             i_current_line - (p_sys->i_height + 1) / 2 :
558             i_current_line;
559         unsigned int i_real_line = b_field + i_field_line * 2;
560         const uint8_t *p_line = p_buffer + i_current_line * p_sys->i_width * 2;
561
562         if ( !(i_field_line % 2) && !b_field )
563             Unpack01( p_line, i_total_size,
564                       p_y + p_sys->i_width * i_real_line,
565                       p_u + (p_sys->i_width / 2) * (i_real_line / 2),
566                       p_v + (p_sys->i_width / 2) * (i_real_line / 2) );
567         else if ( !(i_field_line % 2) )
568             Unpack01( p_line, i_total_size,
569                       p_y + p_sys->i_width * i_real_line,
570                       p_u + (p_sys->i_width / 2) * (i_real_line / 2 + 1),
571                       p_v + (p_sys->i_width / 2) * (i_real_line / 2 + 1) );
572        else if ( !b_field )
573             Unpack2( p_line, i_total_size,
574                      p_y + p_sys->i_width * i_real_line,
575                      p_u + (p_sys->i_width / 2) * (i_real_line / 2 - 1),
576                      p_v + (p_sys->i_width / 2) * (i_real_line / 2 - 1) );
577        else
578             Unpack3( p_line, i_total_size,
579                      p_y + p_sys->i_width * i_real_line,
580                      p_u + (p_sys->i_width / 2) * (i_real_line / 2),
581                      p_v + (p_sys->i_width / 2) * (i_real_line / 2) );
582     }
583
584     /* FIXME: progressive formats ? */
585     ext.b_progressive = false;
586     ext.i_nb_fields = 2;
587     ext.b_top_field_first = true;
588     ext.i_aspect = p_sys->i_forced_aspect ? p_sys->i_forced_aspect :
589                    p_sys->i_aspect;
590
591     memcpy( &p_current_picture->p_buffer[p_sys->i_vblock_size
592                                           - sizeof(struct block_extension_t)],
593             &ext, sizeof(struct block_extension_t) );
594
595     p_current_picture->i_dts = p_current_picture->i_pts = p_sys->i_next_vdate;
596     es_out_Send( p_demux->out, p_sys->p_es_video, p_current_picture );
597
598     es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_next_vdate );
599     p_sys->i_next_vdate += p_sys->i_incr;
600     return VLC_SUCCESS;
601 }
602
603 static int HandleAudio( demux_t *p_demux, const uint8_t *p_buffer )
604 {
605     demux_sys_t *p_sys = p_demux->p_sys;
606
607     for ( int i = 0; i < MAX_AUDIOS; i++ )
608     {
609         hdsdi_audio_t *p_audio = &p_sys->p_audios[i];
610         if ( p_audio->i_channel != -1 && p_audio->p_es != NULL )
611         {
612             block_t *p_block = block_Alloc( p_sys->i_ablock_size );
613             if( unlikely( !p_block ) )
614                 return VLC_ENOMEM;
615             SparseCopy( (int16_t *)p_block->p_buffer, (const int16_t *)p_buffer,
616                         p_sys->i_ablock_size / 4,
617                         p_audio->i_channel * 2, p_sys->i_max_channel + 1 );
618
619             p_block->i_dts = p_block->i_pts
620                 = p_sys->i_next_adate + (mtime_t)p_audio->i_delay
621                    * INT64_C(1000000) / p_sys->i_sample_rate;
622             p_block->i_length = p_sys->i_aincr;
623             es_out_Send( p_demux->out, p_audio->p_es, p_block );
624         }
625     }
626     p_sys->i_next_adate += p_sys->i_aincr;
627     return VLC_SUCCESS;
628 }
629
630 /*****************************************************************************
631  * Low-level device stuff
632  *****************************************************************************/
633 #define MAXLEN 256
634
635 static ssize_t WriteULSysfs( const char *psz_fmt, unsigned int i_link,
636                              unsigned int i_buf )
637 {
638     char psz_file[MAXLEN], psz_data[MAXLEN];
639     int i_fd;
640     ssize_t i_ret;
641
642     snprintf( psz_file, sizeof(psz_file) -1, psz_fmt, i_link );
643
644     snprintf( psz_data, sizeof(psz_data) -1, "%u\n", i_buf );
645
646     if ( (i_fd = vlc_open( psz_file, O_WRONLY )) < 0 )
647         return i_fd;
648
649     i_ret = write( i_fd, psz_data, strlen(psz_data) + 1 );
650     close( i_fd );
651     return i_ret;
652 }
653
654 static int InitCapture( demux_t *p_demux )
655 {
656     demux_sys_t *p_sys = p_demux->p_sys;
657 #ifdef HAVE_MMAP_SDIVIDEO
658     const int i_page_size = getpagesize();
659     unsigned int i_bufmemsize;
660 #endif
661     char psz_vdev[MAXLEN];
662
663     snprintf( psz_vdev, sizeof(psz_vdev), SDIVIDEO_DEVICE, p_sys->i_link );
664     if ( (p_sys->i_vfd = vlc_open( psz_vdev, O_RDONLY ) ) < 0 )
665     {
666         msg_Err( p_demux, "couldn't open device %s", psz_vdev );
667         return VLC_EGENERIC;
668     }
669
670     /* Wait for standard to settle down */
671     while ( vlc_object_alive(p_demux) )
672     {
673         struct pollfd pfd[1];
674
675         pfd[0].fd = p_sys->i_vfd;
676         pfd[0].events = POLLPRI;
677
678         if( poll( pfd, 1, READ_TIMEOUT ) < 0 )
679            continue;
680
681         if ( pfd[0].revents & POLLPRI )
682         {
683             unsigned int i_val;
684
685             if ( ioctl( p_sys->i_vfd, SDIVIDEO_IOC_RXGETEVENTS, &i_val ) < 0 )
686                 msg_Warn( p_demux, "couldn't SDIVIDEO_IOC_RXGETEVENTS: %s",
687                           vlc_strerror_c(errno) );
688             else
689             {
690                 if ( i_val & SDIVIDEO_EVENT_RX_BUFFER )
691                     msg_Warn( p_demux, "driver receive buffer queue overrun" );
692                 if ( i_val & SDIVIDEO_EVENT_RX_FIFO )
693                     msg_Warn( p_demux, "onboard receive FIFO overrun");
694                 if ( i_val & SDIVIDEO_EVENT_RX_CARRIER )
695                     msg_Warn( p_demux, "carrier status change");
696                 if ( i_val & SDIVIDEO_EVENT_RX_DATA )
697                     msg_Warn( p_demux, "data status change");
698                 if ( i_val & SDIVIDEO_EVENT_RX_STD )
699                 {
700                     msg_Warn( p_demux, "standard status change");
701                     break;
702                 }
703             }
704         }
705     }
706     if ( !vlc_object_alive(p_demux) )
707     {
708         close( p_sys->i_vfd );
709         return VLC_EGENERIC;
710     }
711
712     if ( ioctl( p_sys->i_vfd, SDIVIDEO_IOC_RXGETVIDSTATUS, &p_sys->i_standard )
713           < 0 )
714     {
715         msg_Warn( p_demux, "couldn't SDIVIDEO_IOC_RXGETVIDSTATUS: %s",
716                   vlc_strerror_c(errno) );
717         close( p_sys->i_vfd );
718         return VLC_EGENERIC;
719     }
720     close( p_sys->i_vfd );
721
722     if ( InitVideo( p_demux ) != VLC_SUCCESS )
723         return VLC_EGENERIC;
724     p_sys->i_vbuffer_size = p_sys->i_height * p_sys->i_width * 2;
725
726     /* First open the audio for synchronization reasons */
727     if ( p_sys->i_max_channel != -1 )
728     {
729         unsigned int i_rate;
730         char psz_adev[MAXLEN];
731
732         snprintf( psz_adev, sizeof(psz_adev), SDIAUDIO_DEVICE, p_sys->i_link );
733         if ( (p_sys->i_afd = vlc_open( psz_adev, O_RDONLY ) ) < 0 )
734         {
735             msg_Err( p_demux, "couldn't open device %s", psz_adev );
736             return VLC_EGENERIC;
737         }
738
739         if ( ioctl( p_sys->i_afd, SDIAUDIO_IOC_RXGETAUDRATE, &i_rate ) < 0 )
740         {
741             msg_Warn( p_demux, "couldn't SDIAUDIO_IOC_RXGETAUDRATE: %s",
742                       vlc_strerror_c(errno) );
743             return VLC_EGENERIC;
744         }
745         switch ( i_rate )
746         {
747         case SDIAUDIO_CTL_ASYNC_48_KHZ:
748         case SDIAUDIO_CTL_SYNC_48_KHZ:
749             p_sys->i_sample_rate = 48000;
750             break;
751         case SDIAUDIO_CTL_ASYNC_44_1_KHZ:
752         case SDIAUDIO_CTL_SYNC_44_1_KHZ:
753             p_sys->i_sample_rate = 44100;
754             break;
755         case SDIAUDIO_CTL_ASYNC_32_KHZ:
756         case SDIAUDIO_CTL_SYNC_32_KHZ:
757             p_sys->i_sample_rate = 32000;
758             break;
759         case SDIAUDIO_CTL_ASYNC_96_KHZ:
760         case SDIAUDIO_CTL_SYNC_96_KHZ:
761             p_sys->i_sample_rate = 96000;
762             break;
763         case SDIAUDIO_CTL_ASYNC_FREE_RUNNING:
764         case SDIAUDIO_CTL_SYNC_FREE_RUNNING:
765         default:
766             msg_Err( p_demux, "unknown sample rate %u", i_rate );
767             return VLC_EGENERIC;
768         }
769         close( p_sys->i_afd );
770
771         if ( InitAudio( p_demux ) != VLC_SUCCESS )
772             return VLC_EGENERIC;
773         p_sys->i_abuffer_size = p_sys->i_ablock_size
774                                  * (1 + p_sys->i_max_channel);
775
776         /* Use 16-bit audio */
777         if ( WriteULSysfs( SDIAUDIO_SAMPLESIZE_FILE, p_sys->i_link,
778                            SDIAUDIO_CTL_AUDSAMP_SZ_16 ) < 0 )
779         {
780             msg_Err( p_demux, "couldn't write file " SDIAUDIO_SAMPLESIZE_FILE,
781                      p_sys->i_link );
782             return VLC_EGENERIC;
783         }
784
785         if ( WriteULSysfs( SDIAUDIO_CHANNELS_FILE, p_sys->i_link,
786                            (p_sys->i_max_channel + 1) * 2 ) < 0 )
787         {
788             msg_Err( p_demux, "couldn't write file " SDIAUDIO_CHANNELS_FILE,
789                      p_sys->i_link );
790             return VLC_EGENERIC;
791         }
792
793 #ifdef HAVE_MMAP_SDIAUDIO
794         if ( (p_sys->i_abuffers = ReadULSysfs( SDIAUDIO_BUFFERS_FILE,
795                                                p_sys->i_link )) < 0 )
796         {
797             msg_Err( p_demux, "couldn't read file " SDIAUDIO_BUFFERS_FILE,
798                      p_sys->i_link );
799             return VLC_EGENERIC;
800         }
801         p_sys->i_current_abuffer = 0;
802 #endif
803
804         if ( WriteULSysfs( SDIAUDIO_BUFSIZE_FILE, p_sys->i_link,
805                            p_sys->i_abuffer_size ) < 0 )
806         {
807             msg_Err( p_demux, "couldn't write file " SDIAUDIO_BUFSIZE_FILE,
808                      p_sys->i_link );
809             return VLC_EGENERIC;
810         }
811
812         if ( (p_sys->i_afd = open( psz_adev, O_RDONLY ) ) < 0 )
813         {
814             msg_Err( p_demux, "couldn't open device %s", psz_adev );
815             return VLC_EGENERIC;
816         }
817
818 #ifdef HAVE_MMAP_SDIAUDIO
819         i_bufmemsize = ((p_sys->i_abuffer_size + i_page_size - 1) / i_page_size)
820                          * i_page_size;
821         p_sys->pp_abuffers = malloc( p_sys->i_abuffers * sizeof(uint8_t *) );
822         if( unlikely( !p_sys->pp_abuffers ) )
823             return VLC_ENOMEM;
824         for ( unsigned int i = 0; i < p_sys->i_abuffers; i++ )
825         {
826             if ( (p_sys->pp_abuffers[i] = mmap( NULL, p_sys->i_abuffer_size,
827                                                 PROT_READ, MAP_SHARED, p_sys->i_afd,
828                                                 i * i_bufmemsize )) == MAP_FAILED )
829             {
830                 msg_Err( p_demux, "couldn't mmap(%d): %s", i,
831                          vlc_strerror_c(errno) );
832                 return VLC_EGENERIC;
833             }
834         }
835 #endif
836     }
837
838     /* Use 8-bit video */
839     if ( WriteULSysfs( SDIVIDEO_MODE_FILE, p_sys->i_link,
840                        SDIVIDEO_CTL_MODE_UYVY ) < 0 )
841     {
842         msg_Err( p_demux, "couldn't write file " SDIVIDEO_MODE_FILE,
843                  p_sys->i_link );
844         return VLC_EGENERIC;
845     }
846
847     if ( WriteULSysfs( SDIVIDEO_BUFFERS_FILE, p_sys->i_link,
848                        NB_VBUFFERS ) < 0 )
849     {
850         msg_Err( p_demux, "couldn't write file " SDIVIDEO_BUFFERS_FILE,
851                  p_sys->i_link );
852         return VLC_EGENERIC;
853     }
854 #ifdef HAVE_MMAP_SDIVIDEO
855     p_sys->i_vbuffers = NB_VBUFFERS;
856 #endif
857
858     if ( WriteULSysfs( SDIVIDEO_BUFSIZE_FILE, p_sys->i_link,
859                        p_sys->i_vbuffer_size ) < 0 )
860     {
861         msg_Err( p_demux, "couldn't write file " SDIVIDEO_BUFSIZE_FILE,
862                  p_sys->i_link );
863         return VLC_EGENERIC;
864     }
865
866     if ( (p_sys->i_vfd = open( psz_vdev, O_RDONLY ) ) < 0 )
867     {
868         msg_Err( p_demux, "couldn't open device %s", psz_vdev );
869         return VLC_EGENERIC;
870     }
871
872 #ifdef HAVE_MMAP_SDIVIDEO
873     p_sys->i_current_vbuffer = 0;
874     i_bufmemsize = ((p_sys->i_vbuffer_size + i_page_size - 1) / i_page_size)
875                      * i_page_size;
876     p_sys->pp_vbuffers = malloc( p_sys->i_vbuffers * sizeof(uint8_t *) );
877     if( unlikely( !p_sys->pp_vbuffers ) )
878         return VLC_ENOMEM;
879     for ( unsigned int i = 0; i < p_sys->i_vbuffers; i++ )
880     {
881         if ( (p_sys->pp_vbuffers[i] = mmap( NULL, p_sys->i_vbuffer_size,
882                                             PROT_READ, MAP_SHARED, p_sys->i_vfd,
883                                             i * i_bufmemsize )) == MAP_FAILED )
884         {
885             msg_Err( p_demux, "couldn't mmap(%d): %s", i,
886                      vlc_strerror_c(errno) );
887             return VLC_EGENERIC;
888         }
889     }
890 #endif
891
892     return VLC_SUCCESS;
893 }
894
895 static void CloseCapture( demux_t *p_demux )
896 {
897     demux_sys_t *p_sys = p_demux->p_sys;
898
899     StopDecode( p_demux );
900 #ifdef HAVE_MMAP_SDIVIDEO
901     for ( unsigned int i = 0; i < p_sys->i_vbuffers; i++ )
902         munmap( p_sys->pp_vbuffers[i], p_sys->i_vbuffer_size );
903     free( p_sys->pp_vbuffers );
904 #endif
905     close( p_sys->i_vfd );
906     if ( p_sys->i_max_channel != -1 )
907     {
908 #ifdef HAVE_MMAP_SDIAUDIO
909         for ( unsigned int i = 0; i < p_sys->i_abuffers; i++ )
910             munmap( p_sys->pp_abuffers[i], p_sys->i_abuffer_size );
911         free( p_sys->pp_abuffers );
912 #endif
913         close( p_sys->i_afd );
914     }
915 }
916
917 static int Capture( demux_t *p_demux )
918 {
919     demux_sys_t *p_sys = p_demux->p_sys;
920     struct pollfd pfd[2];
921
922     pfd[0].fd = p_sys->i_vfd;
923     pfd[0].events = POLLIN | POLLPRI;
924     if ( p_sys->i_max_channel != -1 )
925     {
926         pfd[1].fd = p_sys->i_afd;
927         pfd[1].events = POLLIN | POLLPRI;
928     }
929
930     if( poll( pfd, 1 + (p_sys->i_max_channel != -1), READ_TIMEOUT ) < 0 )
931         return VLC_SUCCESS;
932
933     if ( pfd[0].revents & POLLPRI )
934     {
935         unsigned int i_val;
936
937         if ( ioctl( p_sys->i_vfd, SDIVIDEO_IOC_RXGETEVENTS, &i_val ) < 0 )
938             msg_Warn( p_demux, "couldn't SDIVIDEO_IOC_RXGETEVENTS: %s",
939                       vlc_strerror_c(errno) );
940         else
941         {
942             if ( i_val & SDIVIDEO_EVENT_RX_BUFFER )
943                 msg_Warn( p_demux, "driver receive buffer queue overrun" );
944             if ( i_val & SDIVIDEO_EVENT_RX_FIFO )
945                 msg_Warn( p_demux, "onboard receive FIFO overrun");
946             if ( i_val & SDIVIDEO_EVENT_RX_CARRIER )
947                 msg_Warn( p_demux, "carrier status change");
948             if ( i_val & SDIVIDEO_EVENT_RX_DATA )
949                 msg_Warn( p_demux, "data status change");
950             if ( i_val & SDIVIDEO_EVENT_RX_STD )
951                 msg_Warn( p_demux, "standard status change");
952         }
953
954         p_sys->i_next_adate += CLOCK_GAP;
955         p_sys->i_next_vdate += CLOCK_GAP;
956     }
957
958     if ( p_sys->i_max_channel != -1 && pfd[1].revents & POLLPRI )
959     {
960         unsigned int i_val;
961
962         if ( ioctl( p_sys->i_afd, SDIAUDIO_IOC_RXGETEVENTS, &i_val ) < 0 )
963             msg_Warn( p_demux, "couldn't SDIAUDIO_IOC_RXGETEVENTS: %s",
964                       vlc_strerror_c(errno) );
965         else
966         {
967             if ( i_val & SDIAUDIO_EVENT_RX_BUFFER )
968                 msg_Warn( p_demux, "driver receive buffer queue overrun" );
969             if ( i_val & SDIAUDIO_EVENT_RX_FIFO )
970                 msg_Warn( p_demux, "onboard receive FIFO overrun");
971             if ( i_val & SDIAUDIO_EVENT_RX_CARRIER )
972                 msg_Warn( p_demux, "carrier status change");
973             if ( i_val & SDIAUDIO_EVENT_RX_DATA )
974                 msg_Warn( p_demux, "data status change");
975         }
976
977         p_sys->i_next_adate += CLOCK_GAP;
978         p_sys->i_next_vdate += CLOCK_GAP;
979     }
980
981     if ( pfd[0].revents & POLLIN )
982     {
983 #ifdef HAVE_MMAP_SDIVIDEO
984         if ( ioctl( p_sys->i_vfd, SDIVIDEO_IOC_DQBUF, p_sys->i_current_vbuffer )
985               < 0 )
986         {
987             msg_Warn( p_demux, "couldn't SDIVIDEO_IOC_DQBUF: %s",
988                       vlc_strerror_c(errno) );
989             return VLC_EGENERIC;
990         }
991
992         if( HandleVideo( p_demux, p_sys->pp_vbuffers[p_sys->i_current_vbuffer] ) != VLC_SUCCESS )
993             return VLC_ENOMEM;
994
995         if ( ioctl( p_sys->i_vfd, SDIVIDEO_IOC_QBUF, p_sys->i_current_vbuffer )
996               < 0 )
997         {
998             msg_Warn( p_demux, "couldn't SDIVIDEO_IOC_QBUF: %s",
999                       vlc_strerror_c(errno) );
1000             return VLC_EGENERIC;
1001         }
1002
1003         p_sys->i_current_vbuffer++;
1004         p_sys->i_current_vbuffer %= p_sys->i_vbuffers;
1005 #else
1006         uint8_t *p_buffer = malloc( p_sys->i_vbuffer_size );
1007         if( unlikely( !p_buffer ) )
1008             return VLC_ENOMEM;
1009
1010         if ( read( p_sys->i_vfd, p_buffer, p_sys->i_vbuffer_size ) < 0 )
1011         {
1012             msg_Warn( p_demux, "couldn't read: %s", vlc_strerror_c(errno) );
1013             free( p_buffer );
1014             return VLC_EGENERIC;
1015         }
1016
1017         if( HandleVideo( p_demux, p_buffer ) != VLC_SUCCESS )
1018         {
1019             free( p_buffer );
1020             return VLC_ENOMEM;
1021         }
1022         free( p_buffer );
1023 #endif
1024     }
1025
1026     if ( p_sys->i_max_channel != -1 && pfd[1].revents & POLLIN )
1027     {
1028 #ifdef HAVE_MMAP_SDIAUDIO
1029         if ( ioctl( p_sys->i_afd, SDIAUDIO_IOC_DQBUF, p_sys->i_current_abuffer )
1030               < 0 )
1031         {
1032             msg_Warn( p_demux, "couldn't SDIAUDIO_IOC_DQBUF: %s",
1033                       vlc_strerror_c(errno) );
1034             return VLC_EGENERIC;
1035         }
1036
1037         if( HandleAudio( p_demux, p_sys->pp_abuffers[p_sys->i_current_abuffer] ) != VLC_SUCCESS )
1038             return VLC_ENOMEM;
1039
1040         if ( ioctl( p_sys->i_afd, SDIAUDIO_IOC_QBUF, p_sys->i_current_abuffer )
1041               < 0 )
1042         {
1043             msg_Warn( p_demux, "couldn't SDIAUDIO_IOC_QBUF: %s",
1044                       vlc_strerror_c(errno) );
1045             return VLC_EGENERIC;
1046         }
1047
1048         p_sys->i_current_abuffer++;
1049         p_sys->i_current_abuffer %= p_sys->i_abuffers;
1050 #else
1051         uint8_t *p_buffer = malloc( p_sys->i_abuffer_size );
1052         if( unlikely( !p_buffer ) )
1053             return VLC_ENOMEM;
1054
1055         if ( read( p_sys->i_afd, p_buffer, p_sys->i_abuffer_size ) < 0 )
1056         {
1057             msg_Warn( p_demux, "couldn't read: %s", vlc_strerror_c(errno) );
1058             free( p_buffer );
1059             return VLC_EGENERIC;
1060         }
1061
1062         if( HandleAudio( p_demux, p_buffer ) != VLC_SUCCESS )
1063         {
1064             free( p_buffer );
1065             return VLC_ENOMEM;
1066         }
1067         free( p_buffer );
1068 #endif
1069     }
1070
1071     return VLC_SUCCESS;
1072 }