Coverage Report

Created: 2026-02-14 08:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/modules/codec/dvbsub.c
Line
Count
Source
1
/*****************************************************************************
2
 * dvbsub.c : DVB subtitles decoder
3
 *            DVB subtitles encoder (developed for Anevia, www.anevia.com)
4
 *****************************************************************************
5
 * Copyright (C) 2003 ANEVIA
6
 * Copyright (C) 2003-2009 VLC authors and VideoLAN
7
 *
8
 * Authors: Gildas Bazin <gbazin@videolan.org>
9
 *          Damien LUCAS <damien.lucas@anevia.com>
10
 *          Laurent Aimar <fenrir@via.ecp.fr>
11
 *          Jean-Paul Saman <jpsaman #_at_# m2x dot nl>
12
 *          Derk-Jan Hartman <hartman #at# videolan dot org>
13
 *          Simon Hailes <simon _a_ screen.subtitling.com>
14
 *
15
 * This program is free software; you can redistribute it and/or modify it
16
 * under the terms of the GNU Lesser General Public License as published by
17
 * the Free Software Foundation; either version 2.1 of the License, or
18
 * (at your option) any later version.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23
 * GNU Lesser General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU Lesser General Public License
26
 * along with this program; if not, write to the Free Software Foundation, Inc.,
27
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
28
 *****************************************************************************/
29
30
/*****************************************************************************
31
 * Preamble
32
 *
33
 * FIXME:
34
 * DVB subtitles coded as strings of characters are not handled correctly.
35
 * The character codes in the string should actually be indexes referring to a
36
 * character table identified in the subtitle descriptor.
37
 *
38
 * The spec is quite vague in this area, but what is meant is perhaps that it
39
 * refers to the character index in the codepage belonging to the language
40
 * specified in the subtitle descriptor. Potentially it's designed for widechar
41
 * (but not for UTF-*) codepages.
42
 *****************************************************************************
43
 *
44
 *****************************************************************************
45
 * Notes on DDS (Display Definition Segment)
46
 * -----------------------------------------
47
 * DDS (Display Definition Segment) tells the decoder how the subtitle image
48
 * relates to the video image.
49
 * For SD, the subtitle image is always considered to be for display at
50
 * 720x576 (although it's assumed that for NTSC, this is 720x480, this
51
 * is not documented well) Also, for SD, the subtitle image is drawn 'on
52
 * the glass' (i.e. after video scaling, letterbox, etc.)
53
 * For 'HD' (subs marked type 0x14/0x24 in PSI), a DDS must be present,
54
 * and the subs area is drawn onto the video area (scales if necessary).
55
 * The DDS tells the decoder what resolution the subtitle images were
56
 * intended for, and hence how to scale the subtitle images for a
57
 * particular video size
58
 * i.e. if HD video is presented as letterbox, the subs will be in the
59
 * same place on the video as if the video was presented on an HD set
60
 * indeed, if the HD video was pillarboxed by the decoder, the subs may
61
 * be cut off as well as the video. The intent here is that the subs can
62
 * be placed accurately on the video - something which was missed in the
63
 * original spec.
64
 *
65
 * A DDS may also specify a window - this is where the subs images are moved so that the (0,0)
66
 * origin of decode is offset.
67
 ********************************************************************************************/
68
69
#ifdef HAVE_CONFIG_H
70
# include "config.h"
71
#endif
72
73
#include <vlc_common.h>
74
#include <vlc_configuration.h>
75
#include <vlc_plugin.h>
76
#include <vlc_codec.h>
77
#include <vlc_sout.h>
78
79
#include <vlc_bits.h>
80
81
#include <limits.h>
82
83
/* #define DEBUG_DVBSUB 1 */
84
85
#define POSX_TEXT N_("Decoding X coordinate")
86
#define POSX_LONGTEXT N_("X coordinate of the rendered subtitle")
87
88
#define POSY_TEXT N_("Decoding Y coordinate")
89
#define POSY_LONGTEXT N_("Y coordinate of the rendered subtitle")
90
91
#define POS_TEXT N_("Subpicture position")
92
#define POS_LONGTEXT N_( \
93
  "You can enforce the subpicture position on the video " \
94
  "(0=center, 1=left, 2=right, 4=top, 8=bottom, you can " \
95
  "also use combinations of these values, e.g. 6=top-right).")
96
97
#define ENC_POSX_TEXT N_("Encoding X coordinate")
98
#define ENC_POSX_LONGTEXT N_("X coordinate of the encoded subtitle" )
99
#define ENC_POSY_TEXT N_("Encoding Y coordinate")
100
#define ENC_POSY_LONGTEXT N_("Y coordinate of the encoded subtitle" )
101
102
static const int pi_pos_values[] = {
103
    0,
104
    SUBPICTURE_ALIGN_LEFT,
105
    SUBPICTURE_ALIGN_RIGHT,
106
    SUBPICTURE_ALIGN_TOP,
107
    SUBPICTURE_ALIGN_BOTTOM,
108
    SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT,
109
    SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_RIGHT,
110
    SUBPICTURE_ALIGN_BOTTOM | SUBPICTURE_ALIGN_LEFT,
111
    SUBPICTURE_ALIGN_BOTTOM | SUBPICTURE_ALIGN_RIGHT,
112
};
113
static const char *const ppsz_pos_descriptions[] =
114
{ N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"),
115
  N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") };
116
117
/*****************************************************************************
118
 * Module descriptor.
119
 *****************************************************************************/
120
static int  Open ( vlc_object_t * );
121
static void Close( vlc_object_t * );
122
static int Decode( decoder_t *, block_t * );
123
static void Flush( decoder_t * );
124
125
#ifdef ENABLE_SOUT
126
static int OpenEncoder  ( vlc_object_t * );
127
static void CloseEncoder( encoder_t * );
128
static block_t *Encode  ( encoder_t *, subpicture_t * );
129
#endif
130
131
104
vlc_module_begin ()
132
52
#   define DVBSUB_CFG_PREFIX "dvbsub-"
133
52
    set_description( N_("DVB subtitles decoder") )
134
52
    set_shortname( N_("DVB subtitles") )
135
52
    set_capability( "spu decoder", 80 )
136
52
    set_subcategory( SUBCAT_INPUT_SCODEC )
137
52
    set_callbacks( Open, Close )
138
139
52
    add_integer( DVBSUB_CFG_PREFIX "position", 8, POS_TEXT, POS_LONGTEXT )
140
52
        change_integer_list( pi_pos_values, ppsz_pos_descriptions )
141
52
    add_integer( DVBSUB_CFG_PREFIX "x", -1, POSX_TEXT, POSX_LONGTEXT )
142
52
    add_integer( DVBSUB_CFG_PREFIX "y", -1, POSY_TEXT, POSY_LONGTEXT )
143
144
52
#ifdef ENABLE_SOUT
145
52
#   define ENC_CFG_PREFIX "sout-dvbsub-"
146
52
    add_submodule ()
147
52
    set_description( N_("DVB subtitles encoder") )
148
52
    set_capability( "spu encoder", 100 )
149
52
    set_callback( OpenEncoder )
150
151
52
    add_integer( ENC_CFG_PREFIX "x", -1, ENC_POSX_TEXT, ENC_POSX_LONGTEXT )
152
52
    add_integer( ENC_CFG_PREFIX "y", -1, ENC_POSY_TEXT, ENC_POSY_LONGTEXT )
153
52
#endif
154
52
vlc_module_end ()
155
156
static const char *const ppsz_enc_options[] = { "x", "y", NULL };
157
158
/****************************************************************************
159
 * Local structures
160
 ****************************************************************************
161
 * Those structures refer closely to the ETSI 300 743 Object model
162
 ****************************************************************************/
163
164
/* The object definition gives the position of the object in a region [7.2.5] */
165
typedef struct dvbsub_objectdef_s
166
{
167
    int i_id;
168
    int i_type;
169
    int i_x;
170
    int i_y;
171
    int i_fg_pc;
172
    int i_bg_pc;
173
    char *psz_text; /* for string of characters objects */
174
175
} dvbsub_objectdef_t;
176
177
/* The entry in the palette CLUT */
178
typedef struct
179
{
180
    uint8_t                 Y;
181
    uint8_t                 Cr;
182
    uint8_t                 Cb;
183
    uint8_t                 T;
184
185
} dvbsub_color_t;
186
187
/* The displays dimensions [7.2.1] */
188
typedef struct dvbsub_display_s
189
{
190
    uint8_t                 i_id;
191
    uint8_t                 i_version;
192
193
    uint16_t                i_width_minus1;
194
    uint16_t                i_height_minus1;
195
196
    bool                    b_windowed;
197
    /* these values are only relevant if windowed */
198
    int                     i_x;
199
    int                     i_y;
200
    int                     i_max_x;
201
    int                     i_max_y;
202
203
} dvbsub_display_t;
204
205
/* [7.2.4] */
206
typedef struct dvbsub_clut_s
207
{
208
    uint8_t                 i_id;
209
    uint8_t                 i_version;
210
    dvbsub_color_t          c_2b[4];
211
    dvbsub_color_t          c_4b[16];
212
    dvbsub_color_t          c_8b[256];
213
    int                     c_8b_entries;
214
    video_color_range_t     color_range;
215
    int                     dynamic_range_and_colour_gamut;
216
217
    struct dvbsub_clut_s    *p_next;
218
219
} dvbsub_clut_t;
220
221
/* The Region is an area on the image [7.2.3]
222
 * with a list of the object definitions associated and a CLUT */
223
typedef struct dvbsub_region_s
224
{
225
    int i_id;
226
    int i_version;
227
    int i_x;
228
    int i_y;
229
    int i_width;
230
    int i_height;
231
    int i_level_comp;
232
    int i_depth;
233
    int i_clut;
234
235
    uint8_t *p_pixbuf;
236
237
    int                    i_object_defs;
238
    dvbsub_objectdef_t     *p_object_defs;
239
240
    struct dvbsub_region_s *p_next;
241
242
} dvbsub_region_t;
243
244
/* The object definition gives the position of the object in a region */
245
typedef struct dvbsub_regiondef_s
246
{
247
    int i_id;
248
    int i_x;
249
    int i_y;
250
251
} dvbsub_regiondef_t;
252
253
/* The page defines the list of regions [7.2.2] */
254
typedef struct
255
{
256
    int i_id;
257
    int i_timeout; /* in seconds */
258
    int i_state;
259
    int i_version;
260
261
    int                i_region_defs;
262
    dvbsub_regiondef_t *p_region_defs;
263
264
} dvbsub_page_t;
265
266
typedef struct
267
{
268
    bs_t               bs;
269
270
    /* Decoder internal data */
271
    int                i_id;
272
    int                i_ancillary_id;
273
    vlc_tick_t         i_pts;
274
275
    int                i_spu_position;
276
    int                i_spu_x;
277
    int                i_spu_y;
278
279
    bool               b_page;
280
    dvbsub_page_t      *p_page;
281
    dvbsub_region_t    *p_regions;
282
    dvbsub_clut_t      *p_cluts;
283
    /* this is very small, so keep forever */
284
    dvbsub_display_t   display;
285
    dvbsub_clut_t      default_clut;
286
} decoder_sys_t;
287
288
289
/* List of different SEGMENT TYPES */
290
/* According to EN 300-743, table 2 */
291
0
#define DVBSUB_ST_PAGE_COMPOSITION      0x10
292
0
#define DVBSUB_ST_REGION_COMPOSITION    0x11
293
0
#define DVBSUB_ST_CLUT_DEFINITION       0x12
294
0
#define DVBSUB_ST_OBJECT_DATA           0x13
295
0
#define DVBSUB_ST_DISPLAY_DEFINITION    0x14
296
0
#define DVBSUB_ST_ALTERNATE_CLUT        0x16
297
0
#define DVBSUB_ST_ENDOFDISPLAY          0x80
298
0
#define DVBSUB_ST_STUFFING              0xff
299
/* List of different OBJECT TYPES */
300
/* According to EN 300-743, table 6 */
301
0
#define DVBSUB_OT_BASIC_BITMAP          0x00
302
0
#define DVBSUB_OT_BASIC_CHAR            0x01
303
0
#define DVBSUB_OT_COMPOSITE_STRING      0x02
304
/* Pixel DATA TYPES */
305
/* According to EN 300-743, table 9 */
306
#define DVBSUB_DT_2BP_CODE_STRING       0x10
307
#define DVBSUB_DT_4BP_CODE_STRING       0x11
308
#define DVBSUB_DT_8BP_CODE_STRING       0x12
309
#define DVBSUB_DT_24_TABLE_DATA         0x20
310
#define DVBSUB_DT_28_TABLE_DATA         0x21
311
#define DVBSUB_DT_48_TABLE_DATA         0x22
312
#define DVBSUB_DT_END_LINE              0xf0
313
/* List of different Page Composition Segment state */
314
/* According to EN 300-743, 7.2.1 table 3 */
315
0
#define DVBSUB_PCS_STATE_ACQUISITION    0x01
316
0
#define DVBSUB_PCS_STATE_CHANGE         0x02
317
/* According to EN 300-743, 7.2.8 table 33 */
318
0
#define DVBSUB_ST_BITDEPTH_8BIT         0x00
319
0
#define DVBSUB_ST_BITDEPTH_10BIT        0x01
320
/* According to EN 300-743, 7.2.8 table 34 */
321
1
#define DVBSUB_ST_COLORIMETRY_CDS       -1
322
0
#define DVBSUB_ST_COLORIMETRY_SDR_709   0x00
323
0
#define DVBSUB_ST_COLORIMETRY_SDR_2020  0x01
324
0
#define DVBSUB_ST_COLORIMETRY_HDR_PQ    0x02
325
0
#define DVBSUB_ST_COLORIMETRY_HDR_HLG   0x03
326
327
/*****************************************************************************
328
 * Local prototypes
329
 *****************************************************************************/
330
static void decode_segment( decoder_t *, bs_t * );
331
static void decode_page_composition( decoder_t *, bs_t *, uint16_t );
332
static void decode_region_composition( decoder_t *, bs_t *, uint16_t );
333
static void decode_object( decoder_t *, bs_t *, uint16_t );
334
static void decode_display_definition( decoder_t *, bs_t *, uint16_t );
335
static void alternative_CLUT( decoder_t *, bs_t *, uint16_t );
336
static void decode_clut( decoder_t *, bs_t *, uint16_t );
337
static void free_all( decoder_t * );
338
339
static void default_clut_init( decoder_t * );
340
static void default_dds_init( decoder_t * );
341
342
static subpicture_t *render( decoder_t * );
343
344
/*****************************************************************************
345
 * Open: probe the decoder and return score
346
 *****************************************************************************
347
 * Tries to launch a decoder and return score so that the interface is able
348
 * to chose.
349
 *****************************************************************************/
350
static int Open( vlc_object_t *p_this )
351
16.2k
{
352
16.2k
    decoder_t     *p_dec = (decoder_t *) p_this;
353
16.2k
    decoder_sys_t *p_sys;
354
16.2k
    int i_posx, i_posy;
355
356
16.2k
    if( p_dec->fmt_in->i_codec != VLC_CODEC_DVBS )
357
16.2k
    {
358
16.2k
        return VLC_EGENERIC;
359
16.2k
    }
360
361
1
    p_dec->pf_decode = Decode;
362
1
    p_dec->pf_flush  = Flush;
363
1
    p_sys = p_dec->p_sys = calloc( 1, sizeof(decoder_sys_t) );
364
1
    if( !p_sys )
365
0
        return VLC_ENOMEM;
366
367
1
    p_sys->i_pts          = VLC_TICK_INVALID;
368
1
    p_sys->i_id           = p_dec->fmt_in->subs.dvb.i_id & 0xFFFF;
369
1
    p_sys->i_ancillary_id = p_dec->fmt_in->subs.dvb.i_id >> 16;
370
371
1
    p_sys->p_regions      = NULL;
372
1
    p_sys->p_cluts        = NULL;
373
1
    p_sys->p_page         = NULL;
374
375
    /* configure for SD res in case DDS is not present */
376
1
    default_dds_init( p_dec );
377
378
1
    p_sys->i_spu_position = var_CreateGetInteger( p_this,
379
1
                                    DVBSUB_CFG_PREFIX "position" );
380
1
    i_posx = var_CreateGetInteger( p_this, DVBSUB_CFG_PREFIX "x" );
381
1
    i_posy = var_CreateGetInteger( p_this, DVBSUB_CFG_PREFIX "y" );
382
383
    /* Check if subpicture position was overridden */
384
1
    p_sys->i_spu_x = p_sys->i_spu_y = 0;
385
386
1
    if( ( i_posx >= 0 ) && ( i_posy >= 0 ) )
387
0
    {
388
0
        p_sys->i_spu_x = i_posx;
389
0
        p_sys->i_spu_y = i_posy;
390
0
    }
391
392
1
    p_dec->fmt_out.i_codec = 0;
393
394
1
    default_clut_init( p_dec );
395
396
1
    return VLC_SUCCESS;
397
1
}
398
399
/*****************************************************************************
400
 * Close:
401
 *****************************************************************************/
402
static void Close( vlc_object_t *p_this )
403
1
{
404
1
    decoder_t     *p_dec = (decoder_t*) p_this;
405
1
    decoder_sys_t *p_sys = p_dec->p_sys;
406
407
1
    var_Destroy( p_this, DVBSUB_CFG_PREFIX "x" );
408
1
    var_Destroy( p_this, DVBSUB_CFG_PREFIX "y" );
409
1
    var_Destroy( p_this, DVBSUB_CFG_PREFIX "position" );
410
411
1
    free_all( p_dec );
412
1
    free( p_sys );
413
1
}
414
415
/*****************************************************************************
416
 * Flush:
417
 *****************************************************************************/
418
static void Flush( decoder_t *p_dec )
419
0
{
420
0
    decoder_sys_t *p_sys = p_dec->p_sys;
421
422
0
    p_sys->i_pts = VLC_TICK_INVALID;
423
0
}
424
425
/*****************************************************************************
426
 * Decode:
427
 *****************************************************************************/
428
static int Decode( decoder_t *p_dec, block_t *p_block )
429
15.2k
{
430
15.2k
    decoder_sys_t *p_sys = p_dec->p_sys;
431
432
15.2k
    if( p_block == NULL ) /* No Drain */
433
7.62k
        return VLCDEC_SUCCESS;
434
435
7.62k
    if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY | BLOCK_FLAG_CORRUPTED) )
