1 /*****************************************************************************
2 * aribcam.c : ARIB STB-B25 software CAM stream filter
3 *****************************************************************************
4 * Copyright (C) 2014 VideoLAN and authors
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
25 #include <vlc_common.h>
26 #include <vlc_plugin.h>
27 #include <vlc_stream.h>
32 #include <aribb25/arib_std_b25.h>
33 #include <aribb25/arib_std_b25_error_code.h>
34 #include <aribb25/b_cas_card.h>
35 #include <aribb25/b_cas_card_error_code.h>
37 static int Open(vlc_object_t *);
38 static void Close(vlc_object_t *);
41 set_category (CAT_INPUT)
42 set_subcategory (SUBCAT_INPUT_STREAM_FILTER)
43 set_capability ("stream_filter", 0)
44 add_shortcut("aribcam")
45 set_description (N_("ARIB STD-B25 Cam module"))
46 set_callbacks (Open, Close)
49 struct error_messages_s
52 const char * const psz_error;
55 static const struct error_messages_s const b25_errors[] =
57 { ARIB_STD_B25_ERROR_INVALID_PARAM, "Invalid parameter" },
58 { ARIB_STD_B25_ERROR_NO_ENOUGH_MEMORY , "Not enough memory" },
59 { ARIB_STD_B25_ERROR_NON_TS_INPUT_STREAM, "Non TS input stream" },
60 { ARIB_STD_B25_ERROR_NO_PAT_IN_HEAD_16M, "No PAT in first 16MB" },
61 { ARIB_STD_B25_ERROR_NO_PMT_IN_HEAD_32M, "No PMT in first 32MB" },
62 { ARIB_STD_B25_ERROR_NO_ECM_IN_HEAD_32M, "No ECM in first 32MB" },
63 { ARIB_STD_B25_ERROR_EMPTY_B_CAS_CARD, "Empty BCAS card" },
64 { ARIB_STD_B25_ERROR_INVALID_B_CAS_STATUS, "Invalid BCAS status" },
65 { ARIB_STD_B25_ERROR_ECM_PROC_FAILURE, "ECM Proc failure" },
66 { ARIB_STD_B25_ERROR_DECRYPT_FAILURE, "Decryption failure" },
67 { ARIB_STD_B25_ERROR_PAT_PARSE_FAILURE, "PAT Parsing failure" },
68 { ARIB_STD_B25_ERROR_PMT_PARSE_FAILURE, "PMT Parsing failure" },
69 { ARIB_STD_B25_ERROR_ECM_PARSE_FAILURE, "ECM Parsing failure" },
70 { ARIB_STD_B25_ERROR_CAT_PARSE_FAILURE, "CAT Parsing failure" },
71 { ARIB_STD_B25_ERROR_EMM_PARSE_FAILURE, "EMM Parsing failure" },
72 { ARIB_STD_B25_ERROR_EMM_PROC_FAILURE, "EMM Proc failure" },
76 static const struct error_messages_s const bcas_errors[] =
78 { B_CAS_CARD_ERROR_INVALID_PARAMETER, "Invalid parameter" },
79 { B_CAS_CARD_ERROR_NOT_INITIALIZED, "Card not initialized" },
80 { B_CAS_CARD_ERROR_NO_SMART_CARD_READER, "No smart card reader" },
81 { B_CAS_CARD_ERROR_ALL_READERS_CONNECTION_FAILED, "Reader connection failed" },
82 { B_CAS_CARD_ERROR_NO_ENOUGH_MEMORY, "Not enough memory" },
83 { B_CAS_CARD_ERROR_TRANSMIT_FAILED, "Transmission failed" },
102 static int Peek( stream_t *, const uint8_t **, unsigned int );
104 static const char * GetErrorMessage( const int i_error,
105 const struct error_messages_s const *p_errors_messages )
108 while( p_errors_messages[i].psz_error )
110 if ( p_errors_messages[i].i_error == i_error )
111 return p_errors_messages[i].psz_error;
114 return "unkown error";
117 static size_t RemainRead( stream_t *p_stream, uint8_t *p_data, size_t i_toread, bool b_peek )
119 stream_sys_t *p_sys = p_stream->p_sys;
123 while( p_sys->remain.p_list && i_toread )
125 size_t i_copy = __MIN( i_toread, p_sys->remain.p_list->i_buffer );
126 memcpy( p_data, p_sys->remain.p_list->p_buffer, i_copy );
134 /* update block data pointer and release if no longer needed */
135 p_sys->remain.p_list->i_buffer -= i_copy;
136 p_sys->remain.p_list->p_buffer += i_copy;
137 p_sys->remain.i_size -= i_copy;
139 if ( p_sys->remain.p_list->i_buffer == 0 )
141 block_t *p_prevhead = p_sys->remain.p_list;
142 p_sys->remain.p_list = p_sys->remain.p_list->p_next;
143 block_Release( p_prevhead );
147 p_sys->remain.p_list = p_sys->remain.p_list->p_next;
152 static bool RemainAdd( stream_t *p_stream, const uint8_t *p_data, size_t i_size )
154 stream_sys_t *p_sys = p_stream->p_sys;
157 block_t *p_block = block_Alloc( i_size );
160 memcpy( p_block->p_buffer, p_data, i_size );
161 p_block->i_buffer = i_size;
162 block_ChainAppend( & p_sys->remain.p_list, p_block );
163 p_sys->remain.i_size += i_size;
167 static void RemainFlush( stream_sys_t *p_sys )
169 block_ChainRelease( p_sys->remain.p_list );
170 p_sys->remain.p_list = NULL;
171 p_sys->remain.i_size = 0;
174 #define ALL_READY (UNIT_SIZE_READY|ECM_READY|PMT_READY)
176 static int DecoderRead( stream_t *p_stream, uint8_t *p_dst, int i_toread, bool b_peek )
178 stream_sys_t *p_sys = p_stream->p_sys;
179 ARIB_STD_B25_BUFFER getbuf = { NULL, 0 };
180 int i_total_read = 0;
183 if ( !p_dst || ! i_toread )
186 /* Use data from previous reads */
187 size_t i_fromremain = RemainRead( p_stream, p_dst, i_toread, b_peek );
188 i_toread -= i_fromremain;
189 i_total_read += i_fromremain;
198 i_ret = p_sys->p_b25->get( p_sys->p_b25, &getbuf );
200 msg_Err( p_stream, "decoder get failed: %s",
201 GetErrorMessage( i_ret, b25_errors ) );
203 /* If the decoders needs buffering or data is not ready, push some */
204 if ( i_ret == 0 && getbuf.size == 0 )
206 /* make use of the existing buffer,
207 overwritten by decoder data later */
208 int i_srcread = stream_Read( p_stream->p_source, p_dst, i_toread );
211 ARIB_STD_B25_BUFFER putbuf = { p_dst, i_srcread };
212 i_ret = p_sys->p_b25->put( p_sys->p_b25, &putbuf );
214 msg_Err( p_stream, "decoder put failed: %s",
215 GetErrorMessage( i_ret, b25_errors ) );
220 msg_Err( p_stream, "Can't read %d bytes from source stream: %d", i_toread, i_srcread );
225 while ( i_ret == 0 && getbuf.size == 0 );
232 /* put everything in remain */
233 RemainAdd( p_stream, getbuf.data, getbuf.size );
237 memcpy( p_dst, getbuf.data, __MIN(getbuf.size, i_toread) );
239 if ( getbuf.size > i_toread )
241 /* Hold remaining data for next call */
242 RemainAdd( p_stream, getbuf.data + i_toread, getbuf.size - i_toread );
246 i_total_read += __MIN(getbuf.size, i_toread);
247 p_dst += __MIN(getbuf.size, i_toread);
248 i_toread -= __MIN(getbuf.size, i_toread);
255 static int Read( stream_t *p_stream, void *p_buf, unsigned int i_toread )
257 stream_sys_t *p_sys = p_stream->p_sys;
259 /* We force unit size from 1st TS packet as the lib wants to auto detect
260 size but requires larger amount of data for that purpose */
261 if ( !p_sys->b_unitsizeset )
263 if ( i_toread >= 188 && i_toread <= 320 )
264 p_sys->b_unitsizeset = ! p_sys->p_b25->set_unit_size( p_sys->p_b25, i_toread );
265 if ( !p_sys->b_unitsizeset )
266 msg_Warn( p_stream, "Unit size not set." );
268 msg_Dbg( p_stream, "Set unit size to %u", i_toread );
271 int i_read = DecoderRead( p_stream, p_buf, i_toread, false );
275 p_sys->i_pos += i_read;
283 static int Peek( stream_t *p_stream, const uint8_t **pp_buf, unsigned int i_len )
285 stream_sys_t *p_sys = p_stream->p_sys;
286 i_len = __MAX(ARIB_STD_B25_TS_PROBING_MIN_DATA, i_len);
288 if ( i_len > p_sys->remain.i_size )
290 uint8_t *p_tmpbuf = malloc( i_len - p_sys->remain.i_size );
291 DecoderRead( p_stream, p_tmpbuf, i_len - p_sys->remain.i_size, true );
295 if ( !p_sys->remain.p_list )
297 assert(p_sys->remain.i_size == 0);
298 /* might not be enough data in the stream to allow returning data */
302 if ( p_sys->remain.p_list->i_buffer < i_len )
304 p_sys->remain.p_list = block_ChainGather( p_sys->remain.p_list );
305 if ( !p_sys->remain.p_list )
307 p_sys->remain.i_size = 0;
312 *pp_buf = p_sys->remain.p_list->p_buffer;
314 return __MIN(i_len, p_sys->remain.i_size);
317 static int Seek( stream_t *p_stream, uint64_t i_pos )
319 int i_ret = stream_Seek( p_stream->p_source, i_pos );
320 if ( i_ret == VLC_SUCCESS )
322 RemainFlush( p_stream->p_sys );
323 p_stream->p_sys->i_pos = i_pos;
331 static int Control( stream_t *p_stream, int i_query, va_list args )
335 case STREAM_GET_POSITION:
336 *va_arg( args, uint64_t *) = p_stream->p_sys->i_pos;
338 case STREAM_SET_POSITION:
339 return Seek( p_stream, va_arg( args, uint64_t ) );
341 return stream_vaControl( p_stream->p_source, i_query, args );
345 static int Open( vlc_object_t *p_object )
347 stream_t *p_stream = (stream_t *) p_object;
349 int64_t i_stream_size = stream_Size( p_stream->p_source );
350 if ( i_stream_size > 0 && i_stream_size < ARIB_STD_B25_TS_PROBING_MIN_DATA )
353 stream_sys_t *p_sys = p_stream->p_sys = calloc( 1, sizeof(*p_sys) );
357 p_sys->p_b25 = create_arib_std_b25();
360 if ( p_sys->p_b25->set_multi2_round( p_sys->p_b25, 4 ) < 0 )
361 msg_Warn( p_stream, "cannot set B25 round number" );
363 if ( p_sys->p_b25->set_strip( p_sys->p_b25, 0 ) < 0 )
364 msg_Warn( p_stream, "cannot set B25 strip option" );
366 if ( p_sys->p_b25->set_emm_proc( p_sys->p_b25, 0 ) < 0 )
367 msg_Warn( p_stream, "cannot set B25 emm_proc" );
369 p_sys->p_bcas = create_b_cas_card();
372 int i_code = p_sys->p_bcas->init( p_sys->p_bcas );
375 /* Card could be just missing */
376 msg_Warn( p_stream, "cannot initialize BCAS card (missing ?): %s",
377 GetErrorMessage( i_code, bcas_errors ) );
382 if ( p_sys->p_bcas->get_id( p_sys->p_bcas, &bcasid ) == 0 )
384 for ( int32_t i=0; i<bcasid.count; i++)
386 msg_Dbg( p_stream, "BCAS card id 0x%"PRId64" initialized",
391 B_CAS_INIT_STATUS bcas_status;
392 if ( p_sys->p_bcas->get_init_status( p_sys->p_bcas, &bcas_status ) == 0 )
394 msg_Dbg( p_stream, "BCAS card system id 0x%"PRIx32,
395 bcas_status.ca_system_id );
398 i_code = p_sys->p_b25->set_b_cas_card( p_sys->p_b25, p_sys->p_bcas );
401 msg_Err( p_stream, "cannot attach BCAS card to decoder: %s",
402 GetErrorMessage( i_code, bcas_errors ) );
407 msg_Err( p_stream, "cannot create BCAS card" );
411 msg_Err( p_stream, "cannot create B25 instance" );
415 p_sys->i_pos = stream_Tell( p_stream->p_source );
417 p_stream->pf_read = Read;
418 p_stream->pf_peek = Peek;
419 p_stream->pf_control = Control;
424 Close( VLC_OBJECT(p_stream) );
428 static void Close ( vlc_object_t *p_object )
430 stream_t *p_stream = (stream_t *)p_object;
431 stream_sys_t *p_sys = p_stream->p_sys;
434 p_sys->p_bcas->release( p_sys->p_bcas );
437 p_sys->p_b25->release( p_sys->p_b25 );