Coverage Report

Created: 2023-03-26 07:08

/src/vlc/modules/codec/textst.c
Line
Count
Source (jump to first uncovered line)
1
/*****************************************************************************
2
 * textst.c: HDMV TextST subtitles decoder
3
 *****************************************************************************
4
 * Copyright (C) 2017 Videolan Authors
5
 *
6
 * Adapted from libluray textst_decode.c
7
 * Copyright (C) 2013  Petri Hintukainen <phintuka@users.sourceforge.net>
8
 *
9
 * This program is free software; you can redistribute it and/or modify it
10
 * under the terms of the GNU Lesser General Public License as published by
11
 * the Free Software Foundation; either version 2.1 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program; if not, write to the Free Software Foundation,
21
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22
 *****************************************************************************/
23
24
/*****************************************************************************
25
 * Preamble
26
 *****************************************************************************/
27
#ifdef HAVE_CONFIG_H
28
# include "config.h"
29
#endif
30
31
#include <vlc_common.h>
32
#include <vlc_plugin.h>
33
#include <vlc_codec.h>
34
35
#include "../demux/mpeg/timestamps.h"
36
37
#include "substext.h"
38
39
/*****************************************************************************
40
 * Module descriptor
41
 *****************************************************************************/
42
static int  Open (vlc_object_t *);
43
44
typedef struct
45
{
46
    uint32_t palette[256];
47
} decoder_sys_t;
48
49
0
vlc_module_begin()
50
0
    set_description(N_("HDMV TextST subtitles decoder"))
51
0
    set_subcategory(SUBCAT_INPUT_SCODEC)
52
0
    set_capability("spu decoder", 10)
53
0
    set_callback(Open)
54
0
vlc_module_end()
55
56
0
#define BD_TEXTST_DATA_STRING      1
57
0
#define BD_TEXTST_DATA_FONT_ID     2
58
0
#define BD_TEXTST_DATA_FONT_STYLE  3
59
0
#define BD_TEXTST_DATA_FONT_SIZE   4
60
0
#define BD_TEXTST_DATA_FONT_COLOR  5
61
0
#define BD_TEXTST_DATA_NEWLINE     0x0a
62
0
#define BD_TEXTST_DATA_RESET_STYLE 0x0b
63
64
static size_t textst_FillRegion(decoder_t *p_dec, const uint8_t *p_data, size_t i_data,
65
                                substext_updater_region_t *p_region)