436
0
    {
437
0
        Flush( p_dec );
438
0
        if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
439
0
            goto end;
440
0
    }
441
442
    /* configure for SD res in case DDS is not present */
443
    /* a change of PTS is a good indication we must get a new DDS */
444
7.62k
    if( p_sys->i_pts != p_block->i_pts )
445
7.62k
        default_dds_init( p_dec );
446
447
7.62k
    p_sys->i_pts = p_block->i_pts;
448
7.62k
    if( p_sys->i_pts == VLC_TICK_INVALID )
449
0
    {
450
#ifdef DEBUG_DVBSUB
451
        /* Some DVB channels send stuffing segments in non-dated packets so
452
         * don't complain too loudly. */
453
        msg_Warn( p_dec, "non dated subtitle" );
454
#endif
455
0
        goto end;
456
0
    }
457
458
7.62k
    bs_init( &p_sys->bs, p_block->p_buffer, p_block->i_buffer );
459
460
7.62k
    if( bs_read( &p_sys->bs, 8 ) != 0x20 ) /* Data identifier */
461
7.62k
    {
462
7.62k
        msg_Dbg( p_dec, "invalid data identifier" );
463
7.62k
        goto end;
464
7.62k
    }
465
466
0
    if( bs_read( &p_sys->bs, 8 ) ) /* Subtitle stream id */
467
0
    {
468
0
        msg_Dbg( p_dec, "invalid subtitle stream id" );
469
0
        goto end;
470
0
    }
471
472
#ifdef DEBUG_DVBSUB
473
    msg_Dbg( p_dec, "subtitle packet received: %"PRId64, p_sys->i_pts );
474
#endif
475
476
0
    p_sys->b_page = false;
477
478
0
    uint8_t i_sync_byte = bs_read( &p_sys->bs, 8 );
479
0
    while( i_sync_byte == 0x0f ) /* Sync byte */
480
0
    {
481
0
        decode_segment( p_dec, &p_sys->bs );
482
0
        i_sync_byte = bs_read( &p_sys->bs, 8 );
483
0
    }
484
485
0
    if( ( i_sync_byte & 0x3f ) != 0x3f ) /* End marker */
486
0
    {
487
0
        msg_Warn( p_dec, "end marker not found (corrupted subtitle ?)" );
488
0
        goto end;
489
0
    }
490
491
    /* Check if the page is to be displayed */
492
0
    if( p_sys->p_page && p_sys->b_page )
493
0
    {
494
0
        subpicture_t *p_spu = render( p_dec );
495
0
        if( p_spu != NULL )
496
0
            decoder_QueueSub( p_dec, p_spu );
497
0
    }
498
499
7.62k
end:
500
7.62k
    block_Release(p_block);
501
7.62k
    return VLCDEC_SUCCESS;
502
0
}
503
504
/* following functions are local */
505
506
/*****************************************************************************
507
 * default_clut_init: default clut as defined in EN 300-743 section 10
508
 *****************************************************************************/
