Coverage Report

Created: 2023-06-07 07:26

/src/vlc/modules/codec/scte18.c
Line
Count
Source (jump to first uncovered line)
1
/*****************************************************************************
2
 * scte18.c : SCTE-18 EAS decoder
3
 *****************************************************************************
4
 * Copyright (C) 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
20
#ifdef HAVE_CONFIG_H
21
# include "config.h"
22
#endif
23
24
#include <vlc_common.h>
25
#include <vlc_plugin.h>
26
#include <vlc_codec.h>
27
28
#include "atsc_a65.h"
29
#include "scte18.h"
30
#include "substext.h"
31
32
#include <time.h>
33
34
/*****************************************************************************
35
 * Module descriptor.
36
 *****************************************************************************/
37
static int  Open (vlc_object_t *);
38
static void Close(vlc_object_t *);
39
40
0
vlc_module_begin ()
41
0
    set_description(N_("SCTE-18 decoder"))
42
0
    set_shortname(N_("SCTE-18"))
43
0
    set_capability( "spu decoder", 51)
44
0
    set_subcategory(SUBCAT_INPUT_SCODEC)
45
0
    set_callbacks(Open, Close)
46
0
vlc_module_end ()
47
48
typedef struct
49
{
50
    atsc_a65_handle_t *p_handle;
51
} decoder_sys_t;
52
53
//#define GPS_UTC_EPOCH_OFFSET 315964800
54
//#define GPS_CUR_UTC_LEAP_OFFSET  16 /* 1 Jul 2015 */
55
56
typedef struct scte18_cea_t
57
{
58
    uint16_t i_eas_event_id;
59
    char     rgc_eas_originator_code[3];
60
    char *   psz_eas_event_code;
61
    char *   psz_nature_of_activation;
62
    uint8_t  alert_message_time_remaining;
63
    uint32_t event_start_time;
64
    uint16_t event_duration;
65
    uint8_t  alert_priority;
66
67
    char *   psz_alert_text;
68
69
} scte18_cea_t;
70
71
/****************************************************************************
72
 * Local prototypes
73
 ****************************************************************************/
