Coverage Report

Created: 2023-03-26 07:08

/src/vlc/modules/codec/cvdsub.c
Line
Count
Source (jump to first uncovered line)
1
/*****************************************************************************
2
 * cvdsub.c : CVD Subtitle decoder
3
 *****************************************************************************
4
 * Copyright (C) 2003, 2004 VLC authors and VideoLAN
5
 *
6
 * Authors: Rocky Bernstein
7
 *          Gildas Bazin <gbazin@videolan.org>
8
 *          Julio Sanchez Fernandez (http://subhandler.sourceforge.net)
9
 *          Laurent Aimar <fenrir@via.ecp.fr>
10
 *
11
 * This program is free software; you can redistribute it and/or modify it
12
 * under the terms of the GNU Lesser General Public License as published by
13
 * the Free Software Foundation; either version 2.1 of the License, or
14
 * (at your option) any later version.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
 * GNU Lesser General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Lesser General Public License
22
 * along with this program; if not, write to the Free Software Foundation,
23
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24
 *****************************************************************************/
25
26
/*****************************************************************************
27
 * Preamble
28
 *****************************************************************************/
29
#ifdef HAVE_CONFIG_H
30
# include "config.h"
31
#endif
32
33
#include <vlc_common.h>
34
#include <vlc_plugin.h>
35
#include <vlc_codec.h>
36
37
#include <vlc_bits.h>
38
39
#include "../demux/mpeg/timestamps.h"
40
41
#define DEBUG_CVDSUB 1
42
43
/*****************************************************************************
44
 * Module descriptor.
45
 *****************************************************************************/
46
static int  DecoderOpen   ( vlc_object_t * );
47
static int  PacketizerOpen( vlc_object_t * );
48
static void DecoderClose  ( vlc_object_t * );
49
50
0
vlc_module_begin ()
51
0
    set_description( N_("CVD subtitle decoder") )
52
0
    set_capability( "spu decoder", 50 )
53
0
    set_callbacks( DecoderOpen, DecoderClose )
54
55
0
    add_submodule ()
56
0
    set_description( N_("Chaoji VCD subtitle packetizer") )
57
0
    set_capability( "packetizer", 50 )
58
0
    set_callbacks( PacketizerOpen, DecoderClose )
59
0
vlc_module_end ()
60
61
/*****************************************************************************
62
 * Local prototypes
63
 *****************************************************************************/
64
static int Decode( decoder_t *, block_t * );
65
static block_t *Packetize  ( decoder_t *, block_t ** );
66
static block_t *Reassemble ( decoder_t *, block_t * );
67
static void ParseMetaInfo  ( decoder_t *, block_t * );
68
static void ParseHeader    ( decoder_t *, block_t * );
69
static subpicture_t *DecodePacket( decoder_t *, block_t * );
70
static void RenderImage( decoder_t *, block_t *, subpicture_region_t * );
71
72
0
#define SUBTITLE_BLOCK_EMPTY 0
73
0
#define SUBTITLE_BLOCK_PARTIAL 1
74
#define SUBTITLE_BLOCK_COMPLETE 2
75
76
typedef struct
77
{
78
  int      b_packetizer;
79
80
  int      i_state;    /* data-gathering state for this subtitle */
81
82
  block_t  *p_spu;   /* Bytes of the packet. */
83
84
  size_t   i_spu_size;     /* goal for subtitle_data_pos while gathering,
85
                             size of used subtitle_data later */
86
87
  uint16_t i_image_offset;      /* offset from subtitle_data to compressed
88
                                   image data */
89
  size_t i_image_length;           /* size of the compressed image data */
90
  size_t first_field_offset;       /* offset of even raster lines */
91
  size_t second_field_offset;      /* offset of odd raster lines */
92
  size_t metadata_offset;          /* offset to data describing the image */
93
  size_t metadata_length;          /* length of metadata */
94
95
  vlc_tick_t i_duration;   /* how long to display the image, 0 stands
96
                           for "until next subtitle" */
97
98
  uint16_t i_x_start, i_y_start; /* position of top leftmost pixel of
99
                                    image when displayed */
100
  uint16_t i_width, i_height;    /* dimensions in pixels of image */
101
102
  uint8_t p_palette[4][4];       /* Palette of colors used in subtitle */
103
  uint8_t p_palette_highlight[4][4];
104
} decoder_sys_t;
105
106
static int OpenCommon( vlc_object_t *p_this, bool b_packetizer )
107
0
{
108
0
    decoder_t     *p_dec = (decoder_t*)p_this;
109
0
    decoder_sys_t *p_sys;
110
111
0
    if( p_dec->fmt_in->i_codec != VLC_CODEC_CVD )
112
0
        return VLC_EGENERIC;
113
114
0
    p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) );