509
static void default_clut_init( decoder_t *p_dec )
510
1
{
511
1
    decoder_sys_t *p_sys = p_dec->p_sys;
512
1
    uint8_t i;
513
514
20
#define RGB_TO_Y(r, g, b) ((int16_t) 77 * r + 150 * g + 29 * b) / 256;
515
20
#define RGB_TO_U(r, g, b) ((int16_t) -44 * r - 87 * g + 131 * b) / 256;
516
20
#define RGB_TO_V(r, g, b) ((int16_t) 131 * r - 110 * g - 21 * b) / 256;
517
518
    /* 4 entries CLUT */
519
5
    for( i = 0; i < 4; i++ )
520
4
    {
521
4
        uint8_t R = 0, G = 0, B = 0, T = 0;
522
523
4
        if( !(i & 0x2) && !(i & 0x1) ) T = 0xFF;
524
3
        else if( !(i & 0x2) && (i & 0x1) ) R = G = B = 0xFF;
525
2
        else if( (i & 0x2) && !(i & 0x1) ) R = G = B = 0;
526
1
        else R = G = B = 0x7F;
527
528
4
        p_sys->default_clut.c_2b[i].Y = RGB_TO_Y(R,G,B);
529
4
        p_sys->default_clut.c_2b[i].Cb = RGB_TO_V(R,G,B);
530
4
        p_sys->default_clut.c_2b[i].Cr = RGB_TO_U(R,G,B);
531
4
        p_sys->default_clut.c_2b[i].T = T;
532
4
    }
533
534
    /* 16 entries CLUT */
535
17
    for( i = 0; i < 16; i++ )
536
16
    {
537
16
        uint8_t R = 0, G = 0, B = 0, T = 0;
538
539
16
        if( !(i & 0x8) )
540
8
        {
541
8
            if( !(i & 0x4) && !(i & 0x2) && !(i & 0x1) )
542
1
            {
543
1
                T = 0xFF;
544
1
            }
545
7
            else
546
7
            {
547
7
                R = (i & 0x1) ? 0xFF : 0;
548
7
                G = (i & 0x2) ? 0xFF : 0;
549
7
                B = (i & 0x4) ? 0xFF : 0;
550
7
            }
551
8
        }
552
8
        else
553
8
        {
554
8
            R = (i & 0x1) ? 0x7F : 0;
555
8
            G = (i & 0x2) ? 0x7F : 0;
556
8
            B = (i & 0x4) ? 0x7F : 0;
557
8
        }
558
559
16
        p_sys->default_clut.c_4b[i].Y = RGB_TO_Y(R,G,B);
560
16
        p_sys->default_clut.c_4b[i].Cr = RGB_TO_V(R,G,B);
561
16
        p_sys->default_clut.c_4b[i].Cb = RGB_TO_U(R,G,B);
562
16
        p_sys->default_clut.c_4b[i].T = T;
563
16
    }
564
565
    /* 256 entries CLUT */
566
1
    memset( p_sys->default_clut.c_8b, 0xFF, 256 * sizeof(dvbsub_color_t) );
567
1
    p_sys->default_clut.c_8b_entries = 256;
568
1
    p_sys->default_clut.color_range = COLOR_RANGE_LIMITED;
569
1
    p_sys->default_clut.dynamic_range_and_colour_gamut = DVBSUB_ST_COLORIMETRY_CDS;
570
1
}
571
572
static void decode_segment( decoder_t *p_dec, bs_t *s )
573
0
{
574
0
    decoder_sys_t *p_sys = p_dec->p_sys;
575
0
    int i_type;
576
0
    int i_page_id;
577
0
    int i_size;
578
579
    /* sync_byte (already checked) */
580
    //bs_skip( s, 8 );
581
582
    /* segment type */
583
0
    i_type = bs_read( s, 8 );
584
585
    /* page id */
586
0
    i_page_id = bs_read( s, 16 );
587
588
    /* segment size */
589
0
    i_size = bs_read( s, 16 );
590
591
0
    if( ( i_page_id != p_sys->i_id ) &&
592
0
        ( i_page_id != p_sys->i_ancillary_id ) )
593
0
    {
594
#ifdef DEBUG_DVBSUB
595
        msg_Dbg( p_dec, "subtitle skipped (page id: %i, %i)",
596
                 i_page_id, p_sys->i_id );
597
#endif
598
0
        bs_skip( s,  8 * i_size );
599
0
        return;
600
0
    }
601
602
0
    if( ( p_sys->i_ancillary_id != p_sys->i_id ) &&
603
0
        ( i_type == DVBSUB_ST_PAGE_COMPOSITION ) &&
604
0
        ( i_page_id == p_sys->i_ancillary_id ) )
605
0
    {
606
#ifdef DEBUG_DVBSUB
607
        msg_Dbg( p_dec, "skipped invalid ancillary subtitle packet" );
608
#endif
609
0
        bs_skip( s,  8 * i_size );
610
0
        return;
611
0
    }
612
613
#ifdef DEBUG_DVBSUB
614
    if( i_page_id == p_sys->i_id )
615
        msg_Dbg( p_dec, "segment (id: %i)", i_page_id );
616
    else
617
        msg_Dbg( p_dec, "ancillary segment (id: %i)", i_page_id );
618
#endif
619
620
0
    switch( i_type )
621
0
    {
622
0
    case DVBSUB_ST_PAGE_COMPOSITION:
623
#ifdef DEBUG_DVBSUB
624
        msg_Dbg( p_dec, "decode_page_composition" );
625
#endif
626
0
        decode_page_composition( p_dec, s, i_size );
627
0
        break;
628
629
0
    case DVBSUB_ST_REGION_COMPOSITION:
630
#ifdef DEBUG_DVBSUB
631
        msg_Dbg( p_dec, "decode_region_composition" );
632
#endif
633
0
        decode_region_composition( p_dec, s, i_size );
634
0
        break;
635
636
0
    case DVBSUB_ST_CLUT_DEFINITION:
637
#ifdef DEBUG_DVBSUB
638
        msg_Dbg( p_dec, "decode_clut" );
639
#endif
640
0
        decode_clut( p_dec, s, i_size );
641
0
        break;
642
643
0
    case DVBSUB_ST_OBJECT_DATA:
644
#ifdef DEBUG_DVBSUB
645
        msg_Dbg( p_dec, "decode_object" );
646
#endif
647
0
        decode_object( p_dec, s, i_size );
648
0
        break;
649
650
0
    case DVBSUB_ST_DISPLAY_DEFINITION:
651
#ifdef DEBUG_DVBSUB
652
        msg_Dbg( p_dec, "decode_display_definition" );
653
#endif
654
0
        decode_display_definition( p_dec, s, i_size );
655
0
        break;
656
657
0
    case DVBSUB_ST_ALTERNATE_CLUT:
658
#ifdef DEBUG_DVBSUB
659
        msg_Dbg( p_dec, "alternative_CLUT" );
660
#endif
661
0
        alternative_CLUT( p_dec, s, i_size );
662
0
        break;
663
664
0
    case DVBSUB_ST_ENDOFDISPLAY:
665
#ifdef DEBUG_DVBSUB
666
        msg_Dbg( p_dec, "end of display" );
667
#endif
668
0
        bs_skip( s,  8 * i_size );
669
0
        break;
670
671
0
    case DVBSUB_ST_STUFFING:
672
#ifdef DEBUG_DVBSUB
673
        msg_Dbg( p_dec, "skip stuffing" );
674
#endif
675
0
        bs_skip( s,  8 * i_size );
676
0
        break;
677
678
0
    default:
679
0
        msg_Warn( p_dec, "unsupported segment type: (%04x)", i_type );
680
0
        bs_skip( s,  8 * i_size );
681
0
        break;
682
0
    }
683
0
}
684
685
static void decode_clut( decoder_t *p_dec, bs_t *s, uint16_t i_segment_length )
686
0
{
687
0
    decoder_sys_t *p_sys = p_dec->p_sys;
688
0
    uint16_t      i_processed_length;
689
0
    dvbsub_clut_t *p_clut, *p_next;
690
0
    int           i_id, i_version;
691
692
0
    i_id             = bs_read( s, 8 );
693
0
    i_version        = bs_read( s, 4 );
694
695
    /* Check if we already have this clut */
696
0
    for( p_clut = p_sys->p_cluts; p_clut != NULL; p_clut = p_clut->p_next )
697
0
    {
698
0
        if( p_clut->i_id == i_id ) break;
699
0
    }
700
701
    /* Check version number */
702
0
    if( p_clut && ( p_clut->i_version == i_version ) )
703
0
    {
704
        /* Nothing to do */
705
0
        bs_skip( s, 8 * i_segment_length - 12 );
706
0
        return;
707
0
    }
708
709
0
    if( !p_clut )
710
0
    {
711
#ifdef DEBUG_DVBSUB
712
        msg_Dbg( p_dec, "new clut: %i", i_id );
713
#endif
714
0
        p_clut = malloc( sizeof( dvbsub_clut_t ) );
715
0
        if( !p_clut )
716
0
            return;
717
0
        p_clut->p_next = p_sys->p_cluts;
718
0
        p_sys->p_cluts = p_clut;
719
0
    }
720
721
    /* Initialize to default clut */
722
0
    p_next = p_clut->p_next;
723
0
    *p_clut = p_sys->default_clut;
724
0
    p_clut->p_next = p_next;
725
726
    /* We don't have this version of the CLUT: Parse it */
727
0
    p_clut->i_version = i_version;
728
0
    p_clut->i_id = i_id;
729
0
    bs_skip( s, 4 ); /* Reserved bits */
730
0
    i_processed_length = 2;
731
0
    while( i_processed_length < i_segment_length )
732
0
    {
733
0
        uint8_t y, cb, cr, t;
734
0
        uint_fast8_t cid = bs_read( s, 8 );
735
0
        uint_fast8_t type = bs_read( s, 3 );
736
737
0
        bs_skip( s, 4 );
738
739
0
        p_clut->color_range = bs_read( s, 1 ) ? COLOR_RANGE_FULL : COLOR_RANGE_LIMITED;
740
0
        if( p_clut->color_range == COLOR_RANGE_FULL )
741
0
        {
742
0
            y  = bs_read( s, 8 );
743
0
            cr = bs_read( s, 8 );
744
0
            cb = bs_read( s, 8 );
745
0
            t  = bs_read( s, 8 );
746
0
            i_processed_length += 6;
747
0
        }
748
0
        else
749
0
        {
750
0
            y  = bs_read( s, 6 ) << 2;
751
0
            cr = bs_read( s, 4 ) << 4;
752
0
            cb = bs_read( s, 4 ) << 4;
753
0
            t  = bs_read( s, 2 ) << 6;
754
0
            i_processed_length += 4;
755
0
        }
756
757
        /* We are not entirely compliant here as full transparency is indicated
758
         * with a luma value of zero, not a transparency value of 0xff
759
         * (full transparency would actually be 0xff + 1). */
760
0
        if( y == 0 )
761
0
        {
762
0
            cr = cb = 0;
763
0
            t  = 0xff;
764
0
        }
765
766
        /* According to EN 300-743 section 7.2.3 note 1, type should
767
         * not have more than 1 bit set to one, but some streams don't
768
         * respect this note. */
769
0
        if( ( type & 0x04 ) && ( cid < 4 ) )
770
0
        {
771
0
            p_clut->c_2b[cid].Y = y;
772
0
            p_clut->c_2b[cid].Cr = cr;
773
0
            p_clut->c_2b[cid].Cb = cb;
774
0
            p_clut->c_2b[cid].T = t;
775
0
        }
776
0
        if( ( type & 0x02 ) && ( cid < 16 ) )
777
0
        {
778
0
            p_clut->c_4b[cid].Y = y;
779
0
            p_clut->c_4b[cid].Cr = cr;
780
0
            p_clut->c_4b[cid].Cb = cb;
781
0
            p_clut->c_4b[cid].T = t;
782
0
        }
783
0
        if( type & 0x01 )
784
0
        {
785
0
            p_clut->c_8b[cid].Y = y;
786
0
            p_clut->c_8b[cid].Cr = cr;
787
0
            p_clut->c_8b[cid].Cb = cb;
788
0
            p_clut->c_8b[cid].T = t;
789
0
        }
790
0
    }
791
0
}
792
793
static void decode_page_composition( decoder_t *p_dec, bs_t *s, uint16_t i_segment_length )
794
0
{
795
0
    decoder_sys_t *p_sys = p_dec->p_sys;
796
0
    int i_version, i_state, i_timeout, i;
797
798
    /* A page is composed by 0 or more region */
799
0
    i_timeout = bs_read( s, 8 );
800
0
    i_version = bs_read( s, 4 );
801
0
    i_state = bs_read( s, 2 );
802
0
    bs_skip( s, 2 ); /* Reserved */
803
804
0
    if( i_state == DVBSUB_PCS_STATE_CHANGE )
805
0
    {
806
        /* End of an epoch, reset decoder buffer */
807
#ifdef DEBUG_DVBSUB
808
        msg_Dbg( p_dec, "page composition mode change" );
809
#endif
810
0
        free_all( p_dec );
811
0
    }
812
0
    else if( !p_sys->p_page && ( i_state != DVBSUB_PCS_STATE_ACQUISITION ) &&
813
0
             ( i_state != DVBSUB_PCS_STATE_CHANGE ) )
814
0
    {
815
        /* Not a full PCS, we need to wait for one */
816
0
        msg_Dbg( p_dec, "didn't receive an acquisition page yet" );
817
818
#if 0
819
        /* Try to start decoding even without an acquisition page */
820
        bs_skip( s,  8 * (i_segment_length - 2) );
821
        return;
822
#endif
823
0
    }
824
825
#ifdef DEBUG_DVBSUB
826
    if( i_state == DVBSUB_PCS_STATE_ACQUISITION )
827
        msg_Dbg( p_dec, "acquisition page composition" );
828
#endif
829
830
    /* Check version number */
831
0
    if( p_sys->p_page && ( p_sys->p_page->i_version == i_version ) )
832
0
    {
833
0
        bs_skip( s,  8 * (i_segment_length - 2) );
834
0
        return;
835
0
    }
836
0
    else if( p_sys->p_page )
837
0
    {
838
0
        if( p_sys->p_page->i_region_defs )
839
0
            free( p_sys->p_page->p_region_defs );
840
0
        p_sys->p_page->p_region_defs = NULL;
841
0
        p_sys->p_page->i_region_defs = 0;
842
0
    }
843
844
0
    if( !p_sys->p_page )
845
0
    {
846
#ifdef DEBUG_DVBSUB
847
        msg_Dbg( p_dec, "new page" );
848
#endif
849
        /* Allocate a new page */
850
0
        p_sys->p_page = malloc( sizeof(dvbsub_page_t) );
851
0
        if( !p_sys->p_page )
852
0
            return;
853
0
    }
854
855
0
    p_sys->p_page->i_version = i_version;
856
0
    p_sys->p_page->i_timeout = i_timeout;
857
0
    p_sys->b_page = true;
858
859
    /* Number of regions */
860
0
    p_sys->p_page->i_region_defs = (i_segment_length - 2) / 6;
861
862
0
    if( p_sys->p_page->i_region_defs == 0 ) return;
863
864
0
    p_sys->p_page->p_region_defs =
865
0
        vlc_alloc( p_sys->p_page->i_region_defs, sizeof(dvbsub_regiondef_t) );
866
0
    if( p_sys->p_page->p_region_defs )
867
0
    {
868
0
        for( i = 0; i < p_sys->p_page->i_region_defs; i++ )
869
0
        {
870
0
            p_sys->p_page->p_region_defs[i].i_id = bs_read( s, 8 );
871
0
            bs_skip( s, 8 ); /* Reserved */
872
0
            p_sys->p_page->p_region_defs[i].i_x = bs_read( s, 16 );
873
0
            p_sys->p_page->p_region_defs[i].i_y = bs_read( s, 16 );
874
875
#ifdef DEBUG_DVBSUB
876
            msg_Dbg( p_dec, "page_composition, region %i (%i,%i)",
877
                    i, p_sys->p_page->p_region_defs[i].i_x,
878
                    p_sys->p_page->p_region_defs[i].i_y );
879
#endif
880
0
        }
881
0
    }
882
0
}
883
884
static void decode_region_composition( decoder_t *p_dec, bs_t *s, uint16_t i_segment_length )
885
0
{
886
0
    decoder_sys_t *p_sys = p_dec->p_sys;
887
0
    dvbsub_region_t *p_region, **pp_region = &p_sys->p_regions;
888
0
    int i_processed_length, i_id, i_version;
889
0
    int i_width, i_height, i_level_comp, i_depth, i_clut;
890
0
    int i_8_bg, i_4_bg, i_2_bg;
891
0
    bool b_fill;
892
893
0
    i_id = bs_read( s, 8 );
894
0
    i_version = bs_read( s, 4 );
895
896
    /* Check if we already have this region */
897
0
    for( p_region = p_sys->p_regions; p_region != NULL;
898
0
         p_region = p_region->p_next )
899
0
    {
900
0
        pp_region = &p_region->p_next;
901
0
        if( p_region->i_id == i_id ) break;
902
0
    }
903
904
    /* Check version number */
905
0
    if( p_region && ( p_region->i_version == i_version ) )
906
0
    {
907
0
        bs_skip( s, 8 * (i_segment_length - 1) - 4 );
908
0
        return;
909
0
    }
910
911
0
    if( !p_region )
912
0
    {
913
#ifdef DEBUG_DVBSUB
914
        msg_Dbg( p_dec, "new region: %i", i_id );
915
#endif
916
0
        p_region = *pp_region = calloc( 1, sizeof(dvbsub_region_t) );
917
0
        if( !p_region )
918
0
            return;
919
0
        p_region->p_object_defs = NULL;
920
0
        p_region->p_pixbuf = NULL;
921
0
        p_region->p_next = NULL;
922
0
    }
923
924
    /* Region attributes */
925
0
    p_region->i_id = i_id;
926
0
    p_region->i_version = i_version;
927
0
    b_fill = bs_read( s, 1 );
928
0
    bs_skip( s, 3 ); /* Reserved */
929
930
0
    i_width = bs_read( s, 16 );
931
0
    i_height = bs_read( s, 16 );
932
#ifdef DEBUG_DVBSUB
933
    msg_Dbg( p_dec, " width=%d height=%d", i_width, i_height );
934
#endif
935
0
    i_level_comp = bs_read( s, 3 );
936
0
    i_depth = bs_read( s, 3 );
937
0
    bs_skip( s, 2 ); /* Reserved */
938
0
    i_clut = bs_read( s, 8 );
939
940
0
    i_8_bg = bs_read( s, 8 );
941
0
    i_4_bg = bs_read( s, 4 );
942
0
    i_2_bg = bs_read( s, 2 );
943
0
    bs_skip( s, 2 ); /* Reserved */
944
945
    /* Free old object defs */
946
0
    while( p_region->i_object_defs )
947
0
        free( p_region->p_object_defs[--p_region->i_object_defs].psz_text );
948
949
0
    free( p_region->p_object_defs );
950
0
    p_region->p_object_defs = NULL;
951
952
    /* Extra sanity checks */
953
0
    if( ( p_region->i_width != i_width ) ||
954
0
        ( p_region->i_height != i_height ) )
955
0
    {
956
0
        if( p_region->p_pixbuf )
957
0
        {
958
0
            msg_Dbg( p_dec, "region size changed (%dx%d->%dx%d)",
959
0
                     p_region->i_width, p_region->i_height, i_width, i_height );
960
0
            free( p_region->p_pixbuf );
961
0
        }
962
963
0
        p_region->p_pixbuf = xmalloc( i_height * i_width );
964
0
        p_region->i_depth = 0;
965
0
        b_fill = true;
966
0
    }
967
0
    if( p_region->i_depth &&
968
0
        ( ( p_region->i_depth != i_depth ) ||
969
0
          ( p_region->i_level_comp != i_level_comp ) ||
970
0
          ( p_region->i_clut != i_clut) ) )
971
0
    {
972
0
        msg_Dbg( p_dec, "region parameters changed (not allowed)" );
973
0
    }
974
975
    /* Erase background of region */
976
0
    if( b_fill )
977
0
    {
978
0
        int i_background = ( i_depth == 1 ) ? i_2_bg :
979
0
            ( ( i_depth == 2 ) ? i_4_bg : i_8_bg );
980
0
        memset( p_region->p_pixbuf, i_background, i_width * i_height );
981
0
    }
982
983
0
    p_region->i_width = i_width;
984
0
    p_region->i_height = i_height;
985
0
    p_region->i_level_comp = i_level_comp;
986
0
    p_region->i_depth = i_depth;
987
0
    p_region->i_clut = i_clut;
988
989
    /* List of objects in the region */
990
0
    i_processed_length = 10;
991
0
    while( i_processed_length < i_segment_length )
992
0
    {
993
0
        dvbsub_objectdef_t *p_obj;
994
995
        /* We create a new object */
996
0
        p_region->i_object_defs++;
997
0
        p_region->p_object_defs = xrealloc( p_region->p_object_defs,
998
0
                     sizeof(dvbsub_objectdef_t) * p_region->i_object_defs );
999
1000
        /* We parse object properties */
1001
0
        p_obj = &p_region->p_object_defs[p_region->i_object_defs - 1];
1002
0
        p_obj->i_id         = bs_read( s, 16 );
1003
0
        p_obj->i_type       = bs_read( s, 2 );
1004
0
        bs_skip( s, 2 ); /* Provider */
1005
0
        p_obj->i_x          = bs_read( s, 12 );
1006
0
        bs_skip( s, 4 ); /* Reserved */
1007
0
        p_obj->i_y          = bs_read( s, 12 );
1008
0
        p_obj->psz_text     = NULL;
1009
1010
0
        i_processed_length += 6;
1011
1012
0
        if( ( p_obj->i_type == DVBSUB_OT_BASIC_CHAR ) ||
1013
0
            ( p_obj->i_type == DVBSUB_OT_COMPOSITE_STRING ) )
1014
0
        {
1015
0
            p_obj->i_fg_pc =  bs_read( s, 8 );
1016
0
            p_obj->i_bg_pc =  bs_read( s, 8 );
1017
0
            i_processed_length += 2;
1018
0
        }
1019
0
    }
1020
0
}
1021
1022
/* ETSI 300 743 [7.2.8] */
1023
static void alternative_CLUT( decoder_t *p_dec, bs_t *s, uint16_t i_segment_length )
1024
0
{
1025
0
    decoder_sys_t *p_sys = p_dec->p_sys;
1026
0
    uint16_t      i_processed_length;
1027
0
    int           i_id, i_version;
1028
0
    dvbsub_clut_t *p_clut;
1029
1030
0
    i_id = bs_read( s, 8 );
1031
0
    i_version = bs_read( s, 4 );
1032
1033
    /* Check if we already have this clut */
1034
0
    for( p_clut = p_sys->p_cluts; p_clut != NULL; p_clut = p_clut->p_next )
1035
0
    {
1036
0
        if( p_clut->i_id == i_id )
1037
0
        {
1038
            /* Check version number */
1039
0
            if( p_clut->i_version == i_version )
1040
0
            {
1041
                /* Nothing to do */
1042
0
                bs_skip( s, 8 * i_segment_length - 12 );
1043
0
                return;
1044
0
            }
1045
1046
0
            break;
1047
0
        }
1048
0
    }
1049
1050
0
    if( !p_clut )
1051
0
    {
1052
#ifdef DEBUG_DVBSUB
1053
        msg_Dbg( p_dec, "new alternative clut: %i", i_id );
1054
#endif
1055
0
        p_clut = malloc( sizeof( dvbsub_clut_t ) );
1056
0
        if( !p_clut )
1057
0
            return;
1058
0
        p_clut->p_next = p_sys->p_cluts;
1059
0
        p_sys->p_cluts = p_clut;
1060
0
    }
1061
1062
    /* We don't have this version of the CLUT: Parse it */
1063
0
    p_clut->i_version = i_version;
1064
0
    p_clut->i_id = i_id;
1065
1066
0
    bs_skip( s, 4 ); // reserved_zero_future_use
1067
1068
    // CLUT_parameters
1069
0
    int CLUT_entry_max_number = bs_read( s, 2 );
1070
0
    int colour_component_type = bs_read( s, 2 );
1071
0
    int output_bit_depth = bs_read( s, 3 );
1072
0
    bs_skip( s, 1 ); // reserved_zero_future_use
1073
0
    int dynamic_range_and_colour_gamut = bs_read( s, 8 );
1074
1075
0
    bool error = false;
1076
0
    i_processed_length = 4;
1077
0
    if (output_bit_depth != DVBSUB_ST_BITDEPTH_8BIT &&
1078
0
        output_bit_depth != DVBSUB_ST_BITDEPTH_10BIT)
1079
0
    {
1080
0
        msg_Err( p_dec, "unsupported alternative clut bitdepth: %i", output_bit_depth );
1081
0
        error = true;
1082
0
    }
1083
0
    if (CLUT_entry_max_number != 0) // 0: 256 entries
1084
0
    {
1085
0
        msg_Err( p_dec, "unsupported alternative clut max entries: %i", CLUT_entry_max_number );
1086
0
        error = true;
1087
0
    }
1088
0
    if (colour_component_type != 0) // 0: YCbCr
1089
0
    {
1090
0
        msg_Err( p_dec, "unsupported alternative clut component type: %i", colour_component_type );
1091
0
        error = true;
1092
0
    }
1093
0
    if (dynamic_range_and_colour_gamut > DVBSUB_ST_COLORIMETRY_HDR_HLG)
1094
0
    {
1095
0
        msg_Err( p_dec, "unsupported alternative clut color range: %i", dynamic_range_and_colour_gamut );
1096
0
        error = true;
1097
0
    }
1098
0
    if (error)
1099
0
        goto done;
1100
1101
0
    p_clut->c_8b_entries = 0;
1102
0
    while( i_processed_length < i_segment_length )
1103
0
    {
1104
0
        uint8_t y, cb, cr, t;
1105
0
        if (output_bit_depth == DVBSUB_ST_BITDEPTH_10BIT)
1106
0
        {
1107
            // TODO: apply the palette locally to keep 10-bit values
1108
0
            y  = bs_read( s, 10 ) >> 2;
1109
0
            cr = bs_read( s, 10 ) >> 2;
1110
0
            cb = bs_read( s, 10 ) >> 2;
1111
0
            t  = bs_read( s, 10 ) >> 2;
1112
0
            i_processed_length += 5;
1113
0
        }
1114
0
        else
1115
0
        {
1116
0
            y  = bs_read( s, 8 );
1117
0
            cr = bs_read( s, 8 );
1118
0
            cb = bs_read( s, 8 );
1119
0
            t  = bs_read( s, 8 );
1120
0
            i_processed_length += 4;
1121
0
        }
1122
1123
        /* We are not entirely compliant here as full transparency is indicated
1124
         * with a luma value of zero, not a transparency value of 0xff
1125
         * (full transparency would actually be 0xff + 1). */
1126
0
        if( y == 0 )
1127
0
        {
1128
0
            cr = cb = 0;
1129
0
            t  = 0xff;
1130
0
        }
1131
1132
0
        p_clut->c_8b[p_clut->c_8b_entries].Y = y;
1133
0
        p_clut->c_8b[p_clut->c_8b_entries].Cr = cr;
1134
0
        p_clut->c_8b[p_clut->c_8b_entries].Cb = cb;
1135
0
        p_clut->c_8b[p_clut->c_8b_entries].T = t;
1136
0
        p_clut->c_8b_entries++;
1137
0
        if (p_clut->c_8b_entries >= (int)ARRAY_SIZE(p_clut->c_8b))
1138
0
            break;
1139
0
    }
1140
0
    p_clut->dynamic_range_and_colour_gamut = dynamic_range_and_colour_gamut;
1141
0
    p_clut->color_range = COLOR_RANGE_FULL;
1142
0
done:
1143
0
    bs_skip( s, 8 * (i_segment_length - i_processed_length) );
1144
0
}
1145
1146
/* ETSI 300 743 [7.2.1] */
1147
static void decode_display_definition( decoder_t *p_dec, bs_t *s, uint16_t i_segment_length )
1148
0
{
1149
0
    decoder_sys_t *p_sys = p_dec->p_sys;
1150
0
    uint16_t      i_processed_length = 40;
1151
0
    int           i_version;
1152
1153
0
    i_version        = bs_read( s, 4 );
1154
1155
    /* Check version number */
1156
0
    if( p_sys->display.i_version == i_version )
1157
0
    {
1158
        /* The definition did not change */
1159
0
        bs_skip( s, 8*i_segment_length - 4 );
1160
0
        return;
1161
0
    }
1162
1163
#ifdef DEBUG_DVBSUB
1164
    msg_Dbg( p_dec, "new display definition: %i", i_version );
1165
#endif
1166
1167
    /* We don't have this version of the display definition: Parse it */
1168
0
    p_sys->display.i_version = i_version;
1169
0
    p_sys->display.b_windowed = bs_read( s, 1 );
1170
0
    bs_skip( s, 3 ); /* Reserved bits */
1171
0
    p_sys->display.i_width_minus1 = bs_read( s, 16 );
1172
0
    p_sys->display.i_height_minus1 = bs_read( s, 16 );
1173
1174
0
    if( p_sys->display.b_windowed )
1175
0
    {
1176
#ifdef DEBUG_DVBSUB
1177
        msg_Dbg( p_dec, "display definition with offsets (windowed)" );
1178
#endif
1179
        /* Coordinates are measured from the top left corner */
1180
0
        p_sys->display.i_x     = bs_read( s, 16 );
1181
0
        p_sys->display.i_max_x = bs_read( s, 16 );
1182
0
        p_sys->display.i_y     = bs_read( s, 16 );
1183
0
        p_sys->display.i_max_y = bs_read( s, 16 );
1184
0
        i_processed_length += 64;
1185
0
    }
1186
0
    else
1187
0
    {
1188
        /* if not windowed, setup the window variables to good defaults */
1189
        /* not necessary, but to avoid future confusion.. */
1190
0
        p_sys->display.i_x     = 0;
1191
0
        p_sys->display.i_max_x = p_sys->display.i_width_minus1;
1192
0
        p_sys->display.i_y     = 0;
1193
0
        p_sys->display.i_max_y = p_sys->display.i_height_minus1;
1194
0
    }
1195
1196
0
    if( i_processed_length != i_segment_length*8 )
1197
0
    {
1198
0
        msg_Err( p_dec, "processed length %d bytes != segment length %d bytes",
1199
0
                 i_processed_length / 8 , i_segment_length );
1200
0
    }
1201
1202
#ifdef DEBUG_DVBSUB
1203
    msg_Dbg( p_dec, "version: %d, width: %d, height: %d",
1204
             p_sys->display.i_version, (int)p_sys->display.i_width_minus1+1, (int)p_sys->display.i_height_minus1+1 );
1205
    if( p_sys->display.b_windowed )
1206
        msg_Dbg( p_dec, "xmin: %d, xmax: %d, ymin: %d, ymax: %d",
1207
                 p_sys->display.i_x, p_sys->display.i_max_x, p_sys->display.i_y, p_sys->display.i_max_y );
1208
#endif
1209
0
}
1210
1211
static void dvbsub_render_pdata( decoder_t *, dvbsub_region_t *, int, int,
1212
                                 uint8_t *, int );
