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" },
99 static const char * GetErrorMessage( const int i_error
,
100 const struct error_messages_s
const *p_errors_messages
)
103 while( p_errors_messages
[i
].psz_error
)
105 if ( p_errors_messages
[i
].i_error
== i_error
)
106 return p_errors_messages
[i
].psz_error
;
109 return "unknown error";
112 static size_t RemainRead( stream_t
*p_stream
, uint8_t *p_data
, size_t i_toread
)
114 stream_sys_t
*p_sys
= p_stream
->p_sys
;
118 while( p_sys
->remain
.p_list
&& i_toread
)
120 size_t i_copy
= __MIN( i_toread
, p_sys
->remain
.p_list
->i_buffer
);
121 memcpy( p_data
, p_sys
->remain
.p_list
->p_buffer
, i_copy
);
127 /* update block data pointer and release if no longer needed */
128 p_sys
->remain
.p_list
->i_buffer
-= i_copy
;
129 p_sys
->remain
.p_list
->p_buffer
+= i_copy
;
130 p_sys
->remain
.i_size
-= i_copy
;
132 if ( p_sys
->remain
.p_list
->i_buffer
== 0 )
134 block_t
*p_prevhead
= p_sys
->remain
.p_list
;
135 p_sys
->remain
.p_list
= p_sys
->remain
.p_list
->p_next
;
136 block_Release( p_prevhead
);
142 static bool RemainAdd( stream_t
*p_stream
, const uint8_t *p_data
, size_t i_size
)
144 stream_sys_t
*p_sys
= p_stream
->p_sys
;
147 block_t
*p_block
= block_Alloc( i_size
);
150 memcpy( p_block
->p_buffer
, p_data
, i_size
);
151 p_block
->i_buffer
= i_size
;
152 block_ChainAppend( & p_sys
->remain
.p_list
, p_block
);
153 p_sys
->remain
.i_size
+= i_size
;
157 static void RemainFlush( stream_sys_t
*p_sys
)
159 block_ChainRelease( p_sys
->remain
.p_list
);
160 p_sys
->remain
.p_list
= NULL
;
161 p_sys
->remain
.i_size
= 0;
164 #define ALL_READY (UNIT_SIZE_READY|ECM_READY|PMT_READY)
166 static ssize_t
Read( stream_t
*p_stream
, void *p_buf
, size_t i_toread
)
168 stream_sys_t
*p_sys
= p_stream
->p_sys
;
169 uint8_t *p_dst
= p_buf
;
170 int i_total_read
= 0;
176 /* Use data from previous reads */
177 size_t i_fromremain
= RemainRead( p_stream
, p_dst
, i_toread
);
178 i_total_read
+= i_fromremain
;
179 p_dst
+= i_fromremain
;
180 i_toread
-= i_fromremain
;
184 /* make use of the existing buffer, overwritten by decoder data later */
185 int i_srcread
= vlc_stream_Read( p_stream
->s
, p_dst
, i_toread
);
188 ARIB_STD_B25_BUFFER putbuf
= { p_dst
, i_srcread
};
189 i_ret
= p_sys
->p_b25
->put( p_sys
->p_b25
, &putbuf
);
192 msg_Err( p_stream
, "decoder put failed: %s",
193 GetErrorMessage( i_ret
, b25_errors
) );
200 msg_Err( p_stream
, "Can't read %lu bytes from source stream: %d", i_toread
, i_srcread
);
204 ARIB_STD_B25_BUFFER getbuf
;
205 i_ret
= p_sys
->p_b25
->get( p_sys
->p_b25
, &getbuf
);
208 msg_Err( p_stream
, "decoder get failed: %s",
209 GetErrorMessage( i_ret
, b25_errors
) );
213 if ( (size_t)getbuf
.size
> i_toread
)
215 /* Hold remaining data for next call */
216 RemainAdd( p_stream
, getbuf
.data
+ i_toread
, getbuf
.size
- i_toread
);
219 int consume
= __MIN( (size_t)getbuf
.size
, i_toread
);
220 memcpy( p_dst
, getbuf
.data
, consume
);
222 i_total_read
+= consume
;
234 static int Seek( stream_t
*p_stream
, uint64_t i_pos
)
236 int i_ret
= vlc_stream_Seek( p_stream
->s
, i_pos
);
237 if ( i_ret
== VLC_SUCCESS
)
238 RemainFlush( p_stream
->p_sys
);
245 static int Control( stream_t
*p_stream
, int i_query
, va_list args
)
247 return vlc_stream_vaControl( p_stream
->s
, i_query
, args
);
250 static int Open( vlc_object_t
*p_object
)
252 stream_t
*p_stream
= (stream_t
*) p_object
;
254 int64_t i_stream_size
= stream_Size( p_stream
->s
);
255 if ( i_stream_size
> 0 && i_stream_size
< ARIB_STD_B25_TS_PROBING_MIN_DATA
)
258 stream_sys_t
*p_sys
= p_stream
->p_sys
= calloc( 1, sizeof(*p_sys
) );
262 p_sys
->p_b25
= create_arib_std_b25();
265 if ( p_sys
->p_b25
->set_multi2_round( p_sys
->p_b25
, 4 ) < 0 )
266 msg_Warn( p_stream
, "cannot set B25 round number" );
268 if ( p_sys
->p_b25
->set_strip( p_sys
->p_b25
, 0 ) < 0 )
269 msg_Warn( p_stream
, "cannot set B25 strip option" );
271 if ( p_sys
->p_b25
->set_emm_proc( p_sys
->p_b25
, 0 ) < 0 )
272 msg_Warn( p_stream
, "cannot set B25 emm_proc" );
274 /* ARIB STD-B25 scrambled TS's packet size is always 188 bytes */
275 if ( p_sys
->p_b25
->set_unit_size( p_sys
->p_b25
, 188 ) < 0)
276 msg_Warn( p_stream
, "cannot set B25 TS packet size" );
278 p_sys
->p_bcas
= create_b_cas_card();
281 int i_code
= p_sys
->p_bcas
->init( p_sys
->p_bcas
);
284 /* Card could be just missing */
285 msg_Warn( p_stream
, "cannot initialize BCAS card (missing ?): %s",
286 GetErrorMessage( i_code
, bcas_errors
) );
291 if ( p_sys
->p_bcas
->get_id( p_sys
->p_bcas
, &bcasid
) == 0 )
293 for ( int32_t i
=0; i
<bcasid
.count
; i
++)
295 msg_Dbg( p_stream
, "BCAS card id 0x%"PRId64
" initialized",
300 B_CAS_INIT_STATUS bcas_status
;
301 if ( p_sys
->p_bcas
->get_init_status( p_sys
->p_bcas
, &bcas_status
) == 0 )
303 msg_Dbg( p_stream
, "BCAS card system id 0x%"PRIx32
,
304 bcas_status
.ca_system_id
);
307 i_code
= p_sys
->p_b25
->set_b_cas_card( p_sys
->p_b25
, p_sys
->p_bcas
);
310 msg_Err( p_stream
, "cannot attach BCAS card to decoder: %s",
311 GetErrorMessage( i_code
, bcas_errors
) );
316 msg_Err( p_stream
, "cannot create BCAS card" );
320 msg_Err( p_stream
, "cannot create B25 instance" );
324 p_stream
->pf_read
= Read
;
325 p_stream
->pf_seek
= Seek
;
326 p_stream
->pf_control
= Control
;
331 Close( VLC_OBJECT(p_stream
) );
335 static void Close ( vlc_object_t
*p_object
)
337 stream_t
*p_stream
= (stream_t
*)p_object
;
338 stream_sys_t
*p_sys
= p_stream
->p_sys
;
341 p_sys
->p_bcas
->release( p_sys
->p_bcas
);
344 p_sys
->p_b25
->release( p_sys
->p_b25
);