115
0
    if( !p_sys )
116
0
        return VLC_ENOMEM;
117
118
0
    p_sys->b_packetizer  = b_packetizer;
119
120
0
    p_sys->i_state = SUBTITLE_BLOCK_EMPTY;
121
0
    p_sys->p_spu   = NULL;
122
123
0
    if( b_packetizer )
124
0
    {
125
0
        p_dec->pf_packetize    = Packetize;
126
0
        p_dec->fmt_out.i_codec = VLC_CODEC_CVD;
127
0
    }
128
0
    else
129
0
    {
130
0
        p_dec->pf_decode       = Decode;
131
0
        p_dec->fmt_out.i_codec = VLC_CODEC_YUVP;
132
0
    }
133
134
0
    return VLC_SUCCESS;
135
0
}
136
/*****************************************************************************
137
 * DecoderOpen: open/initialize the cvdsub decoder.
138
 *****************************************************************************/
139
static int DecoderOpen( vlc_object_t *p_this )
140
0
{
141
0
    return OpenCommon( p_this, false );
142
0
}
143
144
/*****************************************************************************
145
 * PacketizerOpen: open/initialize the cvdsub packetizer.
146
 *****************************************************************************/
147
static int PacketizerOpen( vlc_object_t *p_this )
148
0
{
149
0
    return OpenCommon( p_this, true );
150
0
}
151
152
/*****************************************************************************
153
 * DecoderClose: closes the cvdsub decoder/packetizer.
154
 *****************************************************************************/
155
void DecoderClose( vlc_object_t *p_this )
156
0
{
157
0
    decoder_t     *p_dec = (decoder_t*)p_this;
158
0
    decoder_sys_t *p_sys = p_dec->p_sys;
159
160
0
    if( p_sys->p_spu ) block_ChainRelease( p_sys->p_spu );
161
0
    free( p_sys );
162
0
}
163
164
/*****************************************************************************
165
 * Decode:
166
 *****************************************************************************/
167
static int Decode( decoder_t *p_dec, block_t *p_block )
168
0
{
169
0
    block_t *p_data;
170
171
0
    if( p_block == NULL ) /* No Drain */
172
0
        return VLCDEC_SUCCESS;
173
174
0
    if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
175
0
    {
176
0
        block_Release( p_block );
177
0
        return VLCDEC_SUCCESS;
178
0
    }
179
180
0
    if( !(p_data = Reassemble( p_dec, p_block )) )
181
0
        return VLCDEC_SUCCESS;
182
183
    /* Parse and decode */
184
0
    subpicture_t *p_spu = DecodePacket( p_dec, p_data );
185
0
    block_Release( p_data );
186
0
    if( p_spu != NULL )
187
0
        decoder_QueueSub( p_dec, p_spu );
188
0
    return VLCDEC_SUCCESS;
189
0
}
190
191
/*****************************************************************************
192
 * Packetize:
193
 *****************************************************************************/