1213
static void dvbsub_pdata2bpp( bs_t *, uint8_t *, int, int * );
1214
static void dvbsub_pdata4bpp( bs_t *, uint8_t *, int, int * );
1215
static void dvbsub_pdata8bpp( bs_t *, uint8_t *, int, int * );
1216
1217
static void decode_object( decoder_t *p_dec, bs_t *s, uint16_t i_segment_length )
1218
0
{
1219
0
    decoder_sys_t *p_sys = p_dec->p_sys;
1220
0
    dvbsub_region_t *p_region;
1221
0
    int i_coding_method, i_id, i;
1222
1223
    /* ETSI 300-743 v1.5.1 section 7.2.5 'Object data segment'
1224
     * sync_byte, segment_type, page_id and i_segment_length have already been processed.
1225
     */
1226
0
    i_id             = bs_read( s, 16 );
1227
0
    bs_skip( s, 4 ); /* version */
1228
0
    i_coding_method  = bs_read( s, 2 );
1229
1230
0
    if( i_coding_method > 1 )
1231
0
    {
1232
0
        msg_Dbg( p_dec, "unknown DVB subtitling coding %d is not handled!", i_coding_method );
1233
0
        bs_skip( s, 8 * (i_segment_length - 2) - 6 );
1234
0
        return;
1235
0
    }
1236
1237
    /* Check if the object needs to be rendered in at least one
1238
     * of the regions */
1239
0
    for( p_region = p_sys->p_regions; p_region != NULL;
1240
0
         p_region = p_region->p_next )
1241
0
    {
1242
0
        for( i = 0; i < p_region->i_object_defs; i++ )
1243
0
            if( p_region->p_object_defs[i].i_id == i_id ) break;
1244
1245
0
        if( i != p_region->i_object_defs ) break;
1246
0
    }
1247
0
    if( !p_region )
1248
0
    {
1249
0
        bs_skip( s, 8 * (i_segment_length - 2) - 6 );
1250
0
        return;
1251
0
    }
1252
1253
#ifdef DEBUG_DVBSUB
1254
    msg_Dbg( p_dec, "new object: %i", i_id );
1255
#endif
1256
1257
0
    bs_skip( s, 1 ); /* non_modify_color */
1258
0
    bs_skip( s, 1 ); /* Reserved */
1259
1260
0
    if( i_coding_method == 0x00 )
1261
0
    {
1262
0
        int i_topfield, i_bottomfield;
1263
0
        uint8_t *p_topfield, *p_bottomfield;
1264
1265
0
        i_topfield    = bs_read( s, 16 );
1266
0
        i_bottomfield = bs_read( s, 16 );
1267
0
        p_topfield    = s->p_start + bs_pos( s ) / 8;
1268
0
        p_bottomfield = p_topfield + i_topfield;
1269
1270
0
        bs_skip( s, 8 * (i_segment_length - 7) );
1271
1272
        /* Sanity check */
1273
0
        if( ( i_segment_length < ( i_topfield + i_bottomfield + 7 ) ) ||
1274
0
            ( ( p_topfield + i_topfield + i_bottomfield ) > s->p_end ) )
1275
0
        {
1276
0
            msg_Dbg( p_dec, "corrupted object data" );
1277
0
            return;
1278
0
        }
1279
1280
0
        for( p_region = p_sys->p_regions; p_region != NULL;
1281
0
             p_region = p_region->p_next )
1282
0
        {
1283
0
            for( i = 0; i < p_region->i_object_defs; i++ )
1284
0
            {
1285
0
                if( p_region->p_object_defs[i].i_id != i_id ) continue;
1286
1287
0
                dvbsub_render_pdata( p_dec, p_region,
1288
0
                                     p_region->p_object_defs[i].i_x,
1289
0
                                     p_region->p_object_defs[i].i_y,
1290
0
                                     p_topfield, i_topfield );
1291
1292
0
                if( i_bottomfield )
1293
0
                {
1294
0
                    dvbsub_render_pdata( p_dec, p_region,
1295
0
                                         p_region->p_object_defs[i].i_x,
1296
0
                                         p_region->p_object_defs[i].i_y + 1,
1297
0
                                         p_bottomfield, i_bottomfield );
1298
0
                }
1299
0
                else
1300
0
                {
1301
                    /* Duplicate the top field */
1302
0
                    dvbsub_render_pdata( p_dec, p_region,
1303
0
                                         p_region->p_object_defs[i].i_x,
1304
0
                                         p_region->p_object_defs[i].i_y + 1,
1305
0
                                         p_topfield, i_topfield );
1306
0
                }
1307
0
            }
1308
0
        }
1309
0
    }
1310
0
    else
1311
0
    {
1312
        /* DVB subtitling as characters */
1313
0
        int i_number_of_codes = bs_read( s, 8 );
1314
0
        uint8_t* p_start = s->p_start + bs_pos( s ) / 8;
1315
1316
        /* Sanity check */
1317
0
        if( ( i_segment_length < ( i_number_of_codes*2 + 4 ) ) ||
1318
0
            ( ( p_start + i_number_of_codes*2 ) > s->p_end ) )
1319
0
        {
1320
0
            msg_Dbg( p_dec, "corrupted object data" );
1321
0
            return;
1322
0
        }
1323
1324
0
        for( p_region = p_sys->p_regions; p_region != NULL;
1325
0
             p_region = p_region->p_next )
1326
0
        {
1327
0
            for( i = 0; i < p_region->i_object_defs; i++ )
1328
0
            {
1329
0
                int j;
1330
1331
0
                if( p_region->p_object_defs[i].i_id != i_id ) continue;
1332
1333
0
                p_region->p_object_defs[i].psz_text =
1334
0
                    xrealloc( p_region->p_object_defs[i].psz_text,
1335
0
                             i_number_of_codes + 1 );
1336
1337
                /* FIXME 16bits -> char ??? See Preamble */
1338
0
                for( j = 0; j < i_number_of_codes; j++ )
1339
0
                {
1340
0
                    p_region->p_object_defs[i].psz_text[j] = (char)(bs_read( s, 16 ) & 0xFF);
1341
0
                }
1342
                /* Null terminate the string */
1343
0
                p_region->p_object_defs[i].psz_text[j] = 0;
1344
0
            }
1345
0
        }
1346
0
    }
1347
1348
#ifdef DEBUG_DVBSUB
1349
    msg_Dbg( p_dec, "end object: %i", i_id );
1350
#endif
1351
0
}
1352
1353
static void dvbsub_render_pdata( decoder_t *p_dec, dvbsub_region_t *p_region,
1354
                                 int i_x, int i_y,
1355
                                 uint8_t *p_field, int i_field )