66
0
{
67
0
    decoder_sys_t *p_sys = p_dec->p_sys;
68
0
    text_segment_t **pp_last = &p_region->p_segments;
69
0
    text_style_t *p_style = NULL;
70
71
     /* p_data[0] */
72
     /*   continous_present_flag b1 */
73
     /*   forced_on_flag b1 */
74
     /*   ? b6 */
75
76
0
     assert( i_data >= 4 );
77
78
     //uint8_t region_style_id_ref = p_data[1];
79
0
     uint16_t i_data_length = GetWBE(&p_data[2]);
80
81
0
     p_data += 4; i_data -= 4;
82
0
     if( i_data < i_data_length )
83
0
         return i_data;
84
0
     else
85
0
         i_data = i_data_length;
86
87
0
     while (i_data > 3)
88
0
     {
89
         /* parse header */
90
0
         uint8_t code = p_data[0];
91
0
         if (code != 0x1b) {
92
0
             p_data++; i_data--;
93
0
             continue;
94
0
         }
95
96
0
         uint8_t type   = p_data[1];
97
0
         uint8_t length = p_data[2];
98
99
0
         p_data += 3; i_data -= 3;
100
101
0
         if(length > i_data)
102
0
             break;
103
104
0
         switch (type)
105
0
         {
106
0
             case BD_TEXTST_DATA_STRING:
107
0
                {
108
0
                    char *psz = strndup((char *)p_data, length);
109
0
                    *pp_last = text_segment_New(psz);
110
0
                    free(psz);
111
0
                    if(p_style && *pp_last)
112
0
                        (*pp_last)->style = text_style_Duplicate(p_style);
113
0
                }
114
0
                break;
115
0
             case BD_TEXTST_DATA_FONT_ID:
116
                 //p_data[0] font_id;
117
0
                 break;
118
0
             case BD_TEXTST_DATA_FONT_STYLE:
119
0
                 if(i_data > 2 && (p_style || (p_style = text_style_Create( STYLE_NO_DEFAULTS ))))
120
0
                 {
121
0
                    if(p_data[0] & 0x01)
122
0
                        p_style->i_style_flags |= STYLE_BOLD;
123
0
                    if(p_data[0] & 0x02)
124
0
                        p_style->i_style_flags |= STYLE_ITALIC;
125
0
                    if(p_data[0] & 0x04)
126
0
                        p_style->i_style_flags |= STYLE_OUTLINE;
127
0
                    p_style->i_outline_color = p_sys->palette[p_data[1]] & 0x00FFFFFF;
128
0
                    p_style->i_outline_alpha = p_sys->palette[p_data[1]] >> 24;
129
0
                    p_style->i_features |= STYLE_HAS_FLAGS | STYLE_HAS_OUTLINE_ALPHA | STYLE_HAS_OUTLINE_COLOR;
130
                    //p_data[2] outline__thickness
131
0
                 }
132
0
                 break;
133
0
             case BD_TEXTST_DATA_FONT_SIZE:
134
                 /*if(i_data > 0)
135
                   p_style->f_font_relsize = STYLE_DEFAULT_REL_FONT_SIZE *
136
                                           (p_data[0] << 4) / STYLE_DEFAULT_FONT_SIZE;*/
137
0
                 break;
138
0
             case BD_TEXTST_DATA_FONT_COLOR:
139
0
                 if(i_data > 1 && (p_style || (p_style = text_style_Create( STYLE_NO_DEFAULTS ))))
140
0
                 {
141
0
                    p_style->i_font_color = p_sys->palette[p_data[1]] & 0x00FFFFFF;
142
0
                    p_style->i_font_alpha = p_sys->palette[p_data[1]] >> 24;
143
0
                    p_style->i_features |= STYLE_HAS_FONT_ALPHA | STYLE_HAS_FONT_COLOR;
144
0
                 }
145
0
                 break;
146
0
             case BD_TEXTST_DATA_NEWLINE:
147
0
                 *pp_last = text_segment_New("\n");
148
0
                 break;
149
0
             case BD_TEXTST_DATA_RESET_STYLE:
150
0
                 if(p_style)
151
0
                 {
152
0
                     text_style_Delete(p_style);
153
0
                     p_style = NULL;
154
0
                 }
155
0
                 break;
156
0
             default:
157
0
                 break;
158
0
         }
159
160
0
         if(*pp_last)
161
0
             pp_last = &(*pp_last)->p_next;
162
163
0
         p_data += length; i_data -= length;
164
0
     }
165
166
0
     if(p_style)
167
0
        text_style_Delete(p_style);
168
169
0
     return i_data_length;
170
0
}
171
172
static size_t textst_Decode_palette(decoder_t *p_dec, const uint8_t *p_data, size_t i_data)
173
0
{
174
0
    if(i_data < 2)
175
0
        return i_data;
176
177
0
    decoder_sys_t *p_sys = p_dec->p_sys;
178
179
0
    uint16_t i_size = GetWBE(&p_data[0]);
180
0
    p_data += 2; i_data -= 2;
181
182
0
    i_size = i_data = __MIN(i_data, i_size);
183
0
    while (i_data > 4)
184
0
    {
185
0
        p_sys->palette[p_data[0]] = /* YCrCbT to ARGB */
186
0
                ( (uint32_t)((float)p_data[1] +1.402f * (p_data[2]-128)) << 16 ) |
187
0
                ( (uint32_t)((float)p_data[1] -0.34414 * (p_data[3]-128) -0.71414 * (p_data[2]-128)) << 8 ) |
188
0
                ( (uint32_t)((float)p_data[1] +1.722 * (p_data[3]-128)) ) |
189
0
                ( (0xFF - p_data[4]) << 24 );
190
0
        p_data += 5; i_data -= 5;
191
0
    }
192
193
0
    return i_size;
194
0
}
195
196
static void textst_FillRegions(decoder_t *p_dec, const uint8_t *p_data, size_t i_data,
197
                               substext_updater_region_t *p_region)