194
static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
195
0
{
196
0
    block_t *p_block, *p_spu;
197
198
0
    if( pp_block == NULL || *pp_block == NULL ) return NULL;
199
200
0
    p_block = *pp_block;
201
0
    *pp_block = NULL;
202
203
0
    if( !(p_spu = Reassemble( p_dec, p_block )) ) return NULL;
204
205
0
    p_spu->i_dts = p_spu->i_pts;
206
0
    p_spu->i_length = VLC_TICK_INVALID;
207
208
0
    return p_spu;
209
0
}
210
211
212
/*****************************************************************************
213
 Reassemble:
214
215
 Data for single screen subtitle may come in several non-contiguous
216
 packets of a stream. This routine is called when the next packet in
217
 the stream comes in. The job of this routine is to parse the header,
218
 if this is the beginning, and combine the packets into one complete
219
 subtitle unit.
220
221
 If everything is complete, we will return a block. Otherwise return
222
 NULL.
223
224
 *****************************************************************************/
225
0
#define SPU_HEADER_LEN 1
226
227
static block_t *Reassemble( decoder_t *p_dec, block_t *p_block )
228
0
{
229
0
    decoder_sys_t *p_sys = p_dec->p_sys;
230
231
0
    if( p_block->i_buffer < SPU_HEADER_LEN )
232
0
    {
233
0
        msg_Dbg( p_dec, "invalid packet header (size %zu < %u)" ,
234
0
                 p_block->i_buffer, SPU_HEADER_LEN );
235
0
        block_Release( p_block );
236
0
        return NULL;
237
0
    }
238
239
    /* From the scant data on the format, there is only only way known
240
     * to detect the first packet in a subtitle.  The first packet
241
     * seems to have a valid PTS while later packets for the same
242
     * image don't. */
243
0
    if( p_sys->i_state == SUBTITLE_BLOCK_EMPTY && p_block->i_pts == VLC_TICK_INVALID )
244
0
    {
245
0
        msg_Warn( p_dec, "first packet expected but no PTS present");
246
0
        return NULL;
247
0
    }
248
249
0
    p_block->p_buffer += SPU_HEADER_LEN;
250
0
    p_block->i_buffer -= SPU_HEADER_LEN;
251
252
    /* First packet in the subtitle block */
253
0
    if( p_sys->i_state == SUBTITLE_BLOCK_EMPTY ) ParseHeader( p_dec, p_block );
254
255
0
    block_ChainAppend( &p_sys->p_spu, p_block );
256
0
    p_sys->p_spu = block_ChainGather( p_sys->p_spu );
257
258
0
    if( p_sys->p_spu->i_buffer >= p_sys->i_spu_size )
259
0
    {
260
0
        block_t *p_spu = p_sys->p_spu;
261
262
0
        if( p_spu->i_buffer != p_sys->i_spu_size )
263
0
        {
264
0
            msg_Warn( p_dec, "SPU packets size=%zu should be %zu",
265
0
                      p_spu->i_buffer, p_sys->i_spu_size );
266
0
        }
267
268
0
        msg_Dbg( p_dec, "subtitle packet complete, size=%zuu", p_spu->i_buffer);
269
270
0
        ParseMetaInfo( p_dec, p_spu );
271
272
0
        p_sys->i_state = SUBTITLE_BLOCK_EMPTY;
273
0
        p_sys->p_spu = 0;
274
0
        return p_spu;
275
0
    }
276
0
    else
277
0
    {
278
        /* Not last block in subtitle, so wait for another. */
279
0
        p_sys->i_state = SUBTITLE_BLOCK_PARTIAL;
280
0
    }
281
282
0
    return NULL;
283
0
}
284
285
/*
286
  We do not have information on the subtitle format used on CVD's
287
  except the submux sample code and a couple of samples of dubious
288
  origin. Thus, this is the result of reading some code whose
289
  correctness is not known and some experimentation.
290
291
  CVD subtitles are different in several ways from SVCD OGT subtitles.
292
  Image comes first and metadata is at the end.  So that the metadata
293
  can be found easily, the subtitle packet starts with two bytes
294
  (everything is big-endian again) that give the total size of the
295
  subtitle data and the offset to the metadata - i.e. size of the
296
  image data plus the four bytes at the beginning.
297
298
  Image data comes interlaced is run-length encoded.  Each field is a
299
  four-bit nibble. Each nibble contains a two-bit repeat count and a
300
  two-bit color number so that up to three pixels can be described in
301
  four bits.  The function of a 0 repeat count is unknown; it might be
302
  used for RLE extension.  However when the full nibble is zero, the
303
  rest of the line is filled with the color value in the next nibble.
304
  It is unknown what happens if the color value is greater than three.
305
  The rest seems to use a 4-entries palette.  It is not impossible
306
  that the fill-line complete case above is not as described and the
307
  zero repeat count means fill line.  The sample code never produces
308
  this, so it may be untested.
309
*/
310
311
static void ParseHeader( decoder_t *p_dec, block_t *p_block )
312
0
{
313
0
    decoder_sys_t *p_sys = p_dec->p_sys;
314
0
    uint8_t *p = p_block->p_buffer;
315
316
0
    p_sys->i_spu_size = (p[0] << 8) + p[1] + 4; p += 2;
317
318
    /* FIXME: check data sanity */
319
0
    p_sys->metadata_offset = (p[0] <<  8) +   p[1]; p +=2;
320
0
    p_sys->metadata_length = p_sys->i_spu_size - p_sys->metadata_offset;
321
322
0
    p_sys->i_image_offset = 4;
323
0
    p_sys->i_image_length = p_sys->metadata_offset - p_sys->i_image_offset;
324
325
0
#ifdef DEBUG_CVDSUB
326
0
    msg_Dbg( p_dec, "total size: %zu  image size: %zu",
327
0
             p_sys->i_spu_size, p_sys->i_image_length );
328
0
#endif
329
0
}
330
331
/*
332
  We parse the metadata information here.
333
334
  Although metadata information does not have to come in a fixed field
335
  order, every metadata field consists of a tag byte followed by
336
  parameters. In all cases known, the size including tag byte is
337
  exactly four bytes in length.
338
*/
339
340
0
#define ExtractXY(x, y) x = ((p[1]&0x0f)<<6) + (p[2]>>2); \
341
0
                        y = ((p[2]&0x03)<<8) + p[3];