1356
0
{
1357
0
    uint8_t *p_pixbuf;
1358
0
    int i_offset = 0;
1359
0
    bs_t bs;
1360
1361
    /* Sanity check */
1362
0
    if( !p_region->p_pixbuf )
1363
0
    {
1364
0
        msg_Err( p_dec, "region %i has no pixel buffer!", p_region->i_id );
1365
0
        return;
1366
0
    }
1367
0
    if( i_y < 0 || i_x < 0 || i_y >= p_region->i_height ||
1368
0
        i_x >= p_region->i_width )
1369
0
    {
1370
0
        msg_Dbg( p_dec, "invalid offset (%i,%i)", i_x, i_y );
1371
0
        return;
1372
0
    }
1373
1374
0
    p_pixbuf = p_region->p_pixbuf + i_y * p_region->i_width;
1375
0
    bs_init( &bs, p_field, i_field );
1376
1377
0
    while( !bs_eof( &bs ) )
1378
0
    {
1379
        /* Sanity check */
1380
0
        if( i_y >= p_region->i_height ) return;
1381
1382
0
        switch( bs_read( &bs, 8 ) )
1383
0
        {
1384
0
        case 0x10:
1385
0
            dvbsub_pdata2bpp( &bs, p_pixbuf + i_x, p_region->i_width - i_x,
1386
0
                              &i_offset );
1387
0
            break;
1388
1389
0
        case 0x11:
1390
0
            dvbsub_pdata4bpp( &bs, p_pixbuf + i_x, p_region->i_width - i_x,
1391
0
                              &i_offset );
1392
0
            break;
1393
1394
0
        case 0x12:
1395
0
            dvbsub_pdata8bpp( &bs, p_pixbuf + i_x, p_region->i_width - i_x,
1396
0
                              &i_offset );
1397
0
            break;
1398
1399
0
        case 0x20:
1400
0
        case 0x21:
1401
0
        case 0x22:
1402
            /* We don't use map tables */
1403
0
            break;
1404
1405
0
        case 0xf0: /* End of line code */
1406
0
            p_pixbuf += 2*p_region->i_width;
1407
0
            i_offset = 0; i_y += 2;
1408
0
            break;
1409
0
        }
1410
0
    }
1411
0
}
1412
1413
static void dvbsub_pdata2bpp( bs_t *s, uint8_t *p, int i_width, int *pi_off )
1414
0
{
1415
0
    bool b_stop = false;
1416
1417
0
    while( !b_stop && !bs_eof( s ) )
1418
0
    {
1419
0
        int i_count = 0, i_color = 0;
1420
1421
0
        i_color = bs_read( s, 2 );
1422
0
        if( i_color != 0x00 )
1423
0
        {
1424
0
            i_count = 1;
1425
0
        }
1426
0
        else
1427
0
        {
1428
0
            if( bs_read( s, 1 ) == 0x01 )         // Switch1
1429
0
            {
1430
0
                i_count = 3 + bs_read( s, 3 );
1431
0
                i_color = bs_read( s, 2 );
1432
0
            }
1433
0
            else
1434
0
            {
1435
0
                if( bs_read( s, 1 ) == 0x00 )     //Switch2
1436
0
                {
1437
0
                    switch( bs_read( s, 2 ) )     //Switch3
1438
0
                    {
1439
0
                    case 0x00:
1440
0
                        b_stop = true;
1441
0
                        break;
1442
0
                    case 0x01:
1443
0
                        i_count = 2;
1444
0
                        break;
1445
0
                    case 0x02:
1446
0
                        i_count =  12 + bs_read( s, 4 );
1447
0
                        i_color = bs_read( s, 2 );
1448
0
                        break;
1449
0
                    case 0x03:
1450
0
                        i_count =  29 + bs_read( s, 8 );
1451
0
                        i_color = bs_read( s, 2 );
1452
0
                        break;
1453
0
                    default:
1454
0
                        break;
1455
0
                    }
1456
0
                }
1457
0
                else
1458
0
                {
1459
                    /* 1 pixel color 0 */
1460
0
                    i_count = 1;
1461
0
                }
1462
0
            }
1463
0
        }
1464
1465
0
        if( !i_count ) continue;
1466
1467
        /* Sanity check */
1468
0
        if( ( i_count + *pi_off ) > i_width ) break;
1469
1470
0
        if( i_count == 1 ) p[*pi_off] = i_color;
1471
0
        else memset( ( p + *pi_off ), i_color, i_count );
1472
1473
0
        (*pi_off) += i_count;
1474
0
    }
1475
1476
0
    bs_align( s );
1477
0
}
1478
1479
static void dvbsub_pdata4bpp( bs_t *s, uint8_t *p, int i_width, int *pi_off )
1480
0
{
1481
0
    bool b_stop = false;
1482
1483
0
    while( !b_stop && !bs_eof( s ) )
1484
0
    {
1485
0
        int i_count = 0, i_color = 0;
1486
1487
0
        i_color = bs_read( s, 4 );
1488
0
        if( i_color != 0x00 )
1489
0
        {
1490
            /* Add 1 pixel */
1491
0
            i_count = 1;
1492
0
        }
1493
0
        else
1494
0
        {
1495
0
            if( bs_read( s, 1 ) == 0x00 )           // Switch1
1496
0
            {
1497
0
                i_count = bs_read( s, 3 );
1498
0
                if( i_count != 0x00 )
1499
0
                {
1500
0
                    i_count += 2;
1501
0
                }
1502
0
                else b_stop = true;
1503
0
            }
1504
0
            else
1505
0
            {
1506
0
                if( bs_read( s, 1 ) == 0x00)        //Switch2
1507
0
                {
1508
0
                    i_count =  4 + bs_read( s, 2 );
1509
0
                    i_color = bs_read( s, 4 );
1510
0
                }
1511
0
                else
1512
0
                {
1513
0
                    switch ( bs_read( s, 2 ) )     //Switch3
1514
0
                    {
1515
0
                    case 0x0:
1516
0
                        i_count = 1;
1517
0
                        break;
1518
0
                    case 0x1:
1519
0
                        i_count = 2;
1520
0
                        break;
1521
0
                    case 0x2:
1522
0
                        i_count = 9 + bs_read( s, 4 );
1523
0
                        i_color = bs_read( s, 4 );
1524
0
                        break;
1525
0
                    case 0x3:
1526
0
                        i_count= 25 + bs_read( s, 8 );
1527
0
                        i_color = bs_read( s, 4 );
1528
0
                        break;
1529
0
                    }
1530
0
                }
1531
0
            }
1532
0
        }
1533
1534
0
        if( !i_count ) continue;
1535
1536
        /* Sanity check */
1537
0
        if( ( i_count + *pi_off ) > i_width ) break;
1538
1539
0
        if( i_count == 1 ) p[*pi_off] = i_color;
1540
0
        else memset( ( p + *pi_off ), i_color, i_count );
1541
1542
0
        (*pi_off) += i_count;
1543
0
    }
1544
1545
0
    bs_align( s );
1546
0
}
1547
1548
static void dvbsub_pdata8bpp( bs_t *s, uint8_t *p, int i_width, int *pi_off )
1549
0
{
1550
0
    bool b_stop = false;
1551
1552
0
    while( !b_stop && !bs_eof( s ) )
1553
0
    {
1554
0
        int i_count = 0, i_color = 0;
1555
1556
0
        i_color = bs_read( s, 8 );
1557
0
        if( i_color != 0x00 )
1558
0
        {
1559
            /* Add 1 pixel */
1560
0
            i_count = 1;
1561
0
        }
1562
0
        else
1563
0
        {
1564
0
            if( bs_read( s, 1 ) == 0x00 )           // Switch1
1565
0
            {
1566
0
                i_count = bs_read( s, 7 );
1567
0
                if( i_count == 0x00 )
1568
0
                    b_stop = true;
1569
0
            }
1570
0
            else
1571
0
            {
1572
0
                i_count = bs_read( s, 7 );
1573
0
                i_color = bs_read( s, 8 );
1574
0
            }
1575
0
        }
1576
1577
0
        if( !i_count ) continue;
1578
1579
        /* Sanity check */
1580
0
        if( ( i_count + *pi_off ) > i_width ) break;
1581
1582
0
        if( i_count == 1 ) p[*pi_off] = i_color;
1583
0
        else memset( ( p + *pi_off ), i_color, i_count );
1584
1585
0
        (*pi_off) += i_count;
1586
0
    }
1587
1588
0
    bs_align( s );
1589
0
}
1590
1591
static void free_all( decoder_t *p_dec )
1592
1
{
1593
1
    decoder_sys_t *p_sys = p_dec->p_sys;
1594
1
    dvbsub_region_t *p_reg, *p_reg_next;
1595
1
    dvbsub_clut_t *p_clut, *p_clut_next;
1596
1597
    /*free( p_sys->p_display ); No longer malloced */
1598
1599
1
    for( p_clut = p_sys->p_cluts; p_clut != NULL; p_clut = p_clut_next )
1600
0
    {
1601
0
        p_clut_next = p_clut->p_next;
1602
0
        free( p_clut );
1603
0
    }
1604
1
    p_sys->p_cluts = NULL;
1605
1606
1
    for( p_reg = p_sys->p_regions; p_reg != NULL; p_reg = p_reg_next )
1607
0
    {
1608
0
        p_reg_next = p_reg->p_next;
1609
0
        for( int i = 0; i < p_reg->i_object_defs; i++ )
1610
0
            free( p_reg->p_object_defs[i].psz_text );
1611
0
        if( p_reg->i_object_defs ) free( p_reg->p_object_defs );
1612
0
        free( p_reg->p_pixbuf );
1613
0
        free( p_reg );
1614
0
    }
1615
1
    p_sys->p_regions = NULL;
1616
1617
1
    if( p_sys->p_page )
1618
0
    {
1619
0
        if( p_sys->p_page->i_region_defs )
1620
0
            free( p_sys->p_page->p_region_defs );
1621
0
        free( p_sys->p_page );
1622
0
    }
1623
1
    p_sys->p_page = NULL;
1624
1
}
1625
1626
static subpicture_t *render( decoder_t *p_dec )
1627
0
{
1628
0
    decoder_sys_t *p_sys = p_dec->p_sys;
1629
0
    subpicture_t *p_spu;
1630
0
    int i, j;
1631
0
    int i_base_x;
1632
0
    int i_base_y;
1633
1634
0
    if ( p_sys->p_page == NULL)
1635
0
    {
1636
0
        return NULL;
1637
0
    }
1638
1639
    /* Allocate the subpicture internal data. */
1640
0
    p_spu = decoder_NewSubpicture( p_dec, NULL );
1641
0
    if( !p_spu )
1642
0
        return NULL;
1643
1644
    /* Set the pf_render callback */
1645
0
    p_spu->i_start = p_sys->i_pts;
1646
    //p_spu->i_stop = (vlc_tick_t) 0;
1647
0
    p_spu->b_ephemer = true;
1648
    //p_spu->b_fade = true;
1649
    //p_spu->i_stop = p_spu->i_start + (vlc_tick_t) (i_timeout * 1000000);
1650
0
    p_spu->b_subtitle = true;
1651
1652
    /* Correct positioning of SPU */
1653
0
    i_base_x = p_sys->i_spu_x;
1654
0
    i_base_y = p_sys->i_spu_y;
1655
1656
0
    p_spu->i_original_picture_width = (unsigned)p_sys->display.i_width_minus1 + 1;
1657
0
    p_spu->i_original_picture_height = (unsigned)p_sys->display.i_height_minus1 + 1;
1658
1659
0
    if( p_sys->display.b_windowed )
1660
0
    {
1661
        /* From en_300743v01 - */
1662
        /* the DDS is there to indicate intended size/position of text */
1663
        /* the intended video area is ->i_width/height */
1664
        /* the window is within this... SO... we should leave i_original_picture_width etc. as is */
1665
        /* and ONLY change i_base_x.  effectively i_max_x/y are only there to limit memory requirements*/
1666
        /* we COULD use the upper limits to limit rendering to within these? */
1667
1668
        /* see notes on DDS at the top of the file */
1669
0
        i_base_x += p_sys->display.i_x;
1670
0
        i_base_y += p_sys->display.i_y;
1671
0
    }
1672
1673
    /* Loop on region definitions */
1674
#ifdef DEBUG_DVBSUB
1675
    msg_Dbg( p_dec, "rendering %i regions", p_sys->p_page->i_region_defs );
1676
#endif
1677
1678
0
    for( i = 0; i < p_sys->p_page->i_region_defs; i++ )
1679
0
    {
1680
0
        dvbsub_region_t     *p_region;
1681
0
        dvbsub_regiondef_t  *p_regiondef;
1682
0
        dvbsub_clut_t       *p_clut;
1683
0
        dvbsub_color_t      *p_color;
1684
0
        subpicture_region_t *p_spu_region;
1685
0
        uint8_t *p_src, *p_dst;
1686
0
        video_format_t fmt;
1687
0
        video_palette_t palette;
1688
0
        int i_pitch;
1689
1690
0
        p_regiondef = &p_sys->p_page->p_region_defs[i];
1691
1692
        /* Find associated region */
1693
0
        for( p_region = p_sys->p_regions; p_region != NULL;
1694
0
             p_region = p_region->p_next )
1695
0
        {
1696
0
            if( p_regiondef->i_id == p_region->i_id ) break;
1697
0
        }
1698
1699
#ifdef DEBUG_DVBSUB
1700
        /* if a region exists, then print it's size */
1701
        if (p_region)
1702
        {
1703
                msg_Dbg( p_dec, "rendering region %i (%i,%i) to (%i,%i)", i,
1704
                        p_regiondef->i_x, p_regiondef->i_y,
1705
                p_regiondef->i_x + p_region->i_width,
1706
                p_regiondef->i_y + p_region->i_height );
1707
        }
1708
        else
1709
        {
1710
                msg_Dbg( p_dec, "rendering region %i (%i,%i) (no region matched to render)", i,
1711
                      p_regiondef->i_x, p_regiondef->i_y );
1712
        }
1713
#endif
1714
1715
0
        if( !p_region )
1716
0
        {
1717
0
            msg_Dbg( p_dec, "region %i not found", p_regiondef->i_id );
1718
0
            continue;
1719
0
        }
1720
1721
        /* Find associated CLUT */
1722
0
        for( p_clut = p_sys->p_cluts; p_clut != NULL; p_clut = p_clut->p_next )
1723
0
        {
1724
0
            if( p_region->i_clut == p_clut->i_id ) break;
1725
0
        }
1726
0
        if( !p_clut )
1727
0
        {
1728
0
            msg_Dbg( p_dec, "clut %i not found", p_region->i_clut );
1729
0
            continue;
1730
0
        }
1731
1732
        /* FIXME: don't create a subpicture region with VLC CODEC YUVP
1733
         * when it actually is a TEXT region */
1734
1735
        /* Create new SPU region */
1736
0
        video_format_Init( &fmt, VLC_CODEC_YUVP );
1737
0
        fmt.i_sar_num = 0; /* 0 means use aspect ratio of background video */
1738
0
        fmt.i_sar_den = 1;
1739
0
        fmt.i_width = fmt.i_visible_width = p_region->i_width;
1740
0
        fmt.i_height = fmt.i_visible_height = p_region->i_height;
1741
0
        fmt.i_x_offset = fmt.i_y_offset = 0;
1742
0
        fmt.p_palette = &palette;
1743
0
        fmt.p_palette->i_entries = ( p_region->i_depth == 1 ) ? 4 :
1744
0
            ( ( p_region->i_depth == 2 ) ? 16 : p_clut->c_8b_entries );
1745
0
        p_color = ( p_region->i_depth == 1 ) ? p_clut->c_2b :
1746
0
            ( ( p_region->i_depth == 2 ) ? p_clut->c_4b : p_clut->c_8b );
1747
0
        for( j = 0; j < fmt.p_palette->i_entries; j++ )
1748
0
        {
1749
0
            fmt.p_palette->palette[j][0] = p_color[j].Y;
1750
0
            fmt.p_palette->palette[j][1] = p_color[j].Cb; /* U == Cb */
1751
0
            fmt.p_palette->palette[j][2] = p_color[j].Cr; /* V == Cr */
1752
0
            fmt.p_palette->palette[j][3] = 0xff - p_color[j].T;
1753
0
        }
1754
0
        switch (p_clut->dynamic_range_and_colour_gamut)
1755
0
        {
1756
0
            case DVBSUB_ST_COLORIMETRY_CDS:
1757
0
                fmt.space = COLOR_SPACE_BT601;
1758
0
                fmt.primaries = COLOR_PRIMARIES_BT601_525;
1759
0
                fmt.transfer = TRANSFER_FUNC_BT709;
1760
0
                break;
1761
0
            case DVBSUB_ST_COLORIMETRY_SDR_709:
1762
0
                fmt.space = COLOR_SPACE_BT709;
1763
0
                fmt.primaries = COLOR_PRIMARIES_BT709;
1764
0
                fmt.transfer = TRANSFER_FUNC_BT709;
1765
0
                break;
1766
0
            case DVBSUB_ST_COLORIMETRY_SDR_2020:
1767
0
                fmt.space = COLOR_SPACE_BT2020;
1768
0
                fmt.primaries = COLOR_PRIMARIES_BT2020;
1769
0
                fmt.transfer = TRANSFER_FUNC_BT709;
1770
0
                break;
1771
0
            case DVBSUB_ST_COLORIMETRY_HDR_PQ:
1772
0
                fmt.space = COLOR_SPACE_BT2020;
1773
0
                fmt.primaries = COLOR_PRIMARIES_BT2020;
1774
0
                fmt.transfer = TRANSFER_FUNC_SMPTE_ST2084;
1775
0
                break;
1776
0
            case DVBSUB_ST_COLORIMETRY_HDR_HLG:
1777
0
                fmt.space = COLOR_SPACE_BT2020;
1778
0
                fmt.primaries = COLOR_PRIMARIES_BT2020;
1779
0
                fmt.transfer = TRANSFER_FUNC_HLG;
1780
0
                break;
1781
0
        }
1782
0
        fmt.color_range = p_clut->color_range;
1783
1784
0
        p_spu_region = subpicture_region_New( &fmt );
1785
0
        fmt.p_palette = NULL; /* was stack var */
1786
0
        video_format_Clean( &fmt );
1787
0
        if( !p_spu_region )
1788
0
        {
1789
0
            msg_Err( p_dec, "cannot allocate SPU region" );
1790
0
            continue;
1791
0
        }
1792
0
        p_spu_region->b_absolute = true; p_spu_region->b_in_window = false;
1793
0
        p_spu_region->i_x = i_base_x + p_regiondef->i_x;
1794
0
        p_spu_region->i_y = i_base_y + p_regiondef->i_y;
1795
0
        p_spu_region->i_align = p_sys->i_spu_position;
1796
0
        vlc_spu_regions_push(&p_spu->regions, p_spu_region);
1797
1798
0
        p_src = p_region->p_pixbuf;
1799
0
        p_dst = p_spu_region->p_picture->Y_PIXELS;
1800
0
        i_pitch = p_spu_region->p_picture->Y_PITCH;
1801
1802
        /* Copy pixel buffer */
1803
0
        for( j = 0; j < p_region->i_height; j++ )
1804
0
        {
1805
0
            memcpy( p_dst, p_src, p_region->i_width );
1806
0
            p_src += p_region->i_width;
1807
0
            p_dst += i_pitch;
1808
0
        }
1809
1810
        /* Check subtitles encoded as strings of characters
1811
         * (since there are not rendered in the pixbuffer) */
1812
0
        for( j = 0; j < p_region->i_object_defs; j++ )
1813
0
        {
1814
0
            dvbsub_objectdef_t *p_object_def = &p_region->p_object_defs[j];
1815
1816
0
            if( ( p_object_def->i_type != 1 ) || !p_object_def->psz_text )
1817
0
                continue;
1818
1819
            /* Create new SPU region */
1820
0
            p_spu_region = subpicture_region_NewText();
1821
0
            if( !p_spu_region )
1822
0
            {
1823
0
                msg_Err( p_dec, "cannot allocate SPU region" );
1824
0
                continue;
1825
0
            }
1826
1827
0
            p_spu_region->fmt.i_sar_num = 1;
1828
0
            p_spu_region->fmt.i_sar_den = 1;
1829
0
            p_spu_region->fmt.i_width = p_spu_region->fmt.i_visible_width = p_region->i_width;
1830
0
            p_spu_region->fmt.i_height = p_spu_region->fmt.i_visible_height = p_region->i_height;
1831
1832
0
            p_spu_region->p_text = text_segment_New( p_object_def->psz_text );
1833
0
            p_spu_region->b_absolute = true; p_spu_region->b_in_window = false;
1834
0
            p_spu_region->i_x = i_base_x + p_regiondef->i_x + p_object_def->i_x;
1835
0
            p_spu_region->i_y = i_base_y + p_regiondef->i_y + p_object_def->i_y;
1836
0
            p_spu_region->i_align = p_sys->i_spu_position;
1837
0
            vlc_spu_regions_push(&p_spu->regions, p_spu_region);
1838
0
        }
1839
0
    }
1840
1841
0
    return p_spu;
1842
0
}
1843
1844
/*****************************************************************************
1845
 * encoder_sys_t : encoder descriptor
1846
 *****************************************************************************/
