1 /*****************************************************************************
2 * scte18.c : SCTE-18 EAS decoder
3 *****************************************************************************
4 * Copyright (C) 2016 - VideoLAN 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 General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *****************************************************************************/
24 #include <vlc_common.h>
25 #include <vlc_plugin.h>
26 #include <vlc_codec.h>
34 /*****************************************************************************
36 *****************************************************************************/
37 static int Open (vlc_object_t
*);
38 static void Close(vlc_object_t
*);
41 set_description(N_("SCTE-18 decoder"))
42 set_shortname(N_("SCTE-18"))
43 set_capability( "spu decoder", 51)
44 set_category(CAT_INPUT
)
45 set_subcategory(SUBCAT_INPUT_SCODEC
)
46 set_callbacks(Open
, Close
)
51 atsc_a65_handle_t
*p_handle
;
54 //#define GPS_UTC_EPOCH_OFFSET 315964800
55 //#define GPS_CUR_UTC_LEAP_OFFSET 16 /* 1 Jul 2015 */
57 typedef struct scte18_cea_t
59 uint16_t i_eas_event_id
;
60 char rgc_eas_originator_code
[3];
61 char * psz_eas_event_code
;
62 char * psz_nature_of_activation
;
63 uint8_t alert_message_time_remaining
;
64 uint32_t event_start_time
;
65 uint16_t event_duration
;
66 uint8_t alert_priority
;
68 char * psz_alert_text
;
72 /****************************************************************************
74 ****************************************************************************/
75 #define BUF_ADVANCE(n) p_buffer += n; i_buffer -= n;
77 static inline scte18_cea_t
* scte18_cea_New()
79 return calloc( 1, sizeof(scte18_cea_t
) );
82 static void scte18_cea_Free( scte18_cea_t
*p_cea
)
84 free( p_cea
->psz_alert_text
);
85 free( p_cea
->psz_nature_of_activation
);
86 free( p_cea
->psz_eas_event_code
);
90 static scte18_cea_t
* scte18_cea_Decode( atsc_a65_handle_t
*p_handle
, const block_t
*p_block
)
93 scte18_cea_t
*p_cea
= scte18_cea_New();
97 const uint8_t *p_buffer
= p_block
->p_buffer
;
98 size_t i_buffer
= p_block
->i_buffer
;
100 if( i_buffer
< 34 || p_buffer
[0] != 0 )
105 p_cea
->i_eas_event_id
= GetWBE( p_buffer
);
108 memcpy( p_cea
->rgc_eas_originator_code
, p_buffer
, 3 );
112 if( i_buffer
< 23 + len
)
114 p_cea
->psz_eas_event_code
= malloc( len
+ 1 );
115 memcpy( p_cea
->psz_eas_event_code
, &p_buffer
[1], len
);
116 p_cea
->psz_eas_event_code
[len
] = 0;
117 BUF_ADVANCE( len
+ 1 );
120 if( i_buffer
< len
+ 22 )
122 p_cea
->psz_nature_of_activation
= atsc_a65_Decode_multiple_string( p_handle
, &p_buffer
[1], len
);
123 BUF_ADVANCE(1 + len
);
127 p_cea
->alert_message_time_remaining
= p_buffer
[0];
130 p_cea
->event_start_time
= GetDWBE( p_buffer
);
133 p_cea
->event_duration
= GetWBE( p_buffer
);
134 if( p_cea
->event_duration
!= 0 && ( p_cea
->event_duration
< 15 || p_cea
->event_duration
> 6000 ) )
138 p_cea
->alert_priority
= p_buffer
[1] & 0x0f;
139 switch( p_cea
->alert_priority
)
141 case EAS_PRIORITY_TEST
:
142 case EAS_PRIORITY_LOW
:
143 case EAS_PRIORITY_MEDIUM
:
144 case EAS_PRIORITY_HIGH
:
145 case EAS_PRIORITY_MAX
:
153 BUF_ADVANCE(2); //OOB_ID
158 BUF_ADVANCE(2); //audio_OOB_ID
160 len
= GetWBE( p_buffer
);
161 if( i_buffer
< len
+ 2 )
163 p_cea
->psz_alert_text
= atsc_a65_Decode_multiple_string( p_handle
, &p_buffer
[2], len
);
168 scte18_cea_Free( p_cea
);
172 static int Decode( decoder_t
*p_dec
, block_t
*p_block
)
174 if ( p_block
== NULL
) /* No Drain */
175 return VLCDEC_SUCCESS
;
176 subpicture_t
*p_spu
= NULL
;
178 if (p_block
->i_flags
& (BLOCK_FLAG_CORRUPTED
))
181 scte18_cea_t
*p_cea
= scte18_cea_Decode( p_dec
->p_sys
->p_handle
, p_block
);
184 p_spu
= decoder_NewSubpictureText( p_dec
);
187 subpicture_updater_sys_t
*p_spu_sys
= p_spu
->updater
.p_sys
;
189 p_spu
->i_start
= p_block
->i_pts
;
190 if( p_cea
->alert_message_time_remaining
)
191 p_spu
->i_stop
= p_spu
->i_start
+ CLOCK_FREQ
* p_cea
->alert_message_time_remaining
;
193 p_spu
->i_stop
= VLC_TS_INVALID
;
195 p_spu
->b_ephemer
= true;
196 p_spu
->b_absolute
= false;
198 p_spu_sys
->region
.inner_align
= SUBPICTURE_ALIGN_TOP
;
199 p_spu_sys
->p_default_style
->i_style_flags
= STYLE_BOLD
| STYLE_BACKGROUND
;
200 p_spu_sys
->p_default_style
->i_features
|= STYLE_HAS_FLAGS
;
201 p_spu_sys
->p_default_style
->i_background_color
= 0x000000;
202 p_spu_sys
->p_default_style
->i_background_alpha
= STYLE_ALPHA_OPAQUE
;
203 p_spu_sys
->p_default_style
->i_features
|= STYLE_HAS_BACKGROUND_COLOR
| STYLE_HAS_BACKGROUND_ALPHA
;
204 p_spu_sys
->p_default_style
->i_font_color
= 0xFF0000;
205 p_spu_sys
->p_default_style
->i_features
|= STYLE_HAS_FONT_COLOR
;
207 p_spu_sys
->region
.p_segments
= text_segment_New( p_cea
->psz_alert_text
);
208 decoder_QueueSub( p_dec
, p_spu
);
210 msg_Info( p_dec
, "Received %s", p_cea
->psz_alert_text
);
211 scte18_cea_Free( p_cea
);
215 block_Release( p_block
);
216 return VLCDEC_SUCCESS
;
219 static int Open( vlc_object_t
*object
)
221 decoder_t
*dec
= (decoder_t
*)object
;
223 if ( dec
->fmt_in
.i_codec
!= VLC_CODEC_SCTE_18
)
226 decoder_sys_t
*p_sys
= malloc( sizeof(decoder_sys_t
) );
227 if( unlikely(!p_sys
) )
230 p_sys
->p_handle
= atsc_a65_handle_New( NULL
);
231 if( !p_sys
->p_handle
)
238 dec
->pf_decode
= Decode
;
239 dec
->fmt_out
.i_codec
= 0;
244 static void Close( vlc_object_t
*p_object
)
246 decoder_t
*p_dec
= (decoder_t
*)p_object
;
247 decoder_sys_t
*p_sys
= (decoder_sys_t
*) p_dec
->p_sys
;
248 atsc_a65_handle_Release( p_sys
->p_handle
);