342
343
static void ParseMetaInfo( decoder_t *p_dec, block_t *p_spu  )
344
0
{
345
    /* Last packet in subtitle block. */
346
347
0
    decoder_sys_t *p_sys = p_dec->p_sys;
348
0
    uint8_t       *p     = p_spu->p_buffer + p_sys->metadata_offset;
349
0
    uint8_t       *p_end = p + p_sys->metadata_length;
350
351
0
    for( ; p < p_end; p += 4 )
352
0
    {
353
0
        switch( p[0] )
354
0
        {
355
0
        case 0x04: /* subtitle duration in 1/90000ths of a second */
356
0
            p_sys->i_duration = FROM_SCALE_NZ( (p[1]<<16) + (p[2]<<8) + p[3] );
357
358
0
#ifdef DEBUG_CVDSUB
359
0
            msg_Dbg( p_dec, "subtitle display duration %"PRIu64" ms",
360
0
                     MS_FROM_VLC_TICK(p_sys->i_duration) );
361
0
#endif
362
0
            break;
363
364
0
        case 0x0c: /* unknown */
365
0
#ifdef DEBUG_CVDSUB
366
0
            msg_Dbg( p_dec, "subtitle command unknown "
367
0
                     "0x%02"PRIx8" 0x%02"PRIx8" 0x%02"PRIx8" 0x%02"PRIx8,
368
0
                     p[0], p[1], p[2], p[3] );
369
0
#endif
370
0
            break;
371
372
0
        case 0x17: /* coordinates of subtitle upper left x, y position */
373
0
            ExtractXY(p_sys->i_x_start, p_sys->i_y_start);
374
375
0
#ifdef DEBUG_CVDSUB
376
0
            msg_Dbg( p_dec, "start position (%"PRIu16",%"PRIu16")",
377
0
                     p_sys->i_x_start, p_sys->i_y_start );
378
0
#endif
379
0
            break;
380
381
0
        case 0x1f: /* coordinates of subtitle bottom right x, y position */
382
0
        {
383
0
            int lastx;
384
0
            int lasty;
385
0
            ExtractXY(lastx, lasty);
386
0
            p_sys->i_width  = lastx - p_sys->i_x_start + 1;
387
0
            p_sys->i_height = lasty - p_sys->i_y_start + 1;
388
389
0
#ifdef DEBUG_CVDSUB
390
0
            msg_Dbg( p_dec, "end position (%d,%d), w x h: %"PRIu16"x%"PRIu16,
391
0
                     lastx, lasty, p_sys->i_width, p_sys->i_height );
392
0
#endif
393
0
            break;
394
0
        }
395
396
0
        case 0x24:
397
0
        case 0x25:
398
0
        case 0x26:
399
0
        case 0x27:
400
0
        {
401
0
            uint8_t v = p[0] - 0x24;
402
403
0
#ifdef DEBUG_CVDSUB
404
            /* Primary Palette */
405
0
            msg_Dbg( p_dec, "primary palette %"PRIu8" (y,u,v): "
406
0
                     "(0x%02"PRIx8",0x%02"PRIx8",0x%02"PRIx8")",
407
0
                     v, p[1], p[2], p[3] );
408
0
#endif
409
410
0
            p_sys->p_palette[v][0] = p[1]; /* Y */
411
0
            p_sys->p_palette[v][1] = p[3]; /* Cr / V */
412
0
            p_sys->p_palette[v][2] = p[2]; /* Cb / U */
413
0
            break;
414
0
        }
415
416
0
        case 0x2c:
417
0
        case 0x2d:
418
0
        case 0x2e:
419
0
        case 0x2f:
420
0
        {
421
0
            uint8_t v = p[0] - 0x2c;
422
423
0
#ifdef DEBUG_CVDSUB
424
0
            msg_Dbg( p_dec,"highlight palette %"PRIu8" (y,u,v): "
425
0
                     "(0x%02"PRIx8",0x%02"PRIx8",0x%02"PRIx8")",
426
0
                     v, p[1], p[2], p[3] );
427
0
#endif
428
429
            /* Highlight Palette */
430
0
            p_sys->p_palette_highlight[v][0] = p[1]; /* Y */
431
0
            p_sys->p_palette_highlight[v][1] = p[3]; /* Cr / V */
432
0
            p_sys->p_palette_highlight[v][2] = p[2]; /* Cb / U */
433
0
            break;
434
0
        }
435
436
0
        case 0x37:
437
            /* transparency for primary palette */
438
0
            p_sys->p_palette[0][3] = (p[3] & 0x0f) << 4;
439
0
            p_sys->p_palette[1][3] = (p[3] >> 4) << 4;
440
0
            p_sys->p_palette[2][3] = (p[2] & 0x0f) << 4;
441
0
            p_sys->p_palette[3][3] = (p[2] >> 4) << 4;
442
443
0
#ifdef DEBUG_CVDSUB
444
0
            msg_Dbg( p_dec, "transparency for primary palette 0..3: "
445
0
                     "0x%02"PRIx8" 0x%02"PRIx8" 0x%02"PRIx8" 0x%02"PRIx8,
446
0
                     p_sys->p_palette[0][3], p_sys->p_palette[1][3],
447
0
                     p_sys->p_palette[2][3], p_sys->p_palette[3][3]);
448
0
#endif
449
0
            break;
450
451
0
        case 0x3f:
452
            /* transparency for highlight palette */
453
0
            p_sys->p_palette_highlight[0][3] = (p[2] & 0x0f) << 4;
454
0
            p_sys->p_palette_highlight[1][3] = (p[2] >> 4) << 4;
455
0
            p_sys->p_palette_highlight[2][3] = (p[1] & 0x0f) << 4;
456
0
            p_sys->p_palette_highlight[3][3] = (p[1] >> 4) << 4;
457
458
0
#ifdef DEBUG_CVDSUB
459
0
            msg_Dbg( p_dec, "transparency for highlight palette 0..3: "
460
0
                     "0x%02"PRIx8" 0x%02"PRIx8" 0x%02"PRIx8" 0x%02"PRIx8,
461
0
                     p_sys->p_palette_highlight[0][3],
462
0
                     p_sys->p_palette_highlight[1][3],
463
0
                     p_sys->p_palette_highlight[2][3],
464
0
                     p_sys->p_palette_highlight[3][3] );
465
0
#endif
466
0
            break;
467
468
0
        case 0x47:
469
            /* offset to start of even rows of interlaced image, we correct
470
             * to make it relative to i_image_offset (usually 4) */
471
0
            p_sys->first_field_offset =
472
0
                (p[2] << 8) + p[3] - p_sys->i_image_offset;
473
0
#ifdef DEBUG_CVDSUB
474
0
            msg_Dbg( p_dec, "1st_field_offset %zu",
475
0
                     p_sys->first_field_offset );
476
0
#endif
477
0
            break;
478
479
0
        case 0x4f:
480
            /* offset to start of odd rows of interlaced image, we correct
481
             * to make it relative to i_image_offset (usually 4) */
482
0
            p_sys->second_field_offset =
483
0
                (p[2] << 8) + p[3] - p_sys->i_image_offset;
484
0
#ifdef DEBUG_CVDSUB
485
0
            msg_Dbg( p_dec, "2nd_field_offset %zu",
486
0
                     p_sys->second_field_offset);
487
0
#endif
488
0
            break;
489
490
0
        default:
491
0
#ifdef DEBUG_CVDSUB
492
0
            msg_Warn( p_dec, "unknown sequence in control header "
493
0
                      "0x%02"PRIx8" 0x%02"PRIx8" 0x%02"PRIx8" 0x%02"PRIx8,
494
0
                      p[0], p[1], p[2], p[3]);
495
0
#endif
496
0
        }
497
0
    }
498
0
}
499
500
/*****************************************************************************
501
 * DecodePacket: parse and decode an SPU packet
502
 *****************************************************************************
503
 * This function parses and decodes an SPU packet and, if valid, returns a
504
 * subpicture.
505
 *****************************************************************************/