1847
typedef struct encoder_region_t
1848
{
1849
    int i_width;
1850
    int i_height;
1851
1852
} encoder_region_t;
1853
1854
typedef struct
1855
{
1856
    unsigned int i_page_ver;
1857
    unsigned int i_region_ver;
1858
    unsigned int i_clut_ver;
1859
1860
    size_t           i_regions;
1861
    encoder_region_t *p_regions;
1862
1863
    vlc_tick_t i_pts;
1864
1865
    /* subpicture positioning */
1866
    int i_offset_x;
1867
    int i_offset_y;
1868
} encoder_sys_t;
1869
1870
#ifdef ENABLE_SOUT
1871
static void encode_page_composition( encoder_t *, bs_t *, const subpicture_t * );
1872
static void encode_clut( encoder_t *, bs_t *, subpicture_region_t * );
1873
static void encode_region_composition( encoder_t *, bs_t *, const subpicture_t * );
1874
static void encode_object( encoder_t *, bs_t *, const subpicture_t * );
1875
1876
/*****************************************************************************
1877
 * OpenEncoder: probe the encoder and return score
1878
 *****************************************************************************/
1879
static int OpenEncoder( vlc_object_t *p_this )
1880
0
{
1881
0
    encoder_t *p_enc = (encoder_t *)p_this;
1882
0
    encoder_sys_t *p_sys;
1883
1884
0
    if( ( p_enc->fmt_out.i_codec != VLC_CODEC_DVBS ) &&
1885
0
        !p_enc->obj.force )
1886
0
    {
1887
0
        return VLC_EGENERIC;
1888
0
    }
1889
1890
    /* Allocate the memory needed to store the decoder's structure */
1891
0
    p_sys = malloc(sizeof(encoder_sys_t));
1892
0
    if (p_sys == NULL)
1893
0
        return VLC_ENOMEM;
1894
0
    p_enc->p_sys = p_sys;
1895
1896
0
    p_enc->fmt_out.i_codec = VLC_CODEC_DVBS;
1897
0
    p_enc->fmt_out.subs.dvb.i_id  = 1 << 16 | 1;
1898
1899
0
    config_ChainParse( p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg );
1900
1901
0
    p_sys->i_page_ver = 0;
1902
0
    p_sys->i_region_ver = 0;
1903
0
    p_sys->i_clut_ver = 0;
1904
0
    p_sys->i_regions = 0;
1905
0
    p_sys->p_regions = 0;
1906
1907
0
    p_sys->i_offset_x = var_CreateGetInteger( p_this, ENC_CFG_PREFIX "x" );
1908
0
    p_sys->i_offset_y = var_CreateGetInteger( p_this, ENC_CFG_PREFIX "y" );
1909
1910
0
    static const struct vlc_encoder_operations ops =
1911
0
    {
1912
0
        .close = CloseEncoder,
1913
0
        .encode_sub = Encode,
1914
0
    };
1915
0
    p_enc->ops = &ops;
1916
1917
0
    return VLC_SUCCESS;
1918
0
}
1919
1920
/* FIXME: this routine is a hack to convert VLC_CODEC_YUVA
1921
 *        into VLC_CODEC_YUVP
1922
 */
1923
static void YuvaYuvp( subpicture_t *p_subpic )
1924
0
{
1925
0
    const subpicture_region_t *p_region;
1926
1927
0
    vlc_spu_regions_foreach_const(p_region, &p_subpic->regions)
1928
0
    {
1929
0
        video_format_t *p_fmt = &p_region->p_picture->format;
1930
0
        int i = 0, j = 0, n = 0, p = 0;
1931
0
        int i_max_entries = 256;
1932
1933
#ifdef RANDOM_DITHERING
1934
        int i_seed = 0xdeadbeef; /* random seed */
1935
#else
1936
0
        int *pi_delta;
1937
0
#endif
1938
0
        int i_pixels = p_region->p_picture->p[0].i_visible_lines
1939
0
                        * p_region->p_picture->Y_PITCH;
1940
0
        int i_iterator = p_region->p_picture->p[0].i_visible_lines * 3 / 4
1941
0
                            * p_region->p_picture->Y_PITCH
1942
0
                        + p_region->p_picture->Y_PITCH * 1 / 3;
1943
0
        int i_tolerance = 0;
1944
1945
#ifdef DEBUG_DVBSUB1
1946
        /* p_enc not valid here */
1947
        msg_Dbg( p_enc, "YuvaYuvp: i_pixels=%d, i_iterator=%d", i_pixels, i_iterator );
1948
#endif
1949
0
        p_fmt->i_chroma = VLC_CODEC_YUVP;
1950
0
        p_fmt->p_palette = (video_palette_t *) malloc( sizeof( video_palette_t ) );
1951
0
        if( !p_fmt->p_palette ) break;
1952
0
        p_fmt->p_palette->i_entries = 0;
1953
1954
        /* Find best iterator using Euclide’s algorithm */
1955
0
        for( ; i_iterator > 1 ; i_iterator-- )
1956
0
        {
1957
0
            int a = i_pixels;
1958
0
            int b = i_iterator;
1959
0
            int c;
1960
1961
0
            while( b )
1962
0
            {
1963
0
                c = a % b;
1964
0
                a = b;
1965
0
                b = c;
1966
0
            }
1967
1968
0
            if( a == 1 )
1969
0
            {
1970
0
                break;
1971
0
            }
1972
0
        }
1973
1974
        /* Count colors, build best palette */
1975
0
        for( i_tolerance = 0; i_tolerance < 128; i_tolerance++ )
1976
0
        {
1977
0
            bool b_success = true;
1978
0
            p_fmt->p_palette->i_entries = 0;
1979
1980
0
            for( i = 0; i < i_pixels ; )
1981
0
            {
1982
0
                uint8_t y, u, v, a;
1983
0
                y = p_region->p_picture->Y_PIXELS[i];
1984
0
                u = p_region->p_picture->U_PIXELS[i];
1985
0
                v = p_region->p_picture->V_PIXELS[i];
1986
0
                a = p_region->p_picture->A_PIXELS[i];
1987
0
                for( j = 0; j < p_fmt->p_palette->i_entries; j++ )
1988
0
                {
1989
0
                    if( abs((int)p_fmt->p_palette->palette[j][0] - (int)y) <= i_tolerance &&
1990
0
                        abs((int)p_fmt->p_palette->palette[j][1] - (int)u) <= i_tolerance &&
1991
0
                        abs((int)p_fmt->p_palette->palette[j][2] - (int)v) <= i_tolerance &&
1992
0
                        abs((int)p_fmt->p_palette->palette[j][3] - (int)a) <= i_tolerance / 2 )
1993
0
                    {
1994
0
                        break;
1995
0
                    }
1996
0
                }
1997
0
                if( j == p_fmt->p_palette->i_entries )
1998
0
                {
1999
0
                    p_fmt->p_palette->palette[j][0] = y;
2000
0
                    p_fmt->p_palette->palette[j][1] = u;
2001
0
                    p_fmt->p_palette->palette[j][2] = v;
2002
0
                    p_fmt->p_palette->palette[j][3] = a;
2003
0
                    p_fmt->p_palette->i_entries++;
2004
0
                }
2005
0
                if( p_fmt->p_palette->i_entries >= i_max_entries )
2006
0
                {
2007
0
                    b_success = false;
2008
0
                    break;
2009
0
                }
2010
0
                i += i_iterator;
2011
0
                if( i > i_pixels )
2012
0
                {
2013
0
                    i -= i_pixels;
2014
0
                }
2015
0
            }
2016
2017
0
            if( b_success )
2018
0
            {
2019
0
                break;
2020
0
            }
2021
0
        }
2022
2023
#ifdef DEBUG_DVBSUB1
2024
        /* p_enc not valid here */
2025
        msg_Dbg( p_enc, "best palette has %d colors", p_fmt->p_palette->i_entries );
2026
#endif
2027
2028
0
#ifndef RANDOM_DITHERING
2029
0
        pi_delta = calloc( ( p_region->p_picture->Y_PITCH + 1 ) * 4, sizeof(int) );
2030
0
        if (unlikely(pi_delta == NULL))
2031
0
            return;
2032
0
#endif
2033
2034
        /* Fill image with our new colours */
2035
0
        for( p = 0; p < p_region->p_picture->p[0].i_visible_lines ; p++ )
2036
0
        {
2037
0
            int i_ydelta = 0, i_udelta = 0, i_vdelta = 0, i_adelta = 0;
2038
2039
0
            for( n = 0; n < p_region->p_picture->Y_PITCH ; n++ )
2040
0
            {
2041
0
                int i_offset = p * p_region->p_picture->Y_PITCH + n;
2042
0
                int y, u, v, a;
2043
0
                int i_mindist, i_best;
2044
2045
0
                y = p_region->p_picture->Y_PIXELS[i_offset];
2046
0
                u = p_region->p_picture->U_PIXELS[i_offset];
2047
0
                v = p_region->p_picture->V_PIXELS[i_offset];
2048
0
                a = p_region->p_picture->A_PIXELS[i_offset];
2049
2050
                /* Add dithering compensation */
2051
#ifdef RANDOM_DITHERING
2052
                y += ((i_seed & 0xff) - 0x80) * i_tolerance / 0x80;
2053
                u += (((i_seed >> 8) & 0xff) - 0x80) * i_tolerance / 0x80;
2054
                v += (((i_seed >> 16) & 0xff) - 0x80) * i_tolerance / 0x80;
2055
                a += (((i_seed >> 24) & 0xff) - 0x80) * i_tolerance / 0x80;
2056
#else
2057
0
                y += i_ydelta + pi_delta[ n * 4 + 0 ];
2058
0
                u += i_udelta + pi_delta[ n * 4 + 1 ];
2059
0
                v += i_vdelta + pi_delta[ n * 4 + 2 ];
2060
0
                a += i_adelta + pi_delta[ n * 4 + 3 ];
2061
0
#endif
2062
2063
                /* Find best colour in palette */
2064
0
                for( i_mindist = INT_MAX, i_best = 0, j = 0; j < p_fmt->p_palette->i_entries; j++ )
2065
0
                {
2066
0
                    int i_dist = 0;
2067
2068
0
                    i_dist += abs((int)p_fmt->p_palette->palette[j][0] - y);
2069
0
                    i_dist += abs((int)p_fmt->p_palette->palette[j][1] - u);
2070
0
                    i_dist += abs((int)p_fmt->p_palette->palette[j][2] - v);
2071
0
                    i_dist += 2 * abs((int)p_fmt->p_palette->palette[j][3] - a);
2072
2073
0
                    if( i_dist < i_mindist )
2074
0
                    {
2075
0
                        i_mindist = i_dist;
2076
0
                        i_best = j;
2077
0
                    }
2078
0
                }
2079
2080
                /* Set pixel to best color */
2081
0
                p_region->p_picture->Y_PIXELS[i_offset] = i_best;
2082
2083
                /* Update dithering state */
2084
#ifdef RANDOM_DITHERING
2085
                i_seed = (i_seed * 0x1283837) ^ 0x789479 ^ (i_seed >> 13);
2086
#else
2087
0
                i_ydelta = y - (int)p_fmt->p_palette->palette[i_best][0];
2088
0
                i_udelta = u - (int)p_fmt->p_palette->palette[i_best][1];
2089
0
                i_vdelta = v - (int)p_fmt->p_palette->palette[i_best][2];
2090
0
                i_adelta = a - (int)p_fmt->p_palette->palette[i_best][3];
2091
0
                pi_delta[ n * 4 + 0 ] = i_ydelta * 3 / 8;
2092
0
                pi_delta[ n * 4 + 1 ] = i_udelta * 3 / 8;
2093
0
                pi_delta[ n * 4 + 2 ] = i_vdelta * 3 / 8;
2094
0
                pi_delta[ n * 4 + 3 ] = i_adelta * 3 / 8;
2095
0
                i_ydelta = i_ydelta * 5 / 8;
2096
0
                i_udelta = i_udelta * 5 / 8;
2097
0
                i_vdelta = i_vdelta * 5 / 8;
2098
0
                i_adelta = i_adelta * 5 / 8;
2099
0
#endif
2100
0
            }
2101
0
        }
2102
0
#ifndef RANDOM_DITHERING
2103
0
        free( pi_delta );
2104
0
#endif
2105
2106
        /* pad palette */
2107
0
        for( i = p_fmt->p_palette->i_entries; i < i_max_entries; i++ )
2108
0
            memset(p_fmt->p_palette->palette[i], 0, sizeof(p_fmt->p_palette->palette[i]));
2109
0
        p_fmt->p_palette->i_entries = i_max_entries;
2110
#ifdef DEBUG_DVBSUB1
2111
        /* p_enc not valid here */
2112
        msg_Dbg( p_enc, "best palette has %d colors", p_fmt->p_palette->i_entries );
2113
#endif
2114
0
    }
2115
0
} /* End of hack */
2116
2117
/****************************************************************************
2118
 * Encode: the whole thing
2119
 ****************************************************************************/
