Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc-gpu
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
videolan
vlc-gpu
Commits
ef4c3d63
Commit
ef4c3d63
authored
Nov 06, 2003
by
Damien Lucas
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
oups, ... forgot the interesting file !
parent
1ddb23b6
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
1307 additions
and
0 deletions
+1307
-0
modules/codec/dvbsub.c
modules/codec/dvbsub.c
+1307
-0
No files found.
modules/codec/dvbsub.c
0 → 100644
View file @
ef4c3d63
/*****************************************************************************
* dvbsub.c : DVB subtitles decoder thread
*****************************************************************************
* Copyright (C) 2003 ANEVIA
* $Id: dvbsub.c,v 1.1 2003/11/06 16:37:19 nitrox Exp $
*
* Authors: Damien LUCAS <damien.lucas@anevia.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h>
/* malloc(), free() */
#include <string.h>
/* memcpy(), memset() */
#include <vlc/vlc.h>
#include <vlc/vout.h>
#include <vlc/decoder.h>
#include "codecs.h"
// Wow, that's ugly but very usefull for a memory leak track
// so I just keep it
#if 0
static long long unsigned int trox_malloc_nb = 0;
static long long unsigned int trox_free_nb = 0;
static void* trox_malloc (size_t size)
{ ++trox_malloc_nb; return malloc (size); }
static void trox_free (void* ptr)
{ ++trox_free_nb; free(ptr); return; }
static void trox_call ()
{
fprintf(stderr, "dvbbsub -- Memory usage: %llu mallocs %llu frees (%llu)\n",
trox_malloc_nb,
trox_free_nb,
trox_malloc_nb - trox_free_nb);
return;
}
#else
# define trox_malloc malloc
# define trox_free free
# define trox_call()
#endif
/****************************************************************************
* Local structures
****************************************************************************
* Those structures refer closely to the ETSI 300 743 Object model
****************************************************************************/
/* Storage of a RLE entry */
typedef
struct
dvbsub_rle_s
{
uint16_t
i_num
;
uint8_t
i_color_code
;
uint8_t
y
;
uint8_t
cr
;
uint8_t
cb
;
uint8_t
t
;
struct
dvbsub_rle_s
*
p_next
;
}
dvbsub_rle_t
;
/* A subpicture image is a list of codes
* We need to store the length of each line since nothing specify in
* the standard that all lines shoudl have the same length
* WARNING: We assume here that a spu is less than 576 lines high */
typedef
struct
{
uint16_t
i_rows
;
uint16_t
i_cols
[
576
];
dvbsub_rle_t
*
p_last
;
dvbsub_rle_t
*
p_codes
;
}
dvbsub_image_t
;
/* The object definition gives the position of the object in a region */
typedef
struct
dvbsub_objectdef_s
{
uint16_t
i_id
;
uint8_t
i_type
;
uint8_t
i_provider
;
uint16_t
i_xoffset
;
uint16_t
i_yoffset
;
uint8_t
i_fg_pc
;
uint8_t
i_bg_pc
;
struct
dvbsub_objectdef_s
*
p_next
;
}
dvbsub_objectdef_t
;
/* The Region is an aera on the image
* with a list of the object definitions associated
* and a CLUT */
typedef
struct
dvbsub_region_s
{
uint8_t
i_id
;
uint8_t
i_version_number
;
vlc_bool_t
b_fill
;
uint16_t
i_x
;
uint16_t
i_y
;
uint16_t
i_width
;
uint16_t
i_height
;
uint8_t
i_level_comp
;
uint8_t
i_depth
;
uint8_t
i_clut
;
uint8_t
i_8bp_code
;
uint8_t
i_4bp_code
;
uint8_t
i_2bp_code
;
dvbsub_objectdef_t
*
p_object
;
}
dvbsub_region_t
;
/* The page defines the list of regions */
typedef
struct
{
uint16_t
i_id
;
uint8_t
i_timeout
;
uint8_t
i_state
;
uint8_t
i_version_number
;
uint8_t
i_regions_number
;
dvbsub_region_t
*
regions
;
}
dvbsub_page_t
;
/* An object is constituted of 2 images (for interleaving) */
typedef
struct
dvbsub_object_s
{
uint16_t
i_id
;
uint8_t
i_version_number
;
uint8_t
i_coding_method
;
vlc_bool_t
b_non_modify_color
;
dvbsub_image_t
*
topfield
;
dvbsub_image_t
*
bottomfield
;
struct
dvbsub_object_s
*
p_next
;
}
dvbsub_object_t
;
/* The entry in the palette CLUT */
typedef
struct
{
uint8_t
Y
;
uint8_t
Cr
;
uint8_t
Cb
;
uint8_t
T
;
}
dvbsub_color_t
;
/* */
typedef
struct
{
uint8_t
i_id
;
uint8_t
i_version_number
;
dvbsub_color_t
c_2b
[
0xff
];
dvbsub_color_t
c_4b
[
0xff
];
dvbsub_color_t
c_8b
[
0xff
];
}
dvbsub_clut_t
;
typedef
struct
{
uint8_t
i_x
;
uint16_t
i_y
;
dvbsub_image_t
*
p_rle_top
;
dvbsub_image_t
*
p_rle_bot
;
}
dvbsub_render_t
;
typedef
struct
{
dvbsub_clut_t
*
p_clut
[
0xff
];
dvbsub_page_t
*
p_page
;
dvbsub_object_t
*
p_objects
;
subpicture_t
*
p_spu
[
16
];
}
dvbsub_all_t
;
typedef
struct
{
/* Thread properties and locks */
vlc_thread_t
thread_id
;
/* Id for thread functions */
/* Input properties */
decoder_fifo_t
*
p_fifo
;
/* Stores the PES stream data */
bit_stream_t
bit_stream
;
/* PES data at the bit level */
/* Output properties */
vout_thread_t
*
p_vout
;
/* Needed to create the subpictures */
}
dvbsub_thread_t
;
struct
subpicture_sys_t
{
mtime_t
i_pts
;
void
*
p_data
;
/* rle datas are stored */
vlc_object_t
*
p_input
;
/* Link to the input */
vlc_bool_t
b_obsolete
;
};
// List of different SEGMENT TYPES
// According to EN 300-743, table 2
#define DVBSUB_ST_PAGE_COMPOSITION 0x10
#define DVBSUB_ST_REGION_COMPOSITION 0x11
#define DVBSUB_ST_CLUT_DEFINITION 0x12
#define DVBSUB_ST_OBJECT_DATA 0x13
#define DVBSUB_ST_ENDOFDISPLAY 0x80
#define DVBSUB_ST_STUFFING 0xff
// List of different OBJECT TYPES
// According to EN 300-743, table 6
#define DVBSUB_OT_BASIC_BITMAP 0x00
#define DVBSUB_OT_BASIC_CHAR 0x01
#define DVBSUB_OT_COMPOSITE_STRING 0x02
// Pixel DATA TYPES
// According to EN 300-743, table 9
#define DVBSUB_DT_2BP_CODE_STRING 0x10
#define DVBSUB_DT_4BP_CODE_STRING 0x11
#define DVBSUB_DT_8BP_CODE_STRING 0x12
#define DVBSUB_DT_24_TABLE_DATA 0x20
#define DVBSUB_DT_28_TABLE_DATA 0x21
#define DVBSUB_DT_48_TABLE_DATA 0x22
#define DVBSUB_DT_END_LINE 0xf0
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static
int
OpenDecoder
(
vlc_object_t
*
);
static
int
RunDecoder
(
decoder_fifo_t
*
);
static
int
InitThread
(
dvbsub_thread_t
*
);
static
void
EndThread
(
dvbsub_thread_t
*
i
,
dvbsub_all_t
*
);
static
vout_thread_t
*
FindVout
(
dvbsub_thread_t
*
);
static
void
RenderI42x
(
vout_thread_t
*
,
picture_t
*
,
const
subpicture_t
*
,
vlc_bool_t
);
static
void
RenderYUY2
(
vout_thread_t
*
,
picture_t
*
,
const
subpicture_t
*
,
vlc_bool_t
);
static
void
dvbsub_clut_add_entry
(
dvbsub_clut_t
*
clut
,
uint8_t
type
,
uint8_t
id
,
uint8_t
y
,
uint8_t
cr
,
uint8_t
cb
,
uint8_t
t
);
static
void
dvbsub_add_objectdef_to_region
(
dvbsub_objectdef_t
*
p_obj
,
dvbsub_region_t
*
p_region
);
static
dvbsub_image_t
*
dvbsub_parse_pdata
(
dvbsub_thread_t
*
,
uint16_t
);
static
uint16_t
dvbsub_count0x11
(
dvbsub_thread_t
*
p_spudec
,
uint16_t
*
p
,
dvbsub_image_t
*
p_image
);
static
void
dvbsub_decode_segment
(
dvbsub_thread_t
*
,
dvbsub_all_t
*
);
static
void
dvbsub_decode_page_composition
(
dvbsub_thread_t
*
,
dvbsub_all_t
*
);
static
void
dvbsub_decode_region_composition
(
dvbsub_thread_t
*
,
dvbsub_all_t
*
);
static
void
dvbsub_decode_object
(
dvbsub_thread_t
*
,
dvbsub_all_t
*
);
static
vlc_bool_t
dvbsub_check_page
(
dvbsub_all_t
*
);
static
void
dvbsub_render
(
dvbsub_thread_t
*
p_spudec
,
dvbsub_all_t
*
);
static
int
dvbsub_parse
(
dvbsub_thread_t
*
p_spudec
,
dvbsub_all_t
*
dvbsub
);
static
void
dvbsub_decode_clut
(
dvbsub_thread_t
*
,
dvbsub_all_t
*
);
static
void
dvbsub_stop_display
(
dvbsub_thread_t
*
p_dec
,
dvbsub_all_t
*
dvbsub
);
static
void
free_image
(
dvbsub_image_t
*
p_i
);
static
void
free_object
(
dvbsub_object_t
*
p_o
);
static
void
free_regions
(
dvbsub_region_t
*
p_r
,
uint8_t
nb
);
static
void
free_objects
(
dvbsub_object_t
*
p_o
);
static
void
free_clut
(
dvbsub_clut_t
*
p_c
);
static
void
free_page
(
dvbsub_page_t
*
p_p
);
static
void
free_all
(
dvbsub_all_t
*
p_a
);
/*****************************************************************************
* Module descriptor.
*****************************************************************************/
vlc_module_begin
();
add_category_hint
(
N_
(
"subtitles"
),
NULL
,
VLC_TRUE
);
set_description
(
_
(
"subtitles decoder"
)
);
set_capability
(
"decoder"
,
50
);
set_callbacks
(
OpenDecoder
,
NULL
);
vlc_module_end
();
/*****************************************************************************
* OpenDecoder: probe the decoder and return score
*****************************************************************************
* Tries to launch a decoder and return score so that the interface is able
* to chose.
*****************************************************************************/
static
int
OpenDecoder
(
vlc_object_t
*
p_this
)
{
decoder_t
*
p_dec
=
(
decoder_t
*
)
p_this
;
if
(
p_dec
->
p_fifo
->
i_fourcc
!=
VLC_FOURCC
(
'd'
,
'v'
,
'b'
,
's'
)
)
{
return
VLC_EGENERIC
;
}
p_dec
->
pf_run
=
RunDecoder
;
return
VLC_SUCCESS
;
}
/*****************************************************************************
* RunDecoder: this function is called just after the thread is created
*****************************************************************************/
static
int
RunDecoder
(
decoder_fifo_t
*
p_fifo
)
{
dvbsub_thread_t
*
p_dvbsubdec
;
// vout_thread_t * p_vout_backup = NULL;
dvbsub_all_t
dvbsub
;
unsigned
int
k
;
/* Allocate the memory needed to store the thread's structure */
p_dvbsubdec
=
(
dvbsub_thread_t
*
)
trox_malloc
(
sizeof
(
dvbsub_thread_t
)
);
if
(
p_dvbsubdec
==
NULL
)
{
msg_Err
(
p_fifo
,
"out of memory"
);
DecoderError
(
p_fifo
);
return
(
-
1
);
}
/*
* Initialize the thread properties
*/
p_dvbsubdec
->
p_vout
=
NULL
;
p_dvbsubdec
->
p_fifo
=
p_fifo
;
/*
* Initialize thread and free configuration
*/
p_dvbsubdec
->
p_fifo
->
b_error
=
InitThread
(
p_dvbsubdec
);
dvbsub
.
p_page
=
NULL
;
dvbsub
.
p_objects
=
NULL
;
for
(
k
=
0
;
k
<
0xff
;
k
++
)
dvbsub
.
p_clut
[
k
]
=
NULL
;
for
(
k
=
0
;
k
<
16
;
k
++
)
dvbsub
.
p_spu
[
k
]
=
NULL
;
/*
* Main loop - it is not executed if an error occured during
* initialization
*/
while
(
(
!
p_dvbsubdec
->
p_fifo
->
b_die
)
&&
(
!
p_dvbsubdec
->
p_fifo
->
b_error
)
)
{
dvbsub_parse
(
p_dvbsubdec
,
&
dvbsub
);
p_dvbsubdec
->
p_vout
=
FindVout
(
p_dvbsubdec
);
if
(
p_dvbsubdec
->
p_vout
)
{
// Check if the page is to be displayed
if
(
dvbsub_check_page
(
&
dvbsub
))
{
dvbsub_render
(
p_dvbsubdec
,
&
dvbsub
);
}
vlc_object_release
(
p_dvbsubdec
->
p_vout
);
}
}
// Free all structures
//dvbsub.p_objects=NULL;
//for(k=0; k<16; k++)
// if(dvbsub.p_spu[k] != NULL)
// dvbsub.p_spu[k]->p_sys->b_obsolete = 1;
/*
* Error loop
*/
if
(
p_dvbsubdec
->
p_fifo
->
b_error
)
{
DecoderError
(
p_dvbsubdec
->
p_fifo
);
/* End of thread */
EndThread
(
p_dvbsubdec
,
&
dvbsub
);
return
-
1
;
}
/* End of thread */
EndThread
(
p_dvbsubdec
,
&
dvbsub
);
free_all
(
&
dvbsub
);
return
0
;
}
/* following functions are local */
/*****************************************************************************
* InitThread: initialize dvbsub decoder thread
*****************************************************************************
* This function is called from RunThread and performs the second step of the
* initialization. It returns 0 on success. Note that the thread's flag are not
* modified inside this function.
*****************************************************************************/
static
int
InitThread
(
dvbsub_thread_t
*
p_dvbsubdec
)
{
int
i_ret
;
/* Call InitBitstream anyway so p_spudec->bit_stream is in a known
* state before calling CloseBitstream */
i_ret
=
InitBitstream
(
&
p_dvbsubdec
->
bit_stream
,
p_dvbsubdec
->
p_fifo
,
NULL
,
NULL
);
/* Check for a video output */
p_dvbsubdec
->
p_vout
=
FindVout
(
p_dvbsubdec
);
if
(
!
p_dvbsubdec
->
p_vout
)
{
return
-
1
;
}
/* It was just a check */
vlc_object_release
(
p_dvbsubdec
->
p_vout
);
p_dvbsubdec
->
p_vout
=
NULL
;
return
i_ret
;
}
/*****************************************************************************
* FindVout: Find a vout or wait for one to be created.
*****************************************************************************/
static
vout_thread_t
*
FindVout
(
dvbsub_thread_t
*
p_spudec
)
{
vout_thread_t
*
p_vout
=
NULL
;
/* Find an available video output */
do
{
if
(
p_spudec
->
p_fifo
->
b_die
||
p_spudec
->
p_fifo
->
b_error
)
{
break
;
}
p_vout
=
vlc_object_find
(
p_spudec
->
p_fifo
,
VLC_OBJECT_VOUT
,
FIND_ANYWHERE
);
if
(
p_vout
)
{
break
;
}
msleep
(
VOUT_OUTMEM_SLEEP
);
}
while
(
1
);
return
p_vout
;
}
/*****************************************************************************
* EndThread: thread destruction
*****************************************************************************
* This function is called when the thread ends after a sucessful
* initialization.
*****************************************************************************/
static
void
EndThread
(
dvbsub_thread_t
*
p_dvbsubdec
,
dvbsub_all_t
*
p_dvbsub
)
{
if
(
p_dvbsubdec
->
p_vout
!=
NULL
&&
p_dvbsubdec
->
p_vout
->
p_subpicture
!=
NULL
)
{
subpicture_t
*
p_subpic
;
int
i_subpic
;
for
(
i_subpic
=
0
;
i_subpic
<
VOUT_MAX_SUBPICTURES
;
i_subpic
++
)
{
p_subpic
=
&
p_dvbsubdec
->
p_vout
->
p_subpicture
[
i_subpic
];
if
(
p_subpic
!=
NULL
&&
(
(
p_subpic
->
i_status
==
RESERVED_SUBPICTURE
)
||
(
p_subpic
->
i_status
==
READY_SUBPICTURE
)
)
)
{
vout_DestroySubPicture
(
p_dvbsubdec
->
p_vout
,
p_subpic
);
}
}
}
CloseBitstream
(
&
p_dvbsubdec
->
bit_stream
);
trox_free
(
p_dvbsubdec
);
trox_call
();
}
static
int
dvbsub_parse
(
dvbsub_thread_t
*
p_spudec
,
dvbsub_all_t
*
dvbsub
)
{
unsigned
int
data_identifier
;
unsigned
int
subtitle_stream_id
;
unsigned
int
nextbits
;
uint32_t
end_data_marker
;
/* Re-align the buffer on an 8-bit boundary */
RealignBits
(
&
p_spudec
->
bit_stream
);
data_identifier
=
GetBits
(
&
p_spudec
->
bit_stream
,
8
);
subtitle_stream_id
=
GetBits
(
&
p_spudec
->
bit_stream
,
8
);
nextbits
=
ShowBits
(
&
p_spudec
->
bit_stream
,
8
);
while
(
nextbits
==
0x0f
)
{
dvbsub_decode_segment
(
p_spudec
,
dvbsub
);
nextbits
=
ShowBits
(
&
p_spudec
->
bit_stream
,
8
);
}
end_data_marker
=
GetBits
(
&
p_spudec
->
bit_stream
,
8
);
return
0
;
}
static
void
dvbsub_decode_segment
(
dvbsub_thread_t
*
p_spudec
,
dvbsub_all_t
*
dvbsub
)
{
unsigned
int
sync_byte
;
unsigned
int
segment_type
;
uint16_t
page_id
;
uint16_t
segment_length
;
int
k
;
sync_byte
=
GetBits
(
&
p_spudec
->
bit_stream
,
8
);
segment_type
=
GetBits
(
&
p_spudec
->
bit_stream
,
8
);
page_id
=
GetBits
(
&
p_spudec
->
bit_stream
,
16
);
segment_length
=
ShowBits
(
&
p_spudec
->
bit_stream
,
16
);
if
(
page_id
!=
((
dvb_spuinfo_t
*
)
p_spudec
->
p_fifo
->
p_spuinfo
)
->
i_id
)
{
//TODO should use GetChunk
for
(
k
=
0
;
k
<
segment_length
+
2
;
k
++
)
GetBits
(
&
p_spudec
->
bit_stream
,
8
);
return
;
}
switch
(
segment_type
)
{
case
DVBSUB_ST_CLUT_DEFINITION
:
dvbsub_decode_clut
(
p_spudec
,
dvbsub
);
break
;
case
DVBSUB_ST_PAGE_COMPOSITION
:
dvbsub_decode_page_composition
(
p_spudec
,
dvbsub
);
break
;
case
DVBSUB_ST_REGION_COMPOSITION
:
dvbsub_decode_region_composition
(
p_spudec
,
dvbsub
);
break
;
case
DVBSUB_ST_OBJECT_DATA
:
dvbsub_decode_object
(
p_spudec
,
dvbsub
);
break
;
case
DVBSUB_ST_ENDOFDISPLAY
:
dvbsub_stop_display
(
p_spudec
,
dvbsub
);
break
;
case
DVBSUB_ST_STUFFING
:
default:
fprintf
(
stderr
,
"*** DVBSUB - Unsupported segment type ! (%04x)
\n
"
,
segment_type
);
GetBits
(
&
p_spudec
->
bit_stream
,
16
);
for
(
k
=
0
;
k
<
segment_length
;
k
++
)
GetBits
(
&
p_spudec
->
bit_stream
,
8
);
break
;
}
return
;
}
static
void
dvbsub_decode_page_composition
(
dvbsub_thread_t
*
p_spudec
,
dvbsub_all_t
*
dvbsub
)
{
unsigned
int
i_version_number
;
unsigned
int
i_state
;
unsigned
int
i_segment_length
;
uint8_t
i_timeout
;
unsigned
int
k
;
i_segment_length
=
GetBits
(
&
p_spudec
->
bit_stream
,
16
);
//A page is composed by one or more region:
i_timeout
=
GetBits
(
&
p_spudec
->
bit_stream
,
8
);
i_version_number
=
GetBits
(
&
p_spudec
->
bit_stream
,
4
);
i_state
=
GetBits
(
&
p_spudec
->
bit_stream
,
2
);
// TODO We assume it is a new page (i_state)
if
(
dvbsub
->
p_page
)
free_page
(
dvbsub
->
p_page
);
GetBits
(
&
p_spudec
->
bit_stream
,
2
);
/* Reserved */
//Allocate a new page
dvbsub
->
p_page
=
trox_malloc
(
sizeof
(
dvbsub_page_t
));
dvbsub
->
p_page
->
i_timeout
=
i_timeout
;
// Number of regions:
dvbsub
->
p_page
->
i_regions_number
=
(
i_segment_length
-
2
)
/
6
;
/* Special workaround for CAVENA encoders
* a page with no regions is sent instead of a 0x80 packet (End Of Display) */
if
(
dvbsub
->
p_page
->
i_regions_number
==
0
)
{
dvbsub_stop_display
(
p_spudec
,
dvbsub
);
}
/* /Special workaround */
dvbsub
->
p_page
->
regions
=
trox_malloc
(
dvbsub
->
p_page
->
i_regions_number
*
sizeof
(
dvbsub_region_t
));
for
(
k
=
0
;
k
<
dvbsub
->
p_page
->
i_regions_number
;
k
++
)
{
dvbsub
->
p_page
->
regions
[
k
].
i_id
=
GetBits
(
&
p_spudec
->
bit_stream
,
8
);
GetBits
(
&
p_spudec
->
bit_stream
,
8
);
/* Reserved */
dvbsub
->
p_page
->
regions
[
k
].
i_x
=
GetBits
(
&
p_spudec
->
bit_stream
,
16
);
dvbsub
->
p_page
->
regions
[
k
].
i_y
=
GetBits
(
&
p_spudec
->
bit_stream
,
16
);
dvbsub
->
p_page
->
regions
[
k
].
p_object
=
NULL
;
}
}
static
void
dvbsub_decode_region_composition
(
dvbsub_thread_t
*
p_spudec
,
dvbsub_all_t
*
dvbsub
)
{
unsigned
int
i_segment_length
;
unsigned
int
i_processed_length
;
unsigned
int
i_region_id
;
dvbsub_region_t
*
p_region
;
unsigned
int
k
;
p_region
=
NULL
;
i_segment_length
=
GetBits
(
&
p_spudec
->
bit_stream
,
16
);
// Get region id:
i_region_id
=
GetBits
(
&
p_spudec
->
bit_stream
,
8
);
for
(
k
=
0
;
k
<
dvbsub
->
p_page
->
i_regions_number
;
k
++
)
{
if
(
dvbsub
->
p_page
->
regions
[
k
].
i_id
==
i_region_id
)
p_region
=
&
(
dvbsub
->
p_page
->
regions
[
k
]);
}
if
(
p_region
==
NULL
)
{
// TODO
// The region has never been declared before
// Internal error
fprintf
(
stderr
,
"Decoding of undeclared region N/A...
\n
"
);
return
;
}
// Skip version number and fill flag
if
(
ShowBits
(
&
p_spudec
->
bit_stream
,
4
)
==
p_region
->
i_version_number
)
{
fprintf
(
stderr
,
"Skipping already known region N/A ...
\n
"
);
// TODO Skip the right number of bits
}
// Region attributes
p_region
->
i_version_number
=
GetBits
(
&
p_spudec
->
bit_stream
,
4
);
p_region
->
b_fill
=
GetBits
(
&
p_spudec
->
bit_stream
,
1
);
GetBits
(
&
p_spudec
->
bit_stream
,
3
);
/* Reserved */
p_region
->
i_width
=
GetBits
(
&
p_spudec
->
bit_stream
,
16
);
p_region
->
i_height
=
GetBits
(
&
p_spudec
->
bit_stream
,
16
);
p_region
->
i_level_comp
=
GetBits
(
&
p_spudec
->
bit_stream
,
3
);
p_region
->
i_depth
=
GetBits
(
&
p_spudec
->
bit_stream
,
3
);
GetBits
(
&
p_spudec
->
bit_stream
,
2
);
/* Reserved */
p_region
->
i_clut
=
GetBits
(
&
p_spudec
->
bit_stream
,
8
);
p_region
->
i_8bp_code
=
GetBits
(
&
p_spudec
->
bit_stream
,
8
);
p_region
->
i_4bp_code
=
GetBits
(
&
p_spudec
->
bit_stream
,
4
);
p_region
->
i_2bp_code
=
GetBits
(
&
p_spudec
->
bit_stream
,
2
);
GetBits
(
&
p_spudec
->
bit_stream
,
2
);
/* Reserved */
// List of objects in the region:
// We already skipped 10 bytes
i_processed_length
=
10
;
while
(
i_processed_length
<
i_segment_length
)
{
// We create a new object
dvbsub_objectdef_t
*
p_obj
;
p_obj
=
trox_malloc
(
sizeof
(
dvbsub_objectdef_t
));
// We parse object properties
p_obj
->
i_id
=
GetBits
(
&
p_spudec
->
bit_stream
,
16
);
p_obj
->
i_type
=
GetBits
(
&
p_spudec
->
bit_stream
,
2
);
p_obj
->
i_provider
=
GetBits
(
&
p_spudec
->
bit_stream
,
2
);
p_obj
->
i_xoffset
=
GetBits
(
&
p_spudec
->
bit_stream
,
12
);
GetBits
(
&
p_spudec
->
bit_stream
,
4
);
/* Reserved */
p_obj
->
i_yoffset
=
GetBits
(
&
p_spudec
->
bit_stream
,
12
);
i_processed_length
+=
6
;
if
(
p_obj
->
i_type
==
DVBSUB_OT_BASIC_CHAR
||
p_obj
->
i_type
==
DVBSUB_OT_COMPOSITE_STRING
)
{
p_obj
->
i_fg_pc
=
GetBits
(
&
p_spudec
->
bit_stream
,
8
);
p_obj
->
i_bg_pc
=
GetBits
(
&
p_spudec
->
bit_stream
,
8
);
i_processed_length
+=
2
;
}
p_obj
->
p_next
=
NULL
;
dvbsub_add_objectdef_to_region
(
p_obj
,
p_region
);
}
}
static
void
dvbsub_decode_object
(
dvbsub_thread_t
*
p_spudec
,
dvbsub_all_t
*
dvbsub
)
{
dvbsub_object_t
*
p_obj
;
dvbsub_object_t
*
p_o
;
uint16_t
i_segment_length
;
uint16_t
i_topfield_length
;
uint16_t
i_bottomfield_length
;
// Memory Allocation
p_obj
=
trox_malloc
(
sizeof
(
dvbsub_object_t
)
);
p_obj
->
p_next
=
NULL
;
i_segment_length
=
GetBits
(
&
p_spudec
->
bit_stream
,
16
);
p_obj
->
i_id
=
GetBits
(
&
p_spudec
->
bit_stream
,
16
);
p_obj
->
i_version_number
=
GetBits
(
&
p_spudec
->
bit_stream
,
4
);
// TODO Check we don't already have this object / this version
p_obj
->
i_coding_method
=
GetBits
(
&
p_spudec
->
bit_stream
,
2
);
p_obj
->
b_non_modify_color
=
GetBits
(
&
p_spudec
->
bit_stream
,
1
);
GetBits
(
&
p_spudec
->
bit_stream
,
1
);
/* Reserved */
if
(
p_obj
->
i_coding_method
==
0x00
)
{
i_topfield_length
=
GetBits
(
&
p_spudec
->
bit_stream
,
16
);
i_bottomfield_length
=
GetBits
(
&
p_spudec
->
bit_stream
,
16
);
p_obj
->
topfield
=
dvbsub_parse_pdata
(
p_spudec
,
i_topfield_length
);
p_obj
->
bottomfield
=
dvbsub_parse_pdata
(
p_spudec
,
i_bottomfield_length
);
}
else
{
GetBits
(
&
p_spudec
->
bit_stream
,
(
i_segment_length
-
3
)
*
8
);
//TODO
// DVB subtitling as characters
}
// Add this object to the list of the page
p_o
=
dvbsub
->
p_objects
;
dvbsub
->
p_objects
=
p_obj
;
p_obj
->
p_next
=
p_o
;
return
;
}
static
void
dvbsub_stop_display
(
dvbsub_thread_t
*
p_dec
,
dvbsub_all_t
*
dvbsub
)
{
unsigned
int
j
;
for
(
j
=
0
;
dvbsub
->
p_spu
[
j
]
!=
NULL
;
j
++
)
dvbsub
->
p_spu
[
j
]
->
i_stop
=
p_dec
->
bit_stream
.
p_pes
->
i_pts
;
return
;
}
static
void
dvbsub_decode_clut
(
dvbsub_thread_t
*
p_dec
,
dvbsub_all_t
*
dvbsub
)
{
uint16_t
i_segment_length
;
uint16_t
i_processed_length
;
uint8_t
i_entry_id
;
uint8_t
i_entry_type
;
dvbsub_clut_t
*
clut
;
uint8_t
i_clut_id
;
uint8_t
i_version_number
;
uint8_t
y
;
uint8_t
cr
;
uint8_t
cb
;
uint8_t
t
;
i_segment_length
=
GetBits
(
&
p_dec
->
bit_stream
,
16
);
i_clut_id
=
GetBits
(
&
p_dec
->
bit_stream
,
8
);
i_version_number
=
GetBits
(
&
p_dec
->
bit_stream
,
4
);
// Check that this id doesn't not already exist
// with the same version number
// And allocate memory if necessary
if
(
dvbsub
->
p_clut
[
i_clut_id
]
!=
NULL
)
{
if
(
dvbsub
->
p_clut
[
i_clut_id
]
->
i_version_number
==
i_version_number
)
{
//TODO skip the right number of bits
return
;
}
else
{
memset
(
dvbsub
->
p_clut
[
i_clut_id
],
0
,
sizeof
(
dvbsub_clut_t
));
}
}
else
{
dvbsub
->
p_clut
[
i_clut_id
]
=
trox_malloc
(
sizeof
(
dvbsub_clut_t
));
}
clut
=
dvbsub
->
p_clut
[
i_clut_id
];
/* We don't have this version of the CLUT:
* Parse it */
clut
->
i_version_number
=
i_version_number
;
GetBits
(
&
p_dec
->
bit_stream
,
4
);
/* Reserved bits */
i_processed_length
=
2
;
while
(
i_processed_length
<
i_segment_length
)
{
i_entry_id
=
GetBits
(
&
p_dec
->
bit_stream
,
8
);
i_entry_type
=
GetBits
(
&
p_dec
->
bit_stream
,
3
);
GetBits
(
&
p_dec
->
bit_stream
,
4
);
if
(
GetBits
(
&
p_dec
->
bit_stream
,
1
)
==
0x01
)
{
y
=
GetBits
(
&
p_dec
->
bit_stream
,
8
);
cr
=
GetBits
(
&
p_dec
->
bit_stream
,
8
);
cb
=
GetBits
(
&
p_dec
->
bit_stream
,
8
);
t
=
GetBits
(
&
p_dec
->
bit_stream
,
8
);
i_processed_length
+=
6
;
}
else
{
y
=
GetBits
(
&
p_dec
->
bit_stream
,
6
);
cr
=
GetBits
(
&
p_dec
->
bit_stream
,
4
);
cb
=
GetBits
(
&
p_dec
->
bit_stream
,
4
);
t
=
GetBits
(
&
p_dec
->
bit_stream
,
2
);
i_processed_length
+=
4
;
}
dvbsub_clut_add_entry
(
clut
,
i_entry_type
,
i_entry_id
,
y
,
cr
,
cb
,
t
);
}
}
static
void
dvbsub_clut_add_entry
(
dvbsub_clut_t
*
clut
,
uint8_t
type
,
uint8_t
id
,
uint8_t
y
,
uint8_t
cr
,
uint8_t
cb
,
uint8_t
t
)
{
/* According to EN 300-743 section 7.2.3 note 1, type should
* not have more than 1 bit set to one
But, some strams don't respect this note. */
if
(
type
&
0x04
)
{
clut
->
c_2b
[
id
].
Y
=
y
;
clut
->
c_2b
[
id
].
Cr
=
cr
;
clut
->
c_2b
[
id
].
Cb
=
cb
;
clut
->
c_2b
[
id
].
T
=
t
;
}
if
(
type
&
0x02
)
{
clut
->
c_4b
[
id
].
Y
=
y
;
clut
->
c_4b
[
id
].
Cr
=
cr
;
clut
->
c_4b
[
id
].
Cb
=
cb
;
clut
->
c_4b
[
id
].
T
=
t
;
}
if
(
type
&
0x01
)
{
clut
->
c_8b
[
id
].
Y
=
y
;
clut
->
c_8b
[
id
].
Cr
=
cr
;
clut
->
c_8b
[
id
].
Cb
=
cb
;
clut
->
c_8b
[
id
].
T
=
t
;
}
return
;
}
static
void
dvbsub_add_objectdef_to_region
(
dvbsub_objectdef_t
*
p_obj
,
dvbsub_region_t
*
p_region
)
{
dvbsub_objectdef_t
*
p_o
=
p_region
->
p_object
;
// Seek to the last non null element
if
(
p_o
!=
NULL
)
{
for
(;
p_o
->
p_next
!=
NULL
;
p_o
=
p_o
->
p_next
);
p_o
->
p_next
=
p_obj
;
p_o
->
p_next
->
p_next
=
NULL
;
}
else
{
p_region
->
p_object
=
p_obj
;
p_region
->
p_object
->
p_next
=
NULL
;
}
return
;
}
static
dvbsub_image_t
*
dvbsub_parse_pdata
(
dvbsub_thread_t
*
p_spudec
,
uint16_t
length
)
{
dvbsub_image_t
*
p_image
;
uint16_t
i_processed_length
=
0
;
uint16_t
i_lines
=
0
;
uint16_t
i_cols_last
=
0
;
p_image
=
trox_malloc
(
sizeof
(
dvbsub_image_t
)
);
p_image
->
p_last
=
NULL
;
memset
(
p_image
->
i_cols
,
0
,
576
*
sizeof
(
uint16_t
));
/* Let's parse it a first time to determine the size of the buffer */
while
(
i_processed_length
<
length
)
{
switch
(
GetBits
(
&
p_spudec
->
bit_stream
,
8
))
{
case
0x10
:
fprintf
(
stderr
,
"0x10 N/A
\n
"
);
break
;
case
0x11
:
i_processed_length
+=
1
+
dvbsub_count0x11
(
p_spudec
,
&
(
p_image
->
i_cols
[
i_lines
]),
p_image
);
break
;
case
0x12
:
fprintf
(
stderr
,
"0x12 N/A
\n
"
);
break
;
case
0x20
:
fprintf
(
stderr
,
"0x20 N/A
\n
"
);
break
;
case
0x21
:
fprintf
(
stderr
,
"0x21 N/A
\n
"
);
break
;
case
0x22
:
fprintf
(
stderr
,
"0x22 N/A
\n
"
);
break
;
case
0xf0
:
i_processed_length
++
;
i_lines
++
;
break
;
}
}
p_image
->
i_rows
=
i_lines
;
p_image
->
i_cols
[
i_lines
]
=
i_cols_last
;
// Check word-aligned bits
if
(
ShowBits
(
&
p_spudec
->
bit_stream
,
8
)
==
0x00
)
GetBits
(
&
p_spudec
->
bit_stream
,
8
);
return
p_image
;
}
static
void
add_rle_code
(
dvbsub_image_t
*
p
,
uint16_t
num
,
uint8_t
color
)
{
if
(
p
->
p_last
!=
NULL
)
{
p
->
p_last
->
p_next
=
trox_malloc
(
sizeof
(
dvbsub_rle_t
));
p
->
p_last
=
p
->
p_last
->
p_next
;
}
else
{
p
->
p_codes
=
trox_malloc
(
sizeof
(
dvbsub_rle_t
));
p
->
p_last
=
p
->
p_codes
;
}
p
->
p_last
->
i_num
=
num
;
p
->
p_last
->
i_color_code
=
color
;
p
->
p_last
->
p_next
=
NULL
;
return
;
}
static
uint16_t
dvbsub_count0x11
(
dvbsub_thread_t
*
p_spudec
,
uint16_t
*
p
,
dvbsub_image_t
*
p_image
)
{
uint16_t
i_processed
=
0
;
vlc_bool_t
b_stop
=
0
;
uint16_t
i_count
=
0
;
uint8_t
i_color
=
0
;
while
(
!
b_stop
)
{
if
(
(
i_color
=
GetBits
(
&
p_spudec
->
bit_stream
,
4
))
!=
0x00
)
{
(
*
p
)
++
;
i_processed
+=
4
;
// 1 pixel of color code '0000'
add_rle_code
(
p_image
,
1
,
i_color
);
}
else
{
if
(
GetBits
(
&
p_spudec
->
bit_stream
,
1
)
==
0x00
)
// Switch1
{
if
(
ShowBits
(
&
p_spudec
->
bit_stream
,
3
)
!=
0x00
)
{
i_count
=
2
+
GetBits
(
&
p_spudec
->
bit_stream
,
3
);
(
*
p
)
+=
i_count
;
add_rle_code
(
p_image
,
i_count
,
0x00
);
}
else
{
GetBits
(
&
p_spudec
->
bit_stream
,
3
);
b_stop
=
1
;
}
i_processed
+=
8
;
}
else
{
if
(
GetBits
(
&
p_spudec
->
bit_stream
,
1
)
==
0x00
)
//Switch2
{
i_count
=
4
+
GetBits
(
&
p_spudec
->
bit_stream
,
2
);
i_color
=
GetBits
(
&
p_spudec
->
bit_stream
,
4
);
(
*
p
)
+=
i_count
;
i_processed
+=
12
;
add_rle_code
(
p_image
,
i_count
,
i_color
);
}
else
{
switch
(
GetBits
(
&
p_spudec
->
bit_stream
,
2
)
)
//Switch3
{
case
0x0
:
(
*
p
)
++
;
i_processed
+=
8
;
add_rle_code
(
p_image
,
1
,
0x00
);
break
;
case
0x1
:
(
*
p
)
+=
2
;
i_processed
+=
8
;
add_rle_code
(
p_image
,
2
,
0x00
);
break
;
case
0x2
:
i_count
=
9
+
GetBits
(
&
p_spudec
->
bit_stream
,
4
);
i_color
=
GetBits
(
&
p_spudec
->
bit_stream
,
4
);
(
*
p
)
+=
i_count
;
i_processed
+=
16
;
add_rle_code
(
p_image
,
i_count
,
i_color
);
break
;
case
0x3
:
i_count
=
25
+
GetBits
(
&
p_spudec
->
bit_stream
,
8
);
i_color
=
GetBits
(
&
p_spudec
->
bit_stream
,
4
);
(
*
p
)
+=
i_count
;
i_processed
+=
20
;
add_rle_code
(
p_image
,
i_count
,
i_color
);
break
;
}
}
}
}
}
RealignBits
(
&
p_spudec
->
bit_stream
);
return
(
i_processed
+
7
)
/
8
;
}
static
vlc_bool_t
dvbsub_check_page
(
dvbsub_all_t
*
dvbsub
)
{
if
(
dvbsub
->
p_page
!=
NULL
)
{
if
(
dvbsub
->
p_objects
!=
NULL
)
return
VLC_TRUE
;
}
return
VLC_FALSE
;
}
static
void
free_image
(
dvbsub_image_t
*
p_i
)
{
dvbsub_rle_t
*
p1
;
dvbsub_rle_t
*
p2
=
NULL
;
for
(
p1
=
p_i
->
p_codes
;
p1
!=
NULL
;
p1
=
p2
)
{
p2
=
p1
->
p_next
;
trox_free
(
p1
);
p1
=
NULL
;
}
trox_free
(
p_i
);
}
static
void
free_object
(
dvbsub_object_t
*
p_o
)
{
trox_free
(
p_o
);
}
static
void
free_objectdefs
(
dvbsub_objectdef_t
*
p_o
)
{
dvbsub_objectdef_t
*
p1
;
dvbsub_objectdef_t
*
p2
=
NULL
;
for
(
p1
=
p_o
;
p1
!=
NULL
;
p1
=
p2
)
{
p2
=
p1
->
p_next
;
trox_free
(
p1
);
p1
=
NULL
;
}
}
static
void
free_regions
(
dvbsub_region_t
*
p_r
,
uint8_t
nb
)
{
unsigned
int
i
;
for
(
i
=
0
;
i
<
nb
;
i
++
)
free_objectdefs
(
p_r
[
i
].
p_object
);
trox_free
(
p_r
);
p_r
=
NULL
;
}
static
void
free_objects
(
dvbsub_object_t
*
p_o
)
{
dvbsub_object_t
*
p1
;
dvbsub_object_t
*
p2
=
NULL
;
for
(
p1
=
p_o
;
p1
!=
NULL
;
p1
=
p2
)
{
p2
=
p1
->
p_next
;
free_image
(
p1
->
topfield
);
free_image
(
p1
->
bottomfield
);
free_object
(
p1
);
}
}
static
void
free_clut
(
dvbsub_clut_t
*
p_c
)
{
trox_free
(
p_c
);
}
static
void
free_page
(
dvbsub_page_t
*
p_p
)
{
free_regions
(
p_p
->
regions
,
p_p
->
i_regions_number
);
trox_free
(
p_p
);
p_p
=
NULL
;
}
static
void
free_spu
(
subpicture_t
*
p_spu
)
{
if
(
p_spu
->
p_sys
)
{
free_image
(((
dvbsub_render_t
*
)
p_spu
->
p_sys
->
p_data
)
->
p_rle_top
);
free_image
(((
dvbsub_render_t
*
)
p_spu
->
p_sys
->
p_data
)
->
p_rle_bot
);
trox_free
(
p_spu
->
p_sys
->
p_data
);
trox_free
(
p_spu
->
p_sys
);
p_spu
->
p_sys
=
NULL
;
}
}
static
void
free_all
(
dvbsub_all_t
*
p_a
)
{
unsigned
int
i
;
for
(
i
=
0
;
i
<
0xff
;
i
++
)
if
(
p_a
->
p_clut
[
i
])
free_clut
(
p_a
->
p_clut
[
i
]
);
for
(
i
=
0
;
i
<
16
;
i
++
)
if
(
p_a
->
p_spu
[
i
])
free_spu
(
p_a
->
p_spu
[
i
]
);
if
(
p_a
->
p_page
)
free_page
(
p_a
->
p_page
);
free_objects
(
p_a
->
p_objects
);
}
static
void
dvbsub_RenderDVBSUB
(
vout_thread_t
*
p_vout
,
picture_t
*
p_pic
,
const
subpicture_t
*
p_spu
,
vlc_bool_t
b_crop
)
{
// If we have changed the language on the fly,
if
(
!
p_spu
->
p_sys
)
return
;
if
(
p_spu
->
p_sys
->
b_obsolete
)
return
;
switch
(
p_vout
->
output
.
i_chroma
)
{
/* I420 target, no scaling */
case
VLC_FOURCC
(
'I'
,
'4'
,
'2'
,
'2'
):
case
VLC_FOURCC
(
'I'
,
'4'
,
'2'
,
'0'
):
case
VLC_FOURCC
(
'I'
,
'Y'
,
'U'
,
'V'
):
case
VLC_FOURCC
(
'Y'
,
'V'
,
'1'
,
'2'
):
// As long as we just use Y info, I422 and YV12 are just equivalent
// to I420. Remember to change it the day we'll take into account
// U and V info.
RenderI42x
(
p_vout
,
p_pic
,
p_spu
,
VLC_FALSE
);
break
;
/* RV16 target, scaling */
case
VLC_FOURCC
(
'R'
,
'V'
,
'1'
,
'6'
):
fprintf
(
stderr
,
"Not implemented chroma ! RV16)
\n
"
);
//RenderRV16( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
break
;
/* RV32 target, scaling */
case
VLC_FOURCC
(
'R'
,
'V'
,
'2'
,
'4'
):
case
VLC_FOURCC
(
'R'
,
'V'
,
'3'
,
'2'
):
fprintf
(
stderr
,
"Not implemented chroma ! RV32
\n
"
);
//RenderRV32( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
break
;
/* NVidia overlay, no scaling */
case
VLC_FOURCC
(
'Y'
,
'U'
,
'Y'
,
'2'
):
RenderYUY2
(
p_vout
,
p_pic
,
p_spu
,
VLC_FALSE
);
break
;
default:
msg_Err
(
p_vout
,
"unknown chroma, can't render SPU"
);
break
;
}
}
static
void
RenderYUY2
(
vout_thread_t
*
p_vout
,
picture_t
*
p_pic
,
const
subpicture_t
*
p_spu
,
vlc_bool_t
b_crop
)
{
/* Common variables */
uint8_t
*
p_desty
;
uint16_t
i
,
j
;
uint16_t
i_cnt
;
uint16_t
x
,
y
;
dvbsub_rle_t
*
p_c
;
dvbsub_render_t
*
p_r
=
((
dvbsub_render_t
*
)
p_spu
->
p_sys
->
p_data
);
dvbsub_image_t
*
p_im
=
p_r
->
p_rle_top
;
i
=
0
;
j
=
0
;
p_desty
=
p_pic
->
Y_PIXELS
;
//let's render the 1st frame
for
(
p_c
=
p_im
->
p_codes
;
p_c
->
p_next
!=
NULL
;
p_c
=
p_c
->
p_next
)
{
// if( p_c->y != 0 && p_c->t < 0x20)
if
(
p_c
->
y
!=
0
&&
p_c
->
t
<
0x20
)
{
x
=
j
+
p_r
->
i_x
;
y
=
2
*
i
+
p_r
->
i_y
;
//memset(p_desty+ y*p_pic->Y_PITCH + x, p_c->y, p_c->i_num);
// In YUY2 we have to set pixel per pixel
for
(
i_cnt
=
0
;
i_cnt
<
p_c
->
i_num
;
i_cnt
+=
2
)
{
memset
(
p_desty
+
y
*
p_pic
->
Y_PITCH
+
2
*
x
+
i_cnt
,
p_c
->
y
,
1
);
// memset(p_desty+ y*p_pic->Y_PITCH + 2*x + i_cnt+1, p_c->cr, 1);
// memset(p_desty+ y*p_pic->Y_PITCH + 2*x + i_cnt+2, p_c->y, 1);
// memset(p_desty+ y*p_pic->Y_PITCH + 2*x + i_cnt+3, p_c->cb, 1);
}
}
j
+=
p_c
->
i_num
;
if
(
j
>=
p_im
->
i_cols
[
i
])
{
i
++
;
j
=
0
;
}
if
(
i
>=
p_im
->
i_rows
)
break
;
}
//idem for the second frame
p_im
=
p_r
->
p_rle_bot
;
i
=
0
;
j
=
0
;
for
(
p_c
=
p_im
->
p_codes
;
p_c
->
p_next
!=
NULL
;
p_c
=
p_c
->
p_next
)
{
if
(
p_c
->
y
!=
0
&&
p_c
->
t
<
0x20
)
{
x
=
j
+
p_r
->
i_x
;
y
=
2
*
i
+
1
+
p_r
->
i_y
;
//memset(p_desty+ y*p_pic->Y_PITCH + x, p_c->y, p_c->i_num);
// In YUY2 we have to set pixel per pixel
for
(
i_cnt
=
0
;
i_cnt
<
p_c
->
i_num
;
i_cnt
+=
2
)
{
memset
(
p_desty
+
y
*
p_pic
->
Y_PITCH
+
2
*
x
+
i_cnt
,
p_c
->
y
,
1
);
// memset(p_desty+ y*p_pic->Y_PITCH + 2*x + i_cnt+1, p_c->cr, 1);
// memset(p_desty+ y*p_pic->Y_PITCH + 2*x + i_cnt+2, p_c->y, 1);
// memset(p_desty+ y*p_pic->Y_PITCH + 2*x + i_cnt+3, p_c->cb, 1);
}
}
j
+=
p_c
->
i_num
;
if
(
j
>=
p_im
->
i_cols
[
i
])
{
i
++
;
j
=
0
;
}
if
(
i
>=
p_im
->
i_rows
)
break
;
}
}
static
void
RenderI42x
(
vout_thread_t
*
p_vout
,
picture_t
*
p_pic
,
const
subpicture_t
*
p_spu
,
vlc_bool_t
b_crop
)
{
/* Common variables */
uint8_t
*
p_desty
;
uint8_t
*
p_destu
;
uint8_t
*
p_destv
;
uint16_t
i
,
j
;
uint16_t
x
,
y
;
dvbsub_rle_t
*
p_c
;
dvbsub_render_t
*
p_r
=
((
dvbsub_render_t
*
)
p_spu
->
p_sys
->
p_data
);
dvbsub_image_t
*
p_im
=
p_r
->
p_rle_top
;
i
=
0
;
j
=
0
;
p_desty
=
p_pic
->
Y_PIXELS
;
p_destu
=
p_pic
->
U_PIXELS
;
p_destv
=
p_pic
->
V_PIXELS
;
//let's render the 1st frame
for
(
p_c
=
p_im
->
p_codes
;
p_c
->
p_next
!=
NULL
;
p_c
=
p_c
->
p_next
)
{
if
(
p_c
->
y
!=
0
)
{
x
=
j
+
p_r
->
i_x
;
y
=
2
*
i
+
p_r
->
i_y
;
//memset(p_dest+ y*p_pic->U_PITCH*2 + x, p_c->cr, p_c->i_num);
// memset(p_desty+ (y)*p_pic->Y_PITCH + x, p_c->cr, p_c->i_num);
//memset(p_dest+ y*p_pic->V_PITCH*2 + x, p_c->cb, p_c->i_num);
//memset(p_destu+ (y)*p_pic->Y_PITCH + x, p_c->cb, p_c->i_num);
memset
(
p_desty
+
y
*
p_pic
->
Y_PITCH
+
x
,
p_c
->
y
,
p_c
->
i_num
);
// memset(p_desty+ 2*y*p_pic->U_PITCH + x, p_c->cr, p_c->i_num);
// memset(p_desty+ 2*y*p_pic->V_PITCH + x, p_c->cb, p_c->i_num);
}
j
+=
p_c
->
i_num
;
if
(
j
>=
p_im
->
i_cols
[
i
])
{
i
++
;
j
=
0
;
}
if
(
i
>=
p_im
->
i_rows
)
break
;
}
//idem for the second frame
p_im
=
p_r
->
p_rle_bot
;
i
=
0
;
j
=
0
;
for
(
p_c
=
p_im
->
p_codes
;
p_c
->
p_next
!=
NULL
;
p_c
=
p_c
->
p_next
)
{
if
(
p_c
->
y
!=
0
&&
p_c
->
t
<
0x20
)
{
x
=
j
+
p_r
->
i_x
;
y
=
2
*
i
+
1
+
p_r
->
i_y
;
// memset(p_desty+ y*p_pic->U_PITCH*2 + x, p_c->cr, p_c->i_num);
// memset(p_desty+ y*p_pic->V_PITCH*2 + x, p_c->cb, p_c->i_num);
memset
(
p_desty
+
y
*
p_pic
->
Y_PITCH
+
x
,
p_c
->
y
,
p_c
->
i_num
);
// memset(p_desty+ 2*y*p_pic->U_PITCH + x, p_c->cr, p_c->i_num);
// memset(p_desty+ 2*y*p_pic->V_PITCH + x, p_c->cb, p_c->i_num);
}
j
+=
p_c
->
i_num
;
if
(
j
>=
p_im
->
i_cols
[
i
])
{
i
++
;
j
=
0
;
}
if
(
i
>=
p_im
->
i_rows
)
break
;
}
}
static
void
dvbsub_Destroy
(
subpicture_t
*
p_spu
)
{
free_spu
(
p_spu
);
}
static
void
dvbsub_render
(
dvbsub_thread_t
*
p_dec
,
dvbsub_all_t
*
dvbsub
)
{
dvbsub_region_t
*
p_region
;
dvbsub_objectdef_t
*
p_objectdef
;
dvbsub_object_t
*
p_o
;
dvbsub_object_t
*
p_object
;
dvbsub_object_t
*
p_object_old
;
dvbsub_render_t
*
p_render
;
dvbsub_rle_t
*
p_c
;
uint8_t
i
,
j
;
j
=
0
;
/* loop on regions */
for
(
i
=
0
;
i
<
dvbsub
->
p_page
->
i_regions_number
;
i
++
)
{
p_region
=
&
(
dvbsub
->
p_page
->
regions
[
i
]);
/* loop on objects */
for
(
p_objectdef
=
p_region
->
p_object
;
p_objectdef
!=
NULL
;
p_objectdef
=
p_objectdef
->
p_next
)
{
/* Look for the right object */
p_object
=
dvbsub
->
p_objects
;
while
((
p_object
!=
NULL
)
&&
(
p_object
->
i_id
!=
p_objectdef
->
i_id
))
{
p_object
=
p_object
->
p_next
;
}
if
(
p_object
==
NULL
)
{
fprintf
(
stderr
,
"Internal DvbSub decoder error
\n
"
);
return
;
}
/* Allocate the render structure */
p_render
=
trox_malloc
(
sizeof
(
dvbsub_render_t
));
p_render
->
i_x
=
p_region
->
i_x
+
p_objectdef
->
i_xoffset
;
p_render
->
i_y
=
p_region
->
i_y
+
p_objectdef
->
i_yoffset
;
p_render
->
p_rle_top
=
p_object
->
topfield
;
p_render
->
p_rle_bot
=
p_object
->
bottomfield
;
/* Compute the color datas according to the appropriate CLUT */
for
(
p_c
=
p_render
->
p_rle_top
->
p_codes
;
p_c
->
p_next
!=
NULL
;
p_c
=
p_c
->
p_next
)
{
//TODO We assume here we are working in 4bp
p_c
->
y
=
dvbsub
->
p_clut
[
p_region
->
i_clut
]
->
c_4b
[
p_c
->
i_color_code
].
Y
;
p_c
->
cr
=
dvbsub
->
p_clut
[
p_region
->
i_clut
]
->
c_4b
[
p_c
->
i_color_code
].
Cr
;
p_c
->
cb
=
dvbsub
->
p_clut
[
p_region
->
i_clut
]
->
c_4b
[
p_c
->
i_color_code
].
Cb
;
p_c
->
t
=
dvbsub
->
p_clut
[
p_region
->
i_clut
]
->
c_4b
[
p_c
->
i_color_code
].
T
;
}
for
(
p_c
=
p_render
->
p_rle_bot
->
p_codes
;
p_c
->
p_next
!=
NULL
;
p_c
=
p_c
->
p_next
)
{
//TODO We assume here we are working in 4bp
p_c
->
y
=
dvbsub
->
p_clut
[
p_region
->
i_clut
]
->
c_4b
[
p_c
->
i_color_code
].
Y
;
p_c
->
cr
=
dvbsub
->
p_clut
[
p_region
->
i_clut
]
->
c_4b
[
p_c
->
i_color_code
].
Cr
;
p_c
->
cb
=
dvbsub
->
p_clut
[
p_region
->
i_clut
]
->
c_4b
[
p_c
->
i_color_code
].
Cb
;
p_c
->
t
=
dvbsub
->
p_clut
[
p_region
->
i_clut
]
->
c_4b
[
p_c
->
i_color_code
].
T
;
}
/* Allocate the subpicture internal data. */
dvbsub
->
p_spu
[
j
]
=
vout_CreateSubPicture
(
p_dec
->
p_vout
,
MEMORY_SUBPICTURE
);
if
(
dvbsub
->
p_spu
[
j
]
==
NULL
)
{
fprintf
(
stderr
,
"Unable to allocate memory ... skipping
\n
"
);
return
;
}
/* Set the pf_render callback */
dvbsub
->
p_spu
[
j
]
->
pf_render
=
dvbsub_RenderDVBSUB
;
dvbsub
->
p_spu
[
j
]
->
p_sys
=
trox_malloc
(
sizeof
(
subpicture_sys_t
));
dvbsub
->
p_spu
[
j
]
->
p_sys
->
p_data
=
p_render
;
dvbsub
->
p_spu
[
j
]
->
p_sys
->
b_obsolete
=
0
;
dvbsub
->
p_spu
[
j
]
->
pf_destroy
=
dvbsub_Destroy
;
dvbsub
->
p_spu
[
j
]
->
i_start
=
p_dec
->
bit_stream
.
p_pes
->
i_pts
;
dvbsub
->
p_spu
[
j
]
->
i_stop
=
dvbsub
->
p_spu
[
j
]
->
i_start
+
dvbsub
->
p_page
->
i_timeout
*
1000000
;
dvbsub
->
p_spu
[
j
]
->
b_ephemer
=
VLC_FALSE
;
// At this stage, we have all we need in p_render
// We need to free the object
//Remove this object from the list
p_object_old
=
p_object
;
if
(
p_object
==
dvbsub
->
p_objects
)
dvbsub
->
p_objects
=
p_object
->
p_next
;
else
{
for
(
p_o
=
dvbsub
->
p_objects
;
p_o
->
p_next
!=
p_object
;
p_o
=
p_o
->
p_next
);
p_o
->
p_next
=
p_object
->
p_next
;
}
free_object
(
p_object_old
);
vout_DisplaySubPicture
(
p_dec
->
p_vout
,
dvbsub
->
p_spu
[
j
]
);
j
++
;
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment