1 /*****************************************************************************
2 * linsys_sdi.c: SDI capture for Linear Systems/Computer Modules cards
3 *****************************************************************************
4 * Copyright (C) 2009-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 <fcntl.h>
35 #include <errno.h>
36 #include <limits.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_sdi.h"
48
49 #undef ZVBI_DEBUG
50 #include <libzvbi.h>
51
52 #define SDI_DEVICE "/dev/sdirx%u"
53 #define SDI_BUFFERS_FILE "/sys/class/sdi/sdirx%u/buffers"
54 #define SDI_BUFSIZE_FILE "/sys/class/sdi/sdirx%u/bufsize"
55 #define SDI_MODE_FILE "/sys/class/sdi/sdirx%u/mode"
56 #define READ_TIMEOUT 80000
57 #define RESYNC_TIMEOUT 500000
58 #define CLOCK_GAP INT64_C(500000)
59 #define START_DATE INT64_C(4294967296)
60
61 #define DEMUX_BUFFER_SIZE 1350000
62 #define MAX_AUDIOS 4
63 #define SAMPLERATE_TOLERANCE 0.1f
64
65 /*****************************************************************************
66 * Module descriptor
67 *****************************************************************************/
68 #define LINK_TEXT N_("Link #")
69 #define LINK_LONGTEXT N_( \
70 "Allows you to set the desired link of the board for the capture (starting at 0)." )
71 #define VIDEO_TEXT N_("Video ID")
72 #define VIDEO_LONGTEXT N_( \
73 "Allows you to set the ES ID of the video." )
74 #define VIDEO_ASPECT_TEXT N_("Aspect ratio")
75 #define VIDEO_ASPECT_LONGTEXT N_( \
76 "Allows you to force the aspect ratio of the video." )
77 #define AUDIO_TEXT N_("Audio configuration")
78 #define AUDIO_LONGTEXT N_( \
79 "Allows you to set audio configuration (id=group,pair:id=group,pair...)." )
80 #define TELX_TEXT N_("Teletext configuration")
81 #define TELX_LONGTEXT N_( \
82 "Allows you to set Teletext configuration (id=line1-lineN with both fields)." )
83 #define TELX_LANG_TEXT N_("Teletext language")
84 #define TELX_LANG_LONGTEXT N_( \
85 "Allows you to set Teletext language (page=lang/type,...)." )
86
87 static int Open ( vlc_object_t * );
88 static void Close( vlc_object_t * );
89 static int DemuxOpen ( vlc_object_t * );
90 static void DemuxClose( vlc_object_t * );
91
92 vlc_module_begin()
93 set_description( N_("SDI Input") )
94 set_shortname( N_("SDI") )
95 set_category( CAT_INPUT )
96 set_subcategory( SUBCAT_INPUT_ACCESS )
97
98 add_integer( "linsys-sdi-link", 0,
99 LINK_TEXT, LINK_LONGTEXT, true )
100
101 add_integer( "linsys-sdi-id-video", 0, VIDEO_TEXT, VIDEO_LONGTEXT, true )
102 add_string( "linsys-sdi-aspect-ratio", "", VIDEO_ASPECT_TEXT,
103 VIDEO_ASPECT_LONGTEXT, true )
104 add_string( "linsys-sdi-audio", "0=1,1", AUDIO_TEXT, AUDIO_LONGTEXT, true )
105 add_string( "linsys-sdi-telx", "", TELX_TEXT, TELX_LONGTEXT, true )
106 add_string( "linsys-sdi-telx-lang", "", TELX_LANG_TEXT, TELX_LANG_LONGTEXT,
107 true )
108
109 set_capability( "access_demux", 0 )
110 add_shortcut( "linsys-sdi" )
111 set_callbacks( Open, Close )
112
113 add_submodule()
114 set_description( N_("SDI Demux") )
115 set_capability( "demux", 0 )
116 set_callbacks( DemuxOpen, DemuxClose )
117 vlc_module_end()
118
119 /*****************************************************************************
120 * Local prototypes
121 *****************************************************************************/
122 typedef struct sdi_audio_t
123 {
124 unsigned int i_group, i_pair;
125
126 /* SDI parser */
127 int32_t i_delay;
128 unsigned int i_rate;
129 uint8_t i_block_number;
130 int16_t *p_buffer;
131 unsigned int i_left_samples, i_right_samples, i_nb_samples, i_max_samples;
132
133 /* ES stuff */
134 int i_id;
135 es_out_id_t *p_es;
136 } sdi_audio_t;
137
138 enum {
139 STATE_NOSYNC,
140 STATE_STARTSYNC,
141 STATE_ANCSYNC,
142 STATE_LINESYNC,
143 STATE_ACTIVESYNC,
144 STATE_VBLANKSYNC,
145 STATE_PICSYNC,
146 STATE_SYNC,
147 };
148
149 struct demux_sys_t
150 {
151 /* device reader */
152 int i_fd;
153 unsigned int i_link;
154 uint8_t **pp_buffers;
155 unsigned int i_buffers, i_current_buffer;
156 unsigned int i_buffer_size;
157
158 /* SDI sync */
159 int i_state;
160 mtime_t i_last_state_change;
161 unsigned int i_anc_size, i_active_size, i_picture_size;
162 unsigned int i_line_offset, i_nb_lines;
163
164 /* SDI parser */
165 unsigned int i_line_buffer;
166 unsigned int i_current_line;
167 uint8_t *p_line_buffer;
168 block_t *p_current_picture;
169 uint8_t *p_y, *p_u, *p_v;
170 uint8_t *p_wss_buffer;
171 uint8_t *p_telx_buffer;
172
173 /* picture decoding */
174 unsigned int i_frame_rate, i_frame_rate_base;
175 unsigned int i_width, i_height, i_aspect, i_forced_aspect;
176 unsigned int i_block_size;
177 unsigned int i_telx_line, i_telx_count;
178 char *psz_telx, *psz_telx_lang;
179 bool b_hd, b_vbi;
180 vbi_raw_decoder rd_wss, rd_telx;
181 mtime_t i_next_date;
182 int i_incr;
183
184 /* ES stuff */
185 int i_id_video;
186 es_out_id_t *p_es_video;
187 sdi_audio_t p_audios[MAX_AUDIOS];
188 es_out_id_t *p_es_telx;
189 };
190
191 static int Control( demux_t *, int, va_list );
192 static int DemuxControl( demux_t *, int, va_list );
193 static int Demux( demux_t * );
194 static int DemuxDemux( demux_t * );
195
196 static int InitWSS( demux_t *p_demux );
197 static int InitTelx( demux_t *p_demux );
198
199 static int HandleSDBuffer( demux_t *p_demux, uint8_t *p_buffer,
200 unsigned int i_buffer_size );
201
202 static int InitCapture( demux_t *p_demux );
203 static void CloseCapture( demux_t *p_demux );
204 static int Capture( demux_t *p_demux );
205
206 /*****************************************************************************
207 * DemuxOpen:
208 *****************************************************************************/
DemuxOpen(vlc_object_t * p_this)209 static int DemuxOpen( vlc_object_t *p_this )
210 {
211 demux_t *p_demux = (demux_t *)p_this;
212 demux_sys_t *p_sys;
213 char *psz_parser;
214
215 /* Fill p_demux field */
216 p_demux->pf_demux = DemuxDemux;
217 p_demux->pf_control = DemuxControl;
218 p_demux->p_sys = p_sys = calloc( 1, sizeof( demux_sys_t ) );
219 if( unlikely(!p_sys ) )
220 return VLC_ENOMEM;
221
222 p_sys->i_state = STATE_NOSYNC;
223 p_sys->i_last_state_change = mdate();
224
225 /* SDI AR */
226 unsigned int i_num, i_den;
227 if ( !var_InheritURational( p_demux, &i_num, &i_den,
228 "linsys-hdsdi-aspect-ratio" ) && i_den != 0 )
229 p_sys->i_forced_aspect = p_sys->i_aspect =
230 i_num * VOUT_ASPECT_FACTOR / i_den;
231 else
232 p_sys->i_forced_aspect = 0;
233
234 /* */
235 p_sys->i_id_video = var_InheritInteger( p_demux, "linsys-sdi-id-video" );
236
237 /* Audio ES */
238 char *psz_string = psz_parser = var_InheritString( p_demux,
239 "linsys-sdi-audio" );
240 int i = 0;
241
242 while ( psz_parser != NULL && *psz_parser )
243 {
244 int i_id, i_group, i_pair;
245 char *psz_next = strchr( psz_parser, '=' );
246 if ( psz_next != NULL )
247 {
248 *psz_next = '\0';
249 i_id = strtol( psz_parser, NULL, 0 );
250 psz_parser = psz_next + 1;
251 }
252 else
253 i_id = 0;
254
255 psz_next = strchr( psz_parser, ':' );
256 if ( psz_next != NULL )
257 {
258 *psz_next = '\0';
259 psz_next++;
260 }
261
262 if ( sscanf( psz_parser, "%d,%d", &i_group, &i_pair ) == 2 )
263 {
264 p_sys->p_audios[i].i_group = i_group;
265 p_sys->p_audios[i].i_pair = i_pair;
266 p_sys->p_audios[i].i_id = i_id;
267 i++;
268 }
269 else
270 msg_Warn( p_demux, "malformed audio configuration (%s)",
271 psz_parser );
272
273 psz_parser = psz_next;
274 }
275 free( psz_string );
276
277 /* Teletext ES */
278 p_sys->psz_telx = var_InheritString( p_demux, "linsys-sdi-telx" );
279
280 p_sys->psz_telx_lang = var_InheritString( p_demux, "linsys-sdi-telx-lang" );
281
282 return VLC_SUCCESS;
283 }
284
Open(vlc_object_t * p_this)285 static int Open( vlc_object_t *p_this )
286 {
287 demux_t *p_demux = (demux_t *)p_this;
288 demux_sys_t *p_sys;
289 int i_ret;
290
291 if ( (i_ret = DemuxOpen( p_this )) != VLC_SUCCESS )
292 return i_ret;
293
294 /* Fill p_demux field */
295 p_demux->pf_demux = Demux;
296 p_demux->pf_control = Control;
297 p_sys = p_demux->p_sys;
298
299 p_sys->i_link = var_InheritInteger( p_demux, "linsys-sdi-link" );
300
301 if( InitCapture( p_demux ) != VLC_SUCCESS )
302 {
303 free( p_sys );
304 return VLC_EGENERIC;
305 }
306
307 return VLC_SUCCESS;
308 }
309
310 /*****************************************************************************
311 * DemuxClose:
312 *****************************************************************************/
DemuxClose(vlc_object_t * p_this)313 static void DemuxClose( vlc_object_t *p_this )
314 {
315 demux_t *p_demux = (demux_t *)p_this;
316 demux_sys_t *p_sys = p_demux->p_sys;
317
318 free( p_sys->psz_telx );
319 free( p_sys->psz_telx_lang );
320 free( p_sys );
321 }
322
Close(vlc_object_t * p_this)323 static void Close( vlc_object_t *p_this )
324 {
325 demux_t *p_demux = (demux_t *)p_this;
326
327 CloseCapture( p_demux );
328 DemuxClose( p_this );
329 }
330
331 /*****************************************************************************
332 * DemuxDemux:
333 *****************************************************************************/
DemuxDemux(demux_t * p_demux)334 static int DemuxDemux( demux_t *p_demux )
335 {
336 block_t *p_block = vlc_stream_Block( p_demux->s, DEMUX_BUFFER_SIZE );
337 int i_ret;
338
339 if ( p_block == NULL )
340 return 0;
341
342 i_ret = HandleSDBuffer( p_demux, p_block->p_buffer, p_block->i_buffer );
343 block_Release( p_block );
344
345 return ( i_ret == VLC_SUCCESS );
346 }
347
Demux(demux_t * p_demux)348 static int Demux( demux_t *p_demux )
349 {
350 return ( Capture( p_demux ) == VLC_SUCCESS );
351 }
352
353 /*****************************************************************************
354 * Control:
355 *****************************************************************************/
DemuxControl(demux_t * p_demux,int i_query,va_list args)356 static int DemuxControl( demux_t *p_demux, int i_query, va_list args )
357 {
358 return demux_vaControlHelper( p_demux->s, -1, -1, 270000000, 1, i_query,
359 args );
360 }
361
Control(demux_t * p_demux,int i_query,va_list args)362 static int Control( demux_t *p_demux, int i_query, va_list args )
363 {
364 bool *pb;
365 int64_t *pi64;
366
367 switch( i_query )
368 {
369 /* Special for access_demux */
370 case DEMUX_CAN_PAUSE:
371 case DEMUX_CAN_CONTROL_PACE:
372 /* TODO */
373 pb = va_arg( args, bool * );
374 *pb = false;
375 return VLC_SUCCESS;
376
377 case DEMUX_GET_PTS_DELAY:
378 pi64 = va_arg( args, int64_t * );
379 *pi64 = INT64_C(1000)
380 * var_InheritInteger( p_demux, "live-caching" );
381 return VLC_SUCCESS;
382
383 /* TODO implement others */
384 default:
385 return VLC_EGENERIC;
386 }
387 }
388
389 /*****************************************************************************
390 * Video, audio & VBI decoding
391 *****************************************************************************/
392 #define WSS_LINE 23
393
394 struct block_extension_t
395 {
396 bool b_progressive; /**< is it a progressive frame ? */
397 bool b_top_field_first; /**< which field is first */
398 unsigned int i_nb_fields; /**< # of displayed fields */
399 unsigned int i_aspect; /**< aspect ratio of frame */
400 };
401
NewFrame(demux_t * p_demux)402 static int NewFrame( demux_t *p_demux )
403 {
404 demux_sys_t *p_sys = p_demux->p_sys;
405
406 p_sys->p_current_picture = block_Alloc( p_sys->i_block_size );
407 if( unlikely( !p_sys->p_current_picture ) )
408 return VLC_ENOMEM;
409 p_sys->p_y = p_sys->p_current_picture->p_buffer;
410 p_sys->p_u = p_sys->p_y + p_sys->i_width * p_sys->i_height;
411 p_sys->p_v = p_sys->p_u + p_sys->i_width * p_sys->i_height / 4;
412
413 for ( int i = 0; i < MAX_AUDIOS; i++ )
414 {
415 sdi_audio_t *p_audio = &p_sys->p_audios[i];
416 p_audio->i_left_samples = p_audio->i_right_samples = 0;
417 }
418 return VLC_SUCCESS;
419 }
420
StartDecode(demux_t * p_demux)421 static int StartDecode( demux_t *p_demux )
422 {
423 demux_sys_t *p_sys = p_demux->p_sys;
424 es_format_t fmt;
425 char *psz_parser;
426
427 p_sys->i_next_date = START_DATE;
428 p_sys->i_incr = 1000000 * p_sys->i_frame_rate_base / p_sys->i_frame_rate;
429 p_sys->i_block_size = p_sys->i_width * p_sys->i_height * 3 / 2
430 + sizeof(struct block_extension_t);
431 if( NewFrame( p_demux ) != VLC_SUCCESS )
432 return VLC_ENOMEM;
433
434 /* Video ES */
435 es_format_Init( &fmt, VIDEO_ES, VLC_CODEC_I420 );
436 fmt.i_id = p_sys->i_id_video;
437 fmt.video.i_frame_rate = p_sys->i_frame_rate;
438 fmt.video.i_frame_rate_base = p_sys->i_frame_rate_base;
439 fmt.video.i_width = p_sys->i_width;
440 fmt.video.i_height = p_sys->i_height;
441 int i_aspect = p_sys->i_forced_aspect ? p_sys->i_forced_aspect
442 : p_sys->i_aspect;
443 fmt.video.i_sar_num = i_aspect * fmt.video.i_height
444 / fmt.video.i_width;
445 fmt.video.i_sar_den = VOUT_ASPECT_FACTOR;
446 p_sys->p_es_video = es_out_Add( p_demux->out, &fmt );
447
448 if ( p_sys->b_vbi && InitWSS( p_demux ) != VLC_SUCCESS )
449 p_sys->b_vbi = 0;
450
451 /* Teletext ES */
452 psz_parser = p_sys->psz_telx;
453 if ( psz_parser != NULL && *psz_parser )
454 {
455 if ( !p_sys->b_vbi )
456 {
457 msg_Warn( p_demux, "VBI is unsupported on this input stream" );
458 }
459 else
460 {
461 int i_id;
462 char *psz_next = strchr( psz_parser, '=' );
463 if ( psz_next != NULL )
464 {
465 *psz_next = '\0';
466 i_id = strtol( psz_parser, NULL, 0 );
467 psz_parser = psz_next + 1;
468 }
469 else
470 i_id = 0;
471
472 psz_next = strchr( psz_parser, '-' );
473 if ( psz_next != NULL )
474 *psz_next++ = '\0';
475
476 p_sys->i_telx_line = strtol( psz_parser, NULL, 0 ) - 1;
477 if ( psz_next != NULL )
478 p_sys->i_telx_count = strtol( psz_next, NULL, 0 )
479 - p_sys->i_telx_line - 1 + 1;
480 else
481 p_sys->i_telx_count = 1;
482
483 if ( InitTelx( p_demux ) == VLC_SUCCESS )
484 {
485 int i_dr_size = 0;
486 uint8_t *p_dr = NULL;
487
488 msg_Dbg( p_demux, "capturing VBI lines %d-%d and %d-%d",
489 p_sys->i_telx_line + 1,
490 p_sys->i_telx_line + 1 + p_sys->i_telx_count - 1,
491 p_sys->i_telx_line + 1 + 313,
492 p_sys->i_telx_line + 1 + 313
493 + p_sys->i_telx_count - 1 );
494
495 es_format_Init( &fmt, SPU_ES, VLC_CODEC_TELETEXT );
496 fmt.i_id = i_id;
497
498 /* Teletext language & type */
499 psz_parser = p_sys->psz_telx_lang;
500
501 while ( (psz_next = strchr( psz_parser, '=' )) != NULL )
502 {
503 int i_page;
504 *psz_next++ = '\0';
505 if ( !psz_next[0] || !psz_next[1] || !psz_next[2] )
506 break;
507 i_page = strtol( psz_parser, NULL, 0 );
508 i_dr_size += 5;
509 p_dr = realloc( p_dr, i_dr_size );
510 p_dr[i_dr_size - 5] = *psz_next++;
511 p_dr[i_dr_size - 4] = *psz_next++;
512 p_dr[i_dr_size - 3] = *psz_next++;
513 if ( *psz_next == '/' )
514 {
515 psz_next++;
516 p_dr[i_dr_size - 2] = strtol( psz_next, &psz_next, 0 )
517 << 3;
518 }
519 else /* subtitle for hearing impaired */
520 p_dr[i_dr_size - 2] = 0x5 << 3;
521 p_dr[i_dr_size - 2] |= (i_page / 100) & 0x7;
522 p_dr[i_dr_size - 1] = i_page % 100;
523
524 if ( *psz_next == ',' )
525 psz_next++;
526 psz_parser = psz_next;
527 }
528
529 fmt.i_extra = i_dr_size;
530 fmt.p_extra = p_dr;
531 p_sys->p_es_telx = es_out_Add( p_demux->out, &fmt );
532 }
533 else
534 p_sys->i_telx_count = 0;
535 }
536 }
537 return VLC_SUCCESS;
538 }
539
StopDecode(demux_t * p_demux)540 static void StopDecode( demux_t *p_demux )
541 {
542 demux_sys_t *p_sys = p_demux->p_sys;
543
544 if ( p_sys->i_state != STATE_SYNC )
545 return;
546
547 free( p_sys->p_line_buffer );
548
549 block_Release( p_sys->p_current_picture );
550 p_sys->p_current_picture = NULL;
551 es_out_Del( p_demux->out, p_sys->p_es_video );
552
553 if ( p_sys->b_vbi )
554 {
555 free( p_sys->p_wss_buffer );
556 p_sys->p_wss_buffer = NULL;
557 vbi_raw_decoder_destroy( &p_sys->rd_wss );
558
559 if ( p_sys->p_es_telx )
560 {
561 es_out_Del( p_demux->out, p_sys->p_es_telx );
562 free( p_sys->p_telx_buffer );
563 p_sys->p_telx_buffer = NULL;
564 vbi_raw_decoder_destroy( &p_sys->rd_telx );
565 }
566 }
567
568 for ( int i = 0; i < MAX_AUDIOS; i++ )
569 {
570 sdi_audio_t *p_audio = &p_sys->p_audios[i];
571 if ( p_audio->i_group && p_audio->p_es != NULL )
572 {
573 es_out_Del( p_demux->out, p_audio->p_es );
574 p_audio->p_es = NULL;
575 free( p_audio->p_buffer );
576 p_audio->p_buffer = NULL;
577 }
578 }
579 }
580
InitVideo(demux_t * p_demux)581 static void InitVideo( demux_t *p_demux )
582 {
583 demux_sys_t *p_sys = p_demux->p_sys;
584 int i_total_width = (p_sys->i_anc_size + p_sys->i_active_size) * 4 / 5;
585 p_sys->i_width = (p_sys->i_active_size - 5) * 4 / 10;
586 if ( p_sys->i_nb_lines == 625 )
587 {
588 /* PAL */
589 p_sys->i_frame_rate = 25;
590 p_sys->i_frame_rate_base = 1;
591 p_sys->i_height = 576;
592 p_sys->i_aspect = 4 * VOUT_ASPECT_FACTOR / 3;
593 p_sys->b_hd = false;
594 }
595 else if ( p_sys->i_nb_lines == 525 )
596 {
597 /* NTSC */
598 p_sys->i_frame_rate = 30000;
599 p_sys->i_frame_rate_base = 1001;
600 p_sys->i_height = 480;
601 p_sys->i_aspect = 4 * VOUT_ASPECT_FACTOR / 3;
602 p_sys->b_hd = false;
603 }
604 else if ( p_sys->i_nb_lines == 1125 && i_total_width == 2640 )
605 {
606 /* 1080i50 or 1080p25 */
607 p_sys->i_frame_rate = 25;
608 p_sys->i_frame_rate_base = 1;
609 p_sys->i_height = 1080;
610 p_sys->i_aspect = 16 * VOUT_ASPECT_FACTOR / 9;
611 p_sys->b_hd = true;
612 }
613 else if ( p_sys->i_nb_lines == 1125 && i_total_width == 2200 )
614 {
615 /* 1080i60 or 1080p30 */
616 p_sys->i_frame_rate = 30000;
617 p_sys->i_frame_rate_base = 1001;
618 p_sys->i_height = 1080;
619 p_sys->i_aspect = 16 * VOUT_ASPECT_FACTOR / 9;
620 p_sys->b_hd = true;
621 }
622 else if ( p_sys->i_nb_lines == 750 && i_total_width == 1980 )
623 {
624 /* 720p50 */
625 p_sys->i_frame_rate = 50;
626 p_sys->i_frame_rate_base = 1;
627 p_sys->i_height = 720;
628 p_sys->i_aspect = 16 * VOUT_ASPECT_FACTOR / 9;
629 p_sys->b_hd = true;
630 }
631 else if ( p_sys->i_nb_lines == 750 && i_total_width == 1650 )
632 {
633 /* 720p60 */
634 p_sys->i_frame_rate = 60000;
635 p_sys->i_frame_rate_base = 1001;
636 p_sys->i_height = 720;
637 p_sys->i_aspect = 16 * VOUT_ASPECT_FACTOR / 9;
638 p_sys->b_hd = true;
639 }
640 else
641 {
642 msg_Warn( p_demux, "unable to determine video type" );
643 /* Put sensitive defaults */
644 p_sys->i_frame_rate = 25;
645 p_sys->i_frame_rate_base = 1;
646 p_sys->i_height = p_sys->i_nb_lines;
647 p_sys->i_aspect = 16 * VOUT_ASPECT_FACTOR / 9;
648 p_sys->b_hd = true;
649 }
650 p_sys->b_vbi = !p_sys->b_hd;
651 }
652
DecodeVideo(demux_t * p_demux)653 static void DecodeVideo( demux_t *p_demux )
654 {
655 demux_sys_t *p_sys = p_demux->p_sys;
656 struct block_extension_t ext;
657
658 /* FIXME: progressive formats ? */
659 ext.b_progressive = false;
660 ext.i_nb_fields = 2;
661 ext.b_top_field_first = true;
662 ext.i_aspect = p_sys->i_forced_aspect ? p_sys->i_forced_aspect :
663 p_sys->i_aspect;
664
665 memcpy( &p_sys->p_current_picture->p_buffer[p_sys->i_block_size
666 - sizeof(struct block_extension_t)],
667 &ext, sizeof(struct block_extension_t) );
668
669 p_sys->p_current_picture->i_dts = p_sys->p_current_picture->i_pts
670 = p_sys->i_next_date;
671 es_out_Send( p_demux->out, p_sys->p_es_video, p_sys->p_current_picture );
672 }
673
InitWSS(demux_t * p_demux)674 static int InitWSS( demux_t *p_demux )
675 {
676 demux_sys_t *p_sys = p_demux->p_sys;
677 vbi_raw_decoder_init( &p_sys->rd_wss );
678
679 p_sys->rd_wss.scanning = 625;
680 p_sys->rd_wss.sampling_format = VBI_PIXFMT_UYVY;
681 p_sys->rd_wss.sampling_rate = 13.5e6;
682 p_sys->rd_wss.bytes_per_line = 720 * 2;
683 p_sys->rd_wss.offset = 9.5e-6 * 13.5e6;
684
685 p_sys->rd_wss.start[0] = 23;
686 p_sys->rd_wss.count[0] = 1;
687 p_sys->rd_wss.start[1] = 0;
688 p_sys->rd_wss.count[1] = 0;
689
690 p_sys->rd_wss.interlaced = FALSE;
691 p_sys->rd_wss.synchronous = TRUE;
692
693 if ( vbi_raw_decoder_add_services( &p_sys->rd_wss,
694 VBI_SLICED_WSS_625,
695 /* strict */ 2 ) == 0 )
696 {
697 msg_Warn( p_demux, "cannot initialize zvbi for WSS" );
698 vbi_raw_decoder_destroy ( &p_sys->rd_telx );
699 return VLC_EGENERIC;
700 }
701
702 p_sys->p_wss_buffer = malloc( p_sys->i_width * 2 );
703 if( !p_sys->p_wss_buffer )
704 {
705 vbi_raw_decoder_destroy ( &p_sys->rd_telx );
706 return VLC_ENOMEM;
707 }
708 return VLC_SUCCESS;
709 }
710
DecodeWSS(demux_t * p_demux)711 static void DecodeWSS( demux_t *p_demux )
712 {
713 demux_sys_t *p_sys = p_demux->p_sys;
714 vbi_sliced p_sliced[1];
715
716 if ( vbi_raw_decode( &p_sys->rd_wss, p_sys->p_wss_buffer, p_sliced ) == 0 )
717 {
718 p_sys->i_aspect = 4 * VOUT_ASPECT_FACTOR / 3;
719 }
720 else
721 {
722 unsigned int i_old_aspect = p_sys->i_aspect;
723 uint8_t *p = p_sliced[0].data;
724 int i_aspect, i_parity;
725
726 i_aspect = p[0] & 15;
727 i_parity = i_aspect;
728 i_parity ^= i_parity >> 2;
729 i_parity ^= i_parity >> 1;
730 i_aspect &= 7;
731
732 if ( !(i_parity & 1) )
733 msg_Warn( p_demux, "WSS parity error" );
734 else if ( i_aspect == 7 )
735 p_sys->i_aspect = 16 * VOUT_ASPECT_FACTOR / 9;
736 else
737 p_sys->i_aspect = 4 * VOUT_ASPECT_FACTOR / 3;
738
739 if ( p_sys->i_aspect != i_old_aspect )
740 msg_Dbg( p_demux, "new WSS information (ra=%x md=%x cod=%x hlp=%x rvd=%x sub=%x pos=%x srd=%x c=%x cp=%x)",
741 i_aspect, (p[0] & 0x10) >> 4, (p[0] & 0x20) >> 5,
742 (p[0] & 0x40) >> 6, (p[0] & 0x80) >> 7, p[1] & 0x01,
743 (p[1] >> 1) & 3, (p[1] & 0x08) >> 3, (p[1] & 0x10) >> 4,
744 (p[1] & 0x20) >> 5 );
745 }
746 }
747
InitTelx(demux_t * p_demux)748 static int InitTelx( demux_t *p_demux )
749 {
750 demux_sys_t *p_sys = p_demux->p_sys;
751 vbi_raw_decoder_init( &p_sys->rd_telx );
752
753 p_sys->rd_telx.scanning = 625;
754 p_sys->rd_telx.sampling_format = VBI_PIXFMT_UYVY;
755 p_sys->rd_telx.sampling_rate = 13.5e6;
756 p_sys->rd_telx.bytes_per_line = 720 * 2;
757 p_sys->rd_telx.offset = 9.5e-6 * 13.5e6;
758
759 p_sys->rd_telx.start[0] = p_sys->i_telx_line + 1;
760 p_sys->rd_telx.count[0] = p_sys->i_telx_count;
761 p_sys->rd_telx.start[1] = p_sys->i_telx_line + 1 + 313;
762 p_sys->rd_telx.count[1] = p_sys->i_telx_count;
763
764 p_sys->rd_telx.interlaced = FALSE;
765 p_sys->rd_telx.synchronous = TRUE;
766
767 if ( vbi_raw_decoder_add_services( &p_sys->rd_telx, VBI_SLICED_TELETEXT_B,
768 0 ) == 0 )
769 {
770 msg_Warn( p_demux, "cannot initialize zvbi for Teletext" );
771 vbi_raw_decoder_destroy ( &p_sys->rd_telx );
772 return VLC_EGENERIC;
773 }
774
775 p_sys->p_telx_buffer = vlc_alloc( p_sys->i_telx_count * p_sys->i_width, 4 );
776 if( !p_sys->p_telx_buffer )
777 {
778 vbi_raw_decoder_destroy ( &p_sys->rd_telx );
779 return VLC_ENOMEM;
780 }
781 return VLC_SUCCESS;
782 }
783
DecodeTelx(demux_t * p_demux)784 static int DecodeTelx( demux_t *p_demux )
785 {
786 demux_sys_t *p_sys = p_demux->p_sys;
787 vbi_sliced p_sliced[p_sys->i_telx_count * 2];
788 int i_nb_slices = vbi_raw_decode( &p_sys->rd_telx, p_sys->p_telx_buffer,
789 p_sliced );
790
791 if ( i_nb_slices )
792 {
793 /* 3, 7, 11, 15, etc. */
794 int i_nb_slices_rounded = 3 + (i_nb_slices / 4) * 4;
795 int i;
796 uint8_t *p;
797 block_t *p_block = block_Alloc( 1 + i_nb_slices_rounded * 46 );
798 if( unlikely( !p_block ) )
799 return VLC_ENOMEM;
800 p_block->p_buffer[0] = 0x10; /* FIXME ? data_identifier */
801 p = p_block->p_buffer + 1;
802
803 for ( i = 0; i < i_nb_slices; i++ )
804 {
805 int i_line = p_sliced[i].line;
806 p[0] = 0x3; /* FIXME data_unit_id == subtitles */
807 p[1] = 0x2c; /* data_unit_length */
808 /* reserved | field_parity (kind of inverted) | line */
809 p[2] = 0xc0 | (i_line > 313 ? 0 : 0x20) | (i_line % 313);
810 p[3] = 0xe4; /* framing code */
811 for ( int j = 0; j < 42; j++ )
812 p[4 + j] = vbi_rev8( p_sliced[i].data[j] );
813 p += 46;
814 }
815
816 /* Let's stuff */
817 for ( ; i < i_nb_slices_rounded; i++ )
818 {
819 p[0] = 0xff;
820 p[1] = 0x2c;
821 memset( p + 2, 0xff, 44 );
822 p += 46;
823 }
824
825 p_block->i_dts = p_block->i_pts = p_sys->i_next_date;
826 es_out_Send( p_demux->out, p_sys->p_es_telx, p_block );
827 }
828 return VLC_SUCCESS;
829 }
830
InitAudio(demux_t * p_demux,sdi_audio_t * p_audio)831 static int InitAudio( demux_t *p_demux, sdi_audio_t *p_audio )
832 {
833 demux_sys_t *p_sys = p_demux->p_sys;
834 es_format_t fmt;
835
836 msg_Dbg( p_demux, "starting audio %u/%u rate:%u delay:%d", p_audio->i_group,
837 p_audio->i_pair, p_audio->i_rate, p_audio->i_delay );
838
839 es_format_Init( &fmt, AUDIO_ES, VLC_CODEC_S16L );
840 fmt.i_id = p_audio->i_id;
841 fmt.audio.i_channels = 2;
842 fmt.audio.i_physical_channels = AOUT_CHANS_STEREO;
843 fmt.audio.i_rate = p_audio->i_rate;
844 fmt.audio.i_bitspersample = 16;
845 fmt.audio.i_blockalign = fmt.audio.i_channels *
846 fmt.audio.i_bitspersample / 8;
847 fmt.i_bitrate = fmt.audio.i_channels * fmt.audio.i_rate *
848 fmt.audio.i_bitspersample;
849 p_audio->p_es = es_out_Add( p_demux->out, &fmt );
850
851 p_audio->i_nb_samples = p_audio->i_rate * p_sys->i_frame_rate_base
852 / p_sys->i_frame_rate;
853 p_audio->i_max_samples = (float)p_audio->i_nb_samples *
854 (1.f + SAMPLERATE_TOLERANCE);
855
856 p_audio->p_buffer = vlc_alloc( p_audio->i_max_samples, sizeof(int16_t) * 2 );
857 p_audio->i_left_samples = p_audio->i_right_samples = 0;
858 p_audio->i_block_number = 0;
859
860 if( unlikely( !p_audio->p_buffer ) )
861 return VLC_ENOMEM;
862 return VLC_SUCCESS;
863 }
864
865 /* Fast and efficient linear resampling routine */
ResampleAudio(int16_t * p_out,int16_t * p_in,unsigned int i_out,unsigned int i_in)866 static void ResampleAudio( int16_t *p_out, int16_t *p_in,
867 unsigned int i_out, unsigned int i_in )
868 {
869 unsigned int i_remainder = 0;
870 float f_last_sample = (float)*p_in / 32768.f;
871
872 *p_out = *p_in;
873 p_out += 2;
874 p_in += 2;
875
876 for ( unsigned int i = 1; i < i_in; i++ )
877 {
878 float f_in = (float)*p_in / 32768.f;
879 while ( i_remainder < i_out )
880 {
881 float f_out = f_last_sample;
882 f_out += (f_in - f_last_sample) * i_remainder / i_out;
883 if ( f_out >= 1.f ) *p_out = 32767;
884 else if ( f_out < -1.f ) *p_out = -32768;
885 else *p_out = f_out * 32768.f;
886 p_out += 2;
887 i_remainder += i_in;
888 }
889
890 f_last_sample = f_in;
891 p_in += 2;
892 i_remainder -= i_out;
893 }
894 }
895
DecodeAudio(demux_t * p_demux,sdi_audio_t * p_audio)896 static int DecodeAudio( demux_t *p_demux, sdi_audio_t *p_audio )
897 {
898 demux_sys_t *p_sys = p_demux->p_sys;
899 block_t *p_block;
900 int16_t *p_output;
901
902 if ( p_audio->p_buffer == NULL )
903 return VLC_EGENERIC;
904 if ( !p_audio->i_left_samples && !p_audio->i_right_samples )
905 {
906 msg_Warn( p_demux, "no audio %u/%u", p_audio->i_group,
907 p_audio->i_pair );
908 return VLC_EGENERIC;
909 }
910 if ( p_audio->i_left_samples <
911 (float)p_audio->i_nb_samples * (1.f - SAMPLERATE_TOLERANCE) ||
912 p_audio->i_left_samples >
913 (float)p_audio->i_nb_samples * (1.f + SAMPLERATE_TOLERANCE) )
914 {
915 msg_Warn( p_demux,
916 "left samplerate out of tolerance for audio %u/%u (%u vs. %u)",
917 p_audio->i_group, p_audio->i_pair,
918 p_audio->i_left_samples, p_audio->i_nb_samples );
919 return VLC_EGENERIC;
920 }
921 if ( p_audio->i_right_samples <
922 (float)p_audio->i_nb_samples * (1.f - SAMPLERATE_TOLERANCE) ||
923 p_audio->i_right_samples >
924 (float)p_audio->i_nb_samples * (1.f + SAMPLERATE_TOLERANCE) )
925 {
926 msg_Warn( p_demux,
927 "right samplerate out of tolerance for audio %u/%u (%u vs. %u)",
928 p_audio->i_group, p_audio->i_pair,
929 p_audio->i_right_samples, p_audio->i_nb_samples );
930 return VLC_EGENERIC;
931 }
932
933 p_block = block_Alloc( p_audio->i_nb_samples * sizeof(int16_t) * 2 );
934 if( unlikely( !p_block ) )
935 return VLC_ENOMEM;
936 p_block->i_dts = p_block->i_pts = p_sys->i_next_date
937 + (mtime_t)p_audio->i_delay * INT64_C(1000000) / p_audio->i_rate;
938 p_output = (int16_t *)p_block->p_buffer;
939
940 if ( p_audio->i_left_samples == p_audio->i_nb_samples &&
941 p_audio->i_right_samples == p_audio->i_nb_samples )
942 memcpy( p_output, p_audio->p_buffer,
943 p_audio->i_nb_samples * sizeof(int16_t) * 2 );
944 else
945 {
946 ResampleAudio( p_output, p_audio->p_buffer,
947 p_audio->i_nb_samples, p_audio->i_left_samples );
948
949 ResampleAudio( p_output + 1, p_audio->p_buffer + 1,
950 p_audio->i_nb_samples, p_audio->i_right_samples );
951 }
952
953 es_out_Send( p_demux->out, p_audio->p_es, p_block );
954 return VLC_SUCCESS;
955 }
956
DecodeFrame(demux_t * p_demux)957 static int DecodeFrame( demux_t *p_demux )
958 {
959 demux_sys_t *p_sys = p_demux->p_sys;
960
961 if ( p_sys->b_vbi )
962 {
963 DecodeWSS( p_demux );
964
965 if ( p_sys->i_height == 576 )
966 {
967 /* For PAL, erase first half of line 23, last half of line 623,
968 * and line 624 ; no need to erase chrominance */
969 memset( p_sys->p_y, 0, p_sys->i_width / 2 );
970 memset( p_sys->p_y + p_sys->i_width * 574 + p_sys->i_width / 2,
971 0, p_sys->i_width * 3 / 2 );
972 }
973 }
974
975 if ( p_sys->i_telx_count )
976 if ( DecodeTelx( p_demux ) != VLC_SUCCESS )
977 return VLC_ENOMEM;
978
979 for ( int i = 0; i < MAX_AUDIOS; i++ )
980 {
981 if ( p_sys->p_audios[i].i_group && p_sys->p_audios[i].p_es != NULL )
982 if( DecodeAudio( p_demux, &p_sys->p_audios[i] ) != VLC_SUCCESS )
983 return VLC_EGENERIC;
984 }
985
986 DecodeVideo( p_demux );
987
988 es_out_SetPCR( p_demux->out, p_sys->i_next_date );
989 p_sys->i_next_date += p_sys->i_incr;
990
991 if( NewFrame( p_demux ) != VLC_SUCCESS )
992 return VLC_ENOMEM;
993
994 return VLC_SUCCESS;
995 }
996
997 /*****************************************************************************
998 * SDI syntax parsing stuff
999 *****************************************************************************/
1000 #define FIELD_1_VBLANK_EAV 0xB6
1001 #define FIELD_1_VBLANK_SAV 0xAB
1002 #define FIELD_1_ACTIVE_EAV 0x9D
1003 #define FIELD_1_ACTIVE_SAV 0x80
1004 #define FIELD_2_VBLANK_EAV 0xF1
1005 #define FIELD_2_VBLANK_SAV 0xEC
1006 #define FIELD_2_ACTIVE_EAV 0xDA
1007 #define FIELD_2_ACTIVE_SAV 0xC7
1008
FindReferenceCode(uint8_t i_code,const uint8_t * p_parser,const uint8_t * p_end)1009 static const uint8_t *FindReferenceCode( uint8_t i_code,
1010 const uint8_t *p_parser,
1011 const uint8_t *p_end )
1012 {
1013 while ( p_parser <= p_end - 5 )
1014 {
1015 if ( p_parser[0] == 0xff && p_parser[1] == 0x3 && p_parser[2] == 0x0
1016 && p_parser[3] == 0x0 && p_parser[4] == i_code )
1017 return p_parser;
1018 p_parser += 5;
1019 }
1020
1021 return NULL;
1022 }
1023
CountReference(unsigned int * pi_count,uint8_t i_code,const uint8_t * p_parser,const uint8_t * p_end)1024 static const uint8_t *CountReference( unsigned int *pi_count, uint8_t i_code,
1025 const uint8_t *p_parser,
1026 const uint8_t *p_end )
1027 {
1028 const uint8_t *p_tmp = FindReferenceCode( i_code, p_parser, p_end );
1029 if ( p_tmp == NULL )
1030 {
1031 *pi_count += p_end - p_parser;
1032 return NULL;
1033 }
1034 *pi_count += p_tmp - p_parser;
1035 return p_tmp;
1036 }
1037
GetLine(demux_t * p_demux,const uint8_t ** pp_parser,const uint8_t * p_end)1038 static const uint8_t *GetLine( demux_t *p_demux, const uint8_t **pp_parser,
1039 const uint8_t *p_end )
1040 {
1041 demux_sys_t *p_sys = p_demux->p_sys;
1042 unsigned int i_total_size = p_sys->i_anc_size + p_sys->i_active_size;
1043 const uint8_t *p_tmp;
1044
1045 if ( p_sys->i_line_buffer )
1046 {
1047 unsigned int i_remaining = i_total_size - p_sys->i_line_buffer;
1048 memcpy( p_sys->p_line_buffer + p_sys->i_line_buffer,
1049 *pp_parser, i_remaining );
1050 *pp_parser += i_remaining;
1051 p_sys->i_line_buffer = 0;
1052
1053 return p_sys->p_line_buffer;
1054 }
1055
1056 if ( p_end - *pp_parser < (int)i_total_size )
1057 {
1058 memcpy( p_sys->p_line_buffer, *pp_parser,
1059 p_end - *pp_parser );
1060 p_sys->i_line_buffer = p_end - *pp_parser;
1061 return NULL;
1062 }
1063
1064 p_tmp = *pp_parser;
1065 *pp_parser += i_total_size;
1066 return p_tmp;
1067 }
1068
1069 #define U (uint16_t)((p_line[0]) | ((p_line[1] & 0x3) << 8))
1070 #define Y1 (uint16_t)((p_line[1] >> 2) | ((p_line[2] & 0xf) << 6))
1071 #define V (uint16_t)((p_line[2] >> 4) | ((p_line[3] & 0x3f) << 4))
1072 #define Y2 (uint16_t)((p_line[3] >> 6) | (p_line[4] << 2))
1073
UnpackVBI(const uint8_t * p_line,unsigned int i_size,uint8_t * p_dest)1074 static void UnpackVBI( const uint8_t *p_line, unsigned int i_size,
1075 uint8_t *p_dest )
1076 {
1077 const uint8_t *p_end = p_line + i_size;
1078
1079 while ( p_line < p_end )
1080 {
1081 *p_dest++ = (U + 2) / 4;
1082 *p_dest++ = (Y1 + 2) / 4;
1083 *p_dest++ = (V + 2) / 4;
1084 *p_dest++ = (Y2 + 2) / 4;
1085 p_line += 5;
1086 }
1087 }
1088
1089 /* For lines 0 [4] or 1 [4] */
Unpack01(const uint8_t * p_line,unsigned int i_size,uint8_t * p_y,uint8_t * p_u,uint8_t * p_v)1090 static void Unpack01( const uint8_t *p_line, unsigned int i_size,
1091 uint8_t *p_y, uint8_t *p_u, uint8_t *p_v )
1092 {
1093 const uint8_t *p_end = p_line + i_size;
1094
1095 while ( p_line < p_end )
1096 {
1097 *p_u++ = (U + 2) / 4;
1098 *p_y++ = (Y1 + 2) / 4;
1099 *p_v++ = (V + 2) / 4;
1100 *p_y++ = (Y2 + 2) / 4;
1101 p_line += 5;
1102 }
1103 }
1104
1105 /* For lines 2 [4] */
Unpack2(const uint8_t * p_line,unsigned int i_size,uint8_t * p_y,uint8_t * p_u,uint8_t * p_v)1106 static void Unpack2( const uint8_t *p_line, unsigned int i_size,
1107 uint8_t *p_y, uint8_t *p_u, uint8_t *p_v )
1108 {
1109 const uint8_t *p_end = p_line + i_size;
1110
1111 while ( p_line < p_end )
1112 {
1113 uint16_t tmp;
1114 tmp = 3 * *p_u;
1115 tmp += (U + 2) / 4;
1116 *p_u++ = tmp / 4;
1117 *p_y++ = (Y1 + 2) / 4;
1118 tmp = 3 * *p_v;
1119 tmp += (V + 2) / 4;
1120 *p_v++ = tmp / 4;
1121 *p_y++ = (Y2 + 2) / 4;
1122 p_line += 5;
1123 }
1124 }
1125
1126 /* For lines 3 [4] */
Unpack3(const uint8_t * p_line,unsigned int i_size,uint8_t * p_y,uint8_t * p_u,uint8_t * p_v)1127 static void Unpack3( const uint8_t *p_line, unsigned int i_size,
1128 uint8_t *p_y, uint8_t *p_u, uint8_t *p_v )
1129 {
1130 const uint8_t *p_end = p_line + i_size;
1131
1132 while ( p_line < p_end )
1133 {
1134 uint16_t tmp;
1135 tmp = *p_u;
1136 tmp += 3 * (U + 2) / 4;
1137 *p_u++ = tmp / 4;
1138 *p_y++ = (Y1 + 2) / 4;
1139 tmp = *p_v;
1140 tmp += 3 * (V + 2) / 4;
1141 *p_v++ = tmp / 4;
1142 *p_y++ = (Y2 + 2) / 4;
1143 p_line += 5;
1144 }
1145 }
1146
1147 #undef U
1148 #undef Y1
1149 #undef V
1150 #undef Y2
1151
1152 #define A0 (uint16_t)((p_anc[0]) | ((p_anc[1] & 0x3) << 8))
1153 #define A1 (uint16_t)((p_anc[1] >> 2) | ((p_anc[2] & 0xf) << 6))
1154 #define A2 (uint16_t)((p_anc[2] >> 4) | ((p_anc[3] & 0x3f) << 4))
1155 #define A3 (uint16_t)((p_anc[3] >> 6) | (p_anc[4] << 2))
1156
UnpackAnc(const uint8_t * p_anc,unsigned int i_size,uint16_t * p_dest)1157 static void UnpackAnc( const uint8_t *p_anc, unsigned int i_size,
1158 uint16_t *p_dest )
1159 {
1160 const uint8_t *p_end = p_anc + i_size;
1161
1162 while ( p_anc <= p_end - 5 )
1163 {
1164 *p_dest++ = A0;
1165 *p_dest++ = A1;
1166 *p_dest++ = A2;
1167 *p_dest++ = A3;
1168 p_anc += 5;
1169 }
1170 }
1171
1172 #undef A0
1173 #undef A1
1174 #undef A2
1175 #undef A3
1176
HasAncillary(const uint8_t * p_anc)1177 static int HasAncillary( const uint8_t *p_anc )
1178 {
1179 return ( (p_anc[0] == 0x0 && p_anc[1] == 0xfc && p_anc[2] == 0xff
1180 && (p_anc[3] & 0x3f) == 0x3f) );
1181 }
1182
HandleAudioData(demux_t * p_demux,const uint16_t * p_anc,uint8_t i_data_count,uint8_t i_group,uint8_t i_block_number)1183 static void HandleAudioData( demux_t *p_demux, const uint16_t *p_anc,
1184 uint8_t i_data_count, uint8_t i_group,
1185 uint8_t i_block_number )
1186 {
1187 demux_sys_t *p_sys = p_demux->p_sys;
1188
1189 if ( i_data_count % 3 )
1190 {
1191 msg_Warn( p_demux, "malformed audio data for group %u", i_group );
1192 return;
1193 }
1194
1195 for ( int i = 0; i < MAX_AUDIOS; i++ )
1196 {
1197 sdi_audio_t *p_audio = &p_sys->p_audios[i];
1198 if ( p_audio->i_group == i_group )
1199 {
1200 const uint16_t *x = p_anc;
1201
1202 /* SMPTE 272M says that when parsing a frame, if an audio config
1203 * structure is present we will encounter it first. Otherwise
1204 * it is assumed to be 48 kHz. */
1205 if ( p_audio->p_es == NULL )
1206 {
1207 p_audio->i_rate = 48000;
1208 p_audio->i_delay = 0;
1209 if( InitAudio( p_demux, p_audio ) != VLC_SUCCESS )
1210 return;
1211 }
1212
1213 if ( i_block_number )
1214 {
1215 if ( p_audio->i_block_number + 1 != i_block_number )
1216 msg_Warn( p_demux,
1217 "audio data block discontinuity (%"PRIu8"->%"PRIu8") for group %"PRIu8,
1218 p_audio->i_block_number, i_block_number,
1219 i_group );
1220 if ( i_block_number == 0xff )
1221 p_audio->i_block_number = 0;
1222 else
1223 p_audio->i_block_number = i_block_number;
1224 }
1225
1226 while ( x < p_anc + i_data_count )
1227 {
1228 if ( ((*x & 0x4) && p_audio->i_pair == 2)
1229 || (!(*x & 0x4) && p_audio->i_pair == 1) )
1230 {
1231 uint32_t i_tmp = (uint32_t)((x[0] & 0x1f1) >> 3)
1232 | ((x[1] & 0x1ff) << 6)
1233 | ((x[2] & 0x1f) << 15);
1234 int32_t i_sample;
1235 if ( x[2] & 0x10 )
1236 i_sample = i_tmp | 0xfff00000;
1237 else
1238 i_sample = i_tmp;
1239
1240 if ( x[0] & 0x2 )
1241 {
1242 if ( p_audio->i_right_samples < p_audio->i_max_samples )
1243 p_audio->p_buffer[2 * p_audio->i_right_samples
1244 + 1] = (i_sample + 8) / 16;
1245 p_audio->i_right_samples++;
1246 }
1247 else
1248 {
1249 if ( p_audio->i_left_samples < p_audio->i_max_samples )
1250 p_audio->p_buffer[2 * p_audio->i_left_samples]
1251 = (i_sample + 8) / 16;
1252 p_audio->i_left_samples++;
1253 }
1254 }
1255 x += 3;
1256 }
1257 }
1258 }
1259 }
1260
HandleAudioConfig(demux_t * p_demux,const uint16_t * p_anc,uint8_t i_data_count,uint8_t i_group)1261 static void HandleAudioConfig( demux_t *p_demux, const uint16_t *p_anc,
1262 uint8_t i_data_count, uint8_t i_group )
1263 {
1264 demux_sys_t *p_sys = p_demux->p_sys;
1265
1266 if ( i_data_count != 18 )
1267 {
1268 msg_Warn( p_demux, "malformed audio config for group %u", i_group );
1269 return;
1270 }
1271
1272 for ( int i = 0; i < MAX_AUDIOS; i++ )
1273 {
1274 sdi_audio_t *p_audio = &p_sys->p_audios[i];
1275 if ( p_audio->i_group == i_group && p_audio->p_es == NULL )
1276 {
1277 unsigned int i_rate;
1278
1279 if ( p_audio->i_pair == 2 )
1280 {
1281 i_rate = (p_anc[2] & 0xe0) >> 5;
1282 if ( p_anc[7] & 0x1 )
1283 {
1284 uint32_t i_tmp = ((p_anc[7] & 0x1fe) >> 1)
1285 | ((p_anc[8] & 0x1ff) << 8)
1286 | ((p_anc[9] & 0x1ff) << 17);
1287 if ( p_anc[9] & 0x80 )
1288 p_audio->i_delay = i_tmp | 0xfc000000;
1289 else
1290 p_audio->i_delay = i_tmp;
1291 }
1292 if ( p_anc[13] & 0x1 )
1293 msg_Warn( p_demux, "asymetric audio is not supported" );
1294 }
1295 else
1296 {
1297 i_rate = (p_anc[2] & 0xe) >> 1;
1298 if ( p_anc[4] & 0x1 )
1299 {
1300 uint32_t i_tmp = ((p_anc[4] & 0x1fe) >> 1)
1301 | ((p_anc[5] & 0x1ff) << 8)
1302 | ((p_anc[6] & 0x1ff) << 17);
1303 if ( p_anc[6] & 0x80 )
1304 p_audio->i_delay = i_tmp | 0xfc000000;
1305 else
1306 p_audio->i_delay = i_tmp;
1307 }
1308 if ( p_anc[10] & 0x1 )
1309 msg_Warn( p_demux, "asymetric audio is not supported" );
1310 }
1311
1312 switch ( i_rate )
1313 {
1314 case 0: p_audio->i_rate = 48000; break;
1315 case 1: p_audio->i_rate = 44100; break;
1316 case 2: p_audio->i_rate = 32000; break;
1317 default:
1318 msg_Warn( p_demux, "unknown rate for audio %u/%u (%u)",
1319 i_group, p_sys->p_audios[i].i_pair, i_rate );
1320 continue;
1321 }
1322
1323 if( InitAudio( p_demux, p_audio ) != VLC_SUCCESS )
1324 return;
1325 }
1326 }
1327 }
1328
1329 /*
1330 * Ancillary packet structure:
1331 * byte 0: Ancillary Data Flag (0)
1332 * byte 1: Ancillary Data Flag (0x3ff)
1333 * byte 2: Ancillary Data Flag (0x3ff)
1334 * byte 3: Data ID (2 high order bits = parity)
1335 * byte 4: Data Block Number 1-255 or 0=unknown (if DID < 0x80)
1336 * or Secondary Data ID (if DID >= 0x80)
1337 * byte 5: Data Count (10 bits)
1338 * byte 6+DC: Checksum
1339 */
HandleAncillary(demux_t * p_demux,const uint16_t * p_anc,unsigned int i_size)1340 static void HandleAncillary( demux_t *p_demux, const uint16_t *p_anc,
1341 unsigned int i_size )
1342 {
1343 uint8_t i_data_count;
1344
1345 if ( i_size < 7
1346 || p_anc[0] != 0x0 || p_anc[1] != 0x3ff || p_anc[2] != 0x3ff )
1347 return;
1348
1349 i_data_count = p_anc[5] & 0xff;
1350 if ( i_size - 6 < i_data_count )
1351 {
1352 msg_Warn( p_demux, "malformed ancillary packet (size %u > %u)",
1353 i_data_count, i_size - 6 );
1354 return;
1355 }
1356
1357 switch ( p_anc[3] ) /* Data ID */
1358 {
1359 case 0x2ff:
1360 HandleAudioData( p_demux, p_anc + 6, i_data_count, 1, p_anc[4] & 0xff );
1361 break;
1362 case 0x1fd:
1363 HandleAudioData( p_demux, p_anc + 6, i_data_count, 2, p_anc[4] & 0xff );
1364 break;
1365 case 0x1fb:
1366 HandleAudioData( p_demux, p_anc + 6, i_data_count, 3, p_anc[4] & 0xff );
1367 break;
1368 case 0x2f9:
1369 HandleAudioData( p_demux, p_anc + 6, i_data_count, 4, p_anc[4] & 0xff );
1370 break;
1371
1372 case 0x1ef:
1373 HandleAudioConfig( p_demux, p_anc + 6, i_data_count, 1 );
1374 break;
1375 case 0x2ee:
1376 HandleAudioConfig( p_demux, p_anc + 6, i_data_count, 2 );
1377 break;
1378 case 0x2ed:
1379 HandleAudioConfig( p_demux, p_anc + 6, i_data_count, 3 );
1380 break;
1381 case 0x1ec:
1382 HandleAudioConfig( p_demux, p_anc + 6, i_data_count, 4 );
1383 break;
1384
1385 /* Extended data packets, same order */
1386 case 0x1fe:
1387 case 0x2fc:
1388 case 0x2fa:
1389 case 0x1f8:
1390
1391 default:
1392 break;
1393
1394 case 0x88: /* non-conforming ANC packet */
1395 p_anc += 7;
1396 i_size -= 7;
1397 while ( i_size >= 7 && (p_anc[0] != 0x0 || p_anc[1] != 0x3ff
1398 || p_anc[2] != 0x3ff) )
1399 {
1400 p_anc++;
1401 i_size--;
1402 }
1403 if ( i_size >= 7 )
1404 HandleAncillary( p_demux, p_anc, i_size );
1405 return;
1406 }
1407
1408 return HandleAncillary( p_demux, p_anc + i_data_count + 7,
1409 i_size - i_data_count - 7 );
1410
1411 }
1412
HandleSDBuffer(demux_t * p_demux,uint8_t * p_buffer,unsigned int i_buffer_size)1413 static int HandleSDBuffer( demux_t *p_demux, uint8_t *p_buffer,
1414 unsigned int i_buffer_size )
1415 {
1416 demux_sys_t *p_sys = p_demux->p_sys;
1417 const uint8_t *p_parser = p_buffer;
1418 const uint8_t *p_end = p_parser + i_buffer_size;
1419 const uint8_t *p_line;
1420
1421 if ( p_sys->i_state != STATE_SYNC
1422 && p_sys->i_last_state_change < mdate() - RESYNC_TIMEOUT )
1423 {
1424 p_sys->i_state = STATE_NOSYNC;
1425 p_sys->i_last_state_change = mdate();
1426 return VLC_EGENERIC;
1427 }
1428
1429 switch ( p_sys->i_state )
1430 {
1431 case STATE_NOSYNC:
1432 default:
1433 p_parser = FindReferenceCode( FIELD_2_VBLANK_SAV, p_parser, p_end );
1434 if ( p_parser == NULL )
1435 break;
1436 p_sys->i_state = STATE_STARTSYNC;
1437 p_sys->i_last_state_change = mdate();
1438
1439 case STATE_STARTSYNC:
1440 p_parser = FindReferenceCode( FIELD_1_VBLANK_EAV, p_parser, p_end );
1441 if ( p_parser == NULL )
1442 break;
1443 p_sys->i_anc_size = 0;
1444 p_sys->i_state = STATE_ANCSYNC;
1445 p_sys->i_last_state_change = mdate();
1446
1447 case STATE_ANCSYNC:
1448 p_parser = CountReference( &p_sys->i_anc_size,
1449 FIELD_1_VBLANK_SAV, p_parser, p_end );
1450 if ( p_parser == NULL )
1451 break;
1452 p_sys->i_active_size = 0;
1453 p_sys->i_state = STATE_LINESYNC;
1454 p_sys->i_last_state_change = mdate();
1455
1456 case STATE_LINESYNC:
1457 p_parser = CountReference( &p_sys->i_active_size,
1458 FIELD_1_VBLANK_EAV, p_parser, p_end );
1459 if ( p_parser == NULL )
1460 break;
1461 p_sys->i_picture_size = p_sys->i_anc_size + p_sys->i_active_size;
1462 p_sys->i_state = STATE_ACTIVESYNC;
1463 p_sys->i_last_state_change = mdate();
1464
1465 case STATE_ACTIVESYNC:
1466 p_parser = CountReference( &p_sys->i_picture_size,
1467 FIELD_1_ACTIVE_EAV, p_parser, p_end );
1468 if ( p_parser == NULL )
1469 break;
1470 p_sys->i_line_offset = p_sys->i_picture_size
1471 / (p_sys->i_anc_size + p_sys->i_active_size);
1472 p_sys->i_state = STATE_VBLANKSYNC;
1473 p_sys->i_last_state_change = mdate();
1474
1475 case STATE_VBLANKSYNC:
1476 p_parser = CountReference( &p_sys->i_picture_size,
1477 FIELD_2_ACTIVE_EAV, p_parser, p_end );
1478 if ( p_parser == NULL )
1479 break;
1480 p_sys->i_state = STATE_PICSYNC;
1481 p_sys->i_last_state_change = mdate();
1482
1483 case STATE_PICSYNC:
1484 p_parser = CountReference( &p_sys->i_picture_size,
1485 FIELD_1_VBLANK_EAV, p_parser, p_end );
1486 if ( p_parser == NULL )
1487 break;
1488
1489 if ( p_sys->i_picture_size
1490 % (p_sys->i_anc_size + p_sys->i_active_size) )
1491 {
1492 msg_Warn( p_demux, "wrong picture size (anc=%d active=%d total=%d offset=%d), syncing",
1493 p_sys->i_anc_size, p_sys->i_active_size,
1494 p_sys->i_picture_size, p_sys->i_line_offset + 1 );
1495 p_sys->i_state = STATE_NOSYNC;
1496 p_sys->i_last_state_change = mdate();
1497 break;
1498 }
1499
1500 p_sys->i_nb_lines = p_sys->i_picture_size
1501 / (p_sys->i_anc_size + p_sys->i_active_size);
1502 InitVideo( p_demux );
1503 msg_Dbg( p_demux,
1504 "acquired sync, anc=%d active=%d lines=%d offset=%d",
1505 p_sys->i_anc_size, p_sys->i_active_size,
1506 p_sys->i_nb_lines, p_sys->i_line_offset + 1 );
1507 p_sys->i_state = STATE_SYNC;
1508 if( StartDecode( p_demux ) != VLC_SUCCESS )
1509 {
1510 StopDecode( p_demux );
1511 return VLC_ENOMEM;
1512 }
1513 p_sys->i_current_line = 0;
1514 p_sys->p_line_buffer = malloc( p_sys->i_anc_size
1515 + p_sys->i_active_size );
1516 if( !p_sys->p_line_buffer )
1517 {
1518 StopDecode( p_demux );
1519 return VLC_ENOMEM;
1520 }
1521 p_sys->i_line_buffer = 0;
1522
1523 case STATE_SYNC:
1524 while ( (p_line = GetLine( p_demux, &p_parser, p_end )) != NULL )
1525 {
1526 bool b_field = p_sys->b_hd ? false :
1527 (p_sys->i_current_line >= p_sys->i_nb_lines / 2);
1528 unsigned int i_field_height = p_sys->b_hd ? p_sys->i_height :
1529 p_sys->i_height / 2;
1530 unsigned int i_field_line = b_field ?
1531 p_sys->i_current_line - (p_sys->i_nb_lines + 1) / 2 :
1532 p_sys->i_current_line;
1533 bool b_vbi = i_field_line < p_sys->i_line_offset ||
1534 i_field_line >= p_sys->i_line_offset + i_field_height;
1535 unsigned int anc = p_sys->i_anc_size;
1536
1537 if ( p_line[0] != 0xff || p_line[1] != 0x3
1538 || p_line[2] != 0x0 || p_line[3] != 0x0
1539 || p_line[anc+0] != 0xff || p_line[anc+1] != 0x3
1540 || p_line[anc+2] != 0x0 || p_line[anc+3] != 0x0
1541 || (!b_field && b_vbi &&
1542 (p_line[4] != FIELD_1_VBLANK_EAV ||
1543 p_line[anc+4] != FIELD_1_VBLANK_SAV))
1544 || (!b_field && !b_vbi &&
1545 (p_line[4] != FIELD_1_ACTIVE_EAV ||
1546 p_line[anc+4] != FIELD_1_ACTIVE_SAV))
1547 || (b_field && b_vbi &&
1548 (p_line[4] != FIELD_2_VBLANK_EAV ||
1549 p_line[anc+4] != FIELD_2_VBLANK_SAV))
1550 || (b_field && !b_vbi &&
1551 (p_line[4] != FIELD_2_ACTIVE_EAV ||
1552 p_line[anc+4] != FIELD_2_ACTIVE_SAV)) )
1553 {
1554 msg_Warn( p_demux, "lost sync line:%u SAV:%x EAV:%x",
1555 p_sys->i_current_line + 1, p_line[4], p_line[anc+4] );
1556 StopDecode( p_demux );
1557 p_sys->i_state = STATE_NOSYNC;
1558 p_sys->i_last_state_change = mdate();
1559 break;
1560 }
1561
1562 if ( HasAncillary( p_line + 5 ) )
1563 {
1564 /* HANC */
1565 unsigned int i_anc_words = (p_sys->i_anc_size - 5) * 4 / 5;
1566 uint16_t p_anc[i_anc_words];
1567 UnpackAnc( p_line + 5, p_sys->i_anc_size - 5, p_anc );
1568 HandleAncillary( p_demux, p_anc, i_anc_words );
1569 }
1570
1571 if ( !b_vbi )
1572 {
1573 unsigned int i_active_field_line = i_field_line
1574 - p_sys->i_line_offset;
1575 unsigned int i_active_line = b_field
1576 + i_active_field_line * 2;
1577 if ( !(i_active_field_line % 2) && !b_field )
1578 Unpack01( p_line + anc + 5, p_sys->i_active_size - 5,
1579 p_sys->p_y + p_sys->i_width * i_active_line,
1580 p_sys->p_u + (p_sys->i_width / 2)
1581 * (i_active_line / 2),
1582 p_sys->p_v + (p_sys->i_width / 2)
1583 * (i_active_line / 2) );
1584 else if ( !(i_active_field_line % 2) )
1585 Unpack01( p_line + anc + 5, p_sys->i_active_size - 5,
1586 p_sys->p_y + p_sys->i_width * i_active_line,
1587 p_sys->p_u + (p_sys->i_width / 2)
1588 * (i_active_line / 2 + 1),
1589 p_sys->p_v + (p_sys->i_width / 2)
1590 * (i_active_line / 2 + 1) );
1591 else if ( !b_field )
1592 Unpack2( p_line + anc + 5, p_sys->i_active_size - 5,
1593 p_sys->p_y + p_sys->i_width * i_active_line,
1594 p_sys->p_u + (p_sys->i_width / 2)
1595 * (i_active_line / 2 - 1),
1596 p_sys->p_v + (p_sys->i_width / 2)
1597 * (i_active_line / 2 - 1) );
1598 else
1599 Unpack3( p_line + anc + 5, p_sys->i_active_size - 5,
1600 p_sys->p_y + p_sys->i_width * i_active_line,
1601 p_sys->p_u + (p_sys->i_width / 2)
1602 * (i_active_line / 2),
1603 p_sys->p_v + (p_sys->i_width / 2)
1604 * (i_active_line / 2) );
1605
1606 if ( p_sys->b_vbi && p_sys->i_height == 576
1607 && p_sys->i_current_line == p_sys->i_line_offset )
1608 {
1609 /* Line 23 is half VBI, half active */
1610 UnpackVBI( p_line + anc + 5, p_sys->i_active_size - 5,
1611 p_sys->p_wss_buffer );
1612 }
1613 }
1614 else if ( p_sys->b_vbi && p_sys->i_telx_count &&
1615 i_field_line >= p_sys->i_telx_line &&
1616 i_field_line < p_sys->i_telx_line
1617 + p_sys->i_telx_count )
1618 {
1619 UnpackVBI( p_line + anc + 5, p_sys->i_active_size - 5,
1620 &p_sys->p_telx_buffer[(i_field_line
1621 - p_sys->i_telx_line + b_field * p_sys->i_telx_count)
1622 * p_sys->i_width * 2] );
1623 }
1624 else if ( b_vbi && HasAncillary( p_line + anc + 5 ) )
1625 {
1626 /* VANC */
1627 unsigned int i_anc_words = (p_sys->i_active_size - 5) * 4 / 5;
1628 uint16_t p_anc[i_anc_words];
1629 UnpackAnc( p_line + 5, p_sys->i_active_size - 5,
1630 p_anc );
1631 HandleAncillary( p_demux, p_anc, i_anc_words );
1632 }
1633
1634 p_sys->i_current_line++;
1635 if ( p_sys->i_current_line == p_sys->i_nb_lines )
1636 {
1637 p_sys->i_current_line %= p_sys->i_nb_lines;
1638 if( DecodeFrame( p_demux ) != VLC_SUCCESS )
1639 return VLC_EGENERIC;
1640 }
1641 }
1642 break;
1643 }
1644
1645 return VLC_SUCCESS;
1646 }
1647
1648 /*****************************************************************************
1649 * Low-level device stuff
1650 *****************************************************************************/
1651 #define MAXLEN 256
1652
ReadULSysfs(const char * psz_fmt,unsigned int i_link)1653 static int ReadULSysfs( const char *psz_fmt, unsigned int i_link )
1654 {
1655 char psz_file[MAXLEN];
1656 unsigned int i_data;
1657
1658 snprintf( psz_file, sizeof(psz_file), psz_fmt, i_link );
1659
1660 FILE *stream = vlc_fopen( psz_file, "rt" );
1661 if( stream == NULL )
1662 return -1;
1663
1664 int ret = fscanf( stream, "%u", &i_data );
1665 fclose( stream );
1666
1667 return (ret == 1 && i_data <= INT_MAX) ? (int)i_data : -1;
1668 }
1669
WriteULSysfs(const char * psz_fmt,unsigned int i_link,unsigned int i_buf)1670 static int WriteULSysfs( const char *psz_fmt, unsigned int i_link,
1671 unsigned int i_buf )
1672 {
1673 char psz_file[MAXLEN];
1674
1675 snprintf( psz_file, sizeof(psz_file), psz_fmt, i_link );
1676
1677 FILE *stream = vlc_fopen( psz_file, "wt" );
1678 if( stream == NULL )
1679 return -1;
1680
1681 int ret = fprintf( stream, "%u\n", i_buf );
1682 fclose( stream );
1683 return ret;
1684 }
1685
InitCapture(demux_t * p_demux)1686 static int InitCapture( demux_t *p_demux )
1687 {
1688 demux_sys_t *p_sys = p_demux->p_sys;
1689 const int i_page_size = getpagesize();
1690 unsigned int i_bufmemsize;
1691 int i_ret;
1692 char psz_dev[MAXLEN];
1693
1694 /* 10-bit mode or nothing */
1695 if ( WriteULSysfs( SDI_MODE_FILE, p_sys->i_link, SDI_CTL_MODE_10BIT ) < 0 )
1696 {
1697 msg_Err( p_demux, "couldn't write file " SDI_MODE_FILE, p_sys->i_link );
1698 return VLC_EGENERIC;
1699 }
1700
1701 if ( (i_ret = ReadULSysfs( SDI_BUFFERS_FILE, p_sys->i_link )) < 0 )
1702 {
1703 msg_Err( p_demux, "couldn't read file " SDI_BUFFERS_FILE,
1704 p_sys->i_link );
1705 return VLC_EGENERIC;
1706 }
1707 p_sys->i_buffers = i_ret;
1708 p_sys->i_current_buffer = 0;
1709
1710 if ( (i_ret = ReadULSysfs( SDI_BUFSIZE_FILE, p_sys->i_link )) < 0 )
1711 {
1712 msg_Err( p_demux, "couldn't read file " SDI_BUFSIZE_FILE,
1713 p_sys->i_link );
1714 return VLC_EGENERIC;
1715 }
1716 p_sys->i_buffer_size = i_ret;
1717 if ( p_sys->i_buffer_size % 20 )
1718 {
1719 msg_Err( p_demux, "buffer size must be a multiple of 20" );
1720 return VLC_EGENERIC;
1721 }
1722
1723 snprintf( psz_dev, sizeof(psz_dev) - 1, SDI_DEVICE, p_sys->i_link );
1724 if ( (p_sys->i_fd = vlc_open( psz_dev, O_RDONLY ) ) < 0 )
1725 {
1726 msg_Err( p_demux, "couldn't open device %s", psz_dev );
1727 return VLC_EGENERIC;
1728 }
1729
1730 i_bufmemsize = ((p_sys->i_buffer_size + i_page_size - 1) / i_page_size)
1731 * i_page_size;
1732 p_sys->pp_buffers = vlc_alloc( p_sys->i_buffers, sizeof(uint8_t *) );
1733 if( !p_sys->pp_buffers )
1734 return VLC_ENOMEM;
1735
1736 for ( unsigned int i = 0; i < p_sys->i_buffers; i++ )
1737 {
1738 if ( (p_sys->pp_buffers[i] = mmap( NULL, p_sys->i_buffer_size,
1739 PROT_READ, MAP_SHARED, p_sys->i_fd,
1740 i * i_bufmemsize )) == MAP_FAILED )
1741 {
1742 msg_Err( p_demux, "couldn't mmap(%d): %s", i,
1743 vlc_strerror_c(errno) );
1744 free( p_sys->pp_buffers );
1745 return VLC_EGENERIC;
1746 }
1747 }
1748
1749 return VLC_SUCCESS;
1750 }
1751
CloseCapture(demux_t * p_demux)1752 static void CloseCapture( demux_t *p_demux )
1753 {
1754 demux_sys_t *p_sys = p_demux->p_sys;
1755
1756 StopDecode( p_demux );
1757 for ( unsigned int i = 0; i < p_sys->i_buffers; i++ )
1758 munmap( p_sys->pp_buffers[i], p_sys->i_buffer_size );
1759 vlc_close( p_sys->i_fd );
1760 free( p_sys->pp_buffers );
1761 }
1762
Capture(demux_t * p_demux)1763 static int Capture( demux_t *p_demux )
1764 {
1765 demux_sys_t *p_sys = p_demux->p_sys;
1766 struct pollfd pfd;
1767
1768 pfd.fd = p_sys->i_fd;
1769 pfd.events = POLLIN | POLLPRI;
1770
1771 if ( poll( &pfd, 1, READ_TIMEOUT ) < 0 )
1772 {
1773 msg_Warn( p_demux, "couldn't poll(): %s", vlc_strerror_c(errno) );
1774 return VLC_EGENERIC;
1775 }
1776
1777 if ( pfd.revents & POLLPRI )
1778 {
1779 unsigned int i_val;
1780
1781 if ( ioctl( p_sys->i_fd, SDI_IOC_RXGETEVENTS, &i_val ) < 0 )
1782 msg_Warn( p_demux, "couldn't SDI_IOC_RXGETEVENTS: %s",
1783 vlc_strerror_c(errno) );
1784 else
1785 {
1786 if ( i_val & SDI_EVENT_RX_BUFFER )
1787 msg_Warn( p_demux, "driver receive buffer queue overrun" );
1788 if ( i_val & SDI_EVENT_RX_FIFO )
1789 msg_Warn( p_demux, "onboard receive FIFO overrun");
1790 if ( i_val & SDI_EVENT_RX_CARRIER )
1791 msg_Warn( p_demux, "carrier status change");
1792 }
1793
1794 p_sys->i_next_date += CLOCK_GAP;
1795 }
1796
1797 if ( pfd.revents & POLLIN )
1798 {
1799 int i_ret;
1800
1801 if ( ioctl( p_sys->i_fd, SDI_IOC_DQBUF, p_sys->i_current_buffer ) < 0 )
1802 {
1803 msg_Warn( p_demux, "couldn't SDI_IOC_DQBUF: %s",
1804 vlc_strerror_c(errno) );
1805 return VLC_EGENERIC;
1806 }
1807
1808 i_ret = HandleSDBuffer( p_demux,
1809 p_sys->pp_buffers[p_sys->i_current_buffer],
1810 p_sys->i_buffer_size );
1811
1812 if ( ioctl( p_sys->i_fd, SDI_IOC_QBUF, p_sys->i_current_buffer ) < 0 )
1813 {
1814 msg_Warn( p_demux, "couldn't SDI_IOC_QBUF: %s",
1815 vlc_strerror_c(errno) );
1816 return VLC_EGENERIC;
1817 }
1818
1819 if ( i_ret == VLC_SUCCESS )
1820 {
1821 p_sys->i_current_buffer++;
1822 p_sys->i_current_buffer %= p_sys->i_buffers;
1823 }
1824 else
1825 {
1826 /* Reference codes do not start on a multiple of 5. This sometimes
1827 * happen. We really don't want to allow this. */
1828 msg_Warn( p_demux, "resetting board" );
1829 CloseCapture( p_demux );
1830 InitCapture( p_demux );
1831 }
1832 }
1833
1834 return VLC_SUCCESS;
1835 }
1836
1837