2120
static block_t *Encode( encoder_t *p_enc, subpicture_t *p_subpic )
2121
0
{
2122
0
    subpicture_region_t *p_region = NULL;
2123
0
    bs_t bits, *s = &bits;
2124
0
    block_t *p_block;
2125
2126
0
    if( !p_subpic || vlc_spu_regions_is_empty(&p_subpic->regions) ) return NULL;
2127
2128
    /* FIXME: this is a hack to convert VLC_CODEC_YUVA into
2129
     *  VLC_CODEC_YUVP
2130
     */
2131
0
    p_region = vlc_spu_regions_first_or_null(&p_subpic->regions);
2132
    /* Sanity check */
2133
0
    if( !p_region ) return NULL;
2134
2135
0
    if( !subpicture_region_IsText( p_region ) )
2136
0
    {
2137
0
        if( p_region->p_picture->format.i_chroma == VLC_CODEC_YUVA )
2138
0
        {
2139
0
            YuvaYuvp( p_subpic );
2140
0
        }
2141
2142
0
        if( p_region->p_picture->format.i_chroma != VLC_CODEC_YUVP )
2143
0
        {
2144
0
            msg_Err( p_enc, "chroma %4.4s not supported", (char *)&p_region->p_picture->format.i_chroma );
2145
0
            return NULL;
2146
0
        }
2147
2148
0
        if( p_region->p_picture->format.p_palette )
2149
0
        {
2150
0
            switch( p_region->p_picture->format.p_palette->i_entries )
2151
0
            {
2152
0
                case 0:
2153
0
                case 4:
2154
0
                case 16:
2155
0
                case 256:
2156
0
                    break;
2157
0
                default:
2158
0
                    msg_Err( p_enc, "subpicture palette (%d) not handled",
2159
0
                                p_region->p_picture->format.p_palette->i_entries );
2160
0
                    return NULL;
2161
0
            }
2162
0
        }
2163
0
    }
2164
    /* End of hack */
2165
2166
#ifdef DEBUG_DVBSUB
2167
    msg_Dbg( p_enc, "encoding subpicture" );
2168
#endif
2169
0
    p_block = block_Alloc( 64000 );
2170
0
    if( unlikely(p_block == NULL) )
2171
0
        return NULL;
2172
2173
0
    bs_init( s, p_block->p_buffer, p_block->i_buffer );
2174
2175
0
    bs_write( s, 8, 0x20 ); /* Data identifier */
2176
0
    bs_write( s, 8, 0x0 );  /* Subtitle stream id */
2177
2178
0
    encode_page_composition( p_enc, s, p_subpic );
2179
0
    encode_region_composition( p_enc, s, p_subpic );
2180
0
    encode_clut( p_enc, s, p_region );
2181
0
    encode_object( p_enc, s, p_subpic );
2182
2183
    /* End of display */
2184
0
    bs_write( s, 8, 0x0f ); /* Sync byte */
2185
0
    bs_write( s, 8, DVBSUB_ST_ENDOFDISPLAY ); /* Segment type */
2186
0
    bs_write( s, 16, 1 );  /* Page id */
2187
0
    bs_write( s, 16, 0 );  /* Segment length */
2188
2189
0
    bs_write( s, 8, 0xff );/* End marker */
2190
0
    p_block->i_buffer = bs_pos( s ) / 8;
2191
0
    p_block->i_pts = p_block->i_dts = p_subpic->i_start;
2192
0
    if( !p_subpic->b_ephemer &&
2193
0
        ( p_subpic->i_stop != VLC_TICK_INVALID && p_subpic->i_stop > p_subpic->i_start ) )
2194
0
    {
2195
0
        block_t *p_block_stop;
2196
2197
0
        p_block->i_length = p_subpic->i_stop - p_subpic->i_start;
2198
2199
        /* Send another (empty) subtitle to signal the end of display */
2200
0
        p_block_stop = block_Alloc( 64000 );
2201
0
        if( unlikely(p_block_stop == NULL) )
2202
0
        {
2203
0
            block_Release(p_block);
2204
0
            return NULL;
2205
0
        }
2206
2207
0
        bs_init( s, p_block_stop->p_buffer, p_block_stop->i_buffer );
2208
0
        bs_write( s, 8, 0x20 ); /* Data identifier */
2209
0
        bs_write( s, 8, 0x0 );  /* Subtitle stream id */
2210
0
        encode_page_composition( p_enc, s, 0 );
2211
0
        bs_write( s, 8, 0x0f ); /* Sync byte */
2212
0
        bs_write( s, 8, DVBSUB_ST_ENDOFDISPLAY ); /* Segment type */
2213
0
        bs_write( s, 16, 1 );  /* Page id */
2214
0
        bs_write( s, 16, 0 );  /* Segment length */
2215
0
        bs_write( s, 8, 0xff );/* End marker */
2216
0
        p_block_stop->i_buffer = bs_pos( s ) / 8;
2217
0
        p_block_stop->i_pts = p_block_stop->i_dts = p_subpic->i_stop;
2218
0
        block_ChainAppend( &p_block, p_block_stop );
2219
0
        p_block_stop->i_length = VLC_TICK_FROM_MS(100); /* p_subpic->i_stop - p_subpic->i_start; */
2220
0
    }
2221
#ifdef DEBUG_DVBSUB
2222
    msg_Dbg( p_enc, "subpicture encoded properly" );
2223
#endif
2224
0
    return p_block;
2225
0
}
2226
2227
/*****************************************************************************
2228
 * CloseEncoder: encoder destruction
2229
 *****************************************************************************/
2230
static void CloseEncoder( encoder_t *p_enc )
2231
0
{
2232
0
    encoder_sys_t *p_sys = p_enc->p_sys;
2233
2234
0
    var_Destroy( p_enc , ENC_CFG_PREFIX "x" );
2235
0
    var_Destroy( p_enc , ENC_CFG_PREFIX "y" );
2236
2237
0
    if( p_sys->i_regions ) free( p_sys->p_regions );
2238
0
    free( p_sys );
2239
0
}
2240
2241
static void encode_page_composition( encoder_t *p_enc, bs_t *s,
2242
                                     const subpicture_t *p_subpic )
2243
0
{
2244
0
    encoder_sys_t *p_sys = p_enc->p_sys;
2245
0
    const subpicture_region_t *p_region;
2246
0
    bool b_mode_change = false;
2247
0
    unsigned int i_regions;
2248
0
    int i_timeout;
2249
2250
0
    bs_write( s, 8, 0x0f ); /* Sync byte */
2251
0
    bs_write( s, 8, DVBSUB_ST_PAGE_COMPOSITION ); /* Segment type */
2252
0
    bs_write( s, 16, 1 ); /* Page id */
2253
2254
0
    i_regions = 0;
2255
0
    if (p_subpic)
2256
0
    vlc_spu_regions_foreach_const(p_region, &p_subpic->regions)
2257
0
    {
2258
0
        if( i_regions >= p_sys->i_regions )
2259
0
        {
2260
0
            encoder_region_t region;
2261
0
            region.i_width = region.i_height = 0;
2262
0
            p_sys->p_regions = xrealloc( p_sys->p_regions,
2263
0
                          sizeof(encoder_region_t) * (p_sys->i_regions + 1) );
2264
0
            p_sys->p_regions[p_sys->i_regions++] = region;
2265
0
        }
2266
2267
0
        if( ( p_sys->p_regions[i_regions].i_width <
2268
0
              (int)p_region->fmt.i_visible_width ) ||
2269
0
            ( p_sys->p_regions[i_regions].i_width >
2270
0
              (int)p_region->fmt.i_visible_width ) )
2271
0
        {
2272
0
            b_mode_change = true;
2273
0
            msg_Dbg( p_enc, "region %u width change: %i -> %i",
2274
0
                     i_regions, p_sys->p_regions[i_regions].i_width,
2275
0
                     p_region->fmt.i_visible_width );
2276
0
            p_sys->p_regions[i_regions].i_width =
2277
0
                p_region->fmt.i_visible_width;
2278
0
        }
2279
0
        if( p_sys->p_regions[i_regions].i_height <
2280
0
             (int)p_region->fmt.i_visible_height )
2281
0
        {
2282
0
            b_mode_change = true;
2283
0
            msg_Dbg( p_enc, "region %u height change: %i -> %i",
2284
0
                     i_regions, p_sys->p_regions[i_regions].i_height,
2285
0
                     p_region->fmt.i_visible_height );
2286
0
            p_sys->p_regions[i_regions].i_height =
2287
0
                p_region->fmt.i_visible_height;
2288
0
        }
2289
0
        i_regions++;
2290
0
    }
2291
2292
0
    bs_write( s, 16, i_regions * 6 + 2 ); /* Segment length */
2293
2294
0
    i_timeout = 0;
2295
0
    if( p_subpic && !p_subpic->b_ephemer &&
2296
0
        ( p_subpic->i_stop != VLC_TICK_INVALID && p_subpic->i_stop > p_subpic->i_start ) )
2297
0
    {
2298
0
        i_timeout = SEC_FROM_VLC_TICK(p_subpic->i_stop - p_subpic->i_start);
2299
0
    }
2300
2301
0
    bs_write( s, 8, i_timeout ); /* Timeout */
2302
0
    bs_write( s, 4, p_sys->i_page_ver++ );
2303
0
    bs_write( s, 2, b_mode_change ?
2304
0
              DVBSUB_PCS_STATE_CHANGE : DVBSUB_PCS_STATE_ACQUISITION );
2305
0
    bs_write( s, 2, 0 ); /* Reserved */
2306
2307
0
    i_regions = 0;
2308
0
    if (p_subpic)
2309
0
    vlc_spu_regions_foreach_const(p_region, &p_subpic->regions)
2310
0
    {
2311
0
        bs_write( s, 8, i_regions );
2312
0
        bs_write( s, 8, 0 ); /* Reserved */
2313
0
        if( (p_sys->i_offset_x > 0) && (p_sys->i_offset_y > 0) )
2314
0
        {
2315
0
            bs_write( s, 16, p_sys->i_offset_x ); /* override x position */
2316
0
            bs_write( s, 16, p_sys->i_offset_y ); /* override y position */
2317
0
        }
2318
0
        else
2319
0
        {
2320
0
            bs_write( s, 16, p_region->i_x );
2321
0
            bs_write( s, 16, p_region->i_y );
2322
0
        }
2323
0
        i_regions++;
2324
0
    }
2325
0
}
2326
2327
static void encode_clut( encoder_t *p_enc, bs_t *s, subpicture_region_t *p_region )
2328
0
{
2329
0
    encoder_sys_t *p_sys = p_enc->p_sys;
2330
0
    video_palette_t *p_pal, empty_palette = { .i_entries = 4 };
2331
2332
    /* Sanity check */
2333
0
    if( !p_region ) return;
2334
2335
0
    if( !subpicture_region_IsText( p_region ) && p_region->p_picture->format.i_chroma == VLC_CODEC_YUVP )
2336
0
    {
2337
0
        p_pal = p_region->p_picture->format.p_palette;
2338
0
    }
2339
0
    else
2340
0
        p_pal = &empty_palette;
2341
2342
0
    bs_write( s, 8, 0x0f ); /* Sync byte */
2343
0
    bs_write( s, 8, DVBSUB_ST_CLUT_DEFINITION ); /* Segment type */
2344
0
    bs_write( s, 16, 1 );  /* Page id */
2345
2346
0
    bs_write( s, 16, p_pal->i_entries * 6 + 2 ); /* Segment length */
2347
0
    bs_write( s, 8, 1 ); /* Clut id */
2348
0
    bs_write( s, 4, p_sys->i_clut_ver++ );
2349
0
    bs_write( s, 4, 0 ); /* Reserved */
2350
2351
0
    for( int i = 0; i < p_pal->i_entries; i++ )
2352
0
    {
2353
0
        bs_write( s, 8, i ); /* Clut entry id */
2354
0
        bs_write( s, 1, p_pal->i_entries == 4 );   /* 2bit/entry flag */
2355
0
        bs_write( s, 1, p_pal->i_entries == 16 );  /* 4bit/entry flag */
2356
0
        bs_write( s, 1, p_pal->i_entries == 256 ); /* 8bit/entry flag */
2357
0
        bs_write( s, 4, 0 ); /* Reserved */
2358
0
        bs_write( s, 1, 1 ); /* Full range flag */
2359
0
        bs_write( s, 8, p_pal->palette[i][3] ?  /* Y value */
2360
0
                  (p_pal->palette[i][0] ? p_pal->palette[i][0] : 16) : 0 );
2361
0
        bs_write( s, 8, p_pal->palette[i][1] ); /* Cr value */
2362
0
        bs_write( s, 8, p_pal->palette[i][2] ); /* Cb value */
2363
0
        bs_write( s, 8, 0xff - p_pal->palette[i][3] ); /* T value */
2364
0
    }
2365
0
}
2366
2367
static void encode_region_composition( encoder_t *p_enc, bs_t *s,
2368
                                       const subpicture_t *p_subpic )
2369
0
{
2370
0
    encoder_sys_t *p_sys = p_enc->p_sys;
2371
0
    const subpicture_region_t *p_region;
2372
0
    unsigned int i_region;
2373
2374
0
    i_region = 0;
2375
0
    vlc_spu_regions_foreach_const(p_region, &p_subpic->regions)
2376
0
    {
2377
0
        int i_entries = 4, i_depth = 0x1, i_bg = 0;
2378
0
        bool b_text = subpicture_region_IsText( p_region );
2379
2380
0
        if( !b_text )
2381
0
        {
2382
0
            video_palette_t *p_pal = p_region->p_picture->format.p_palette;
2383
2384
0
            if( !p_pal )
2385
0
            {
2386
0
                msg_Err( p_enc, "subpicture has no palette - ignoring it" );
2387
0
                break;
2388
0
            }
2389
2390
0
            i_entries = p_pal->i_entries;
2391
0
            i_depth = i_entries == 4 ? 0x1 : i_entries == 16 ? 0x2 : 0x3;
2392
2393
0
            for( i_bg = 0; i_bg < p_pal->i_entries; i_bg++ )
2394
0
            {
2395
0
                if( !p_pal->palette[i_bg][3] ) break;
2396
0
            }
2397
0
        }
2398
2399
0
        bs_write( s, 8, 0x0f ); /* Sync byte */
2400
0
        bs_write( s, 8, DVBSUB_ST_REGION_COMPOSITION ); /* Segment type */
2401
0
        bs_write( s, 16, 1 );   /* Page id */
2402
2403
0
        bs_write( s, 16, 10 + 6 + (b_text ? 2 : 0) ); /* Segment length */
2404
0
        bs_write( s, 8, i_region );
2405
0
        bs_write( s, 4, p_sys->i_region_ver++ );
2406
2407
        /* Region attributes */
2408
0
        bs_write( s, 1, i_bg < i_entries ); /* Fill */
2409
0
        bs_write( s, 3, 0 ); /* Reserved */
2410
0
        bs_write( s, 16, p_sys->p_regions[i_region].i_width );
2411
0
        bs_write( s, 16, p_sys->p_regions[i_region].i_height );
2412
0
        bs_write( s, 3, i_depth );  /* Region level of compatibility */
2413
0
        bs_write( s, 3, i_depth  ); /* Region depth */
2414
0
        bs_write( s, 2, 0 ); /* Reserved */
2415
0
        bs_write( s, 8, 1 ); /* Clut id */
2416
0
        bs_write( s, 8, i_bg ); /* region 8bit pixel code */
2417
0
        bs_write( s, 4, i_bg ); /* region 4bit pixel code */
2418
0
        bs_write( s, 2, i_bg ); /* region 2bit pixel code */
2419
0
        bs_write( s, 2, 0 ); /* Reserved */
2420
2421
        /* In our implementation we only have 1 object per region */
2422
0
        bs_write( s, 16, i_region );
2423
0
        bs_write( s, 2, b_text ? DVBSUB_OT_BASIC_CHAR:DVBSUB_OT_BASIC_BITMAP );
2424
0
        bs_write( s, 2, 0 ); /* object provider flag */
2425
0
        bs_write( s, 12, 0 );/* object horizontal position */
2426
0
        bs_write( s, 4, 0 ); /* Reserved */
2427
0
        bs_write( s, 12, 0 );/* object vertical position */
2428
2429
0
        if( b_text )
2430
0
        {
2431
0
            bs_write( s, 8, 1 ); /* foreground pixel code */
2432
0
            bs_write( s, 8, 0 ); /* background pixel code */
2433
0
        }
2434
0
        i_region++;
2435
0
    }
2436
0
}
2437
2438
static void encode_pixel_data( encoder_t *p_enc, bs_t *s,
2439
                               const subpicture_region_t *p_region,
2440
                               bool b_top );