506
static subpicture_t *DecodePacket( decoder_t *p_dec, block_t *p_data )
507
0
{
508
0
    decoder_sys_t *p_sys = p_dec->p_sys;
509
0
    subpicture_t  *p_spu;
510
0
    subpicture_region_t *p_region;
511
0
    video_format_t fmt;
512
0
    video_palette_t palette;
513
0
    int i;
514
515
    /* Allocate the subpicture internal data. */
516
0
    p_spu = decoder_NewSubpicture( p_dec, NULL );
517
0
    if( !p_spu ) return NULL;
518
519
0
    p_spu->i_start = p_data->i_pts;
520
0
    p_spu->i_stop  = p_data->i_pts + p_sys->i_duration;
521
0
    p_spu->b_ephemer = true;
522
523
    /* Create new SPU region */
524
0
    video_format_Init( &fmt, VLC_CODEC_YUVP );
525
0
    fmt.i_sar_num = 1;
526
0
    fmt.i_sar_den = 1;
527
0
    fmt.i_width = fmt.i_visible_width = p_sys->i_width;
528
0
    fmt.i_height = fmt.i_visible_height = p_sys->i_height;
529
0
    fmt.i_x_offset = fmt.i_y_offset = 0;
530
0
    fmt.p_palette = &palette;
531
0
    fmt.p_palette->i_entries = 4;
532
0
    for( i = 0; i < fmt.p_palette->i_entries; i++ )
533
0
    {
534
0
        fmt.p_palette->palette[i][0] = p_sys->p_palette[i][0];
535
0
        fmt.p_palette->palette[i][1] = p_sys->p_palette[i][1];
536
0
        fmt.p_palette->palette[i][2] = p_sys->p_palette[i][2];
537
0
        fmt.p_palette->palette[i][3] = p_sys->p_palette[i][3];
538
0
    }
539
540
0
    p_region = subpicture_region_New( &fmt );
541
0
    if( !p_region )
542
0
    {
543
0
        msg_Err( p_dec, "cannot allocate SPU region" );
544
0
        subpicture_Delete( p_spu );
545
0
        return NULL;
546
0
    }
547
548
0
    p_spu->p_region = p_region;
549
0
    p_region->i_x = p_sys->i_x_start;
550
0
    p_region->i_x = p_region->i_x * 3 / 4; /* FIXME: use aspect ratio for x? */
551
0
    p_region->i_y = p_sys->i_y_start;
552
553
0
    RenderImage( p_dec, p_data, p_region );
554
555
0
    return p_spu;
556
0
}
557
558
/*****************************************************************************
559
 * ParseImage: parse and render the image part of the subtitle
560
 *****************************************************************************
561
 This part parses the subtitle graphical data and renders it.
562
563
 Image data comes interlaced and is run-length encoded (RLE). Each
564
 field is a four-bit nibbles that is further subdivided in a two-bit
565
 repeat count and a two-bit color number - up to three pixels can be
566
 described in four bits.  What a 0 repeat count means is unknown.  It
567
 might be used for RLE extension.  There is a special case of a 0
568
 repeat count though.  When the full nibble is zero, the rest of the
569
 line is filled with the color value in the next nibble.  It is
570
 unknown what happens if the color value is greater than three.  The
571
 rest seems to use a 4-entries palette.  It is not impossible that the
572
 fill-line complete case above is not as described and the zero repeat
573
 count means fill line.  The sample code never produces this, so it
574
 may be untested.
575
576
 However we'll transform this so that that the RLE is expanded and
577
 interlacing will also be removed. On output each pixel entry will by
578
 a 4-bit alpha (filling 8 bits), and 8-bit y, u, and v entry.
579
580
 *****************************************************************************/
