]> git.sesse.net Git - vlc/blob - modules/stream_filter/aribcam.c
vlc_plugin: allow overriding module meta-infos
[vlc] / modules / stream_filter / aribcam.c
1 /*****************************************************************************
2  * aribcam.c : ARIB STB-B25 software CAM stream filter
3  *****************************************************************************
4  * Copyright (C) 2014 VideoLAN and authors
5  *
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.
10  *
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.
15  *
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  *****************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 #include <vlc_common.h>
26 #include <vlc_plugin.h>
27 #include <vlc_stream.h>
28
29 #include <inttypes.h>
30 #include <assert.h>
31
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>
36
37 static int  Open(vlc_object_t *);
38 static void Close(vlc_object_t *);
39
40 vlc_module_begin ()
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)
47 vlc_module_end ()
48
49 struct error_messages_s
50 {
51     const int8_t i_error;
52     const char * const psz_error;
53 };
54
55 static const struct error_messages_s const b25_errors[] =
56 {
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" },
73     { 0, NULL },
74 };
75
76 static const struct error_messages_s const bcas_errors[] =
77 {
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" },
84     { 0, NULL },
85 };
86
87 struct stream_sys_t
88 {
89     ARIB_STD_B25 *p_b25;
90     B_CAS_CARD   *p_bcas;
91     struct
92     {
93         uint8_t *p_buf;
94         size_t   i_size;
95         block_t *p_list;
96     } remain;
97
98     size_t i_pos;
99     bool   b_unitsizeset;
100 };
101
102 static int Peek( stream_t *, const uint8_t **, unsigned int );
103
104 static const char * GetErrorMessage( const int i_error,
105                                const struct error_messages_s const *p_errors_messages )
106 {
107     int i = 0;
108     while( p_errors_messages[i].psz_error )
109     {
110         if ( p_errors_messages[i].i_error == i_error )
111             return p_errors_messages[i].psz_error;
112         i++;
113     }
114     return "unkown error";
115 }
116
117 static size_t RemainRead( stream_t *p_stream, uint8_t *p_data, size_t i_toread, bool b_peek )
118 {
119     stream_sys_t *p_sys = p_stream->p_sys;
120
121     size_t i_total = 0;
122
123     while( p_sys->remain.p_list && i_toread )
124     {
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 );
127
128         i_toread -= i_copy;
129         i_total += i_copy;
130         p_data += i_copy;
131
132         if ( !b_peek )
133         {
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;
138
139             if ( p_sys->remain.p_list->i_buffer == 0 )
140             {
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 );
144             }
145         }
146         else
147             p_sys->remain.p_list = p_sys->remain.p_list->p_next;
148     }
149     return i_total;
150 }
151
152 static bool RemainAdd( stream_t *p_stream, const uint8_t *p_data, size_t i_size )
153 {
154     stream_sys_t *p_sys = p_stream->p_sys;
155     if ( i_size == 0 )
156         return true;
157     block_t *p_block = block_Alloc( i_size );
158     if ( !p_block )
159         return false;
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;
164     return true;
165 }
166
167 static void RemainFlush( stream_sys_t *p_sys )
168 {
169     block_ChainRelease( p_sys->remain.p_list );
170     p_sys->remain.p_list = NULL;
171     p_sys->remain.i_size = 0;
172 }
173
174 #define ALL_READY (UNIT_SIZE_READY|ECM_READY|PMT_READY)
175
176 static int DecoderRead( stream_t *p_stream, uint8_t *p_dst, int i_toread, bool b_peek )
177 {
178     stream_sys_t *p_sys = p_stream->p_sys;
179     ARIB_STD_B25_BUFFER getbuf = { NULL, 0 };
180     int i_total_read = 0;
181     int i_ret;
182
183     if ( !p_dst || ! i_toread )
184         return -1;
185
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;
190
191     while( i_toread )
192     {
193
194         do
195         {
196             getbuf.size = 0;
197
198             i_ret = p_sys->p_b25->get( p_sys->p_b25, &getbuf );
199             if ( i_ret < 0 )
200                 msg_Err( p_stream, "decoder get failed: %s",
201                          GetErrorMessage( i_ret, b25_errors ) );
202
203             /* If the decoders needs buffering or data is not ready, push some */
204             if ( i_ret == 0 && getbuf.size == 0 )
205             {
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 );
209                 if ( i_srcread > 0 )
210                 {
211                     ARIB_STD_B25_BUFFER putbuf = { p_dst, i_srcread };
212                     i_ret = p_sys->p_b25->put( p_sys->p_b25, &putbuf );
213                     if ( i_ret < 0 )
214                         msg_Err( p_stream, "decoder put failed: %s",
215                                  GetErrorMessage( i_ret, b25_errors ) );
216                 }
217                 else
218                 {
219                     if ( i_srcread < 0 )
220                         msg_Err( p_stream, "Can't read %d bytes from source stream: %d", i_toread, i_srcread );
221                     i_ret = -1;
222                 }
223             }
224         }
225         while ( i_ret == 0 && getbuf.size == 0 );
226
227         if ( i_ret < 0 )
228             return -1;
229
230         if ( b_peek )
231         {
232             /* put everything in remain */
233             RemainAdd( p_stream, getbuf.data, getbuf.size );
234         }
235         else
236         {
237             memcpy( p_dst, getbuf.data, __MIN(getbuf.size, i_toread) );
238
239             if ( getbuf.size > i_toread )
240             {
241                 /* Hold remaining data for next call */
242                 RemainAdd( p_stream, getbuf.data + i_toread, getbuf.size - i_toread );
243             }
244         }
245
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);
249
250     }
251
252     return i_total_read;
253 }
254
255 static int Read( stream_t *p_stream, void *p_buf, unsigned int i_toread )
256 {
257     stream_sys_t *p_sys = p_stream->p_sys;
258
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 )
262     {
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." );
267         else
268             msg_Dbg( p_stream, "Set unit size to %u", i_toread );
269     }
270
271     int i_read = DecoderRead( p_stream, p_buf, i_toread, false );
272     if ( i_read < 0 )
273         return -1;
274     else
275         p_sys->i_pos += i_read;
276     return i_read;
277 }
278
279 /**
280  *
281  */
282
283 static int Peek( stream_t *p_stream, const uint8_t **pp_buf, unsigned int i_len )
284 {
285     stream_sys_t *p_sys = p_stream->p_sys;
286     i_len = __MAX(ARIB_STD_B25_TS_PROBING_MIN_DATA, i_len);
287
288     if ( i_len > p_sys->remain.i_size )
289     {
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 );
292         free( p_tmpbuf );
293     }
294
295     if ( !p_sys->remain.p_list )
296     {
297         assert(p_sys->remain.i_size == 0);
298         /* might not be enough data in the stream to allow returning data */
299         return 0;
300     }
301
302     if ( p_sys->remain.p_list->i_buffer < i_len )
303     {
304         p_sys->remain.p_list = block_ChainGather( p_sys->remain.p_list );
305         if ( !p_sys->remain.p_list )
306         {
307             p_sys->remain.i_size = 0;
308             return 0;
309         }
310     }
311
312     *pp_buf = p_sys->remain.p_list->p_buffer;
313
314     return __MIN(i_len, p_sys->remain.i_size);
315 }
316
317 static int Seek( stream_t *p_stream, uint64_t i_pos )
318 {
319     int i_ret = stream_Seek( p_stream->p_source, i_pos );
320     if ( i_ret == VLC_SUCCESS )
321     {
322         RemainFlush( p_stream->p_sys );
323         p_stream->p_sys->i_pos = i_pos;
324     }
325     return i_ret;
326 }
327
328 /**
329  *
330  */
331 static int Control( stream_t *p_stream, int i_query, va_list args )
332 {
333     switch( i_query )
334     {
335     case STREAM_GET_POSITION:
336         *va_arg( args, uint64_t *) = p_stream->p_sys->i_pos;
337         return VLC_SUCCESS;
338     case STREAM_SET_POSITION:
339         return Seek( p_stream, va_arg( args, uint64_t ) );
340     default:
341         return stream_vaControl( p_stream->p_source, i_query, args );
342     }
343 }
344
345 static int Open( vlc_object_t *p_object )
346 {
347     stream_t *p_stream = (stream_t *) p_object;
348
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 )
351         return VLC_EGENERIC;
352
353     stream_sys_t *p_sys = p_stream->p_sys = calloc( 1, sizeof(*p_sys) );
354     if (p_sys == NULL)
355         return VLC_ENOMEM;
356
357     p_sys->p_b25 = create_arib_std_b25();
358     if ( p_sys->p_b25 )
359     {
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" );
362
363         if ( p_sys->p_b25->set_strip( p_sys->p_b25, 0 ) < 0 )
364             msg_Warn( p_stream, "cannot set B25 strip option" );
365
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" );
368
369         p_sys->p_bcas = create_b_cas_card();
370         if ( p_sys->p_bcas )
371         {
372             int i_code = p_sys->p_bcas->init( p_sys->p_bcas );
373             if ( i_code < 0 )
374             {
375                 /* Card could be just missing */
376                 msg_Warn( p_stream, "cannot initialize BCAS card (missing ?): %s",
377                           GetErrorMessage( i_code, bcas_errors ) );
378                 goto error;
379             }
380
381             B_CAS_ID bcasid;
382             if ( p_sys->p_bcas->get_id( p_sys->p_bcas, &bcasid ) == 0 )
383             {
384                 for ( int32_t i=0; i<bcasid.count; i++)
385                 {
386                     msg_Dbg( p_stream, "BCAS card id 0x%"PRId64" initialized",
387                              bcasid.data[i] );
388                 }
389             }
390
391             B_CAS_INIT_STATUS bcas_status;
392             if ( p_sys->p_bcas->get_init_status( p_sys->p_bcas, &bcas_status ) == 0 )
393             {
394                 msg_Dbg( p_stream, "BCAS card system id 0x%"PRIx32,
395                          bcas_status.ca_system_id );
396             }
397
398             i_code = p_sys->p_b25->set_b_cas_card( p_sys->p_b25, p_sys->p_bcas );
399             if ( i_code < 0 )
400             {
401                 msg_Err( p_stream, "cannot attach BCAS card to decoder: %s",
402                          GetErrorMessage( i_code, bcas_errors ) );
403                 goto error;
404             }
405         }
406         else
407             msg_Err( p_stream, "cannot create BCAS card" );
408     }
409     else
410     {
411         msg_Err( p_stream, "cannot create B25 instance" );
412         goto error;
413     }
414
415     p_sys->i_pos = stream_Tell( p_stream->p_source );
416
417     p_stream->pf_read = Read;
418     p_stream->pf_peek = Peek;
419     p_stream->pf_control = Control;
420
421     return VLC_SUCCESS;
422
423 error:
424     Close( VLC_OBJECT(p_stream) );
425     return VLC_EGENERIC;
426 }
427
428 static void Close ( vlc_object_t *p_object )
429 {
430     stream_t *p_stream = (stream_t *)p_object;
431     stream_sys_t *p_sys = p_stream->p_sys;
432
433     if ( p_sys->p_bcas )
434         p_sys->p_bcas->release( p_sys->p_bcas );
435
436     if ( p_sys->p_b25 )
437         p_sys->p_b25->release( p_sys->p_b25 );
438
439     free( p_sys );
440 }