198
0
{
199
0
    substext_updater_region_t **pp_last = &p_region;
200
0
    bool palette_update_flag = p_data[0] >> 7;
201
0
    p_data++; i_data--;
202
203
0
    if (palette_update_flag)
204
0
    {
205
0
        size_t i_read = textst_Decode_palette(p_dec, p_data, i_data);
206
0
        p_data += i_read; i_data -= i_read;
207
0
    }
208
209
0
    if(i_data > 2)
210
0
    {
211
0
        uint8_t i_region_count = p_data[0];
212
0
        p_data++; i_data--;
213
214
0
        for(uint8_t i=0; i<i_region_count && i_data > 4; i++)
215
0
        {
216
0
            if(*pp_last == NULL)
217
0
            {
218
0
                *pp_last = SubpictureUpdaterSysRegionNew();
219
0
                if(!*pp_last)
220
0
                    break;
221
0
            }
222
0
            size_t i_read = textst_FillRegion(p_dec, p_data, i_data, *pp_last);
223
0
            (*pp_last)->align = SUBPICTURE_ALIGN_BOTTOM;
224
0
            pp_last = &(*pp_last)->p_next;
225
0
            p_data += i_read; i_data -= i_read;
226
0
        }
227
0
    }
228
0
}
229
230
static int Decode(decoder_t *p_dec, block_t *p_block)
231
0
{
232
0
    subpicture_t *p_sub = NULL;
233
0
    if (p_block == NULL) /* No Drain */
234
0
        return VLCDEC_SUCCESS;
235
236
0
    if (p_block->i_buffer > 18 &&
237
0
        (p_block->i_flags & BLOCK_FLAG_CORRUPTED) == 0 &&
238
0
        (p_sub = decoder_NewSubpictureText(p_dec)))
239
0
    {
240
0
        p_sub->i_start = FROM_SCALE(((int64_t)(p_block->p_buffer[3] & 0x01) << 32) | GetDWBE(&p_block->p_buffer[4]));
241
0
        p_sub->i_stop = FROM_SCALE(((int64_t)(p_block->p_buffer[8] & 0x01) << 32) | GetDWBE(&p_block->p_buffer[9]));
242
0
        if (p_sub->i_start < p_block->i_dts)
243
0
        {
244
0
            p_sub->i_stop += p_block->i_dts - p_sub->i_start;
245
0
            p_sub->i_start = p_block->i_dts;
246
0
        }
247
248
0
        subtext_updater_sys_t *p_spusys = p_sub->updater.p_sys;
249
0
        textst_FillRegions(p_dec, &p_block->p_buffer[13], p_block->i_buffer - 13,
250
0
                           &p_spusys->region);
251
252
0
        p_sub->b_absolute = false;
253
0
        decoder_QueueSub(p_dec, p_sub);
254
0
    }
255
256
0
    block_Release(p_block);
257
0
    return VLCDEC_SUCCESS;
258
0
}
259
260
static int Open(vlc_object_t *object)
261
0
{
262
0
    decoder_t *p_dec = (decoder_t*)object;
263
264
0
    if (p_dec->fmt_in->i_codec != VLC_CODEC_BD_TEXT)
265
0
        return VLC_EGENERIC;
266
267
0
    decoder_sys_t *p_sys = vlc_obj_malloc(object, sizeof(decoder_sys_t));
268
0
    if(!p_sys)
269
0
        return VLC_ENOMEM;
270
0
    memset(p_sys->palette, 0xFF, 256 * sizeof(uint32_t));
271
272
0
    p_dec->p_sys = p_sys;
273
0
    p_dec->pf_decode = Decode;
274
0
    p_dec->fmt_out.i_codec = 0;
275
276
0
    return VLC_SUCCESS;
277
0
}
278