74
0
#define BUF_ADVANCE(n) p_buffer += n; i_buffer -= n;
75
76
static inline scte18_cea_t * scte18_cea_New(void)
77
0
{
78
0
    return calloc( 1, sizeof(scte18_cea_t) );
79
0
}
80
81
static void scte18_cea_Free( scte18_cea_t *p_cea )
82
0
{
83
0
    free( p_cea->psz_alert_text );
84
0
    free( p_cea->psz_nature_of_activation );
85
0
    free( p_cea->psz_eas_event_code );
86
0
    free( p_cea );
87
0
}
88
89
static scte18_cea_t * scte18_cea_Decode( atsc_a65_handle_t *p_handle, const block_t *p_block )
90
0
{
91
0
    size_t len;
92
0
    scte18_cea_t *p_cea = scte18_cea_New();
93
0
    if( !p_cea )
94
0
        return NULL;
95
96
0
    const uint8_t *p_buffer = p_block->p_buffer;
97
0
    size_t i_buffer = p_block->i_buffer;
98
99
0
    if( i_buffer < 34 || p_buffer[0] != 0 )
100
0
        goto error;
101
102
0
    BUF_ADVANCE(1);
103
104
0
    p_cea->i_eas_event_id = GetWBE( p_buffer );
105
0
    BUF_ADVANCE(2);
106
107
0
    memcpy( p_cea->rgc_eas_originator_code, p_buffer, 3 );
108
0
    BUF_ADVANCE(3);
109
110
0
    len = p_buffer[0];
111
0
    if( i_buffer < 23 + len )
112
0
        goto error;
113
0
    p_cea->psz_eas_event_code = malloc( len + 1 );
114
0
    memcpy( p_cea->psz_eas_event_code, &p_buffer[1], len );
115
0
    p_cea->psz_eas_event_code[len] = 0;
116
0
    BUF_ADVANCE( len + 1 );
117
118
0
    len = p_buffer[0];
119
0
    if( i_buffer < len + 22 )
120
0
        goto error;
121
0
    p_cea->psz_nature_of_activation = atsc_a65_Decode_multiple_string( p_handle, &p_buffer[1], len );
122
0
    BUF_ADVANCE(1 + len);
123
124
0
    if( i_buffer < 21 )
125
0
        goto error;
126
0
    p_cea->alert_message_time_remaining = p_buffer[0];
127
0
    BUF_ADVANCE(1);
128
129
0
    p_cea->event_start_time = GetDWBE( p_buffer );
130
0
    BUF_ADVANCE(4);
131
132
0
    p_cea->event_duration = GetWBE( p_buffer );
133
0
    if( p_cea->event_duration != 0 && ( p_cea->event_duration < 15 || p_cea->event_duration > 6000 ) )
134
0
        goto error;
135
0
    BUF_ADVANCE(2);
136
137
0
    p_cea->alert_priority = p_buffer[1] & 0x0f;
138
0
    switch( p_cea->alert_priority )
139
0
    {
140
0
        case EAS_PRIORITY_TEST:
141
0
        case EAS_PRIORITY_LOW:
142
0
        case EAS_PRIORITY_MEDIUM:
143
0
        case EAS_PRIORITY_HIGH:
144
0
        case EAS_PRIORITY_MAX:
145
0
            break;
146
0
        default:
147
0
            goto error;
148
0
    }
149
150
0
    BUF_ADVANCE(2);
151
152
0
    BUF_ADVANCE(2); //OOB_ID
153
154
0
    BUF_ADVANCE(2); //
155
0
    BUF_ADVANCE(2); //
156
157
0
    BUF_ADVANCE(2); //audio_OOB_ID
158
159
0
    len = GetWBE( p_buffer );
160
0
    if( i_buffer < len + 2 )
161
0
        goto error;
162
0
    p_cea->psz_alert_text = atsc_a65_Decode_multiple_string( p_handle, &p_buffer[2], len );
163
164
0
    return p_cea;
165
166
0
error:
167
0
    scte18_cea_Free( p_cea );
168
0
    return NULL;
169
0
}
170
171
static int Decode( decoder_t *p_dec, block_t *p_block )
172
0
{
173
0
    if ( p_block == NULL ) /* No Drain */
174
0
        return VLCDEC_SUCCESS;
175
0
    subpicture_t *p_spu = NULL;
176
177
0
    if (p_block->i_flags & (BLOCK_FLAG_CORRUPTED))
178
0
        goto exit;
179
180
0
    decoder_sys_t *p_sys = p_dec->p_sys;
181
182
0
    scte18_cea_t *p_cea = scte18_cea_Decode( p_sys->p_handle, p_block );
183
0
    if( p_cea )
184
0
    {
185
0
        p_spu = decoder_NewSubpictureText( p_dec );
186
0
        if( p_spu )
187
0
        {
188
0
            subtext_updater_sys_t *p_spu_sys = p_spu->updater.p_sys;
189
190
0
            p_spu->i_start = p_block->i_pts;
191
0
            if( p_cea->alert_message_time_remaining )
192
0
                p_spu->i_stop = p_spu->i_start + vlc_tick_from_sec( p_cea->alert_message_time_remaining );
193
0
            else
194
0
                p_spu->i_stop = VLC_TICK_INVALID;
195
196
0
            p_spu->b_ephemer  = true;
197
0
            p_spu->b_absolute = false;
198
199
0
            p_spu_sys->region.inner_align = SUBPICTURE_ALIGN_TOP;
200
0
            p_spu_sys->p_default_style->i_style_flags = STYLE_BOLD | STYLE_BACKGROUND;
201
0
            p_spu_sys->p_default_style->i_features |= STYLE_HAS_FLAGS;
202
0
            p_spu_sys->p_default_style->i_background_color = 0x000000;
203
0
            p_spu_sys->p_default_style->i_background_alpha = STYLE_ALPHA_OPAQUE;
204
0
            p_spu_sys->p_default_style->i_features |= STYLE_HAS_BACKGROUND_COLOR | STYLE_HAS_BACKGROUND_ALPHA;
205
0
            p_spu_sys->p_default_style->i_font_color = 0xFF0000;
206
0
            p_spu_sys->p_default_style->i_features |= STYLE_HAS_FONT_COLOR;
207
208
0
            p_spu_sys->region.p_segments = text_segment_New( p_cea->psz_alert_text );
209
0
            decoder_QueueSub( p_dec, p_spu );
210
0
        }
211
0
        msg_Info( p_dec, "Received %s", p_cea->psz_alert_text );
212
0
        scte18_cea_Free( p_cea );
213
0
    }
214
215
0
exit:
216
0
    block_Release( p_block );
217
0
    return VLCDEC_SUCCESS;
218
0
}
219
220
static int Open( vlc_object_t *object )
221
0
{
222
0
    decoder_t *dec = (decoder_t *)object;
223
224
0
    if ( dec->fmt_in->i_codec != VLC_CODEC_SCTE_18 )
225
0
        return VLC_EGENERIC;
226
227
0
    decoder_sys_t *p_sys = malloc( sizeof(decoder_sys_t) );
228
0
    if( unlikely(!p_sys) )
229
0
        return VLC_ENOMEM;
230
231
0
    p_sys->p_handle = atsc_a65_handle_New( NULL );
232
0
    if( !p_sys->p_handle )
233
0
    {
234
0
        free( p_sys );
235
0
        return VLC_EGENERIC;
236
0
    }
237
238
0
    dec->p_sys = p_sys;
239
0
    dec->pf_decode = Decode;
240
0
    dec->fmt_out.i_codec = 0;
241
242
0
    return VLC_SUCCESS;
243
0
}
244
245
static void Close( vlc_object_t *p_object )
246
0
{
247
0
    decoder_t *p_dec = (decoder_t *)p_object;
248
0
    decoder_sys_t *p_sys = (decoder_sys_t *) p_dec->p_sys;
249
0
    atsc_a65_handle_Release( p_sys->p_handle );
250
0
    free( p_sys );
251
0
}
252