2441
2442
static void encode_object( encoder_t *p_enc, bs_t *s, const subpicture_t *p_subpic )
2443
0
{
2444
0
    encoder_sys_t *p_sys = p_enc->p_sys;
2445
0
    const subpicture_region_t *p_region;
2446
0
    int i_region;
2447
2448
0
    int i_length_pos, i_update_pos, i_pixel_data_pos;
2449
2450
0
    i_region = 0;
2451
0
    vlc_spu_regions_foreach_const(p_region, &p_subpic->regions)
2452
0
    {
2453
0
        bs_write( s, 8, 0x0f ); /* Sync byte */
2454
0
        bs_write( s, 8, DVBSUB_ST_OBJECT_DATA ); /* Segment type */
2455
0
        bs_write( s, 16, 1 ); /* Page id */
2456
2457
0
        i_length_pos = bs_pos( s );
2458
0
        bs_write( s, 16, 0 ); /* Segment length */
2459
0
        bs_write( s, 16, i_region ); /* Object id */
2460
0
        bs_write( s, 4, p_sys->i_region_ver++ );
2461
2462
        /* object coding method */
2463
0
        if (subpicture_region_IsText( p_region ))
2464
0
            bs_write( s, 2, 1 );
2465
0
        else if ( p_region->p_picture->format.i_chroma == VLC_CODEC_YUVP )
2466
0
            bs_write( s, 2, 0 );
2467
0
        else
2468
0
        {
2469
0
            msg_Err( p_enc, "FOURCC %4.4s not supported by encoder.",
2470
0
                     (const char*)&p_region->p_picture->format.i_chroma );
2471
0
            i_region++;
2472
0
            continue;
2473
0
        }
2474
2475
0
        bs_write( s, 1, 0 ); /* non modifying color flag */
2476
0
        bs_write( s, 1, 0 ); /* Reserved */
2477
2478
0
        if(subpicture_region_IsText( p_region ))
2479
0
        {
2480
0
            int i_size, i;
2481
2482
0
            if( !p_region->p_text )
2483
0
            {
2484
0
                i_region++;
2485
0
                continue;
2486
0
            }
2487
2488
0
            i_size = __MIN( strlen( p_region->p_text->psz_text ), 256 );
2489
2490
0
            bs_write( s, 8, i_size ); /* number of characters in string */
2491
0
            for( i = 0; i < i_size; i++ )
2492
0
            {
2493
0
                bs_write( s, 16, p_region->p_text->psz_text[i] );
2494
0
            }
2495
2496
            /* Update segment length */
2497
0
            SetWBE( &s->p_start[i_length_pos/8],
2498
0
                    (bs_pos(s) - i_length_pos)/8 -2 );
2499
0
            i_region++;
2500
0
            continue;
2501
0
        }
2502
2503
        /* Coding of a bitmap object */
2504
0
        i_update_pos = bs_pos( s );
2505
0
        bs_write( s, 16, 0 ); /* topfield data block length */
2506
0
        bs_write( s, 16, 0 ); /* bottomfield data block length */
2507
2508
        /* Top field */
2509
0
        i_pixel_data_pos = bs_pos( s );
2510
0
        encode_pixel_data( p_enc, s, p_region, true );
2511
0
        i_pixel_data_pos = ( bs_pos( s ) - i_pixel_data_pos ) / 8;
2512
0
        SetWBE( &s->p_start[i_update_pos/8], i_pixel_data_pos );
2513
2514
        /* Bottom field */
2515
0
        i_pixel_data_pos = bs_pos( s );
2516
0
        encode_pixel_data( p_enc, s, p_region, false );
2517
0
        i_pixel_data_pos = ( bs_pos( s ) - i_pixel_data_pos ) / 8;
2518
0
        SetWBE( &s->p_start[i_update_pos/8+2], i_pixel_data_pos );
2519
2520
        /* Stuffing for word alignment */
2521
0
        bs_align_0( s );
2522
0
        if( bs_pos( s ) % 16 ) bs_write( s, 8, 0 );
2523
2524
        /* Update segment length */
2525
0
        SetWBE( &s->p_start[i_length_pos/8], (bs_pos(s) - i_length_pos)/8 -2 );
2526
0
        i_region++;
2527
0
    }
2528
0
}
2529
2530
static void encode_pixel_line_2bp( bs_t *s, const subpicture_region_t *p_region,
2531
                                   int i_line );
2532
static void encode_pixel_line_4bp( bs_t *s, const subpicture_region_t *p_region,
2533
                                   int i_line );
2534
static void encode_pixel_line_8bp( bs_t *s, const subpicture_region_t *p_region,
2535
                                   int i_line );
2536
static void encode_pixel_data( encoder_t *p_enc, bs_t *s,
2537
                               const subpicture_region_t *p_region,
2538
                               bool b_top )
2539
0
{
2540
0
    unsigned int i_line;
2541
2542
    /* Encode line by line */
2543
0
    for( i_line = !b_top; i_line < p_region->fmt.i_visible_height;
2544
0
         i_line += 2 )
2545
0
    {
2546
0
        switch( p_region->p_picture->format.p_palette->i_entries )
2547
0
        {
2548
0
        case 0:
2549
0
            break;
2550
2551
0
        case 4:
2552
0
            bs_write( s, 8, 0x10 ); /* 2 bit/pixel code string */
2553
0
            encode_pixel_line_2bp( s, p_region, i_line );
2554
0
            break;
2555
2556
0
        case 16:
2557
0
            bs_write( s, 8, 0x11 ); /* 4 bit/pixel code string */
2558
0
            encode_pixel_line_4bp( s, p_region, i_line );
2559
0
            break;
2560
2561
0
        case 256:
2562
0
            bs_write( s, 8, 0x12 ); /* 8 bit/pixel code string */
2563
0
            encode_pixel_line_8bp( s, p_region, i_line );
2564
0
            break;
2565
2566
0
        default:
2567
0
            msg_Err( p_enc, "subpicture palette (%i) not handled",
2568
0
                     p_region->p_picture->format.p_palette->i_entries );
2569
0
            break;
2570
0
        }
2571
2572
0
        bs_write( s, 8, 0xf0 ); /* End of object line code */
2573
0
    }
2574
0
}
2575
2576
static void encode_pixel_line_2bp( bs_t *s, const subpicture_region_t *p_region,
2577
                                   int i_line )
2578
0
{
2579
0
    unsigned int i, i_length = 0;
2580
0
    int i_pitch = p_region->p_picture->p->i_pitch;
2581
0
    uint8_t *p_data = &p_region->p_picture->p->p_pixels[ i_pitch * i_line ];
2582
0
    int i_last_pixel = p_data[0];
2583
2584
0
    for( i = 0; i <= p_region->fmt.i_visible_width; i++ )
2585
0
    {
2586
0
        if( ( i != p_region->fmt.i_visible_width ) &&
2587
0
            ( p_data[i] == i_last_pixel ) && ( i_length != 284 ) )
2588
0
        {
2589
0
            i_length++;
2590
0
            continue;
2591
0
        }
2592
2593
0
        if( ( i_length == 1 ) || ( i_length == 11 ) || ( i_length == 28 ) )
2594
0
        {
2595
            /* 2bit/pixel code */
2596
0
            if( i_last_pixel )
2597
0
                bs_write( s, 2, i_last_pixel );
2598
0
            else
2599
0
            {
2600
0
                bs_write( s, 2, 0 );
2601
0
                bs_write( s, 1, 0 );
2602
0
                bs_write( s, 1, 1 ); /* pseudo color 0 */
2603
0
            }
2604
0
            i_length--;
2605
0
        }
2606
2607
0
        if( i_length == 2 )
2608
0
        {
2609
0
            if( i_last_pixel )
2610
0
            {
2611
0
                bs_write( s, 2, i_last_pixel );
2612
0
                bs_write( s, 2, i_last_pixel );
2613
0
            }
2614
0
            else
2615
0
            {
2616
0
                bs_write( s, 2, 0 );
2617
0
                bs_write( s, 1, 0 );
2618
0
                bs_write( s, 1, 0 );
2619
0
                bs_write( s, 2, 1 ); /* 2 * pseudo color 0 */
2620
0
            }
2621
0
        }
2622
0
        else if( i_length > 2 )
2623
0
        {
2624
0
            bs_write( s, 2, 0 );
2625
0
            if( i_length <= 10 )
2626
0
            {
2627
0
                bs_write( s, 1, 1 );
2628
0
                bs_write( s, 3, i_length - 3 );
2629
0
                bs_write( s, 2, i_last_pixel );
2630
0
            }
2631
0
            else
2632
0
            {
2633
0
                bs_write( s, 1, 0 );
2634
0
                bs_write( s, 1, 0 );
2635
2636
0
                if( i_length <= 27 )
2637
0
                {
2638
0
                    bs_write( s, 2, 2 );
2639
0
                    bs_write( s, 4, i_length - 12 );
2640
0
                    bs_write( s, 2, i_last_pixel );
2641
0
                }
2642
0
                else
2643
0
                {
2644
0
                    bs_write( s, 2, 3 );
2645
0
                    bs_write( s, 8, i_length - 29 );
2646
0
                    bs_write( s, 2, i_last_pixel );
2647
0
                }
2648
0
            }
2649
0
        }
2650
2651
0
        if( i == p_region->fmt.i_visible_width ) break;
2652
2653
0
        i_last_pixel = p_data[i];
2654
0
        i_length = 1;
2655
0
    }
2656
2657
    /* Stop */
2658
0
    bs_write( s, 2, 0 );
2659
0
    bs_write( s, 1, 0 );
2660
0
    bs_write( s, 1, 0 );
2661
0
    bs_write( s, 2, 0 );
2662
2663
    /* Stuffing */
2664
0
    bs_align_0( s );
2665
0
}
2666
2667
static void encode_pixel_line_4bp( bs_t *s, const subpicture_region_t *p_region,
2668
                                   int i_line )
2669
0
{
2670
0
    unsigned int i, i_length = 0;
2671
0
    int i_pitch = p_region->p_picture->p->i_pitch;
2672
0
    uint8_t *p_data = &p_region->p_picture->p->p_pixels[ i_pitch * i_line ];
2673
0
    int i_last_pixel = p_data[0];
2674
2675
0
    for( i = 0; i <= p_region->fmt.i_visible_width; i++ )
2676
0
    {
2677
0
        if( i != p_region->fmt.i_visible_width &&
2678
0
            p_data[i] == i_last_pixel && i_length != 280 )
2679
0
        {
2680
0
            i_length++;
2681
0
            continue;
2682
0
        }
2683
2684
0
        if( ( i_length == 1 ) ||
2685
0
            ( ( i_length == 3 ) && i_last_pixel ) ||
2686
0
            ( i_length == 8 ) )
2687
0
        {
2688
            /* 4bit/pixel code */
2689
0
            if( i_last_pixel )
2690
0
                bs_write( s, 4, i_last_pixel );
2691
0
            else
2692
0
            {
2693
0
                bs_write( s, 4, 0 );
2694
0
                bs_write( s, 1, 1 );
2695
0
                bs_write( s, 1, 1 );
2696
0
                bs_write( s, 2, 0 ); /* pseudo color 0 */
2697
0
            }
2698
0
            i_length--;
2699
0
        }
2700
2701
0
        if( i_length == 2 )
2702
0
        {
2703
0
            if( i_last_pixel )
2704
0
            {
2705
0
                bs_write( s, 4, i_last_pixel );
2706
0
                bs_write( s, 4, i_last_pixel );
2707
0
            }
2708
0
            else
2709
0
            {
2710
0
                bs_write( s, 4, 0 );
2711
0
                bs_write( s, 1, 1 );
2712
0
                bs_write( s, 1, 1 );
2713
0
                bs_write( s, 2, 1 ); /* 2 * pseudo color 0 */
2714
0
            }
2715
0
        }
2716
0
        else if( !i_last_pixel && ( i_length >= 3 ) && ( i_length <= 9 ) )
2717
0
        {
2718
0
            bs_write( s, 4, 0 );
2719
0
            bs_write( s, 1, 0 );
2720
0
            bs_write( s, 3, i_length - 2 ); /* (i_length - 2) * color 0 */
2721
0
        }
2722
0
        else if( i_length > 2 )
2723
0
        {
2724
0
            bs_write( s, 4, 0 );
2725
0
            bs_write( s, 1, 1 );
2726
2727
0
            if( i_length <= 7 )
2728
0
            {
2729
0
                bs_write( s, 1, 0 );
2730
0
                bs_write( s, 2, i_length - 4 );
2731
0
                bs_write( s, 4, i_last_pixel );
2732
0
            }
2733
0
            else
2734
0
            {
2735
0
                bs_write( s, 1, 1 );
2736
2737
0
                if( i_length <= 24 )
2738
0
                {
2739
0
                    bs_write( s, 2, 2 );
2740
0
                    bs_write( s, 4, i_length - 9 );
2741
0
                    bs_write( s, 4, i_last_pixel );
2742
0
                }
2743
0
                else
2744
0
                {
2745
0
                    bs_write( s, 2, 3 );
2746
0
                    bs_write( s, 8, i_length - 25 );
2747
0
                    bs_write( s, 4, i_last_pixel );
2748
0
                }
2749
0
            }
2750
0
        }
2751
2752
0
        if( i == p_region->fmt.i_visible_width ) break;
2753
2754
0
        i_last_pixel = p_data[i];
2755
0
        i_length = 1;
2756
0
    }
2757
2758
    /* Stop */
2759
0
    bs_write( s, 8, 0 );
2760
2761
    /* Stuffing */
2762
0
    bs_align_0( s );
2763
0
}
2764
2765
static void encode_pixel_line_8bp( bs_t *s, const subpicture_region_t *p_region,
2766
                                   int i_line )
2767
0
{
2768
0
    unsigned int i, i_length = 0;
2769
0
    int i_pitch = p_region->p_picture->p->i_pitch;
2770
0
    uint8_t *p_data = &p_region->p_picture->p->p_pixels[ i_pitch * i_line ];
2771
0
    int i_last_pixel = p_data[0];
2772
2773
0
    for( i = 0; i <= p_region->fmt.i_visible_width; i++ )
2774
0
    {
2775
0
        if( ( i != p_region->fmt.i_visible_width ) &&
2776
0
            ( p_data[i] == i_last_pixel ) && ( i_length != 127 ) )
2777
0
        {
2778
0
            i_length++;
2779
0
            continue;
2780
0
        }
2781
2782
0
        if( ( i_length == 1 ) && i_last_pixel )
2783
0
        {
2784
            /* 8bit/pixel code */
2785
0
            bs_write( s, 8, i_last_pixel );
2786
0
        }
2787
0
        else if( ( i_length == 2 ) && i_last_pixel )
2788
0
        {
2789
            /* 8bit/pixel code */
2790
0
            bs_write( s, 8, i_last_pixel );
2791
0
            bs_write( s, 8, i_last_pixel );
2792
0
        }
2793
0
        else if( i_length <= 127 )
2794
0
        {
2795
0
            bs_write( s, 8, 0 );
2796
2797
0
            if( !i_last_pixel )
2798
0
            {
2799
0
                bs_write( s, 1, 0 );
2800
0
                bs_write( s, 7, i_length ); /* pseudo color 0 */
2801
0
            }
2802
0
            else
2803
0
            {
2804
0
                bs_write( s, 1, 1 );
2805
0
                bs_write( s, 7, i_length );
2806
0
                bs_write( s, 8, i_last_pixel );
2807
0
            }
2808
0
        }
2809
2810
0
        if( i == p_region->fmt.i_visible_width ) break;
2811
2812
0
        i_last_pixel = p_data[i];
2813
0
        i_length = 1;
2814
0
    }
2815
2816
    /* Stop */
2817
0
    bs_write( s, 8, 0 );
2818
0
    bs_write( s, 8, 0 );
2819
2820
    /* Stuffing */
2821
0
    bs_align_0( s );
2822
0
}
2823
2824
#endif
2825
2826
static void default_dds_init( decoder_t * p_dec )
2827
7.62k
{
2828
7.62k
    decoder_sys_t *p_sys = p_dec->p_sys;
2829
2830
    /* see notes on DDS at the top of the file */
2831
2832
    /* configure for SD res in case DDS is not present */
2833
7.62k
    p_sys->display.i_version = 0xff; /* an invalid version so it's always different */
2834
7.62k
    p_sys->display.i_width_minus1 = 720-1;
2835
7.62k
    p_sys->display.i_height_minus1 = 576-1;
2836
    p_sys->display.b_windowed = false;
2837
7.62k
}