/src/vlc/modules/demux/mpeg/ts_si.c
Line | Count | Source |
1 | | /***************************************************************************** |
2 | | * ts_psi_eit.c : TS demuxer SI handling |
3 | | ***************************************************************************** |
4 | | * Copyright (C) 2014-2016 - VideoLAN 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 General Public License |
17 | | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | | *****************************************************************************/ |
19 | | #ifdef HAVE_CONFIG_H |
20 | | # include "config.h" |
21 | | #endif |
22 | | |
23 | | #include <vlc_common.h> |
24 | | #include <vlc_demux.h> |
25 | | #include <vlc_meta.h> |
26 | | #include <vlc_epg.h> |
27 | | #include <vlc_charset.h> /* FromCharset, for EIT */ |
28 | | #include <vlc_input.h> |
29 | | |
30 | | #ifndef _DVBPSI_DVBPSI_H_ |
31 | | #include <dvbpsi/dvbpsi.h> |
32 | | #endif |
33 | | #include <dvbpsi/demux.h> |
34 | | #include <dvbpsi/descriptor.h> |
35 | | #include <dvbpsi/sdt.h> |
36 | | #include <dvbpsi/eit.h> /* EIT support */ |
37 | | #include <dvbpsi/tot.h> /* TDT support */ |
38 | | #include <dvbpsi/dr.h> |
39 | | #include <dvbpsi/psi.h> |
40 | | #include "../../mux/mpeg/dvbpsi_compat.h" /* dvbpsi_messages */ |
41 | | |
42 | | #include "ts_si.h" |
43 | | #include "ts_arib.h" |
44 | | #include "ts_decoders.h" |
45 | | |
46 | | #include "ts_pid.h" |
47 | | #include "ts_streams_private.h" |
48 | | #include "ts.h" |
49 | | #include "../dvb-text.h" |
50 | | |
51 | | #ifdef HAVE_ARIBB24 |
52 | | #include <aribb24/decoder.h> |
53 | | #endif |
54 | | |
55 | | #include <time.h> |
56 | | #include <assert.h> |
57 | | #include <limits.h> |
58 | | |
59 | | struct ts_si_context_t |
60 | | { |
61 | | dvbpsi_t *p_handle; |
62 | | int i_version; |
63 | | }; |
64 | | |
65 | | #ifndef SI_DEBUG_EIT |
66 | | #define SI_DEBUG_TIMESHIFT(t) |
67 | | #else |
68 | | static time_t i_eit_debug_offset = 0; |
69 | | #define SI_DEBUG_TIMESHIFT(t) \ |
70 | | do {\ |
71 | | if( i_eit_debug_offset == 0 )\ |
72 | | i_eit_debug_offset = time(NULL) - t;\ |
73 | | t = t + i_eit_debug_offset;\ |
74 | | } while(0); |
75 | | #endif |
76 | | |
77 | | |
78 | | static void SINewTableCallBack( dvbpsi_t *h, uint8_t i_table_id, |
79 | | uint16_t i_extension, void *p_pid_cbdata ); |
80 | | |
81 | | void ts_si_Packet_Push( ts_pid_t *p_pid, const uint8_t *p_pktbuffer ) |
82 | 17.2k | { |
83 | 17.2k | if( likely(p_pid->type == TYPE_SI) && |
84 | 17.2k | dvbpsi_decoder_present( p_pid->u.p_si->p_ctx->p_handle ) ) |
85 | 17.2k | dvbpsi_packet_push( p_pid->u.p_si->p_ctx->p_handle, (uint8_t *) p_pktbuffer ); |
86 | 17.2k | } |
87 | | |
88 | | static char *EITConvertToUTF8( demux_t *p_demux, |
89 | | const unsigned char *psz_instring, |
90 | | size_t i_length, |
91 | | bool b_broken ) |
92 | 1.33k | { |
93 | 1.33k | demux_sys_t *p_sys = p_demux->p_sys; |
94 | | #ifdef HAVE_ARIBB24 |
95 | | if( p_sys->standard == TS_STANDARD_ARIB ) |
96 | | { |
97 | | if ( !p_sys->arib.p_instance ) |
98 | | p_sys->arib.p_instance = arib_instance_new( p_demux ); |
99 | | if ( !p_sys->arib.p_instance ) |
100 | | return NULL; |
101 | | arib_decoder_t *p_decoder = arib_get_decoder( p_sys->arib.p_instance ); |
102 | | if ( !p_decoder ) |
103 | | return NULL; |
104 | | |
105 | | char *psz_outstring = NULL; |
106 | | size_t i_out; |
107 | | |
108 | | i_out = i_length * 4; |
109 | | psz_outstring = (char*) calloc( i_out + 1, sizeof(char) ); |
110 | | if( !psz_outstring ) |
111 | | return NULL; |
112 | | |
113 | | arib_initialize_decoder( p_decoder ); |
114 | | i_out = arib_decode_buffer( p_decoder, psz_instring, i_length, |
115 | | psz_outstring, i_out ); |
116 | | arib_finalize_decoder( p_decoder ); |
117 | | |
118 | | return psz_outstring; |
119 | | } |
120 | | #else |
121 | 1.33k | VLC_UNUSED(p_sys); |
122 | 1.33k | #endif |
123 | | /* Deal with no longer broken providers (no switch byte |
124 | | but sending ISO_8859-1 instead of ISO_6937) without |
125 | | removing them from the broken providers table |
126 | | (keep the entry for correctly handling recorded TS). |
127 | | */ |
128 | 1.33k | b_broken = b_broken && i_length && *psz_instring > 0x20; |
129 | | |
130 | 1.33k | if( b_broken ) |
131 | 0 | return FromCharset( "ISO_8859-1", psz_instring, i_length ); |
132 | 1.33k | return vlc_from_EIT( psz_instring, i_length ); |
133 | 1.33k | } |
134 | | |
135 | 288 | #define attach_SI_decoders(i_pid, name, member) do {\ |
136 | 288 | ts_pid_t *pid = GetPID(p_sys, i_pid);\ |
137 | 288 | if ( PIDSetup( p_demux, TYPE_SI, pid, NULL ) )\ |
138 | 288 | {\ |
139 | 288 | if( !ts_attach_SI_Tables_Decoders( pid ) )\ |
140 | 288 | {\ |
141 | 0 | msg_Err( p_demux, "Can't attach SI table decoders for pid %d", i_pid );\ |
142 | 0 | PIDRelease( p_demux, pid );\ |
143 | 0 | }\ |
144 | 288 | else\ |
145 | 288 | {\ |
146 | 288 | sdt->u.p_si->member = pid;\ |
147 | 288 | SetPIDFilter( p_demux->p_sys, pid, true );\ |
148 | 288 | msg_Dbg( p_demux, " * pid=%d listening for "name, i_pid );\ |
149 | 288 | }\ |
150 | 288 | }\ |
151 | 288 | } while(0)\ |
152 | | |
153 | | static void SDTCallBack( void *opaque, dvbpsi_sdt_t *p_sdt ) |
154 | 266 | { |
155 | 266 | demux_t *p_demux = opaque; |
156 | 266 | demux_sys_t *p_sys = p_demux->p_sys; |
157 | 266 | ts_pid_t *sdt = GetPID(p_sys, TS_SI_SDT_PID); |
158 | 266 | ts_pat_t *p_pat = ts_pid_Get(&p_sys->pids, 0)->u.p_pat; |
159 | 266 | dvbpsi_sdt_service_t *p_srv; |
160 | | |
161 | 266 | msg_Dbg( p_demux, "SDTCallBack called" ); |
162 | | |
163 | 266 | if( p_sys->es_creation != CREATE_ES || |
164 | 266 | !p_sdt->b_current_next || |
165 | 266 | p_sdt->i_version == sdt->u.p_si->p_ctx->i_version ) |
166 | 122 | { |
167 | 122 | dvbpsi_sdt_delete( p_sdt ); |
168 | 122 | return; |
169 | 122 | } |
170 | | |
171 | | /* First callback */ |
172 | 144 | if( sdt->u.p_si->p_ctx->i_version == -1 ) |
173 | 144 | { |
174 | 144 | attach_SI_decoders( TS_SI_EIT_PID, "EIT", eitpid ); |
175 | 144 | attach_SI_decoders( TS_SI_TDT_PID, "TDT", tdtpid ); |
176 | 144 | if( p_sys->standard == TS_STANDARD_ARIB ) |
177 | 0 | attach_SI_decoders( TS_ARIB_CDT_PID, "CDT", cdtpid ); |
178 | 144 | } |
179 | | |
180 | | |
181 | 144 | msg_Dbg( p_demux, "new SDT ts_id=%"PRIu16" version=%"PRIu8" current_next=%d " |
182 | 144 | "network_id=%"PRIu16, |
183 | 144 | p_sdt->i_extension, |
184 | 144 | p_sdt->i_version, p_sdt->b_current_next, |
185 | 144 | p_sdt->i_network_id ); |
186 | | |
187 | 144 | p_sys->b_broken_charset = false; |
188 | | |
189 | 824 | for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next ) |
190 | 680 | { |
191 | 680 | ts_pmt_t *p_pmt = ts_pat_Get_pmt( p_pat, p_srv->i_service_id ); |
192 | 680 | vlc_meta_t *p_meta; |
193 | 680 | dvbpsi_descriptor_t *p_dr; |
194 | | |
195 | 680 | const char *psz_type = NULL; |
196 | 680 | const char *psz_status = NULL; |
197 | | |
198 | 680 | msg_Dbg( p_demux, " * service id=%"PRIu16" eit schedule=%d present=%d " |
199 | 680 | "running=%"PRIu8" free_ca=%d", |
200 | 680 | p_srv->i_service_id, p_srv->b_eit_schedule, |
201 | 680 | p_srv->b_eit_present, p_srv->i_running_status, |
202 | 680 | p_srv->b_free_ca ); |
203 | | |
204 | 680 | if( p_sys->vdr.i_service && p_srv->i_service_id != p_sys->vdr.i_service ) |
205 | 5 | { |
206 | 5 | msg_Dbg( p_demux, " * service id=%d skipped (not declared in vdr header)", |
207 | 5 | p_sys->vdr.i_service ); |
208 | 5 | continue; |
209 | 5 | } |
210 | | |
211 | 675 | p_meta = vlc_meta_New(); |
212 | 1.34k | for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next ) |
213 | 665 | { |
214 | 665 | if( p_dr->i_tag == 0x48 ) |
215 | 665 | { |
216 | 665 | static const char *ppsz_type[17] = { |
217 | 665 | "Reserved", |
218 | 665 | "Digital television service", |
219 | 665 | "Digital radio sound service", |
220 | 665 | "Teletext service", |
221 | 665 | "NVOD reference service", |
222 | 665 | "NVOD time-shifted service", |
223 | 665 | "Mosaic service", |
224 | 665 | "PAL coded signal", |
225 | 665 | "SECAM coded signal", |
226 | 665 | "D/D2-MAC", |
227 | 665 | "FM Radio", |
228 | 665 | "NTSC coded signal", |
229 | 665 | "Data broadcast service", |
230 | 665 | "Reserved for Common Interface Usage", |
231 | 665 | "RCS Map (see EN 301 790 [35])", |
232 | 665 | "RCS FLS (see EN 301 790 [35])", |
233 | 665 | "DVB MHP service" |
234 | 665 | }; |
235 | 665 | dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr ); |
236 | 665 | char *str1 = NULL; |
237 | 665 | char *str2 = NULL; |
238 | | |
239 | | /* Workarounds for broadcasters with broken EPG */ |
240 | | |
241 | 665 | if( p_sdt->i_network_id == 133 ) |
242 | 0 | p_sys->b_broken_charset = true; /* SKY DE & BetaDigital use ISO8859-1 */ |
243 | | |
244 | | /* List of providers using ISO8859-1 */ |
245 | 665 | static const char ppsz_broken_providers[][8] = { |
246 | 665 | "CSAT", /* CanalSat FR */ |
247 | 665 | "GR1", /* France televisions */ |
248 | 665 | "MULTI4", /* NT1 */ |
249 | 665 | "MR5", /* France 2/M6 HD */ |
250 | 665 | "" |
251 | 665 | }; |
252 | 3.32k | for( int i = 0; *ppsz_broken_providers[i]; i++ ) |
253 | 2.66k | { |
254 | 2.66k | const size_t i_length = strlen(ppsz_broken_providers[i]); |
255 | 2.66k | if( pD->i_service_provider_name_length == i_length && |
256 | 1.33k | !strncmp( (char *)pD->i_service_provider_name, ppsz_broken_providers[i], i_length ) ) |
257 | 0 | p_sys->b_broken_charset = true; |
258 | 2.66k | } |
259 | | |
260 | | /* FIXME: Digital+ ES also uses ISO8859-1 */ |
261 | | |
262 | 665 | str1 = EITConvertToUTF8(p_demux, |
263 | 665 | pD->i_service_provider_name, |
264 | 665 | pD->i_service_provider_name_length, |
265 | 665 | p_sys->b_broken_charset ); |
266 | 665 | str2 = EITConvertToUTF8(p_demux, |
267 | 665 | pD->i_service_name, |
268 | 665 | pD->i_service_name_length, |
269 | 665 | p_sys->b_broken_charset ); |
270 | | |
271 | 665 | msg_Dbg( p_demux, " - type=%"PRIu8" provider=%s name=%s", |
272 | 665 | pD->i_service_type, str1, str2 ); |
273 | | |
274 | 665 | if( !str2 || strcmp( "Service01", str2 ) ) /* Skip bogus libav/ffmpeg SDT */ |
275 | 665 | { |
276 | 665 | vlc_meta_SetTitle( p_meta, str2 ); |
277 | 665 | vlc_meta_SetPublisher( p_meta, str1 ); |
278 | 665 | if( pD->i_service_type >= 0x01 && pD->i_service_type <= 0x10 ) |
279 | 0 | psz_type = ppsz_type[pD->i_service_type]; |
280 | 665 | } |
281 | 665 | free( str1 ); |
282 | 665 | free( str2 ); |
283 | 665 | } |
284 | 0 | else if( p_sys->standard == TS_STANDARD_ARIB && |
285 | 0 | p_dr->i_tag == TS_ARIB_DR_LOGO_TRANSMISSION && p_pmt ) |
286 | 0 | { |
287 | 0 | ts_arib_logo_dr_t *p_logodr = ts_arib_logo_dr_Decode( p_dr->p_data, p_dr->i_length ); |
288 | 0 | if( p_logodr ) |
289 | 0 | { |
290 | 0 | if( p_logodr->i_transmission_mode == 0 ) |
291 | 0 | { |
292 | 0 | p_pmt->arib.i_logo_id = p_logodr->i_logo_id; |
293 | 0 | p_pmt->arib.i_download_id = p_logodr->i_download_data_id; |
294 | 0 | } |
295 | 0 | else if( p_logodr->i_transmission_mode == 1 ) |
296 | 0 | { |
297 | 0 | p_pmt->arib.i_logo_id = p_logodr->i_logo_id; |
298 | 0 | } |
299 | 0 | else /* TODO simple logo identifier */ |
300 | 0 | { |
301 | |
|
302 | 0 | } |
303 | |
|
304 | 0 | if( p_pmt->arib.i_logo_id > -1 ) |
305 | 0 | { |
306 | 0 | char *psz_name; |
307 | 0 | if( asprintf( &psz_name, "attachment://onid[%"PRIx16"]_channel_logo_id[%"PRIx16"]q[%d]", |
308 | 0 | p_sdt->i_network_id, p_logodr->i_logo_id, |
309 | 0 | TS_ARIB_LOGO_TYPE_HD_LARGE ) > -1 ) |
310 | 0 | { |
311 | 0 | vlc_meta_SetArtURL( p_meta, psz_name ); |
312 | 0 | vlc_meta_SetExtra( p_meta, "ARTURL", psz_name ); |
313 | 0 | free( psz_name ); |
314 | 0 | } |
315 | 0 | } |
316 | |
|
317 | 0 | ts_arib_logo_dr_Delete( p_logodr ); |
318 | 0 | } |
319 | 0 | } |
320 | 665 | } |
321 | | |
322 | 675 | if( p_srv->i_running_status >= 0x01 && p_srv->i_running_status <= 0x04 ) |
323 | 670 | { |
324 | 670 | static const char *ppsz_status[5] = { |
325 | 670 | "Unknown", |
326 | 670 | "Not running", |
327 | 670 | "Starts in a few seconds", |
328 | 670 | "Pausing", |
329 | 670 | "Running" |
330 | 670 | }; |
331 | 670 | psz_status = ppsz_status[p_srv->i_running_status]; |
332 | 670 | } |
333 | | |
334 | 675 | if( psz_type ) |
335 | 0 | vlc_meta_SetExtra( p_meta, "Type", psz_type ); |
336 | 675 | if( psz_status ) |
337 | 670 | vlc_meta_SetExtra( p_meta, "Status", psz_status ); |
338 | | |
339 | 675 | es_out_Control( p_demux->out, ES_OUT_SET_GROUP_META, |
340 | 675 | p_srv->i_service_id, p_meta ); |
341 | 675 | vlc_meta_Delete( p_meta ); |
342 | 675 | } |
343 | | |
344 | 144 | sdt->u.p_si->p_ctx->i_version = p_sdt->i_version; |
345 | 144 | dvbpsi_sdt_delete( p_sdt ); |
346 | 144 | } |
347 | | |
348 | | static void EITDecodeMjd( int i_mjd, int *p_y, int *p_m, int *p_d ) |
349 | 3 | { |
350 | 3 | const int yp = (int)( ( (double)i_mjd - 15078.2)/365.25 ); |
351 | 3 | const int mp = (int)( ((double)i_mjd - 14956.1 - (int)(yp * 365.25)) / 30.6001 ); |
352 | 3 | const int c = ( mp == 14 || mp == 15 ) ? 1 : 0; |
353 | | |
354 | 3 | *p_y = 1900 + yp + c*1; |
355 | 3 | *p_m = mp - 1 - c*12; |
356 | 3 | *p_d = i_mjd - 14956 - (int)(yp*365.25) - (int)(mp*30.6001); |
357 | 3 | } |
358 | 9 | #define CVT_FROM_BCD(v) ((((v) >> 4)&0xf)*10 + ((v)&0xf)) |
359 | | static int64_t EITConvertStartTime( uint64_t i_date ) |
360 | 3 | { |
361 | 3 | const int i_mjd = i_date >> 24; |
362 | 3 | struct tm tm; |
363 | | |
364 | 3 | tm.tm_hour = CVT_FROM_BCD(i_date >> 16); |
365 | 3 | tm.tm_min = CVT_FROM_BCD(i_date >> 8); |
366 | 3 | tm.tm_sec = CVT_FROM_BCD(i_date ); |
367 | | |
368 | | /* if all 40 bits are 1, the start is unknown */ |
369 | 3 | if( i_date == UINT64_C(0xffffffffff) ) |
370 | 0 | return -1; |
371 | | |
372 | 3 | EITDecodeMjd( i_mjd, &tm.tm_year, &tm.tm_mon, &tm.tm_mday ); |
373 | 3 | tm.tm_year -= 1900; |
374 | 3 | tm.tm_mon--; |
375 | 3 | tm.tm_isdst = 0; |
376 | | |
377 | 3 | return timegm( &tm ); |
378 | 3 | } |
379 | | static int EITConvertDuration( uint32_t i_duration ) |
380 | 0 | { |
381 | 0 | return CVT_FROM_BCD(i_duration >> 16) * 3600 + |
382 | 0 | CVT_FROM_BCD(i_duration >> 8 ) * 60 + |
383 | 0 | CVT_FROM_BCD(i_duration ); |
384 | 0 | } |
385 | | #undef CVT_FROM_BCD |
386 | | |
387 | | static void TDTCallBack( void *opaque, dvbpsi_tot_t *p_tdt ) |
388 | 3 | { |
389 | 3 | demux_t *p_demux = opaque; |
390 | 3 | demux_sys_t *p_sys = p_demux->p_sys; |
391 | | |
392 | | |
393 | 3 | p_sys->i_network_time = EITConvertStartTime( p_tdt->i_utc_time ); |
394 | 3 | p_sys->i_network_time_update = time(NULL); |
395 | 3 | if( p_sys->standard == TS_STANDARD_ARIB ) |
396 | 0 | { |
397 | | /* All ARIB-B10 times are in JST time, where DVB is UTC. (spec being a fork) |
398 | | DVB TOT should include DTS offset in descriptor 0x58 (including DST), |
399 | | but as there's no DST in JAPAN (since Showa 27/1952) |
400 | | and considering that no-one seems to send TDT or desc 0x58, |
401 | | falling back on fixed offset is safe */ |
402 | 0 | p_sys->i_network_time += 9 * 3600; |
403 | 0 | } |
404 | | |
405 | | /* Because libdvbpsi is broken and deduplicating timestamp tables, |
406 | | * we need to reset it to get next timestamp callback */ |
407 | 3 | ts_pid_t *pid = ts_pid_Get( &p_sys->pids, TS_SI_TDT_PID ); |
408 | 3 | dvbpsi_decoder_reset( pid->u.p_si->p_ctx->p_handle->p_decoder, true ); |
409 | 3 | dvbpsi_tot_delete(p_tdt); |
410 | | |
411 | 3 | es_out_Control( p_demux->out, ES_OUT_SET_EPG_TIME, (int64_t) p_sys->i_network_time ); |
412 | 3 | } |
413 | | |
414 | | static void EITExtractDrDescItems( demux_t *p_demux, const dvbpsi_extended_event_dr_t *pE, |
415 | | vlc_epg_event_t *p_evt ) |
416 | 0 | { |
417 | 0 | demux_sys_t *p_sys = p_demux->p_sys; |
418 | |
|
419 | 0 | if( pE->i_entry_count ) |
420 | 0 | { |
421 | 0 | char **ppsz_prev = NULL; |
422 | | /* Continued items from previous descriptor (ARIB) */ |
423 | 0 | if( p_evt->i_description_items > 0 ) |
424 | 0 | ppsz_prev = &p_evt->description_items[p_evt->i_description_items - 1].psz_value; |
425 | |
|
426 | 0 | for( int i = 0; i < pE->i_entry_count; i++ ) |
427 | 0 | { |
428 | 0 | char *psz_key = NULL; |
429 | | /* Continued items have NULL key */ |
430 | 0 | const bool b_appending = ( pE->i_item_description_length[i] == 0 ); |
431 | 0 | if( !b_appending ) |
432 | 0 | { |
433 | 0 | void *p_realloc = NULL; |
434 | 0 | if( (size_t)p_evt->i_description_items < SIZE_MAX / sizeof(*p_evt->description_items) ) |
435 | 0 | { |
436 | 0 | p_realloc = realloc( p_evt->description_items, |
437 | 0 | (p_evt->i_description_items + 1) * |
438 | 0 | sizeof(*p_evt->description_items) ); |
439 | 0 | } |
440 | 0 | if( !p_realloc ) |
441 | 0 | { |
442 | 0 | free( psz_key ); |
443 | 0 | break; |
444 | 0 | } |
445 | 0 | p_evt->description_items = p_realloc; |
446 | |
|
447 | 0 | psz_key = EITConvertToUTF8( p_demux, |
448 | 0 | pE->i_item_description[i], |
449 | 0 | pE->i_item_description_length[i], |
450 | 0 | p_sys->b_broken_charset ); |
451 | 0 | if( !psz_key ) |
452 | 0 | { |
453 | 0 | ppsz_prev = NULL; |
454 | 0 | continue; |
455 | 0 | } |
456 | 0 | } |
457 | 0 | else if( ppsz_prev == NULL ) |
458 | 0 | continue; |
459 | | |
460 | 0 | char *psz_itm = EITConvertToUTF8( p_demux, |
461 | 0 | pE->i_item[i], pE->i_item_length[i], |
462 | 0 | p_sys->b_broken_charset ); |
463 | 0 | if( !psz_itm ) |
464 | 0 | { |
465 | 0 | free( psz_key ); |
466 | 0 | ppsz_prev = NULL; |
467 | 0 | continue; |
468 | 0 | } |
469 | | |
470 | 0 | msg_Dbg( p_demux, " - desc='%s' item='%s'", |
471 | 0 | psz_key ? psz_key : "(null)", psz_itm ); |
472 | 0 | if( b_appending ) |
473 | 0 | { |
474 | | /* Continued items */ |
475 | 0 | size_t i_total = strlen(*ppsz_prev) + strlen(psz_itm) + 1; |
476 | 0 | char *psz_realloc = realloc( *ppsz_prev, i_total ); |
477 | 0 | if( psz_realloc ) |
478 | 0 | { |
479 | 0 | *ppsz_prev = psz_realloc; |
480 | 0 | strcat( *ppsz_prev, psz_itm ); |
481 | 0 | } |
482 | 0 | free( psz_itm ); |
483 | 0 | } |
484 | 0 | else |
485 | 0 | { |
486 | 0 | p_evt->description_items[p_evt->i_description_items].psz_key = psz_key; |
487 | 0 | p_evt->description_items[p_evt->i_description_items].psz_value = psz_itm; |
488 | 0 | ppsz_prev = &p_evt->description_items[p_evt->i_description_items].psz_value; |
489 | 0 | p_evt->i_description_items++; |
490 | 0 | } |
491 | 0 | } |
492 | 0 | } |
493 | 0 | } |
494 | | |
495 | | static void EITCallBack( void *opaque, dvbpsi_eit_t *p_eit ) |
496 | 0 | { |
497 | 0 | demux_t *p_demux = opaque; |
498 | 0 | demux_sys_t *p_sys = p_demux->p_sys; |
499 | 0 | const dvbpsi_eit_event_t *p_evt; |
500 | 0 | uint64_t i_runevt = 0; |
501 | 0 | uint64_t i_fallbackevt = 0; |
502 | 0 | vlc_epg_t *p_epg; |
503 | |
|
504 | 0 | msg_Dbg( p_demux, "EITCallBack called" ); |
505 | 0 | if( !p_eit->b_current_next ) |
506 | 0 | { |
507 | 0 | dvbpsi_eit_delete( p_eit ); |
508 | 0 | return; |
509 | 0 | } |
510 | | |
511 | 0 | msg_Dbg( p_demux, "new EIT service_id=%"PRIu16" version=%"PRIu8" current_next=%d " |
512 | 0 | "ts_id=%"PRIu16" network_id=%"PRIu16" segment_last_section_number=%"PRIu8" " |
513 | 0 | "last_table_id=%"PRIu8, |
514 | 0 | p_eit->i_extension, |
515 | 0 | p_eit->i_version, p_eit->b_current_next, |
516 | 0 | p_eit->i_ts_id, p_eit->i_network_id, |
517 | 0 | p_eit->i_segment_last_section_number, p_eit->i_last_table_id ); |
518 | | |
519 | | /* Use table ID for segmenting our EPG tables updates. 1 table id has 256 sections which |
520 | | * represents 8 segments of 32 sections each. Thus a max of 24 hours per table ID |
521 | | * (Should be even better with tableid+segmentid compound if dvbpsi would export segment id) |
522 | | * see TS 101 211, 4.1.4.2.1 */ |
523 | 0 | p_epg = vlc_epg_New( p_eit->i_table_id, p_eit->i_extension ); |
524 | 0 | if( !p_epg ) |
525 | 0 | { |
526 | 0 | dvbpsi_eit_delete( p_eit ); |
527 | 0 | return; |
528 | 0 | } |
529 | | |
530 | 0 | for( p_evt = p_eit->p_first_event; p_evt; p_evt = p_evt->p_next ) |
531 | 0 | { |
532 | 0 | dvbpsi_descriptor_t *p_dr; |
533 | 0 | int64_t i_start; |
534 | 0 | int i_duration; |
535 | |
|
536 | 0 | i_start = EITConvertStartTime( p_evt->i_start_time ); |
537 | 0 | SI_DEBUG_TIMESHIFT(i_start); |
538 | 0 | i_duration = EITConvertDuration( p_evt->i_duration ); |
539 | | |
540 | | /* We have to fix ARIB-B10 as all timestamps are JST */ |
541 | 0 | if( p_sys->standard == TS_STANDARD_ARIB ) |
542 | 0 | { |
543 | | /* See comments on TDT callback */ |
544 | 0 | i_start += 9 * 3600; |
545 | 0 | } |
546 | |
|
547 | 0 | msg_Dbg( p_demux, " * event id=%"PRIu16" start_time:%"PRId64" duration=%d " |
548 | 0 | "running=%"PRIu8" free_ca=%d", |
549 | 0 | p_evt->i_event_id, i_start, i_duration, |
550 | 0 | p_evt->i_running_status, p_evt->b_free_ca ); |
551 | | |
552 | | /* */ |
553 | 0 | if( i_start <= 0 ) |
554 | 0 | continue; |
555 | | |
556 | 0 | vlc_epg_event_t *p_epgevt = vlc_epg_event_New( p_evt->i_event_id, |
557 | 0 | i_start, i_duration ); |
558 | 0 | if( !p_epgevt ) |
559 | 0 | continue; |
560 | | |
561 | 0 | if( !vlc_epg_AddEvent( p_epg, p_epgevt ) ) |
562 | 0 | { |
563 | 0 | vlc_epg_event_Delete( p_epgevt ); |
564 | 0 | continue; |
565 | 0 | } |
566 | | |
567 | 0 | for( p_dr = p_evt->p_first_descriptor; p_dr; p_dr = p_dr->p_next ) |
568 | 0 | { |
569 | 0 | switch(p_dr->i_tag) |
570 | 0 | { |
571 | 0 | case 0x4d: |
572 | 0 | { |
573 | 0 | dvbpsi_short_event_dr_t *pE = dvbpsi_DecodeShortEventDr( p_dr ); |
574 | | |
575 | | /* Only take first description, as we don't handle language-info |
576 | | for epg atm*/ |
577 | 0 | if( pE ) |
578 | 0 | { |
579 | 0 | char **ppsz = &p_epgevt->psz_name; |
580 | 0 | free( *ppsz ); |
581 | 0 | *ppsz = EITConvertToUTF8( p_demux, |
582 | 0 | pE->i_event_name, pE->i_event_name_length, |
583 | 0 | p_sys->b_broken_charset ); |
584 | 0 | ppsz = &p_epgevt->psz_short_description; |
585 | 0 | free( *ppsz ); |
586 | 0 | *ppsz = EITConvertToUTF8( p_demux, |
587 | 0 | pE->i_text, pE->i_text_length, |
588 | 0 | p_sys->b_broken_charset ); |
589 | 0 | msg_Dbg( p_demux, " - short event lang=%3.3s '%s' : '%s'", |
590 | 0 | pE->i_iso_639_code, p_epgevt->psz_name, *ppsz ); |
591 | 0 | } |
592 | 0 | } |
593 | 0 | break; |
594 | | |
595 | 0 | case 0x4e: |
596 | 0 | { |
597 | 0 | dvbpsi_extended_event_dr_t *pE = dvbpsi_DecodeExtendedEventDr( p_dr ); |
598 | 0 | if( pE ) |
599 | 0 | { |
600 | 0 | msg_Dbg( p_demux, " - extended event lang=%3.3s [%"PRIu8"/%"PRIu8"]", |
601 | 0 | pE->i_iso_639_code, |
602 | 0 | pE->i_descriptor_number, pE->i_last_descriptor_number ); |
603 | |
|
604 | 0 | if( pE->i_text_length > 0 ) |
605 | 0 | { |
606 | 0 | char *psz_text = EITConvertToUTF8( p_demux, |
607 | 0 | pE->i_text, pE->i_text_length, |
608 | 0 | p_sys->b_broken_charset ); |
609 | 0 | if( psz_text ) |
610 | 0 | { |
611 | 0 | msg_Dbg( p_demux, " - text='%s'", psz_text ); |
612 | |
|
613 | 0 | if( p_epgevt->psz_description ) |
614 | 0 | { |
615 | 0 | size_t i_total = strlen( p_epgevt->psz_description ) + strlen( psz_text ) + 1; |
616 | 0 | char *psz_realloc = realloc( p_epgevt->psz_description, i_total ); |
617 | 0 | if( psz_realloc ) |
618 | 0 | { |
619 | 0 | p_epgevt->psz_description = psz_realloc; |
620 | 0 | strcat( psz_realloc, psz_text ); |
621 | 0 | } |
622 | 0 | free( psz_text ); |
623 | 0 | } |
624 | 0 | else |
625 | 0 | { |
626 | 0 | p_epgevt->psz_description = psz_text; |
627 | 0 | } |
628 | 0 | } |
629 | 0 | } |
630 | |
|
631 | 0 | EITExtractDrDescItems( p_demux, pE, p_epgevt ); |
632 | 0 | } |
633 | 0 | } |
634 | 0 | break; |
635 | | |
636 | 0 | case 0x55: |
637 | 0 | { |
638 | 0 | dvbpsi_parental_rating_dr_t *pR = dvbpsi_DecodeParentalRatingDr( p_dr ); |
639 | 0 | if ( pR ) |
640 | 0 | { |
641 | 0 | int i_min_age = 0; |
642 | 0 | for ( int i = 0; i < pR->i_ratings_number; i++ ) |
643 | 0 | { |
644 | 0 | const dvbpsi_parental_rating_t *p_rating = & pR->p_parental_rating[ i ]; |
645 | 0 | if ( p_rating->i_rating > 0x00 && p_rating->i_rating <= 0x0F ) |
646 | 0 | { |
647 | 0 | if ( p_rating->i_rating + 3 > i_min_age ) |
648 | 0 | i_min_age = p_rating->i_rating + 3; |
649 | 0 | msg_Dbg( p_demux, " - parental control set to %d years", |
650 | 0 | i_min_age ); |
651 | 0 | } |
652 | 0 | } |
653 | 0 | p_epgevt->i_rating = i_min_age; |
654 | 0 | } |
655 | 0 | } |
656 | 0 | break; |
657 | | |
658 | 0 | default: |
659 | 0 | msg_Dbg( p_demux, " - event unknown dr 0x%"PRIx8"(%"PRIu8")", p_dr->i_tag, p_dr->i_tag ); |
660 | 0 | break; |
661 | 0 | } |
662 | 0 | } |
663 | | |
664 | 0 | switch ( p_evt->i_running_status ) |
665 | 0 | { |
666 | 0 | case TS_SI_RUNSTATUS_RUNNING: |
667 | 0 | if( i_runevt == 0 ) |
668 | 0 | i_runevt = i_start; |
669 | 0 | break; |
670 | 0 | case TS_SI_RUNSTATUS_UNDEFINED: |
671 | 0 | { |
672 | 0 | if( i_fallbackevt == 0 && |
673 | 0 | i_start <= p_sys->i_network_time && |
674 | 0 | p_sys->i_network_time < i_start + i_duration ) |
675 | 0 | i_fallbackevt = i_start; |
676 | 0 | break; |
677 | 0 | } |
678 | 0 | default: |
679 | 0 | break; |
680 | 0 | } |
681 | 0 | } |
682 | | |
683 | | /* Update "now playing" field */ |
684 | 0 | if( i_runevt || i_fallbackevt ) |
685 | 0 | vlc_epg_SetCurrent( p_epg, (i_runevt) ? i_runevt : i_fallbackevt ); |
686 | |
|
687 | 0 | if( p_epg->i_event > 0 ) |
688 | 0 | { |
689 | 0 | if( p_epg->b_present && p_epg->p_current ) |
690 | 0 | { |
691 | 0 | ts_pat_t *p_pat = ts_pid_Get(&p_sys->pids, 0)->u.p_pat; |
692 | 0 | ts_pmt_t *p_pmt = ts_pat_Get_pmt(p_pat, p_eit->i_extension); |
693 | 0 | if(p_pmt) |
694 | 0 | { |
695 | 0 | p_pmt->eit.i_event_start = p_epg->p_current->i_start; |
696 | 0 | p_pmt->eit.i_event_length = p_epg->p_current->i_duration; |
697 | 0 | } |
698 | 0 | } |
699 | 0 | p_epg->b_present = (p_eit->i_table_id == 0x4e); |
700 | 0 | es_out_Control( p_demux->out, ES_OUT_SET_GROUP_EPG, p_eit->i_extension, p_epg ); |
701 | 0 | } |
702 | 0 | vlc_epg_Delete( p_epg ); |
703 | |
|
704 | 0 | dvbpsi_eit_delete( p_eit ); |
705 | 0 | } |
706 | | |
707 | | static void ARIB_CDT_RawCallback( dvbpsi_t *p_handle, const dvbpsi_psi_section_t* p_section, |
708 | | void *p_cdtpid ) |
709 | 0 | { |
710 | 0 | VLC_UNUSED(p_cdtpid); |
711 | 0 | demux_t *p_demux = (demux_t *) p_handle->p_sys; |
712 | 0 | demux_sys_t *p_sys = p_demux->p_sys; |
713 | 0 | const ts_pat_t *p_pat = GetPID(p_sys, 0)->u.p_pat; |
714 | |
|
715 | 0 | while( p_section ) |
716 | 0 | { |
717 | 0 | const uint8_t *p_data = p_section->p_payload_start; |
718 | 0 | size_t i_data = p_section->p_payload_end - p_section->p_payload_start; |
719 | |
|
720 | 0 | if( i_data < (6U + 7 + 1) || p_data[2] != TS_ARIB_CDT_DATA_TYPE_LOGO ) |
721 | 0 | continue; |
722 | | |
723 | 0 | uint16_t i_onid = (p_data[0] << 8) | p_data[1]; |
724 | 0 | uint16_t i_dr_len = ((p_data[3] & 0x0F) << 4) | p_data[4]; |
725 | 0 | if( i_data < i_dr_len + (6U + 7 + 1) ) |
726 | 0 | continue; |
727 | | |
728 | | /* STD-B21 A.5.4 (Japanese spec only) */ |
729 | | |
730 | 0 | const uint8_t *p_dmb = &p_data[5 + i_dr_len]; |
731 | 0 | size_t i_dmb = i_data - 5 - i_dr_len; |
732 | |
|
733 | 0 | while( i_dmb > 7 ) |
734 | 0 | { |
735 | 0 | uint8_t i_logo_type = p_dmb[0]; |
736 | 0 | uint16_t i_logo_id = ((p_dmb[1] & 0x01) << 8) | p_dmb[2]; |
737 | 0 | uint16_t i_size = (p_dmb[5] << 8) | p_dmb[6]; |
738 | |
|
739 | 0 | if( 7U + i_size > i_dmb ) |
740 | 0 | break; |
741 | | |
742 | 0 | for( int i=0; i<p_pat->programs.i_size; i++ ) |
743 | 0 | { |
744 | 0 | ts_pmt_t *p_pmt = p_pat->programs.p_elems[i]->u.p_pmt; |
745 | 0 | if( p_pmt->arib.i_logo_id == i_logo_id && i_logo_type == TS_ARIB_LOGO_TYPE_HD_LARGE ) |
746 | 0 | { |
747 | 0 | char *psz_name; |
748 | 0 | if( asprintf( &psz_name, "onid[%"PRIx16"]_channel_logo_id[%"PRIx16"]q[%d]", |
749 | 0 | i_onid, i_logo_id, i_logo_type ) > -1 ) |
750 | 0 | { |
751 | 0 | uint8_t *p_png; size_t i_png; |
752 | 0 | if( !vlc_dictionary_has_key( &p_sys->attachments, psz_name ) && |
753 | 0 | ts_arib_inject_png_palette( &p_dmb[7], i_size, &p_png, &i_png ) ) |
754 | 0 | { |
755 | 0 | input_attachment_t *p_att = vlc_input_attachment_New( |
756 | 0 | psz_name, "image/png", NULL, p_png, i_png ); |
757 | 0 | if( p_att ) |
758 | 0 | { |
759 | 0 | vlc_dictionary_insert( &p_sys->attachments, psz_name, p_att ); |
760 | 0 | p_sys->updates |= INPUT_UPDATE_META; |
761 | 0 | } |
762 | 0 | free( p_png ); |
763 | 0 | } |
764 | 0 | free( psz_name ); |
765 | 0 | } |
766 | 0 | } |
767 | 0 | } |
768 | |
|
769 | 0 | i_dmb -= 7 + i_size; |
770 | 0 | p_dmb += 7 + i_size; |
771 | 0 | } |
772 | |
|
773 | 0 | p_section = p_section->p_next; |
774 | 0 | } |
775 | 0 | } |
776 | | |
777 | | static void SINewTableCallBack( dvbpsi_t *h, uint8_t i_table_id, |
778 | | uint16_t i_extension, void *p_pid_cbdata ) |
779 | 12.9k | { |
780 | 12.9k | assert( h ); |
781 | 12.9k | ts_pid_t *p_pid = (ts_pid_t *) p_pid_cbdata; |
782 | 12.9k | demux_t *p_demux = (demux_t *) h->p_sys; |
783 | | #if 0 |
784 | | msg_Dbg( p_demux, "SINewTableCallback: table 0x%"PRIx8"(%"PRIu16") ext=0x%"PRIx16"(%"PRIu16")", |
785 | | i_table_id, i_table_id, i_extension, i_extension ); |
786 | | #endif |
787 | 12.9k | if( p_pid->i_pid == TS_SI_SDT_PID && i_table_id == 0x42 ) |
788 | 167 | { |
789 | 167 | if( !dvbpsi_sdt_attach( h, i_table_id, i_extension, SDTCallBack, p_demux ) ) |
790 | 167 | msg_Err( p_demux, "SINewTableCallback: failed attaching SDTCallback" ); |
791 | 167 | } |
792 | 12.7k | else if( p_pid->i_pid == TS_SI_EIT_PID && |
793 | 2.23k | ( i_table_id == 0x4e || /* Current/Following */ |
794 | 2.08k | (i_table_id >= 0x50 && i_table_id <= 0x5f) ) ) /* Schedule */ |
795 | 200 | { |
796 | 200 | if( !dvbpsi_eit_attach( h, i_table_id, i_extension, |
797 | 200 | EITCallBack, p_demux ) ) |
798 | 200 | msg_Err( p_demux, "SINewTableCallback: failed attaching EITCallback" ); |
799 | 200 | } |
800 | 12.5k | else if( p_pid->i_pid == TS_SI_TDT_PID && |
801 | 38 | (i_table_id == TS_SI_TDT_TABLE_ID || i_table_id == TS_SI_TOT_TABLE_ID) ) |
802 | 3 | { |
803 | 3 | if( !dvbpsi_tot_attach( h, i_table_id, i_extension, TDTCallBack, p_demux ) ) |
804 | 3 | msg_Err( p_demux, "SINewTableCallback: failed attaching TDTCallback" ); |
805 | 3 | } |
806 | 12.5k | else if( p_pid->i_pid == TS_ARIB_CDT_PID && i_table_id == TS_ARIB_CDT_TABLE_ID ) |
807 | 0 | { |
808 | 0 | if( dvbpsi_demuxGetSubDec( (dvbpsi_demux_t *) h->p_decoder, i_table_id, i_extension ) == NULL && |
809 | 0 | !ts_dvbpsi_AttachRawSubDecoder( h, i_table_id, i_extension, ARIB_CDT_RawCallback, p_pid ) ) |
810 | 0 | msg_Err( p_demux, "SINewTableCallback: failed attaching ARIB_CDT_RawCallback" ); |
811 | 0 | } |
812 | 12.9k | } |
813 | | |
814 | | bool ts_attach_SI_Tables_Decoders( ts_pid_t *p_pid ) |
815 | 39.9k | { |
816 | 39.9k | if( p_pid->type != TYPE_SI ) |
817 | 0 | return false; |
818 | | |
819 | 39.9k | if( dvbpsi_decoder_present( p_pid->u.p_si->p_ctx->p_handle ) ) |
820 | 24.5k | return true; |
821 | | |
822 | 15.4k | return dvbpsi_AttachDemux( p_pid->u.p_si->p_ctx->p_handle, SINewTableCallBack, p_pid ); |
823 | 39.9k | } |
824 | | |
825 | | void ts_si_context_Delete( ts_si_context_t *p_ctx ) |
826 | 15.4k | { |
827 | 15.4k | if( dvbpsi_decoder_present( p_ctx->p_handle ) ) |
828 | 15.4k | dvbpsi_DetachDemux( p_ctx->p_handle ); |
829 | 15.4k | dvbpsi_delete( p_ctx->p_handle ); |
830 | 15.4k | free( p_ctx ); |
831 | 15.4k | } |
832 | | |
833 | | ts_si_context_t * ts_si_context_New( demux_t *p_demux ) |
834 | 15.4k | { |
835 | 15.4k | ts_si_context_t *p_ctx = malloc(sizeof(*p_ctx)); |
836 | 15.4k | if(likely(p_ctx)) |
837 | 15.4k | { |
838 | 15.4k | p_ctx->p_handle = dvbpsi_new( &dvbpsi_messages, DVBPSI_MSG_DEBUG ); |
839 | 15.4k | if( !p_ctx->p_handle ) |
840 | 0 | { |
841 | 0 | free( p_ctx ); |
842 | 0 | return NULL; |
843 | 0 | } |
844 | 15.4k | p_ctx->p_handle->p_sys = (void *) p_demux; |
845 | 15.4k | p_ctx->i_version = -1; |
846 | 15.4k | } |
847 | 15.4k | return p_ctx; |
848 | 15.4k | } |