581
static void RenderImage( decoder_t *p_dec, block_t *p_data,
582
                         subpicture_region_t *p_region )
583
0
{
584
0
    decoder_sys_t *p_sys = p_dec->p_sys;
585
0
    uint8_t *p_dest = p_region->p_picture->Y_PIXELS;
586
0
    int i_field;            /* The subtitles are interlaced */
587
0
    int i_row, i_column;    /* scanline row/column number */
588
0
    uint8_t i_color, i_count;
589
0
    bs_t bs;
590
591
0
    bs_init( &bs, p_data->p_buffer + p_sys->i_image_offset,
592
0
             p_data->i_buffer - p_sys->i_image_offset );
593
594
0
    for( i_field = 0; i_field < 2; i_field++ )
595
0
    {
596
0
        for( i_row = i_field; i_row < p_sys->i_height; i_row += 2 )
597
0
        {
598
0
            for( i_column = 0; i_column < p_sys->i_width; i_column++ )
599
0
            {
600
0
                uint8_t i_val = bs_read( &bs, 4 );
601
602
0
                if( i_val == 0 )
603
0
                {
604
                    /* Fill the rest of the line with next color */
605
0
                    i_color = bs_read( &bs, 4 );
606
607
0
                    memset( &p_dest[i_row * p_region->p_picture->Y_PITCH +
608
0
                                    i_column], i_color,
609
0
                            p_sys->i_width - i_column );
610
0
                    i_column = p_sys->i_width;
611
0
                    continue;
612
0
                }
613
0
                else
614
0
                {
615
                    /* Normal case: get color and repeat count */
616
0
                    i_count = (i_val >> 2);
617
0
                    i_color = i_val & 0x3;
618
619
0
                    i_count = __MIN( i_count, p_sys->i_width - i_column );
620
621
0
                    memset( &p_dest[i_row * p_region->p_picture->Y_PITCH +
622
0
                                    i_column], i_color, i_count );
623
0
                    i_column += i_count - 1;
624
0
                    continue;
625
0
                }
626
0
            }
627
628
0
            bs_align( &bs );
629
0
        }
630
0
    }
631
0
}