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
c26db46d
Commit
c26db46d
authored
Apr 28, 2011
by
Laurent Aimar
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
No functionnal changes (vout).
K&R and removed variables prefixe.
parent
790c5845
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
1157 additions
and
1297 deletions
+1157
-1297
include/vlc_spu.h
include/vlc_spu.h
+1
-1
src/video_output/interlacing.c
src/video_output/interlacing.c
+102
-119
src/video_output/postprocessing.c
src/video_output/postprocessing.c
+60
-72
src/video_output/video_epg.c
src/video_output/video_epg.c
+163
-172
src/video_output/vout_subpictures.c
src/video_output/vout_subpictures.c
+831
-933
No files found.
include/vlc_spu.h
View file @
c26db46d
...
...
@@ -80,7 +80,7 @@ VLC_EXPORT( void, spu_PutSubpicture, ( spu_t *, subpicture_t * ) );
*
* The returned value if non NULL must be released by subpicture_Delete().
*/
VLC_EXPORT
(
subpicture_t
*
,
spu_Render
,
(
spu_t
*
,
const
vlc_fourcc_t
*
p_chroma_list
,
const
video_format_t
*
p_fmt_dst
,
const
video_format_t
*
p_fmt_src
,
mtime_t
render_subtitle_date
,
mtime_t
render_osd_date
,
bool
b_subtitle_only
)
);
VLC_EXPORT
(
subpicture_t
*
,
spu_Render
,
(
spu_t
*
,
const
vlc_fourcc_t
*
p_chroma_list
,
const
video_format_t
*
p_fmt_dst
,
const
video_format_t
*
p_fmt_src
,
mtime_t
render_subtitle_date
,
mtime_t
render_osd_date
,
bool
ignore_osd
)
);
/**
* It registers a new SPU channel.
...
...
src/video_output/interlacing.c
View file @
c26db46d
...
...
@@ -55,207 +55,190 @@ static const char *deinterlace_modes[] = {
static
bool
DeinterlaceIsModeValid
(
const
char
*
mode
)
{
for
(
unsigned
i
=
0
;
deinterlace_modes
[
i
];
i
++
)
{
if
(
!
strcmp
(
deinterlace_modes
[
i
],
mode
))
if
(
!
strcmp
(
deinterlace_modes
[
i
],
mode
))
return
true
;
}
return
false
;
}
static
char
*
FilterFind
(
char
*
psz_filter_base
,
const
char
*
psz_module
)
static
char
*
FilterFind
(
char
*
filter_base
,
const
char
*
module_name
)
{
const
size_t
i_module
=
strlen
(
psz_module
);
const
char
*
psz_filter
=
psz_
filter_base
;
const
size_t
module_length
=
strlen
(
module_name
);
const
char
*
filter
=
filter_base
;
if
(
!
psz_filter
||
i_module
<=
0
)
if
(
!
filter
||
module_length
<=
0
)
return
NULL
;
for
(
;;
)
{
char
*
psz_find
=
strstr
(
psz_filter
,
psz_module
);
if
(
!
psz_find
)
for
(;;)
{
char
*
start
=
strstr
(
filter
,
module_name
);
if
(
!
start
)
return
NULL
;
if
(
psz_find
[
i_module
]
==
'\0'
||
psz_find
[
i_module
]
==
':'
)
return
psz_find
;
psz_filter
=
&
psz_find
[
i_module
];
if
(
start
[
module_length
]
==
'\0'
||
start
[
module_length
]
==
':'
)
return
start
;
filter
=
&
start
[
module_length
];
}
}
static
bool
DeinterlaceIsPresent
(
vout_thread_t
*
p_vout
)
static
bool
DeinterlaceIsPresent
(
vout_thread_t
*
vout
)
{
char
*
psz_filter
=
var_GetNonEmptyString
(
p_vout
,
"video-filter"
);
char
*
filter
=
var_GetNonEmptyString
(
vout
,
"video-filter"
);
bool
b_found
=
FilterFind
(
psz_filter
,
"deinterlace"
)
!=
NULL
;
bool
is_found
=
FilterFind
(
filter
,
"deinterlace"
)
!=
NULL
;
free
(
psz_filter
);
free
(
filter
);
return
b
_found
;
return
is
_found
;
}
static
void
DeinterlaceRemove
(
vout_thread_t
*
p_vout
)
static
void
DeinterlaceRemove
(
vout_thread_t
*
vout
)
{
char
*
psz_filter
=
var_GetNonEmptyString
(
p_vout
,
"video-filter"
);
char
*
filter
=
var_GetNonEmptyString
(
vout
,
"video-filter"
);
char
*
psz
=
FilterFind
(
psz_filter
,
"deinterlace"
);
if
(
!
psz
)
{
free
(
psz_filter
);
char
*
start
=
FilterFind
(
filter
,
"deinterlace"
);
if
(
!
start
)
{
free
(
filter
);
return
;
}
/* */
strcpy
(
&
psz
[
0
],
&
psz
[
strlen
(
"deinterlace"
)]
);
if
(
*
psz
==
':'
)
strcpy
(
&
psz
[
0
],
&
psz
[
1
]
);
strcpy
(
&
start
[
0
],
&
start
[
strlen
(
"deinterlace"
)]
);
if
(
*
start
==
':'
)
strcpy
(
&
start
[
0
],
&
start
[
1
]
);
var_SetString
(
p_vout
,
"video-filter"
,
psz_filter
);
free
(
psz_filter
);
var_SetString
(
vout
,
"video-filter"
,
filter
);
free
(
filter
);
}
static
void
DeinterlaceAdd
(
vout_thread_t
*
p_vout
)
static
void
DeinterlaceAdd
(
vout_thread_t
*
vout
)
{
char
*
psz_filter
=
var_GetNonEmptyString
(
p_vout
,
"video-filter"
);
char
*
filter
=
var_GetNonEmptyString
(
vout
,
"video-filter"
);
if
(
FilterFind
(
psz_filter
,
"deinterlace"
)
)
{
free
(
psz_filter
);
if
(
FilterFind
(
filter
,
"deinterlace"
))
{
free
(
filter
);
return
;
}
/* */
if
(
psz_filter
)
{
char
*
psz_tmp
=
psz_filter
;
if
(
asprintf
(
&
psz_filter
,
"%s:%s"
,
psz_tmp
,
"deinterlace"
)
<
0
)
psz_filter
=
psz_tmp
;
if
(
filter
)
{
char
*
tmp
=
filter
;
if
(
asprintf
(
&
filter
,
"%s:%s"
,
tmp
,
"deinterlace"
)
<
0
)
filter
=
tmp
;
else
free
(
psz_tmp
);
}
else
{
psz_filter
=
strdup
(
"deinterlace"
);
free
(
tmp
);
}
else
{
filter
=
strdup
(
"deinterlace"
);
}
if
(
psz_filter
)
{
var_SetString
(
p_vout
,
"video-filter"
,
psz_filter
);
free
(
psz_filter
);
if
(
filter
)
{
var_SetString
(
vout
,
"video-filter"
,
filter
);
free
(
filter
);
}
}
static
int
DeinterlaceCallback
(
vlc_object_t
*
p_this
,
char
const
*
psz_
cmd
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
p_data
)
static
int
DeinterlaceCallback
(
vlc_object_t
*
object
,
char
const
*
cmd
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
data
)
{
VLC_UNUSED
(
psz_cmd
);
VLC_UNUSED
(
oldval
);
VLC_UNUSED
(
newval
);
VLC_UNUSED
(
p_
data
);
vout_thread_t
*
p_vout
=
(
vout_thread_t
*
)
p_this
;
VLC_UNUSED
(
cmd
);
VLC_UNUSED
(
oldval
);
VLC_UNUSED
(
newval
);
VLC_UNUSED
(
data
);
vout_thread_t
*
vout
=
(
vout_thread_t
*
)
object
;
/* */
const
int
i_deinterlace
=
var_GetInteger
(
p_this
,
"deinterlace"
);
char
*
psz_mode
=
var_GetString
(
p_this
,
"deinterlace-mode"
);
const
bool
is_needed
=
var_GetBool
(
p_this
,
"deinterlace-needed"
);
if
(
!
psz_mode
||
!
DeinterlaceIsModeValid
(
psz_mode
)
)
const
int
deinterlace_state
=
var_GetInteger
(
vout
,
"deinterlace"
);
char
*
mode
=
var_GetString
(
vout
,
"deinterlace-mode"
);
const
bool
is_needed
=
var_GetBool
(
vout
,
"deinterlace-needed"
);
if
(
!
mode
||
!
DeinterlaceIsModeValid
(
mode
)
)
return
VLC_EGENERIC
;
/* */
char
*
psz_old
=
var_CreateGetString
(
p_vout
,
"sout-deinterlace-mode"
);
var_SetString
(
p_vout
,
"sout-deinterlace-mode"
,
psz_mode
);
char
*
old
=
var_CreateGetString
(
vout
,
"sout-deinterlace-mode"
);
var_SetString
(
vout
,
"sout-deinterlace-mode"
,
mode
);
msg_Dbg
(
p_vout
,
"deinterlace %d, mode %s, is_needed %d"
,
i_deinterlace
,
psz_mode
,
is_needed
);
if
(
i_deinterlace
==
0
||
(
i_deinterlace
==
-
1
&&
!
is_needed
)
)
{
DeinterlaceRemove
(
p_vout
);
}
else
if
(
!
DeinterlaceIsPresent
(
p_vout
)
)
{
DeinterlaceAdd
(
p_vout
);
}
else
if
(
psz_old
&&
strcmp
(
psz_old
,
psz_mode
)
)
{
var_TriggerCallback
(
p_vout
,
"video-filter"
);
}
msg_Dbg
(
vout
,
"deinterlace %d, mode %s, is_needed %d"
,
deinterlace_state
,
mode
,
is_needed
);
if
(
deinterlace_state
==
0
||
(
deinterlace_state
==
-
1
&&
!
is_needed
))
DeinterlaceRemove
(
vout
);
else
if
(
!
DeinterlaceIsPresent
(
vout
))
DeinterlaceAdd
(
vout
);
else
if
(
old
&&
strcmp
(
old
,
mode
))
var_TriggerCallback
(
vout
,
"video-filter"
);
/* */
free
(
psz_old
);
free
(
psz_mode
);
free
(
old
);
free
(
mode
);
return
VLC_SUCCESS
;
}
void
vout_InitInterlacingSupport
(
vout_thread_t
*
p_vout
,
bool
is_interlaced
)
void
vout_InitInterlacingSupport
(
vout_thread_t
*
vout
,
bool
is_interlaced
)
{
vlc_value_t
val
,
text
;
msg_Dbg
(
p_vout
,
"Deinterlacing available"
);
msg_Dbg
(
vout
,
"Deinterlacing available"
);
/* Create the configuration variables */
/* */
var_Create
(
p_vout
,
"deinterlace"
,
VLC_VAR_INTEGER
|
VLC_VAR_DOINHERIT
|
VLC_VAR_HASCHOICE
);
int
i_deinterlace
=
var_GetInteger
(
p_vout
,
"deinterlace"
);
i_deinterlace
=
__MAX
(
__MIN
(
i_deinterlace
,
1
),
-
1
);
var_Create
(
vout
,
"deinterlace"
,
VLC_VAR_INTEGER
|
VLC_VAR_DOINHERIT
|
VLC_VAR_HASCHOICE
);
int
deinterlace_state
=
var_GetInteger
(
vout
,
"deinterlace"
);
deinterlace_state
=
__MAX
(
__MIN
(
deinterlace_state
,
1
),
-
1
);
text
.
psz_string
=
_
(
"Deinterlace"
);
var_Change
(
p_vout
,
"deinterlace"
,
VLC_VAR_SETTEXT
,
&
text
,
NULL
);
const
module_config_t
*
p_optd
=
config_FindConfig
(
VLC_OBJECT
(
p_vout
),
"deinterlace"
);
var_Change
(
p_vout
,
"deinterlace"
,
VLC_VAR_CLEARCHOICES
,
NULL
,
NULL
);
for
(
int
i
=
0
;
p_optd
&&
i
<
p_optd
->
i_list
;
i
++
)
{
val
.
i_int
=
p_optd
->
pi_list
[
i
];
text
.
psz_string
=
(
char
*
)
vlc_gettext
(
p_optd
->
ppsz_list_text
[
i
]);
var_Change
(
p_vout
,
"deinterlace"
,
VLC_VAR_ADDCHOICE
,
&
val
,
&
text
);
var_Change
(
vout
,
"deinterlace"
,
VLC_VAR_SETTEXT
,
&
text
,
NULL
);
const
module_config_t
*
optd
=
config_FindConfig
(
VLC_OBJECT
(
vout
),
"deinterlace"
);
var_Change
(
vout
,
"deinterlace"
,
VLC_VAR_CLEARCHOICES
,
NULL
,
NULL
);
for
(
int
i
=
0
;
optd
&&
i
<
optd
->
i_list
;
i
++
)
{
val
.
i_int
=
optd
->
pi_list
[
i
];
text
.
psz_string
=
(
char
*
)
vlc_gettext
(
optd
->
ppsz_list_text
[
i
]);
var_Change
(
vout
,
"deinterlace"
,
VLC_VAR_ADDCHOICE
,
&
val
,
&
text
);
}
var_AddCallback
(
p_vout
,
"deinterlace"
,
DeinterlaceCallback
,
NULL
);
var_AddCallback
(
vout
,
"deinterlace"
,
DeinterlaceCallback
,
NULL
);
/* */
var_Create
(
p_vout
,
"deinterlace-mode"
,
VLC_VAR_STRING
|
VLC_VAR_DOINHERIT
|
VLC_VAR_HASCHOICE
);
char
*
psz_deinterlace
=
var_GetNonEmptyString
(
p_vout
,
"deinterlace-mode"
);
var_Create
(
vout
,
"deinterlace-mode"
,
VLC_VAR_STRING
|
VLC_VAR_DOINHERIT
|
VLC_VAR_HASCHOICE
);
char
*
deinterlace_mode
=
var_GetNonEmptyString
(
vout
,
"deinterlace-mode"
);
text
.
psz_string
=
_
(
"Deinterlace mode"
);
var_Change
(
p_vout
,
"deinterlace-mode"
,
VLC_VAR_SETTEXT
,
&
text
,
NULL
);
var_Change
(
vout
,
"deinterlace-mode"
,
VLC_VAR_SETTEXT
,
&
text
,
NULL
);
const
module_config_t
*
p_optm
=
config_FindConfig
(
VLC_OBJECT
(
p_vout
),
"deinterlace-mode"
);
var_Change
(
p_vout
,
"deinterlace-mode"
,
VLC_VAR_CLEARCHOICES
,
NULL
,
NULL
);
for
(
int
i
=
0
;
p_optm
&&
i
<
p_optm
->
i_list
;
i
++
)
{
if
(
!
DeinterlaceIsModeValid
(
p_optm
->
ppsz_list
[
i
]
)
)
const
module_config_t
*
optm
=
config_FindConfig
(
VLC_OBJECT
(
vout
),
"deinterlace-mode"
);
var_Change
(
vout
,
"deinterlace-mode"
,
VLC_VAR_CLEARCHOICES
,
NULL
,
NULL
);
for
(
int
i
=
0
;
optm
&&
i
<
optm
->
i_list
;
i
++
)
{
if
(
!
DeinterlaceIsModeValid
(
optm
->
ppsz_list
[
i
]))
continue
;
val
.
psz_string
=
p_
optm
->
ppsz_list
[
i
];
text
.
psz_string
=
(
char
*
)
vlc_gettext
(
p_
optm
->
ppsz_list_text
[
i
]);
var_Change
(
p_vout
,
"deinterlace-mode"
,
VLC_VAR_ADDCHOICE
,
&
val
,
&
text
);
val
.
psz_string
=
optm
->
ppsz_list
[
i
];
text
.
psz_string
=
(
char
*
)
vlc_gettext
(
optm
->
ppsz_list_text
[
i
]);
var_Change
(
vout
,
"deinterlace-mode"
,
VLC_VAR_ADDCHOICE
,
&
val
,
&
text
);
}
var_AddCallback
(
p_vout
,
"deinterlace-mode"
,
DeinterlaceCallback
,
NULL
);
var_AddCallback
(
vout
,
"deinterlace-mode"
,
DeinterlaceCallback
,
NULL
);
/* */
var_Create
(
p_vout
,
"deinterlace-needed"
,
VLC_VAR_BOOL
);
var_AddCallback
(
p_vout
,
"deinterlace-needed"
,
DeinterlaceCallback
,
NULL
);
var_Create
(
vout
,
"deinterlace-needed"
,
VLC_VAR_BOOL
);
var_AddCallback
(
vout
,
"deinterlace-needed"
,
DeinterlaceCallback
,
NULL
);
/* Override the initial value from filters if present */
char
*
psz_filter_mode
=
NULL
;
if
(
DeinterlaceIsPresent
(
p_vout
)
)
psz_filter_mode
=
var_CreateGetNonEmptyString
(
p_vout
,
"sout-deinterlace-mode"
);
if
(
psz_filter_mode
)
{
i_deinterlace
=
1
;
free
(
psz_deinterlace
);
psz_deinterlace
=
psz_filter_mode
;
char
*
filter_mode
=
NULL
;
if
(
DeinterlaceIsPresent
(
vout
))
filter_mode
=
var_CreateGetNonEmptyString
(
vout
,
"sout-deinterlace-mode"
);
if
(
filter_mode
)
{
deinterlace_state
=
1
;
free
(
deinterlace_mode
);
deinterlace_mode
=
filter_mode
;
}
/* */
val
.
psz_string
=
psz_deinterlace
?
psz_deinterlace
:
p_
optm
->
orig
.
psz
;
var_Change
(
p_vout
,
"deinterlace-mode"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
val
.
psz_string
=
deinterlace_mode
?
deinterlace_mode
:
optm
->
orig
.
psz
;
var_Change
(
vout
,
"deinterlace-mode"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
val
.
b_bool
=
is_interlaced
;
var_Change
(
p_vout
,
"deinterlace-needed"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
var_Change
(
vout
,
"deinterlace-needed"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
var_SetInteger
(
p_vout
,
"deinterlace"
,
i_deinterlace
);
free
(
psz_deinterlace
);
var_SetInteger
(
vout
,
"deinterlace"
,
deinterlace_state
);
free
(
deinterlace_mode
);
}
void
vout_SetInterlacingState
(
vout_thread_t
*
p_vout
,
vout_interlacing_support_t
*
state
,
bool
is_interlaced
)
void
vout_SetInterlacingState
(
vout_thread_t
*
vout
,
vout_interlacing_support_t
*
state
,
bool
is_interlaced
)
{
/* Wait 30s before quiting interlacing mode */
const
int
interlacing_change
=
(
!!
is_interlaced
)
-
(
!!
state
->
is_interlaced
);
if
((
interlacing_change
==
1
)
||
(
interlacing_change
==
-
1
&&
state
->
date
+
30000000
<
mdate
()))
{
msg_Dbg
(
p_vout
,
"Detected %s video"
,
is_interlaced
?
"interlaced"
:
"progressive"
);
var_SetBool
(
p_vout
,
"deinterlace-needed"
,
is_interlaced
);
msg_Dbg
(
vout
,
"Detected %s video"
,
is_interlaced
?
"interlaced"
:
"progressive"
);
var_SetBool
(
vout
,
"deinterlace-needed"
,
is_interlaced
);
state
->
is_interlaced
=
is_interlaced
;
}
...
...
src/video_output/postprocessing.c
View file @
c26db46d
...
...
@@ -31,113 +31,101 @@
#include "postprocessing.h"
static
bool
PostProcessIsPresent
(
const
char
*
psz_filter
)
static
bool
PostProcessIsPresent
(
const
char
*
filter
)
{
const
char
*
p
sz_pp
=
"postproc"
;
const
size_t
i_pp
=
strlen
(
psz_
pp
);
return
psz_
filter
&&
!
strncmp
(
psz_filter
,
psz_pp
,
strlen
(
psz_pp
)
)
&&
(
psz_filter
[
i_pp
]
==
'\0'
||
psz_filter
[
i_pp
]
==
':'
);
const
char
*
p
p
=
"postproc"
;
const
size_t
pp_length
=
strlen
(
pp
);
return
filter
&&
!
strncmp
(
filter
,
pp
,
strlen
(
pp
)
)
&&
(
filter
[
pp_length
]
==
'\0'
||
filter
[
pp_length
]
==
':'
);
}
static
int
PostProcessCallback
(
vlc_object_t
*
p_this
,
char
const
*
psz_
cmd
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
p_data
)
static
int
PostProcessCallback
(
vlc_object_t
*
object
,
char
const
*
cmd
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
data
)
{
vout_thread_t
*
p_vout
=
(
vout_thread_t
*
)
p_this
;
VLC_UNUSED
(
psz_cmd
);
VLC_UNUSED
(
oldval
);
VLC_UNUSED
(
p_
data
);
vout_thread_t
*
vout
=
(
vout_thread_t
*
)
object
;
VLC_UNUSED
(
cmd
);
VLC_UNUSED
(
oldval
);
VLC_UNUSED
(
data
);
static
const
char
*
p
sz_p
p
=
"postproc"
;
static
const
char
*
pp
=
"postproc"
;
char
*
psz_vf2
=
var_GetString
(
p_vout
,
"video-filter"
);
char
*
filters
=
var_GetString
(
vout
,
"video-filter"
);
if
(
newval
.
i_int
<=
0
)
{
if
(
PostProcessIsPresent
(
psz_vf2
)
)
{
strcpy
(
psz_vf2
,
&
psz_vf2
[
strlen
(
psz_pp
)]
);
if
(
*
psz_vf2
==
':'
)
strcpy
(
psz_vf2
,
&
psz_vf2
[
1
]
);
if
(
newval
.
i_int
<=
0
)
{
if
(
PostProcessIsPresent
(
filters
))
{
strcpy
(
filters
,
&
filters
[
strlen
(
pp
)]);
if
(
*
filters
==
':'
)
strcpy
(
filters
,
&
filters
[
1
]);
}
}
else
{
if
(
!
PostProcessIsPresent
(
psz_vf2
)
)
{
if
(
psz_vf2
)
{
char
*
psz_tmp
=
psz_vf2
;
if
(
asprintf
(
&
psz_vf2
,
"%s:%s"
,
psz_pp
,
psz_tmp
)
<
0
)
psz_vf2
=
psz_tmp
;
}
else
{
if
(
!
PostProcessIsPresent
(
filters
))
{
if
(
filters
)
{
char
*
tmp
=
filters
;
if
(
asprintf
(
&
filters
,
"%s:%s"
,
pp
,
tmp
)
<
0
)
filters
=
tmp
;
else
free
(
psz_tmp
);
}
else
{
psz_vf2
=
strdup
(
psz_pp
);
free
(
tmp
);
}
else
{
filters
=
strdup
(
pp
);
}
}
}
if
(
newval
.
i_int
>
0
)
var_SetInteger
(
p_vout
,
"postproc-q"
,
newval
.
i_int
);
if
(
psz_vf2
)
{
var_SetString
(
p_vout
,
"video-filter"
,
psz_vf2
);
free
(
psz_vf2
);
}
else
if
(
newval
.
i_int
>
0
)
{
var_TriggerCallback
(
p_vout
,
"video-filter"
);
if
(
newval
.
i_int
>
0
)
var_SetInteger
(
vout
,
"postproc-q"
,
newval
.
i_int
);
if
(
filters
)
{
var_SetString
(
vout
,
"video-filter"
,
filters
);
free
(
filters
);
}
else
if
(
newval
.
i_int
>
0
)
{
var_TriggerCallback
(
vout
,
"video-filter"
);
}
return
VLC_SUCCESS
;
}
static
void
PostProcessEnable
(
vout_thread_t
*
p_vout
)
static
void
PostProcessEnable
(
vout_thread_t
*
vout
)
{
vlc_value_t
text
;
msg_Dbg
(
p_vout
,
"Post-processing available"
);
var_Create
(
p_vout
,
"postprocess"
,
VLC_VAR_INTEGER
|
VLC_VAR_HASCHOICE
);
msg_Dbg
(
vout
,
"Post-processing available"
);
var_Create
(
vout
,
"postprocess"
,
VLC_VAR_INTEGER
|
VLC_VAR_HASCHOICE
);
text
.
psz_string
=
_
(
"Post processing"
);
var_Change
(
p_vout
,
"postprocess"
,
VLC_VAR_SETTEXT
,
&
text
,
NULL
);
var_Change
(
vout
,
"postprocess"
,
VLC_VAR_SETTEXT
,
&
text
,
NULL
);
for
(
int
i
=
0
;
i
<=
6
;
i
++
)
{
for
(
int
i
=
0
;
i
<=
6
;
i
++
)
{
vlc_value_t
val
;
vlc_value_t
text
;
char
psz_text
[
1
+
1
];
char
tmp
[
1
+
1
];
val
.
i_int
=
i
;
snprintf
(
psz_text
,
sizeof
(
psz_text
),
"%d"
,
i
);
if
(
i
==
0
)
snprintf
(
tmp
,
sizeof
(
tmp
),
"%d"
,
i
);
if
(
i
==
0
)
text
.
psz_string
=
_
(
"Disable"
);
else
text
.
psz_string
=
psz_text
;
var_Change
(
p_vout
,
"postprocess"
,
VLC_VAR_ADDCHOICE
,
&
val
,
&
text
);
text
.
psz_string
=
tmp
;
var_Change
(
vout
,
"postprocess"
,
VLC_VAR_ADDCHOICE
,
&
val
,
&
text
);
}
var_AddCallback
(
p_vout
,
"postprocess"
,
PostProcessCallback
,
NULL
);
var_AddCallback
(
vout
,
"postprocess"
,
PostProcessCallback
,
NULL
);
/* */
char
*
psz_filter
=
var_GetNonEmptyString
(
p_vout
,
"video-filter"
);
int
i_
postproc_q
=
0
;
if
(
PostProcessIsPresent
(
psz_filter
)
)
i_postproc_q
=
var_CreateGetInteger
(
p_vout
,
"postproc-q"
);
char
*
filters
=
var_GetNonEmptyString
(
vout
,
"video-filter"
);
int
postproc_q
=
0
;
if
(
PostProcessIsPresent
(
filters
)
)
postproc_q
=
var_CreateGetInteger
(
vout
,
"postproc-q"
);
var_SetInteger
(
p_vout
,
"postprocess"
,
i_postproc_q
);
var_SetInteger
(
vout
,
"postprocess"
,
postproc_q
);
free
(
psz_filter
);
free
(
filters
);
}
static
void
PostProcessDisable
(
vout_thread_t
*
p_vout
)
static
void
PostProcessDisable
(
vout_thread_t
*
vout
)
{
msg_Dbg
(
p_vout
,
"Post-processing no more available"
);
var_Destroy
(
p_vout
,
"postprocess"
);
msg_Dbg
(
vout
,
"Post-processing no more available"
);
var_Destroy
(
vout
,
"postprocess"
);
}
void
vout_SetPostProcessingState
(
vout_thread_t
*
vout
,
vout_postprocessing_support_t
*
state
,
int
qtype
)
{
const
int
postproc_change
=
(
qtype
!=
QTYPE_NONE
)
-
(
state
->
qtype
!=
QTYPE_NONE
);
if
(
postproc_change
==
1
)
PostProcessEnable
(
vout
);
else
if
(
postproc_change
==
-
1
)
PostProcessDisable
(
vout
);
if
(
postproc_change
)
state
->
qtype
=
qtype
;
const
int
postproc_change
=
(
qtype
!=
QTYPE_NONE
)
-
(
state
->
qtype
!=
QTYPE_NONE
);
if
(
postproc_change
==
1
)
PostProcessEnable
(
vout
);
else
if
(
postproc_change
==
-
1
)
PostProcessDisable
(
vout
);
if
(
postproc_change
)
state
->
qtype
=
qtype
;
}
src/video_output/video_epg.c
View file @
c26db46d
...
...
@@ -37,285 +37,276 @@
#define EPG_NAME_SIZE 0.05
#define EPG_PROGRAM_SIZE 0.03
static
subpicture_region_t
*
vout_OSDEpgSlider
(
int
i_x
,
int
i_
y
,
int
i_width
,
int
i_
height
,
float
f_ratio
)
static
subpicture_region_t
*
vout_OSDEpgSlider
(
int
x
,
int
y
,
int
width
,
int
height
,
float
ratio
)
{
video_format_t
fmt
;
subpicture_region_t
*
p_
region
;
subpicture_region_t
*
region
;
/* Create a new subpicture region */
video_format_Init
(
&
fmt
,
VLC_CODEC_YUVA
);
fmt
.
i_width
=
fmt
.
i_visible_width
=
i_
width
;
fmt
.
i_height
=
fmt
.
i_visible_height
=
i_
height
;
video_format_Init
(
&
fmt
,
VLC_CODEC_YUVA
);
fmt
.
i_width
=
fmt
.
i_visible_width
=
width
;
fmt
.
i_height
=
fmt
.
i_visible_height
=
height
;
fmt
.
i_sar_num
=
0
;
fmt
.
i_sar_den
=
1
;
p_region
=
subpicture_region_New
(
&
fmt
);
if
(
!
p_region
)
region
=
subpicture_region_New
(
&
fmt
);
if
(
!
region
)
return
NULL
;
p_region
->
i_x
=
i_
x
;
p_region
->
i_y
=
i_
y
;
region
->
i_x
=
x
;
region
->
i_y
=
y
;
picture_t
*
p
_picture
=
p_
region
->
p_picture
;
picture_t
*
p
icture
=
region
->
p_picture
;
f_ratio
=
__MIN
(
__MAX
(
f_ratio
,
0
),
1
);
int
i_filled_part_width
=
f_ratio
*
i_
width
;
ratio
=
__MIN
(
__MAX
(
ratio
,
0
),
1
);
int
filled_part_width
=
ratio
*
width
;
for
(
int
j
=
0
;
j
<
i_height
;
j
++
)
{
for
(
int
i
=
0
;
i
<
i_width
;
i
++
)
{
#define WRITE_COMP( plane, value ) \
p_picture->p[plane].p_pixels[p_picture->p[plane].i_pitch * j + i] = value
for
(
int
j
=
0
;
j
<
height
;
j
++
)
{
for
(
int
i
=
0
;
i
<
width
;
i
++
)
{
#define WRITE_COMP(plane, value) \
picture->p[plane].p_pixels[picture->p[plane].i_pitch * j + i] = value
/* Draw the slider. */
bool
is_outline
=
j
==
0
||
j
==
i_height
-
1
||
i
==
0
||
i
==
i_width
-
1
;
WRITE_COMP
(
0
,
is_outline
?
0x00
:
0xff
);
WRITE_COMP
(
1
,
0x80
);
WRITE_COMP
(
2
,
0x80
);
bool
is_outline
=
j
==
0
||
j
==
height
-
1
||
i
==
0
||
i
==
width
-
1
;
WRITE_COMP
(
0
,
is_outline
?
0x00
:
0xff
);
WRITE_COMP
(
1
,
0x80
);
WRITE_COMP
(
2
,
0x80
);
/* We can see the video through the part of the slider
which corresponds to the leaving time. */
bool
is_border
=
j
<
3
||
j
>
i_height
-
4
||
i
<
3
||
i
>
i_width
-
4
||
i
<
i_
filled_part_width
;
WRITE_COMP
(
3
,
is_border
?
0xff
:
0x00
);
bool
is_border
=
j
<
3
||
j
>
height
-
4
||
i
<
3
||
i
>
width
-
4
||
i
<
filled_part_width
;
WRITE_COMP
(
3
,
is_border
?
0xff
:
0x00
);
#undef WRITE_COMP
}
}
return
p_
region
;
return
region
;
}
static
subpicture_region_t
*
vout_OSDEpgText
(
const
char
*
psz_string
,
int
i_x
,
int
i_
y
,
int
i_size
,
uint32_t
i_color
)
static
subpicture_region_t
*
vout_OSDEpgText
(
const
char
*
text
,
int
x
,
int
y
,
int
size
,
uint32_t
color
)
{
video_format_t
fmt
;
subpicture_region_t
*
p_
region
;
subpicture_region_t
*
region
;
if
(
!
psz_string
)
if
(
!
text
)
return
NULL
;
/* Create a new subpicture region */
video_format_Init
(
&
fmt
,
VLC_CODEC_TEXT
);
video_format_Init
(
&
fmt
,
VLC_CODEC_TEXT
);
fmt
.
i_sar_num
=
0
;
fmt
.
i_sar_den
=
1
;
p_region
=
subpicture_region_New
(
&
fmt
);
if
(
!
p_region
)
region
=
subpicture_region_New
(
&
fmt
);
if
(
!
region
)
return
NULL
;
/* Set subpicture parameters */
p_region
->
psz_text
=
strdup
(
psz_string
);
p_region
->
i_align
=
0
;
p_region
->
i_x
=
i_
x
;
p_region
->
i_y
=
i_
y
;
region
->
psz_text
=
strdup
(
text
);
region
->
i_align
=
0
;
region
->
i_x
=
x
;
region
->
i_y
=
y
;
/* Set text style */
p_region
->
p_style
=
text_style_New
();
if
(
p_region
->
p_style
)
{
p_region
->
p_style
->
i_font_size
=
i_size
;
p_region
->
p_style
->
i_font_color
=
i_color
;
p_region
->
p_style
->
i_font_alpha
=
0
;
region
->
p_style
=
text_style_New
();
if
(
region
->
p_style
)
{
region
->
p_style
->
i_font_size
=
size
;
region
->
p_style
->
i_font_color
=
color
;
region
->
p_style
->
i_font_alpha
=
0
;
}
return
p_
region
;
return
region
;
}
static
subpicture_region_t
*
vout_BuildOSDEpg
(
vlc_epg_t
*
p_
epg
,
int
i_x
,
int
i_
y
,
int
i_
visible_width
,
int
i_visible_height
)
static
subpicture_region_t
*
vout_BuildOSDEpg
(
vlc_epg_t
*
epg
,
int
x
,
int
y
,
int
visible_width
,
int
visible_height
)
{
subpicture_region_t
*
p_region_ret
;
subpicture_region_t
**
pp_region
=
&
p_region_ret
;
subpicture_region_t
*
head
;
subpicture_region_t
**
last_ptr
=
&
head
;
time_t
i_test
=
time
(
NULL
);
time_t
current_time
=
time
(
NULL
);
/* Display the name of the channel. */
*
pp_region
=
vout_OSDEpgText
(
p_
epg
->
psz_name
,
i_x
+
i_visible_width
*
EPG_LEFT
,
i_y
+
i_
visible_height
*
EPG_TOP
,
i_
visible_height
*
EPG_NAME_SIZE
,
0x00ffffff
);
*
last_ptr
=
vout_OSDEpgText
(
epg
->
psz_name
,
x
+
visible_width
*
EPG_LEFT
,
y
+
visible_height
*
EPG_TOP
,
visible_height
*
EPG_NAME_SIZE
,
0x00ffffff
);
if
(
!*
pp_region
)
return
p_region_ret
;
if
(
!*
last_ptr
)
return
head
;
/* Display the name of the current program. */
pp_region
=
&
(
*
pp_region
)
->
p_next
;
*
pp_region
=
vout_OSDEpgText
(
p_
epg
->
p_current
->
psz_name
,
i_x
+
i_visible_width
*
(
EPG_LEFT
+
0
.
025
),
i_y
+
i_visible_height
*
(
EPG_TOP
+
0
.
05
),
i_
visible_height
*
EPG_PROGRAM_SIZE
,
0x00ffffff
);
last_ptr
=
&
(
*
last_ptr
)
->
p_next
;
*
last_ptr
=
vout_OSDEpgText
(
epg
->
p_current
->
psz_name
,
x
+
visible_width
*
(
EPG_LEFT
+
0
.
025
),
y
+
visible_height
*
(
EPG_TOP
+
0
.
05
),
visible_height
*
EPG_PROGRAM_SIZE
,
0x00ffffff
);
if
(
!*
pp_region
)
return
p_region_ret
;
if
(
!*
last_ptr
)
return
head
;
/* Display the current program time slider. */
pp_region
=
&
(
*
pp_region
)
->
p_next
;
*
pp_region
=
vout_OSDEpgSlider
(
i_x
+
i_visible_width
*
EPG_LEFT
,
i_y
+
i_visible_height
*
(
EPG_TOP
+
0
.
1
),
i_visible_width
*
(
1
-
2
*
EPG_LEFT
),
i_
visible_height
*
0
.
05
,
(
i_test
-
p_epg
->
p_current
->
i_start
)
/
(
float
)
p_epg
->
p_current
->
i_duration
);
last_ptr
=
&
(
*
last_ptr
)
->
p_next
;
*
last_ptr
=
vout_OSDEpgSlider
(
x
+
visible_width
*
EPG_LEFT
,
y
+
visible_height
*
(
EPG_TOP
+
0
.
1
),
visible_width
*
(
1
-
2
*
EPG_LEFT
),
visible_height
*
0
.
05
,
(
current_time
-
epg
->
p_current
->
i_start
)
/
(
float
)
epg
->
p_current
->
i_duration
);
if
(
!*
pp_region
)
return
p_region_ret
;
if
(
!*
last_ptr
)
return
head
;
/* Format the hours of the beginning and the end of the current program. */
struct
tm
tm_start
,
tm_end
;
time_t
t_start
=
p_
epg
->
p_current
->
i_start
;
time_t
t_end
=
p_epg
->
p_current
->
i_start
+
p_
epg
->
p_current
->
i_duration
;
localtime_r
(
&
t_start
,
&
tm_start
);
localtime_r
(
&
t_end
,
&
tm_end
);
char
psz
_start
[
128
];
char
psz
_end
[
128
];
snprintf
(
psz_start
,
sizeof
(
psz
_start
),
"%2.2d:%2.2d"
,
tm_start
.
tm_hour
,
tm_start
.
tm_min
);
snprintf
(
psz_end
,
sizeof
(
psz
_end
),
"%2.2d:%2.2d"
,
tm_end
.
tm_hour
,
tm_end
.
tm_min
);
time_t
t_start
=
epg
->
p_current
->
i_start
;
time_t
t_end
=
epg
->
p_current
->
i_start
+
epg
->
p_current
->
i_duration
;
localtime_r
(
&
t_start
,
&
tm_start
);
localtime_r
(
&
t_end
,
&
tm_end
);
char
text
_start
[
128
];
char
text
_end
[
128
];
snprintf
(
text_start
,
sizeof
(
text
_start
),
"%2.2d:%2.2d"
,
tm_start
.
tm_hour
,
tm_start
.
tm_min
);
snprintf
(
text_end
,
sizeof
(
text
_end
),
"%2.2d:%2.2d"
,
tm_end
.
tm_hour
,
tm_end
.
tm_min
);
/* Display those hours. */
pp_region
=
&
(
*
pp_region
)
->
p_next
;
*
pp_region
=
vout_OSDEpgText
(
psz
_start
,
i_x
+
i_visible_width
*
(
EPG_LEFT
+
0
.
02
),
i_y
+
i_visible_height
*
(
EPG_TOP
+
0
.
15
),
i_
visible_height
*
EPG_PROGRAM_SIZE
,
0x00ffffff
);
if
(
!*
pp_region
)
return
p_region_ret
;
pp_region
=
&
(
*
pp_region
)
->
p_next
;
*
pp_region
=
vout_OSDEpgText
(
psz
_end
,
i_x
+
i_visible_width
*
(
1
-
EPG_LEFT
-
0
.
085
),
i_y
+
i_visible_height
*
(
EPG_TOP
+
0
.
15
),
i_
visible_height
*
EPG_PROGRAM_SIZE
,
0x00ffffff
);
return
p_region_ret
;
last_ptr
=
&
(
*
last_ptr
)
->
p_next
;
*
last_ptr
=
vout_OSDEpgText
(
text
_start
,
x
+
visible_width
*
(
EPG_LEFT
+
0
.
02
),
y
+
visible_height
*
(
EPG_TOP
+
0
.
15
),
visible_height
*
EPG_PROGRAM_SIZE
,
0x00ffffff
);
if
(
!*
last_ptr
)
return
head
;
last_ptr
=
&
(
*
last_ptr
)
->
p_next
;
*
last_ptr
=
vout_OSDEpgText
(
text
_end
,
x
+
visible_width
*
(
1
-
EPG_LEFT
-
0
.
085
),
y
+
visible_height
*
(
EPG_TOP
+
0
.
15
),
visible_height
*
EPG_PROGRAM_SIZE
,
0x00ffffff
);
return
head
;
}
struct
subpicture_updater_sys_t
{
vlc_epg_t
*
p_
epg
;
vlc_epg_t
*
epg
;
};
static
int
OSDEpgValidate
(
subpicture_t
*
p_
subpic
,
bool
has_src_changed
,
const
video_format_t
*
p_
fmt_src
,
bool
has_dst_changed
,
const
video_format_t
*
p_
fmt_dst
,
mtime_t
i_ts
)
static
int
OSDEpgValidate
(
subpicture_t
*
subpic
,
bool
has_src_changed
,
const
video_format_t
*
fmt_src
,
bool
has_dst_changed
,
const
video_format_t
*
fmt_dst
,
mtime_t
ts
)
{
VLC_UNUSED
(
p_subpic
);
VLC_UNUSED
(
i_ts
);
VLC_UNUSED
(
p_
fmt_src
);
VLC_UNUSED
(
has_dst_changed
);
VLC_UNUSED
(
p_
fmt_dst
);
VLC_UNUSED
(
subpic
);
VLC_UNUSED
(
ts
);
VLC_UNUSED
(
fmt_src
);
VLC_UNUSED
(
has_dst_changed
);
VLC_UNUSED
(
fmt_dst
);
if
(
!
has_src_changed
&&
!
has_dst_changed
)
if
(
!
has_src_changed
&&
!
has_dst_changed
)
return
VLC_SUCCESS
;
return
VLC_EGENERIC
;
}
static
void
OSDEpgUpdate
(
subpicture_t
*
p_
subpic
,
const
video_format_t
*
p_
fmt_src
,
const
video_format_t
*
p_
fmt_dst
,
mtime_t
i_ts
)
static
void
OSDEpgUpdate
(
subpicture_t
*
subpic
,
const
video_format_t
*
fmt_src
,
const
video_format_t
*
fmt_dst
,
mtime_t
ts
)
{
subpicture_updater_sys_t
*
p_sys
=
p_
subpic
->
updater
.
p_sys
;
VLC_UNUSED
(
p_fmt_dst
);
VLC_UNUSED
(
i_
ts
);
p_subpic
->
i_original_picture_width
=
p_
fmt_src
->
i_width
;
p_subpic
->
i_original_picture_height
=
p_
fmt_src
->
i_height
;
p_subpic
->
p_region
=
vout_BuildOSDEpg
(
p_sys
->
p_
epg
,
p_
fmt_src
->
i_x_offset
,
p_
fmt_src
->
i_y_offset
,
p_
fmt_src
->
i_visible_width
,
p_fmt_src
->
i_visible_height
);
subpicture_updater_sys_t
*
sys
=
subpic
->
updater
.
p_sys
;
VLC_UNUSED
(
fmt_dst
);
VLC_UNUSED
(
ts
);
subpic
->
i_original_picture_width
=
fmt_src
->
i_width
;
subpic
->
i_original_picture_height
=
fmt_src
->
i_height
;
subpic
->
p_region
=
vout_BuildOSDEpg
(
sys
->
epg
,
fmt_src
->
i_x_offset
,
fmt_src
->
i_y_offset
,
fmt_src
->
i_visible_width
,
fmt_src
->
i_visible_height
);
}
static
void
OSDEpgDestroy
(
subpicture_t
*
p_subpic
)
static
void
OSDEpgDestroy
(
subpicture_t
*
subpic
)
{
subpicture_updater_sys_t
*
p_sys
=
p_
subpic
->
updater
.
p_sys
;
subpicture_updater_sys_t
*
sys
=
subpic
->
updater
.
p_sys
;
vlc_epg_Delete
(
p_sys
->
p_epg
);
free
(
p_sys
);
vlc_epg_Delete
(
sys
->
epg
);
free
(
sys
);
}
/**
* \brief Show EPG information about the current program of an input item
* \param
p_
vout pointer to the vout the information is to be showed on
* \param vout pointer to the vout the information is to be showed on
* \param p_input pointer to the input item the information is to be showed
*/
int
vout_OSDEpg
(
vout_thread_t
*
p_vout
,
input_item_t
*
p_input
)
int
vout_OSDEpg
(
vout_thread_t
*
vout
,
input_item_t
*
input
)
{
subpicture_t
*
p_spu
;
mtime_t
i_now
=
mdate
()
;
char
*
now_playing
=
input_item_GetNowPlaying
(
input
)
;
vlc_epg_t
*
epg
=
NULL
;
char
*
psz_now_playing
=
input_item_GetNowPlaying
(
p_input
);
vlc_epg_t
*
p_epg
=
NULL
;
vlc_mutex_lock
(
&
p_input
->
lock
);
vlc_mutex_lock
(
&
input
->
lock
);
/* Look for the current program EPG event */
for
(
int
i
=
0
;
i
<
p_input
->
i_epg
;
i
++
)
{
vlc_epg_t
*
p_tmp
=
p_input
->
pp_epg
[
i
];
if
(
p_tmp
->
p_current
&&
p_tmp
->
p_current
->
psz_name
&&
psz_now_playing
!=
NULL
&&
!
strcmp
(
p_tmp
->
p_current
->
psz_name
,
psz_now_playing
)
)
{
p_epg
=
vlc_epg_New
(
p_tmp
->
psz_name
);
vlc_epg_Merge
(
p_epg
,
p_tmp
);
for
(
int
i
=
0
;
i
<
input
->
i_epg
;
i
++
)
{
vlc_epg_t
*
tmp
=
input
->
pp_epg
[
i
];
if
(
tmp
->
p_current
&&
tmp
->
p_current
->
psz_name
&&
now_playing
!=
NULL
&&
!
strcmp
(
tmp
->
p_current
->
psz_name
,
now_playing
))
{
epg
=
vlc_epg_New
(
tmp
->
psz_name
);
vlc_epg_Merge
(
epg
,
tmp
);
break
;
}
}
vlc_mutex_unlock
(
&
p_input
->
lock
);
vlc_mutex_unlock
(
&
input
->
lock
);
/* If no EPG event has been found. */
if
(
p_epg
==
NULL
)
if
(
epg
==
NULL
)
return
VLC_EGENERIC
;
subpicture_updater_sys_t
*
p_sys
=
malloc
(
sizeof
(
*
p_sys
)
);
if
(
!
p_sys
)
{
vlc_epg_Delete
(
p_epg
);
subpicture_updater_sys_t
*
sys
=
malloc
(
sizeof
(
*
sys
));
if
(
!
sys
)
{
vlc_epg_Delete
(
epg
);
return
VLC_EGENERIC
;
}
p_sys
->
p_epg
=
p_
epg
;
sys
->
epg
=
epg
;
subpicture_updater_t
updater
=
{
.
pf_validate
=
OSDEpgValidate
,
.
pf_update
=
OSDEpgUpdate
,
.
pf_destroy
=
OSDEpgDestroy
,
.
p_sys
=
p_
sys
.
p_sys
=
sys
};
p_spu
=
subpicture_New
(
&
updater
);
if
(
!
p_spu
)
{
vlc_epg_Delete
(
p_sys
->
p_epg
);
free
(
p_sys
);
const
mtime_t
now
=
mdate
(
);
subpicture_t
*
subpic
=
subpicture_New
(
&
updater
);
if
(
!
subpic
)
{
vlc_epg_Delete
(
sys
->
epg
);
free
(
sys
);
return
VLC_EGENERIC
;
}
p_spu
->
i_channel
=
SPU_DEFAULT_CHANNEL
;
p_spu
->
i_start
=
i_
now
;
p_spu
->
i_stop
=
i_
now
+
3000
*
INT64_C
(
1000
);
p_spu
->
b_ephemer
=
true
;
p_spu
->
b_absolute
=
true
;
p_spu
->
b_fade
=
true
;
subpic
->
i_channel
=
SPU_DEFAULT_CHANNEL
;
subpic
->
i_start
=
now
;
subpic
->
i_stop
=
now
+
3000
*
INT64_C
(
1000
);
subpic
->
b_ephemer
=
true
;
subpic
->
b_absolute
=
true
;
subpic
->
b_fade
=
true
;
vout_PutSubpicture
(
p_vout
,
p_spu
);
vout_PutSubpicture
(
vout
,
subpic
);
return
VLC_SUCCESS
;
}
src/video_output/vout_subpictures.c
View file @
c26db46d
...
...
@@ -52,224 +52,221 @@
#define VOUT_MAX_SUBPICTURES (__MAX(VOUT_MAX_PICTURES, SPU_MAX_PREPARE_TIME/5000))
/* */
typedef
struct
{
subpicture_t
*
p_subpicture
;
bool
b_reject
;
typedef
struct
{
subpicture_t
*
subpicture
;
bool
reject
;
}
spu_heap_entry_t
;
typedef
struct
{
spu_heap_entry_t
p_entry
[
VOUT_MAX_SUBPICTURES
];
typedef
struct
{
spu_heap_entry_t
entry
[
VOUT_MAX_SUBPICTURES
];
}
spu_heap_t
;
struct
spu_private_t
{
vlc_mutex_t
lock
;
/* lock to protect all followings fields */
vlc_object_t
*
p_input
;
struct
spu_private_t
{
vlc_mutex_t
lock
;
/* lock to protect all followings fields */
vlc_object_t
*
input
;
spu_heap_t
heap
;
spu_heap_t
heap
;
int
i_channel
;
/**< number of subpicture channels registered */
filter_t
*
p_text
;
/**< text renderer module */
filter_t
*
p_scale_yuvp
;
/**< scaling module for YUVP */
filter_t
*
p_scale
;
/**< scaling module (all but YUVP) */
bool
b_force_crop
;
/**< force cropping of subpicture */
int
i_crop_x
,
i_crop_y
,
i_crop_width
,
i_crop_height
;
/**< cropping */
int
channel
;
/**< number of subpicture channels registered */
filter_t
*
text
;
/**< text renderer module */
filter_t
*
scale_yuvp
;
/**< scaling module for YUVP */
filter_t
*
scale
;
/**< scaling module (all but YUVP) */
bool
force_crop
;
/**< force cropping of subpicture */
struct
{
int
x
;
int
y
;
int
width
;
int
height
;
}
crop
;
/**< cropping */
int
i_margin
;
/**< force position of a subpicture */
bool
b_force_palette
;
/**< force palette of subpicture */
uint8_t
palette
[
4
][
4
];
/**< forced palette */
int
margin
;
/**< force position of a subpicture */
bool
force_palette
;
/**< force palette of subpicture */
uint8_t
palette
[
4
][
4
];
/**< forced palette */
/* Subpiture filters */
char
*
psz_
source_chain_update
;
char
*
source_chain_update
;
vlc_mutex_t
source_chain_lock
;
filter_chain_t
*
p_
source_chain
;
char
*
psz_
filter_chain_update
;
filter_chain_t
*
source_chain
;
char
*
filter_chain_update
;
vlc_mutex_t
filter_chain_lock
;
filter_chain_t
*
p_
filter_chain
;
filter_chain_t
*
filter_chain
;
/* */
mtime_t
i_
last_sort_date
;
mtime_t
last_sort_date
;
};
/*****************************************************************************
* heap managment
*****************************************************************************/
static
void
SpuHeapInit
(
spu_heap_t
*
p_heap
)
static
void
SpuHeapInit
(
spu_heap_t
*
heap
)
{
for
(
int
i
=
0
;
i
<
VOUT_MAX_SUBPICTURES
;
i
++
)
{
spu_heap_entry_t
*
e
=
&
p_heap
->
p_entry
[
i
];
for
(
int
i
=
0
;
i
<
VOUT_MAX_SUBPICTURES
;
i
++
)
{
spu_heap_entry_t
*
e
=
&
heap
->
entry
[
i
];
e
->
p_
subpicture
=
NULL
;
e
->
b_reject
=
false
;
e
->
subpicture
=
NULL
;
e
->
reject
=
false
;
}
}
static
int
SpuHeapPush
(
spu_heap_t
*
p_heap
,
subpicture_t
*
p_subpic
)
static
int
SpuHeapPush
(
spu_heap_t
*
heap
,
subpicture_t
*
subpic
)
{
for
(
int
i
=
0
;
i
<
VOUT_MAX_SUBPICTURES
;
i
++
)
{
spu_heap_entry_t
*
e
=
&
p_heap
->
p_entry
[
i
];
for
(
int
i
=
0
;
i
<
VOUT_MAX_SUBPICTURES
;
i
++
)
{
spu_heap_entry_t
*
e
=
&
heap
->
entry
[
i
];
if
(
e
->
p_subpicture
)
if
(
e
->
subpicture
)
continue
;
e
->
p_subpicture
=
p_
subpic
;
e
->
b_reject
=
false
;
e
->
subpicture
=
subpic
;
e
->
reject
=
false
;
return
VLC_SUCCESS
;
}
return
VLC_EGENERIC
;
}
static
void
SpuHeapDeleteAt
(
spu_heap_t
*
p_heap
,
int
i_index
)
static
void
SpuHeapDeleteAt
(
spu_heap_t
*
heap
,
int
index
)
{
spu_heap_entry_t
*
e
=
&
p_heap
->
p_entry
[
i_
index
];
spu_heap_entry_t
*
e
=
&
heap
->
entry
[
index
];
if
(
e
->
p_subpicture
)
subpicture_Delete
(
e
->
p_subpicture
);
if
(
e
->
subpicture
)
subpicture_Delete
(
e
->
subpicture
);
e
->
p_
subpicture
=
NULL
;
e
->
subpicture
=
NULL
;
}
static
int
SpuHeapDeleteSubpicture
(
spu_heap_t
*
p_heap
,
subpicture_t
*
p_subpic
)
static
int
SpuHeapDeleteSubpicture
(
spu_heap_t
*
heap
,
subpicture_t
*
subpic
)
{
for
(
int
i
=
0
;
i
<
VOUT_MAX_SUBPICTURES
;
i
++
)
{
spu_heap_entry_t
*
e
=
&
p_heap
->
p_entry
[
i
];
for
(
int
i
=
0
;
i
<
VOUT_MAX_SUBPICTURES
;
i
++
)
{
spu_heap_entry_t
*
e
=
&
heap
->
entry
[
i
];
if
(
e
->
p_subpicture
!=
p_subpic
)
if
(
e
->
subpicture
!=
subpic
)
continue
;
SpuHeapDeleteAt
(
p_heap
,
i
);
SpuHeapDeleteAt
(
heap
,
i
);
return
VLC_SUCCESS
;
}
return
VLC_EGENERIC
;
}
static
void
SpuHeapClean
(
spu_heap_t
*
p_heap
)
static
void
SpuHeapClean
(
spu_heap_t
*
heap
)
{
for
(
int
i
=
0
;
i
<
VOUT_MAX_SUBPICTURES
;
i
++
)
{
spu_heap_entry_t
*
e
=
&
p_heap
->
p_entry
[
i
];
if
(
e
->
p_subpicture
)
subpicture_Delete
(
e
->
p_subpicture
);
for
(
int
i
=
0
;
i
<
VOUT_MAX_SUBPICTURES
;
i
++
)
{
spu_heap_entry_t
*
e
=
&
heap
->
entry
[
i
];
if
(
e
->
subpicture
)
subpicture_Delete
(
e
->
subpicture
);
}
}
struct
filter_owner_sys_t
{
spu_t
*
p_spu
;
int
i_channel
;
struct
filter_owner_sys_t
{
spu_t
*
spu
;
int
channel
;
};
static
void
FilterRelease
(
filter_t
*
p_filter
)
static
void
FilterRelease
(
filter_t
*
filter
)
{
if
(
p_filter
->
p_module
)
module_unneed
(
p_filter
,
p_filter
->
p_module
);
if
(
p_filter
->
p_owner
)
free
(
p_filter
->
p_owner
);
if
(
filter
->
p_module
)
module_unneed
(
filter
,
filter
->
p_module
);
if
(
filter
->
p_owner
)
free
(
filter
->
p_owner
);
vlc_object_release
(
p_filter
);
vlc_object_release
(
filter
);
}
static
picture_t
*
spu_new_video_buffer
(
filter_t
*
p_filter
)
static
picture_t
*
spu_new_video_buffer
(
filter_t
*
filter
)
{
const
video_format_t
*
p_fmt
=
&
p_
filter
->
fmt_out
.
video
;
const
video_format_t
*
fmt
=
&
filter
->
fmt_out
.
video
;
VLC_UNUSED
(
p_
filter
);
return
picture_NewFromFormat
(
p_fmt
);
VLC_UNUSED
(
filter
);
return
picture_NewFromFormat
(
fmt
);
}
static
void
spu_del_video_buffer
(
filter_t
*
p_filter
,
picture_t
*
p_picture
)
static
void
spu_del_video_buffer
(
filter_t
*
filter
,
picture_t
*
picture
)
{
VLC_UNUSED
(
p_
filter
);
picture_Release
(
p_picture
);
VLC_UNUSED
(
filter
);
picture_Release
(
picture
);
}
static
int
spu_get_attachments
(
filter_t
*
p_
filter
,
input_attachment_t
***
ppp_attachment
,
int
*
pi_attachment
)
static
int
spu_get_attachments
(
filter_t
*
filter
,
input_attachment_t
***
attachment_ptr
,
int
*
attachment_count
)
{
spu_t
*
p_spu
=
p_filter
->
p_owner
->
p_
spu
;
int
i_
ret
=
VLC_EGENERIC
;
if
(
p_spu
->
p
->
p_input
)
i_ret
=
input_Control
(
(
input_thread_t
*
)
p_spu
->
p
->
p_
input
,
INPUT_GET_ATTACHMENTS
,
ppp_attachment
,
pi_attachment
);
return
i_
ret
;
spu_t
*
spu
=
filter
->
p_owner
->
spu
;
int
ret
=
VLC_EGENERIC
;
if
(
spu
->
p
->
input
)
ret
=
input_Control
((
input_thread_t
*
)
spu
->
p
->
input
,
INPUT_GET_ATTACHMENTS
,
attachment_ptr
,
attachment_count
);
return
ret
;
}
static
filter_t
*
SpuRenderCreateAndLoadText
(
spu_t
*
p_spu
)
static
filter_t
*
SpuRenderCreateAndLoadText
(
spu_t
*
spu
)
{
filter_t
*
p_text
=
vlc_custom_create
(
p_spu
,
sizeof
(
*
p_
text
),
VLC_OBJECT_GENERIC
,
"spu text"
);
if
(
!
p_text
)
filter_t
*
text
=
vlc_custom_create
(
spu
,
sizeof
(
*
text
),
VLC_OBJECT_GENERIC
,
"spu text"
);
if
(
!
text
)
return
NULL
;
p_text
->
p_owner
=
xmalloc
(
sizeof
(
*
p_text
->
p_owner
)
);
p_text
->
p_owner
->
p_spu
=
p_
spu
;
text
->
p_owner
=
xmalloc
(
sizeof
(
*
text
->
p_owner
)
);
text
->
p_owner
->
spu
=
spu
;
es_format_Init
(
&
p_text
->
fmt_in
,
VIDEO_ES
,
0
);
es_format_Init
(
&
text
->
fmt_in
,
VIDEO_ES
,
0
);
es_format_Init
(
&
p_text
->
fmt_out
,
VIDEO_ES
,
0
);
p_text
->
fmt_out
.
video
.
i_width
=
p_text
->
fmt_out
.
video
.
i_visible_width
=
32
;
p_text
->
fmt_out
.
video
.
i_height
=
p_
text
->
fmt_out
.
video
.
i_visible_height
=
32
;
es_format_Init
(
&
text
->
fmt_out
,
VIDEO_ES
,
0
);
text
->
fmt_out
.
video
.
i_width
=
text
->
fmt_out
.
video
.
i_visible_width
=
32
;
text
->
fmt_out
.
video
.
i_height
=
text
->
fmt_out
.
video
.
i_visible_height
=
32
;
p_
text
->
pf_get_attachments
=
spu_get_attachments
;
text
->
pf_get_attachments
=
spu_get_attachments
;
vlc_object_attach
(
p_text
,
p_spu
);
p_text
->
p_module
=
module_need
(
p_text
,
"text renderer"
,
"$text-renderer"
,
false
);
vlc_object_attach
(
text
,
spu
);
text
->
p_module
=
module_need
(
text
,
"text renderer"
,
"$text-renderer"
,
false
);
/* Create a few variables used for enhanced text rendering */
var_Create
(
p_text
,
"spu-elapsed"
,
VLC_VAR_TIME
);
var_Create
(
p_text
,
"text-rerender"
,
VLC_VAR_BOOL
);
var_Create
(
p_text
,
"scale"
,
VLC_VAR_INTEGER
);
var_Create
(
text
,
"spu-elapsed"
,
VLC_VAR_TIME
);
var_Create
(
text
,
"text-rerender"
,
VLC_VAR_BOOL
);
var_Create
(
text
,
"scale"
,
VLC_VAR_INTEGER
);
return
p_
text
;
return
text
;
}
static
filter_t
*
SpuRenderCreateAndLoadScale
(
vlc_object_t
*
p_obj
,
vlc_fourcc_t
i_src_chroma
,
vlc_fourcc_t
i_dst_chroma
,
bool
b_resize
)
static
filter_t
*
SpuRenderCreateAndLoadScale
(
vlc_object_t
*
object
,
vlc_fourcc_t
src_chroma
,
vlc_fourcc_t
dst_chroma
,
bool
require_resize
)
{
filter_t
*
p_scale
=
vlc_custom_create
(
p_obj
,
sizeof
(
*
p_
scale
),
VLC_OBJECT_GENERIC
,
"scale"
);
if
(
!
p_scale
)
filter_t
*
scale
=
vlc_custom_create
(
object
,
sizeof
(
*
scale
),
VLC_OBJECT_GENERIC
,
"scale"
);
if
(
!
scale
)
return
NULL
;
es_format_Init
(
&
p_scale
->
fmt_in
,
VIDEO_ES
,
0
);
p_scale
->
fmt_in
.
video
.
i_chroma
=
i_
src_chroma
;
p_
scale
->
fmt_in
.
video
.
i_width
=
p_
scale
->
fmt_in
.
video
.
i_height
=
32
;
es_format_Init
(
&
scale
->
fmt_in
,
VIDEO_ES
,
0
);
scale
->
fmt_in
.
video
.
i_chroma
=
src_chroma
;
scale
->
fmt_in
.
video
.
i_width
=
scale
->
fmt_in
.
video
.
i_height
=
32
;
es_format_Init
(
&
p_scale
->
fmt_out
,
VIDEO_ES
,
0
);
p_scale
->
fmt_out
.
video
.
i_chroma
=
i_
dst_chroma
;
p_
scale
->
fmt_out
.
video
.
i_width
=
p_scale
->
fmt_out
.
video
.
i_height
=
b
_resize
?
16
:
32
;
es_format_Init
(
&
scale
->
fmt_out
,
VIDEO_ES
,
0
);
scale
->
fmt_out
.
video
.
i_chroma
=
dst_chroma
;
scale
->
fmt_out
.
video
.
i_width
=
scale
->
fmt_out
.
video
.
i_height
=
require
_resize
?
16
:
32
;
p_
scale
->
pf_video_buffer_new
=
spu_new_video_buffer
;
p_
scale
->
pf_video_buffer_del
=
spu_del_video_buffer
;
scale
->
pf_video_buffer_new
=
spu_new_video_buffer
;
scale
->
pf_video_buffer_del
=
spu_del_video_buffer
;
vlc_object_attach
(
p_scale
,
p_obj
);
p_scale
->
p_module
=
module_need
(
p_scale
,
"video filter2"
,
NULL
,
false
);
vlc_object_attach
(
scale
,
object
);
scale
->
p_module
=
module_need
(
scale
,
"video filter2"
,
NULL
,
false
);
return
p_
scale
;
return
scale
;
}
static
void
SpuRenderText
(
spu_t
*
p_spu
,
bool
*
pb_
rerender_text
,
subpicture_region_t
*
p_
region
,
mtime_t
render_date
)
static
void
SpuRenderText
(
spu_t
*
spu
,
bool
*
rerender_text
,
subpicture_region_t
*
region
,
mtime_t
render_date
)
{
filter_t
*
p_text
=
p_spu
->
p
->
p_
text
;
filter_t
*
text
=
spu
->
p
->
text
;
assert
(
p_region
->
fmt
.
i_chroma
==
VLC_CODEC_TEXT
);
assert
(
region
->
fmt
.
i_chroma
==
VLC_CODEC_TEXT
);
if
(
!
p_text
||
!
p_text
->
p_module
)
if
(
!
text
||
!
text
->
p_module
)
return
;
/* Setup 3 variables which can be used to render
...
...
@@ -291,18 +288,14 @@ static void SpuRenderText( spu_t *p_spu, bool *pb_rerender_text,
* least show up on screen, but the effect won't change
* the text over time.
*/
var_SetTime
(
p_text
,
"spu-elapsed"
,
render_date
);
var_SetBool
(
p_text
,
"text-rerender"
,
false
);
if
(
p_text
->
pf_render_html
&&
p_region
->
psz_html
)
{
p_text
->
pf_render_html
(
p_text
,
p_region
,
p_region
);
}
else
if
(
p_text
->
pf_render_text
)
{
p_text
->
pf_render_text
(
p_text
,
p_region
,
p_region
);
}
*
pb_rerender_text
=
var_GetBool
(
p_text
,
"text-rerender"
);
var_SetTime
(
text
,
"spu-elapsed"
,
render_date
);
var_SetBool
(
text
,
"text-rerender"
,
false
);
if
(
text
->
pf_render_html
&&
region
->
psz_html
)
text
->
pf_render_html
(
text
,
region
,
region
);
else
if
(
text
->
pf_render_text
)
text
->
pf_render_text
(
text
,
region
,
region
);
*
rerender_text
=
var_GetBool
(
text
,
"text-rerender"
);
}
/**
...
...
@@ -310,43 +303,42 @@ static void SpuRenderText( spu_t *p_spu, bool *pb_rerender_text,
*/
#define SCALE_UNIT (1000)
typedef
struct
{
typedef
struct
{
int
w
;
int
h
;
}
spu_scale_t
;
static
spu_scale_t
spu_scale_create
(
int
w
,
int
h
)
static
spu_scale_t
spu_scale_create
(
int
w
,
int
h
)
{
spu_scale_t
s
=
{
.
w
=
w
,
.
h
=
h
};
if
(
s
.
w
<=
0
)
if
(
s
.
w
<=
0
)
s
.
w
=
SCALE_UNIT
;
if
(
s
.
h
<=
0
)
if
(
s
.
h
<=
0
)
s
.
h
=
SCALE_UNIT
;
return
s
;
}
static
spu_scale_t
spu_scale_unit
(
void
)
static
spu_scale_t
spu_scale_unit
(
void
)
{
return
spu_scale_create
(
SCALE_UNIT
,
SCALE_UNIT
);
return
spu_scale_create
(
SCALE_UNIT
,
SCALE_UNIT
);
}
static
spu_scale_t
spu_scale_createq
(
int64_t
wn
,
int64_t
wd
,
int64_t
hn
,
int64_t
hd
)
static
spu_scale_t
spu_scale_createq
(
int64_t
wn
,
int64_t
wd
,
int64_t
hn
,
int64_t
hd
)
{
return
spu_scale_create
(
wn
*
SCALE_UNIT
/
wd
,
hn
*
SCALE_UNIT
/
hd
);
return
spu_scale_create
(
wn
*
SCALE_UNIT
/
wd
,
hn
*
SCALE_UNIT
/
hd
);
}
static
int
spu_scale_w
(
int
v
,
const
spu_scale_t
s
)
static
int
spu_scale_w
(
int
v
,
const
spu_scale_t
s
)
{
return
v
*
s
.
w
/
SCALE_UNIT
;
}
static
int
spu_scale_h
(
int
v
,
const
spu_scale_t
s
)
static
int
spu_scale_h
(
int
v
,
const
spu_scale_t
s
)
{
return
v
*
s
.
h
/
SCALE_UNIT
;
}
static
int
spu_invscale_w
(
int
v
,
const
spu_scale_t
s
)
static
int
spu_invscale_w
(
int
v
,
const
spu_scale_t
s
)
{
return
v
*
SCALE_UNIT
/
s
.
w
;
}
static
int
spu_invscale_h
(
int
v
,
const
spu_scale_t
s
)
static
int
spu_invscale_h
(
int
v
,
const
spu_scale_t
s
)
{
return
v
*
SCALE_UNIT
/
s
.
h
;
}
...
...
@@ -354,175 +346,150 @@ static int spu_invscale_h( int v, const spu_scale_t s )
/**
* A few area functions helpers
*/
typedef
struct
{
int
i_x
;
int
i_y
;
int
i_width
;
int
i_height
;
typedef
struct
{
int
x
;
int
y
;
int
width
;
int
height
;
spu_scale_t
scale
;
}
spu_area_t
;
static
spu_area_t
spu_area_create
(
int
x
,
int
y
,
int
w
,
int
h
,
spu_scale_t
s
)
static
spu_area_t
spu_area_create
(
int
x
,
int
y
,
int
w
,
int
h
,
spu_scale_t
s
)
{
spu_area_t
a
=
{
.
i_x
=
x
,
.
i_y
=
y
,
.
i_width
=
w
,
.
i_
height
=
h
,
.
scale
=
s
};
spu_area_t
a
=
{
.
x
=
x
,
.
y
=
y
,
.
width
=
w
,
.
height
=
h
,
.
scale
=
s
};
return
a
;
}
static
spu_area_t
spu_area_scaled
(
spu_area_t
a
)
static
spu_area_t
spu_area_scaled
(
spu_area_t
a
)
{
if
(
a
.
scale
.
w
==
SCALE_UNIT
&&
a
.
scale
.
h
==
SCALE_UNIT
)
if
(
a
.
scale
.
w
==
SCALE_UNIT
&&
a
.
scale
.
h
==
SCALE_UNIT
)
return
a
;
a
.
i_x
=
spu_scale_w
(
a
.
i_x
,
a
.
scale
);
a
.
i_y
=
spu_scale_h
(
a
.
i_y
,
a
.
scale
);
a
.
i_width
=
spu_scale_w
(
a
.
i_width
,
a
.
scale
);
a
.
i_height
=
spu_scale_h
(
a
.
i_height
,
a
.
scale
);
a
.
x
=
spu_scale_w
(
a
.
x
,
a
.
scale
);
a
.
y
=
spu_scale_h
(
a
.
y
,
a
.
scale
);
a
.
width
=
spu_scale_w
(
a
.
width
,
a
.
scale
);
a
.
height
=
spu_scale_h
(
a
.
height
,
a
.
scale
);
a
.
scale
=
spu_scale_unit
();
return
a
;
}
static
spu_area_t
spu_area_unscaled
(
spu_area_t
a
,
spu_scale_t
s
)
static
spu_area_t
spu_area_unscaled
(
spu_area_t
a
,
spu_scale_t
s
)
{
if
(
a
.
scale
.
w
==
s
.
w
&&
a
.
scale
.
h
==
s
.
h
)
if
(
a
.
scale
.
w
==
s
.
w
&&
a
.
scale
.
h
==
s
.
h
)
return
a
;
a
=
spu_area_scaled
(
a
);
a
.
i_x
=
spu_invscale_w
(
a
.
i_x
,
s
);
a
.
i_y
=
spu_invscale_h
(
a
.
i_y
,
s
);
a
=
spu_area_scaled
(
a
);
a
.
i_width
=
spu_invscale_w
(
a
.
i_width
,
s
);
a
.
i_height
=
spu_invscale_h
(
a
.
i_height
,
s
);
a
.
x
=
spu_invscale_w
(
a
.
x
,
s
);
a
.
y
=
spu_invscale_h
(
a
.
y
,
s
);
a
.
width
=
spu_invscale_w
(
a
.
width
,
s
);
a
.
height
=
spu_invscale_h
(
a
.
height
,
s
);
a
.
scale
=
s
;
return
a
;
}
static
bool
spu_area_overlap
(
spu_area_t
a
,
spu_area_t
b
)
static
bool
spu_area_overlap
(
spu_area_t
a
,
spu_area_t
b
)
{
const
int
i_
dx
=
0
;
const
int
i_
dy
=
0
;
const
int
dx
=
0
;
const
int
dy
=
0
;
a
=
spu_area_scaled
(
a
);
b
=
spu_area_scaled
(
b
);
a
=
spu_area_scaled
(
a
);
b
=
spu_area_scaled
(
b
);
return
__MAX
(
a
.
i_x
-
i_dx
,
b
.
i_x
)
<
__MIN
(
a
.
i_x
+
a
.
i_width
+
i_dx
,
b
.
i_x
+
b
.
i_width
)
&&
__MAX
(
a
.
i_y
-
i_dy
,
b
.
i_y
)
<
__MIN
(
a
.
i_y
+
a
.
i_height
+
i_dy
,
b
.
i_y
+
b
.
i_height
);
return
__MAX
(
a
.
x
-
dx
,
b
.
x
)
<
__MIN
(
a
.
x
+
a
.
width
+
dx
,
b
.
x
+
b
.
width
)
&&
__MAX
(
a
.
y
-
dy
,
b
.
y
)
<
__MIN
(
a
.
y
+
a
.
height
+
dy
,
b
.
y
+
b
.
height
);
}
/**
* Avoid area overlapping
*/
static
void
SpuAreaFixOverlap
(
spu_area_t
*
p_
dst
,
const
spu_area_t
*
p_sub
,
int
i_sub
,
int
i_align
)
static
void
SpuAreaFixOverlap
(
spu_area_t
*
dst
,
const
spu_area_t
*
sub_array
,
int
sub_count
,
int
align
)
{
spu_area_t
a
=
spu_area_scaled
(
*
p_dst
);
bool
b
_moved
=
false
;
bool
b
_ok
;
spu_area_t
a
=
spu_area_scaled
(
*
dst
);
bool
is
_moved
=
false
;
bool
is
_ok
;
/* Check for overlap
* XXX It is not fast O(n^2) but we should not have a lot of region */
do
{
b_ok
=
true
;
for
(
int
i
=
0
;
i
<
i_sub
;
i
++
)
{
spu_area_t
sub
=
spu_area_scaled
(
p_sub
[
i
]
);
if
(
!
spu_area_overlap
(
a
,
sub
)
)
do
{
is_ok
=
true
;
for
(
int
i
=
0
;
i
<
sub_count
;
i
++
)
{
spu_area_t
sub
=
spu_area_scaled
(
sub_array
[
i
]);
if
(
!
spu_area_overlap
(
a
,
sub
))
continue
;
if
(
i_align
&
SUBPICTURE_ALIGN_TOP
)
{
if
(
align
&
SUBPICTURE_ALIGN_TOP
)
{
/* We go down */
int
i_y
=
sub
.
i_y
+
sub
.
i_height
;
a
.
i_y
=
i_y
;
b_moved
=
true
;
}
else
if
(
i_align
&
SUBPICTURE_ALIGN_BOTTOM
)
{
int
i_y
=
sub
.
y
+
sub
.
height
;
a
.
y
=
i_y
;
is_moved
=
true
;
}
else
if
(
align
&
SUBPICTURE_ALIGN_BOTTOM
)
{
/* We go up */
int
i_y
=
sub
.
i_y
-
a
.
i_height
;
a
.
i_y
=
i_y
;
b_moved
=
true
;
}
else
{
int
i_y
=
sub
.
y
-
a
.
height
;
a
.
y
=
i_y
;
is_moved
=
true
;
}
else
{
/* TODO what to do in this case? */
//fprintf(
stderr, "Overlap with unsupported alignment\n"
);
//fprintf(
stderr, "Overlap with unsupported alignment\n"
);
break
;
}
b
_ok
=
false
;
is
_ok
=
false
;
break
;
}
}
while
(
!
b_ok
);
}
while
(
!
is_ok
);
if
(
b_moved
)
*
p_dst
=
spu_area_unscaled
(
a
,
p_dst
->
scale
);
if
(
is_moved
)
*
dst
=
spu_area_unscaled
(
a
,
dst
->
scale
);
}
static
void
SpuAreaFitInside
(
spu_area_t
*
p_area
,
const
spu_area_t
*
p_boundary
)
static
void
SpuAreaFitInside
(
spu_area_t
*
area
,
const
spu_area_t
*
boundary
)
{
spu_area_t
a
=
spu_area_scaled
(
*
p_area
);
spu_area_t
a
=
spu_area_scaled
(
*
area
);
const
int
i_error_x
=
(
a
.
i_x
+
a
.
i_width
)
-
p_boundary
->
i_
width
;
if
(
i_error_x
>
0
)
a
.
i_
x
-=
i_error_x
;
if
(
a
.
i_x
<
0
)
a
.
i_
x
=
0
;
const
int
i_error_x
=
(
a
.
x
+
a
.
width
)
-
boundary
->
width
;
if
(
i_error_x
>
0
)
a
.
x
-=
i_error_x
;
if
(
a
.
x
<
0
)
a
.
x
=
0
;
const
int
i_error_y
=
(
a
.
i_y
+
a
.
i_height
)
-
p_boundary
->
i_
height
;
if
(
i_error_y
>
0
)
a
.
i_
y
-=
i_error_y
;
if
(
a
.
i_y
<
0
)
a
.
i_
y
=
0
;
const
int
i_error_y
=
(
a
.
y
+
a
.
height
)
-
boundary
->
height
;
if
(
i_error_y
>
0
)
a
.
y
-=
i_error_y
;
if
(
a
.
y
<
0
)
a
.
y
=
0
;
*
p_area
=
spu_area_unscaled
(
a
,
p_area
->
scale
);
*
area
=
spu_area_unscaled
(
a
,
area
->
scale
);
}
/**
* Place a region
*/
static
void
SpuRegionPlace
(
int
*
pi_x
,
int
*
pi_
y
,
const
subpicture_t
*
p_
subpic
,
const
subpicture_region_t
*
p_region
)
static
void
SpuRegionPlace
(
int
*
x
,
int
*
y
,
const
subpicture_t
*
subpic
,
const
subpicture_region_t
*
region
)
{
assert
(
p_region
->
i_x
!=
INT_MAX
&&
p_region
->
i_y
!=
INT_MAX
);
if
(
p_subpic
->
b_absolute
)
{
*
pi_x
=
p_region
->
i_x
;
*
pi_y
=
p_region
->
i_y
;
}
else
{
if
(
p_region
->
i_align
&
SUBPICTURE_ALIGN_TOP
)
{
*
pi_y
=
p_region
->
i_y
;
}
else
if
(
p_region
->
i_align
&
SUBPICTURE_ALIGN_BOTTOM
)
{
*
pi_y
=
p_subpic
->
i_original_picture_height
-
p_region
->
fmt
.
i_height
-
p_region
->
i_y
;
}
assert
(
region
->
i_x
!=
INT_MAX
&&
region
->
i_y
!=
INT_MAX
);
if
(
subpic
->
b_absolute
)
{
*
x
=
region
->
i_x
;
*
y
=
region
->
i_y
;
}
else
{
if
(
region
->
i_align
&
SUBPICTURE_ALIGN_TOP
)
*
y
=
region
->
i_y
;
else
if
(
region
->
i_align
&
SUBPICTURE_ALIGN_BOTTOM
)
*
y
=
subpic
->
i_original_picture_height
-
region
->
fmt
.
i_height
-
region
->
i_y
;
else
{
*
pi_y
=
p_subpic
->
i_original_picture_height
/
2
-
p_region
->
fmt
.
i_height
/
2
;
}
*
y
=
subpic
->
i_original_picture_height
/
2
-
region
->
fmt
.
i_height
/
2
;
if
(
p_region
->
i_align
&
SUBPICTURE_ALIGN_LEFT
)
{
*
pi_x
=
p_region
->
i_x
;
}
else
if
(
p_region
->
i_align
&
SUBPICTURE_ALIGN_RIGHT
)
{
*
pi_x
=
p_subpic
->
i_original_picture_width
-
p_region
->
fmt
.
i_width
-
p_region
->
i_x
;
}
if
(
region
->
i_align
&
SUBPICTURE_ALIGN_LEFT
)
*
x
=
region
->
i_x
;
else
if
(
region
->
i_align
&
SUBPICTURE_ALIGN_RIGHT
)
*
x
=
subpic
->
i_original_picture_width
-
region
->
fmt
.
i_width
-
region
->
i_x
;
else
{
*
pi_x
=
p_subpic
->
i_original_picture_width
/
2
-
p_region
->
fmt
.
i_width
/
2
;
}
*
x
=
subpic
->
i_original_picture_width
/
2
-
region
->
fmt
.
i_width
/
2
;
}
}
...
...
@@ -530,7 +497,7 @@ static void SpuRegionPlace( int *pi_x, int *pi_y,
* This function compares two 64 bits integers.
* It can be used by qsort.
*/
static
int
IntegerCmp
(
int64_t
i0
,
int64_t
i1
)
static
int
IntegerCmp
(
int64_t
i0
,
int64_t
i1
)
{
return
i0
<
i1
?
-
1
:
i0
>
i1
?
1
:
0
;
}
...
...
@@ -545,19 +512,19 @@ static int IntegerCmp( int64_t i0, int64_t i1 )
*
* XXX spu_RenderSubpictures depends heavily on this order.
*/
static
int
SubpictureCmp
(
const
void
*
s0
,
const
void
*
s1
)
static
int
SubpictureCmp
(
const
void
*
s0
,
const
void
*
s1
)
{
subpicture_t
*
p_
subpic0
=
*
(
subpicture_t
**
)
s0
;
subpicture_t
*
p_
subpic1
=
*
(
subpicture_t
**
)
s1
;
subpicture_t
*
subpic0
=
*
(
subpicture_t
**
)
s0
;
subpicture_t
*
subpic1
=
*
(
subpicture_t
**
)
s1
;
int
r
;
r
=
IntegerCmp
(
!
p_subpic0
->
b_absolute
,
!
p_subpic1
->
b_absolute
);
if
(
!
r
)
r
=
IntegerCmp
(
p_subpic0
->
i_start
,
p_subpic1
->
i_start
);
if
(
!
r
)
r
=
IntegerCmp
(
p_subpic0
->
i_channel
,
p_subpic1
->
i_channel
);
if
(
!
r
)
r
=
IntegerCmp
(
p_subpic0
->
i_order
,
p_subpic1
->
i_order
);
r
=
IntegerCmp
(
!
subpic0
->
b_absolute
,
!
subpic1
->
b_absolute
);
if
(
!
r
)
r
=
IntegerCmp
(
subpic0
->
i_start
,
subpic1
->
i_start
);
if
(
!
r
)
r
=
IntegerCmp
(
subpic0
->
i_channel
,
subpic1
->
i_channel
);
if
(
!
r
)
r
=
IntegerCmp
(
subpic0
->
i_order
,
subpic1
->
i_order
);
return
r
;
}
...
...
@@ -571,141 +538,129 @@ static int SubpictureCmp( const void *s0, const void *s1 )
* to be removed if a newer one is available), which makes it a lot
* more difficult to guess if a subpicture has to be rendered or not.
*****************************************************************************/
static
void
SpuSelectSubpictures
(
spu_t
*
p_
spu
,
unsigned
int
*
pi_subpicture
,
subpicture_t
**
pp_subpicture
,
mtime_t
render_subtitle_date
,
mtime_t
render_osd_date
,
bool
b_subtitle_only
)
static
void
SpuSelectSubpictures
(
spu_t
*
spu
,
unsigned
int
*
subpicture_count
,
subpicture_t
**
subpicture_array
,
mtime_t
render_subtitle_date
,
mtime_t
render_osd_date
,
bool
ignore_osd
)
{
spu_private_t
*
p_sys
=
p_
spu
->
p
;
spu_private_t
*
sys
=
spu
->
p
;
/* */
*
pi_subpicture
=
0
;
*
subpicture_count
=
0
;
/* Create a list of channels */
int
pi_
channel
[
VOUT_MAX_SUBPICTURES
];
int
i_
channel_count
=
0
;
int
channel
[
VOUT_MAX_SUBPICTURES
];
int
channel_count
=
0
;
for
(
int
i_index
=
0
;
i_index
<
VOUT_MAX_SUBPICTURES
;
i_index
++
)
{
spu_heap_entry_t
*
p_entry
=
&
p_sys
->
heap
.
p_entry
[
i_index
];
if
(
!
p_entry
->
p_subpicture
||
p_entry
->
b_reject
)
for
(
int
index
=
0
;
index
<
VOUT_MAX_SUBPICTURES
;
index
++
)
{
spu_heap_entry_t
*
entry
=
&
sys
->
heap
.
entry
[
index
];
if
(
!
entry
->
subpicture
||
entry
->
reject
)
continue
;
const
int
i_channel
=
p_entry
->
p_
subpicture
->
i_channel
;
const
int
i_channel
=
entry
->
subpicture
->
i_channel
;
int
i
;
for
(
i
=
0
;
i
<
i_channel_count
;
i
++
)
{
if
(
pi_channel
[
i
]
==
i_channel
)
for
(
i
=
0
;
i
<
channel_count
;
i
++
)
{
if
(
channel
[
i
]
==
i_channel
)
break
;
}
if
(
i_channel_count
<=
i
)
pi_channel
[
i_
channel_count
++
]
=
i_channel
;
if
(
channel_count
<=
i
)
channel
[
channel_count
++
]
=
i_channel
;
}
/* Fill up the pp_subpicture arrays with relevent pictures */
for
(
int
i
=
0
;
i
<
i_channel_count
;
i
++
)
{
const
int
i_channel
=
pi_channel
[
i
];
subpicture_t
*
p_available_subpic
[
VOUT_MAX_SUBPICTURES
];
bool
pb_available_late
[
VOUT_MAX_SUBPICTURES
];
int
i_available
=
0
;
/* Fill up the subpicture_array arrays with relevent pictures */
for
(
int
i
=
0
;
i
<
channel_count
;
i
++
)
{
subpicture_t
*
available_subpic
[
VOUT_MAX_SUBPICTURES
];
bool
is_available_late
[
VOUT_MAX_SUBPICTURES
];
int
available_count
=
0
;
mtime_t
start_date
=
render_subtitle_date
;
mtime_t
ephemer_subtitle_date
=
0
;
mtime_t
ephemer_osd_date
=
0
;
int64_t
i_ephemer_subtitle_order
=
INT64_MIN
;
int64_t
i_ephemer_system_order
=
INT64_MIN
;
int
i_index
;
int64_t
ephemer_subtitle_order
=
INT64_MIN
;
int64_t
ephemer_system_order
=
INT64_MIN
;
/* Select available pictures */
for
(
i_index
=
0
;
i_index
<
VOUT_MAX_SUBPICTURES
;
i_index
++
)
{
spu_heap_entry_t
*
p_entry
=
&
p_sys
->
heap
.
p_entry
[
i_index
];
subpicture_t
*
p_current
=
p_entry
->
p_subpicture
;
bool
b_stop_valid
;
bool
b_late
;
if
(
!
p_current
||
p_entry
->
b_reject
)
{
if
(
p_entry
->
b_reject
)
SpuHeapDeleteAt
(
&
p_sys
->
heap
,
i_index
);
for
(
int
index
=
0
;
index
<
VOUT_MAX_SUBPICTURES
;
index
++
)
{
spu_heap_entry_t
*
entry
=
&
sys
->
heap
.
entry
[
index
];
subpicture_t
*
current
=
entry
->
subpicture
;
bool
is_stop_valid
;
bool
is_late
;
if
(
!
current
||
entry
->
reject
)
{
if
(
entry
->
reject
)
SpuHeapDeleteAt
(
&
sys
->
heap
,
index
);
continue
;
}
if
(
p_current
->
i_channel
!=
i_channel
||
(
b_subtitle_only
&&
!
p_current
->
b_subtitle
)
)
{
if
(
current
->
i_channel
!=
channel
[
i
]
||
(
ignore_osd
&&
!
current
->
b_subtitle
))
continue
;
}
const
mtime_t
render_date
=
p_current
->
b_subtitle
?
render_subtitle_date
:
render_osd_date
;
if
(
render_date
&&
render_date
<
p_current
->
i_start
)
{
const
mtime_t
render_date
=
current
->
b_subtitle
?
render_subtitle_date
:
render_osd_date
;
if
(
render_date
&&
render_date
<
current
->
i_start
)
{
/* Too early, come back next monday */
continue
;
}
mtime_t
*
pi_ephemer_date
=
p_current
->
b_subtitle
?
&
ephemer_subtitle_date
:
&
ephemer_osd_date
;
int64_t
*
pi_ephemer_order
=
p_current
->
b_subtitle
?
&
i_ephemer_subtitle_order
:
&
i_ephemer_system_order
;
if
(
p_current
->
i_start
>=
*
pi_ephemer_date
)
{
*
pi_ephemer_date
=
p_current
->
i_start
;
if
(
p_current
->
i_order
>
*
pi_ephemer_order
)
*
pi_ephemer_order
=
p_current
->
i_order
;
mtime_t
*
ephemer_date_ptr
=
current
->
b_subtitle
?
&
ephemer_subtitle_date
:
&
ephemer_osd_date
;
int64_t
*
ephemer_order_ptr
=
current
->
b_subtitle
?
&
ephemer_subtitle_order
:
&
ephemer_system_order
;
if
(
current
->
i_start
>=
*
ephemer_date_ptr
)
{
*
ephemer_date_ptr
=
current
->
i_start
;
if
(
current
->
i_order
>
*
ephemer_order_ptr
)
*
ephemer_order_ptr
=
current
->
i_order
;
}
b_stop_valid
=
!
p_current
->
b_ephemer
||
p_current
->
i_stop
>
p_
current
->
i_start
;
is_stop_valid
=
!
current
->
b_ephemer
||
current
->
i_stop
>
current
->
i_start
;
b_late
=
b_stop_valid
&&
p_
current
->
i_stop
<=
render_date
;
is_late
=
is_stop_valid
&&
current
->
i_stop
<=
render_date
;
/* start_date will be used for correct automatic overlap support
* in case picture that should not be displayed anymore (display_time)
* overlap with a picture to be displayed (
p_
current->i_start) */
if
(
p_current
->
b_subtitle
&&
!
b_late
&&
!
p_current
->
b_ephemer
)
start_date
=
p_
current
->
i_start
;
* overlap with a picture to be displayed (current->i_start) */
if
(
current
->
b_subtitle
&&
!
is_late
&&
!
current
->
b_ephemer
)
start_date
=
current
->
i_start
;
/* */
p_available_subpic
[
i_available
]
=
p_
current
;
pb_available_late
[
i_available
]
=
b
_late
;
i_available
++
;
available_subpic
[
available_count
]
=
current
;
is_available_late
[
available_count
]
=
is
_late
;
available_count
++
;
}
/* Only forced old picture display at the transition */
if
(
start_date
<
p_sys
->
i_last_sort_date
)
start_date
=
p_sys
->
i_
last_sort_date
;
if
(
start_date
<=
0
)
if
(
start_date
<
sys
->
last_sort_date
)
start_date
=
sys
->
last_sort_date
;
if
(
start_date
<=
0
)
start_date
=
INT64_MAX
;
/* Select pictures to be displayed */
for
(
i_index
=
0
;
i_index
<
i_available
;
i_index
++
)
{
subpicture_t
*
p_current
=
p_available_subpic
[
i_index
];
bool
b_late
=
pb_available_late
[
i_index
];
for
(
int
index
=
0
;
index
<
available_count
;
index
++
)
{
subpicture_t
*
current
=
available_subpic
[
index
];
bool
is_late
=
is_available_late
[
index
];
const
mtime_t
stop_date
=
p_current
->
b_subtitle
?
__MAX
(
start_date
,
p_sys
->
i_last_sort_date
)
:
render_osd_date
;
const
mtime_t
ephemer_date
=
p_current
->
b_subtitle
?
ephemer_subtitle_date
:
ephemer_osd_date
;
const
int64_t
i_ephemer_order
=
p_current
->
b_subtitle
?
i_ephemer_subtitle_order
:
i_
ephemer_system_order
;
const
mtime_t
stop_date
=
current
->
b_subtitle
?
__MAX
(
start_date
,
sys
->
last_sort_date
)
:
render_osd_date
;
const
mtime_t
ephemer_date
=
current
->
b_subtitle
?
ephemer_subtitle_date
:
ephemer_osd_date
;
const
int64_t
ephemer_order
=
current
->
b_subtitle
?
ephemer_subtitle_order
:
ephemer_system_order
;
/* Destroy late and obsolete ephemer subpictures */
bool
b_rejet
=
b_late
&&
p_current
->
i_stop
<=
stop_date
;
if
(
p_current
->
b_ephemer
)
{
if
(
p_current
->
i_start
<
ephemer_date
)
b_rejet
=
true
;
else
if
(
p_current
->
i_start
==
ephemer_date
&&
p_current
->
i_order
<
i_ephemer_order
)
b_rejet
=
true
;
bool
is_rejeted
=
is_late
&&
current
->
i_stop
<=
stop_date
;
if
(
current
->
b_ephemer
)
{
if
(
current
->
i_start
<
ephemer_date
)
is_rejeted
=
true
;
else
if
(
current
->
i_start
==
ephemer_date
&&
current
->
i_order
<
ephemer_order
)
is_rejeted
=
true
;
}
if
(
b_rejet
)
SpuHeapDeleteSubpicture
(
&
p_sys
->
heap
,
p_current
);
if
(
is_rejeted
)
SpuHeapDeleteSubpicture
(
&
sys
->
heap
,
current
);
else
pp_subpicture
[(
*
pi_subpicture
)
++
]
=
p_
current
;
subpicture_array
[(
*
subpicture_count
)
++
]
=
current
;
}
}
p_sys
->
i_
last_sort_date
=
render_subtitle_date
;
sys
->
last_sort_date
=
render_subtitle_date
;
}
...
...
@@ -713,469 +668,430 @@ static void SpuSelectSubpictures( spu_t *p_spu,
/**
* It will transform the provided region into another region suitable for rendering.
*/
static
void
SpuRenderRegion
(
spu_t
*
p_spu
,
subpicture_region_t
**
pp_dst
,
spu_area_t
*
p_dst_area
,
subpicture_t
*
p_subpic
,
subpicture_region_t
*
p_region
,
const
spu_scale_t
scale_size
,
const
vlc_fourcc_t
*
p_chroma_list
,
const
video_format_t
*
p_fmt
,
const
spu_area_t
*
p_subtitle_area
,
int
i_subtitle_area
,
mtime_t
render_date
)
static
void
SpuRenderRegion
(
spu_t
*
spu
,
subpicture_region_t
**
dst_ptr
,
spu_area_t
*
dst_area
,
subpicture_t
*
subpic
,
subpicture_region_t
*
region
,
const
spu_scale_t
scale_size
,
const
vlc_fourcc_t
*
chroma_list
,
const
video_format_t
*
fmt
,
const
spu_area_t
*
subtitle_area
,
int
subtitle_area_count
,
mtime_t
render_date
)
{
spu_private_t
*
p_sys
=
p_
spu
->
p
;
spu_private_t
*
sys
=
spu
->
p
;
video_format_t
fmt_original
=
p_
region
->
fmt
;
bool
b_
restore_text
=
false
;
int
i_
x_offset
;
int
i_
y_offset
;
video_format_t
fmt_original
=
region
->
fmt
;
bool
restore_text
=
false
;
int
x_offset
;
int
y_offset
;
video_format_t
region_fmt
;
picture_t
*
p_
region_picture
;
picture_t
*
region_picture
;
/* Invalidate area by default */
*
p_dst_area
=
spu_area_create
(
0
,
0
,
0
,
0
,
scale_size
);
*
pp_dst
=
NULL
;
*
dst_area
=
spu_area_create
(
0
,
0
,
0
,
0
,
scale_size
);
*
dst_ptr
=
NULL
;
/* Render text region */
if
(
p_region
->
fmt
.
i_chroma
==
VLC_CODEC_TEXT
)
{
SpuRenderText
(
p_spu
,
&
b_restore_text
,
p_region
,
render_date
);
if
(
region
->
fmt
.
i_chroma
==
VLC_CODEC_TEXT
)
{
SpuRenderText
(
spu
,
&
restore_text
,
region
,
render_date
);
/* Check if the rendering has failed ... */
if
(
p_region
->
fmt
.
i_chroma
==
VLC_CODEC_TEXT
)
if
(
region
->
fmt
.
i_chroma
==
VLC_CODEC_TEXT
)
goto
exit
;
}
/* Force palette if requested
* FIXME b_force_palette and
b_
force_crop are applied to all subpictures using palette
* FIXME b_force_palette and force_crop are applied to all subpictures using palette
* instead of only the right one (being the dvd spu).
*/
const
bool
b_using_palette
=
p_
region
->
fmt
.
i_chroma
==
VLC_CODEC_YUVP
;
const
bool
b_force_palette
=
b_using_palette
&&
p_sys
->
b_
force_palette
;
const
bool
b_force_crop
=
b_force_palette
&&
p_sys
->
b_
force_crop
;
bool
b_
changed_palette
=
false
;
const
bool
using_palette
=
region
->
fmt
.
i_chroma
==
VLC_CODEC_YUVP
;
const
bool
force_palette
=
using_palette
&&
sys
->
force_palette
;
const
bool
force_crop
=
force_palette
&&
sys
->
force_crop
;
bool
changed_palette
=
false
;
/* Compute the margin which is expressed in destination pixel unit
* The margin is applied only to subtitle and when no forced crop is
* requested (dvd menu) */
int
i_margin_y
=
0
;
if
(
!
b_force_crop
&&
p_subpic
->
b_subtitle
)
i_margin_y
=
spu_invscale_h
(
p_sys
->
i_margin
,
scale_size
);
int
y_margin
=
0
;
if
(
!
force_crop
&&
subpic
->
b_subtitle
)
y_margin
=
spu_invscale_h
(
sys
->
margin
,
scale_size
);
/* Place the picture
* We compute the position in the rendered size */
SpuRegionPlace
(
&
i_x_offset
,
&
i_
y_offset
,
p_subpic
,
p_region
);
SpuRegionPlace
(
&
x_offset
,
&
y_offset
,
subpic
,
region
);
/* Save this position for subtitle overlap support
* it is really important that there are given without scale_size applied */
*
p_dst_area
=
spu_area_create
(
i_x_offset
,
i_
y_offset
,
p_region
->
fmt
.
i_width
,
p_
region
->
fmt
.
i_height
,
scale_size
);
*
dst_area
=
spu_area_create
(
x_offset
,
y_offset
,
region
->
fmt
.
i_width
,
region
->
fmt
.
i_height
,
scale_size
);
/* Handle overlapping subtitles when possible */
if
(
p_subpic
->
b_subtitle
&&
!
p_subpic
->
b_absolute
)
{
SpuAreaFixOverlap
(
p_dst_area
,
p_subtitle_area
,
i_subtitle_area
,
p_region
->
i_align
);
}
if
(
subpic
->
b_subtitle
&&
!
subpic
->
b_absolute
)
SpuAreaFixOverlap
(
dst_area
,
subtitle_area
,
subtitle_area_count
,
region
->
i_align
);
/* we copy the area: for the subtitle overlap support we want
* to only save the area without margin applied */
spu_area_t
restrained
=
*
p_
dst_area
;
spu_area_t
restrained
=
*
dst_area
;
/* apply margin to subtitles and correct if they go over the picture edge */
if
(
p_subpic
->
b_subtitle
)
restrained
.
i_y
-=
i_margin_y
;
if
(
subpic
->
b_subtitle
)
restrained
.
y
-=
y_margin
;
spu_area_t
display
=
spu_area_create
(
0
,
0
,
p_fmt
->
i_width
,
p_
fmt
->
i_height
,
spu_scale_unit
()
);
SpuAreaFitInside
(
&
restrained
,
&
display
);
spu_area_t
display
=
spu_area_create
(
0
,
0
,
fmt
->
i_width
,
fmt
->
i_height
,
spu_scale_unit
()
);
SpuAreaFitInside
(
&
restrained
,
&
display
);
/* Fix the position for the current scale_size */
i_x_offset
=
spu_scale_w
(
restrained
.
i_x
,
restrained
.
scale
);
i_y_offset
=
spu_scale_h
(
restrained
.
i_y
,
restrained
.
scale
);
x_offset
=
spu_scale_w
(
restrained
.
x
,
restrained
.
scale
);
y_offset
=
spu_scale_h
(
restrained
.
y
,
restrained
.
scale
);
/* */
if
(
b_force_palette
)
{
video_palette_t
*
p_palette
=
p_region
->
fmt
.
p_palette
;
video_palette_t
palette
;
if
(
force_palette
)
{
video_palette_t
*
old_palette
=
region
->
fmt
.
p_palette
;
video_palette_t
new_palette
;
/* We suppose DVD palette here */
palette
.
i_entries
=
4
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
for
(
int
j
=
0
;
j
<
4
;
j
++
)
palette
.
palette
[
i
][
j
]
=
p_sys
->
palette
[
i
][
j
];
if
(
p_palette
->
i_entries
==
palette
.
i_entries
)
{
for
(
int
i
=
0
;
i
<
p_palette
->
i_entries
;
i
++
)
for
(
int
j
=
0
;
j
<
4
;
j
++
)
b_changed_palette
|=
p_palette
->
palette
[
i
][
j
]
!=
palette
.
palette
[
i
][
j
];
}
else
{
b_changed_palette
=
true
;
new_palette
.
i_entries
=
4
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
for
(
int
j
=
0
;
j
<
4
;
j
++
)
new_palette
.
palette
[
i
][
j
]
=
sys
->
palette
[
i
][
j
];
if
(
old_palette
->
i_entries
==
new_palette
.
i_entries
)
{
for
(
int
i
=
0
;
i
<
old_palette
->
i_entries
;
i
++
)
for
(
int
j
=
0
;
j
<
4
;
j
++
)
changed_palette
|=
old_palette
->
palette
[
i
][
j
]
!=
new_palette
.
palette
[
i
][
j
];
}
else
{
changed_palette
=
true
;
}
*
p_palette
=
palette
;
*
old_palette
=
new_
palette
;
}
/* */
region_fmt
=
p_region
->
fmt
;
p_region_picture
=
p_region
->
p_picture
;
bool
b_convert_chroma
=
true
;
for
(
int
i
=
0
;
p_chroma_list
[
i
]
&&
b_convert_chroma
;
i
++
)
{
if
(
region_fmt
.
i_chroma
==
p_chroma_list
[
i
]
)
b_convert_chroma
=
false
;
region_fmt
=
region
->
fmt
;
region_picture
=
region
->
p_picture
;
bool
convert_chroma
=
true
;
for
(
int
i
=
0
;
chroma_list
[
i
]
&&
convert_chroma
;
i
++
)
{
if
(
region_fmt
.
i_chroma
==
chroma_list
[
i
])
convert_chroma
=
false
;
}
/* Scale from rendered size to destination size */
if
(
p_sys
->
p_scale
&&
p_sys
->
p_scale
->
p_module
&&
(
!
b_using_palette
||
(
p_sys
->
p_scale_yuvp
&&
p_sys
->
p_scale_yuvp
->
p_module
)
)
&&
(
scale_size
.
w
!=
SCALE_UNIT
||
scale_size
.
h
!=
SCALE_UNIT
||
b_using_palette
||
b_convert_chroma
)
)
{
const
unsigned
i_dst_width
=
spu_scale_w
(
p_region
->
fmt
.
i_width
,
scale_size
);
const
unsigned
i_dst_height
=
spu_scale_h
(
p_region
->
fmt
.
i_height
,
scale_size
);
if
(
sys
->
scale
&&
sys
->
scale
->
p_module
&&
(
!
using_palette
||
(
sys
->
scale_yuvp
&&
sys
->
scale_yuvp
->
p_module
))
&&
(
scale_size
.
w
!=
SCALE_UNIT
||
scale_size
.
h
!=
SCALE_UNIT
||
using_palette
||
convert_chroma
))
{
const
unsigned
dst_width
=
spu_scale_w
(
region
->
fmt
.
i_width
,
scale_size
);
const
unsigned
dst_height
=
spu_scale_h
(
region
->
fmt
.
i_height
,
scale_size
);
/* Destroy the cache if unusable */
if
(
p_region
->
p_private
)
{
subpicture_region_private_t
*
p_private
=
p_region
->
p_private
;
bool
b_changed
=
false
;
if
(
region
->
p_private
)
{
subpicture_region_private_t
*
private
=
region
->
p_private
;
bool
is_changed
=
false
;
/* Check resize changes */
if
(
i_dst_width
!=
p_
private
->
fmt
.
i_width
||
i_dst_height
!=
p_private
->
fmt
.
i_height
)
b
_changed
=
true
;
if
(
dst_width
!=
private
->
fmt
.
i_width
||
dst_height
!=
private
->
fmt
.
i_height
)
is
_changed
=
true
;
/* Check forced palette changes */
if
(
b_changed_palette
)
b
_changed
=
true
;
if
(
changed_palette
)
is
_changed
=
true
;
if
(
b_convert_chroma
&&
p_private
->
fmt
.
i_chroma
!=
p_chroma_list
[
0
]
)
b
_changed
=
true
;
if
(
convert_chroma
&&
private
->
fmt
.
i_chroma
!=
chroma_list
[
0
]
)
is
_changed
=
true
;
if
(
b_changed
)
{
subpicture_region_private_Delete
(
p_private
);
p_region
->
p_private
=
NULL
;
if
(
is_changed
)
{
subpicture_region_private_Delete
(
private
);
region
->
p_private
=
NULL
;
}
}
/* Scale if needed into cache */
if
(
!
p_region
->
p_private
&&
i_dst_width
>
0
&&
i_dst_height
>
0
)
{
filter_t
*
p_scale
=
p_sys
->
p_scale
;
if
(
!
region
->
p_private
&&
dst_width
>
0
&&
dst_height
>
0
)
{
filter_t
*
scale
=
sys
->
scale
;
picture_t
*
p
_picture
=
p_
region
->
p_picture
;
picture_Hold
(
p_picture
);
picture_t
*
p
icture
=
region
->
p_picture
;
picture_Hold
(
picture
);
/* Convert YUVP to YUVA/RGBA first for better scaling quality */
if
(
b_using_palette
)
{
filter_t
*
p_scale_yuvp
=
p_sys
->
p_scale_yuvp
;
if
(
using_palette
)
{
filter_t
*
scale_yuvp
=
sys
->
scale_yuvp
;
p_scale_yuvp
->
fmt_in
.
video
=
p_
region
->
fmt
;
scale_yuvp
->
fmt_in
.
video
=
region
->
fmt
;
p_scale_yuvp
->
fmt_out
.
video
=
p_
region
->
fmt
;
p_scale_yuvp
->
fmt_out
.
video
.
i_chroma
=
p_
chroma_list
[
0
];
scale_yuvp
->
fmt_out
.
video
=
region
->
fmt
;
scale_yuvp
->
fmt_out
.
video
.
i_chroma
=
chroma_list
[
0
];
p_picture
=
p_scale_yuvp
->
pf_video_filter
(
p_scale_yuvp
,
p_picture
);
if
(
!
p_picture
)
{
picture
=
scale_yuvp
->
pf_video_filter
(
scale_yuvp
,
picture
);
if
(
!
picture
)
{
/* Well we will try conversion+scaling */
msg_Warn
(
p_
spu
,
"%4.4s to %4.4s conversion failed"
,
(
const
char
*
)
&
p_
scale_yuvp
->
fmt_in
.
video
.
i_chroma
,
(
const
char
*
)
&
p_scale_yuvp
->
fmt_out
.
video
.
i_chroma
);
msg_Warn
(
spu
,
"%4.4s to %4.4s conversion failed"
,
(
const
char
*
)
&
scale_yuvp
->
fmt_in
.
video
.
i_chroma
,
(
const
char
*
)
&
scale_yuvp
->
fmt_out
.
video
.
i_chroma
);
}
}
/* Conversion(except from YUVP)/Scaling */
if
(
p_
picture
&&
(
p_picture
->
format
.
i_width
!=
i_
dst_width
||
p_picture
->
format
.
i_height
!=
i_
dst_height
||
(
b_convert_chroma
&&
!
b_using_palette
)
)
)
if
(
picture
&&
(
picture
->
format
.
i_width
!=
dst_width
||
picture
->
format
.
i_height
!=
dst_height
||
(
convert_chroma
&&
!
using_palette
))
)
{
p_scale
->
fmt_in
.
video
=
p_
picture
->
format
;
p_scale
->
fmt_out
.
video
=
p_
picture
->
format
;
if
(
b_convert_chroma
)
p_
scale
->
fmt_out
.
i_codec
=
p_scale
->
fmt_out
.
video
.
i_chroma
=
p_
chroma_list
[
0
];
p_scale
->
fmt_out
.
video
.
i_width
=
i_
dst_width
;
p_scale
->
fmt_out
.
video
.
i_height
=
i_
dst_height
;
p_
scale
->
fmt_out
.
video
.
i_visible_width
=
spu_scale_w
(
p_region
->
fmt
.
i_visible_width
,
scale_size
);
p_
scale
->
fmt_out
.
video
.
i_visible_height
=
spu_scale_h
(
p_region
->
fmt
.
i_visible_height
,
scale_size
);
p
_picture
=
p_scale
->
pf_video_filter
(
p_scale
,
p_picture
);
if
(
!
p_picture
)
msg_Err
(
p_spu
,
"scaling failed"
);
scale
->
fmt_in
.
video
=
picture
->
format
;
scale
->
fmt_out
.
video
=
picture
->
format
;
if
(
convert_chroma
)
scale
->
fmt_out
.
i_codec
=
scale
->
fmt_out
.
video
.
i_chroma
=
chroma_list
[
0
];
scale
->
fmt_out
.
video
.
i_width
=
dst_width
;
scale
->
fmt_out
.
video
.
i_height
=
dst_height
;
scale
->
fmt_out
.
video
.
i_visible_width
=
spu_scale_w
(
region
->
fmt
.
i_visible_width
,
scale_size
);
scale
->
fmt_out
.
video
.
i_visible_height
=
spu_scale_h
(
region
->
fmt
.
i_visible_height
,
scale_size
);
p
icture
=
scale
->
pf_video_filter
(
scale
,
picture
);
if
(
!
picture
)
msg_Err
(
spu
,
"scaling failed"
);
}
/* */
if
(
p_picture
)
{
p_region
->
p_private
=
subpicture_region_private_New
(
&
p_picture
->
format
);
if
(
p_region
->
p_private
)
{
p_region
->
p_private
->
p_picture
=
p_picture
;
if
(
!
p_region
->
p_private
->
p_picture
)
{
subpicture_region_private_Delete
(
p_region
->
p_private
);
p_region
->
p_private
=
NULL
;
if
(
picture
)
{
region
->
p_private
=
subpicture_region_private_New
(
&
picture
->
format
);
if
(
region
->
p_private
)
{
region
->
p_private
->
p_picture
=
picture
;
if
(
!
region
->
p_private
->
p_picture
)
{
subpicture_region_private_Delete
(
region
->
p_private
);
region
->
p_private
=
NULL
;
}
}
else
{
picture_Release
(
p_picture
);
}
else
{
picture_Release
(
picture
);
}
}
}
/* And use the scaled picture */
if
(
p_region
->
p_private
)
{
region_fmt
=
p_region
->
p_private
->
fmt
;
p_region_picture
=
p_region
->
p_private
->
p_picture
;
if
(
region
->
p_private
)
{
region_fmt
=
region
->
p_private
->
fmt
;
region_picture
=
region
->
p_private
->
p_picture
;
}
}
/* Force cropping if requested */
if
(
b_force_crop
)
{
int
i_crop_x
=
spu_scale_w
(
p_sys
->
i_crop_x
,
scale_size
);
int
i_crop_y
=
spu_scale_h
(
p_sys
->
i_crop_y
,
scale_size
);
int
i_crop_width
=
spu_scale_w
(
p_sys
->
i_crop_width
,
scale_size
);
int
i_crop_height
=
spu_scale_h
(
p_sys
->
i_crop_height
,
scale_size
);
if
(
force_crop
)
{
int
crop_x
=
spu_scale_w
(
sys
->
crop
.
x
,
scale_size
);
int
crop_y
=
spu_scale_h
(
sys
->
crop
.
y
,
scale_size
);
int
crop_width
=
spu_scale_w
(
sys
->
crop
.
width
,
scale_size
);
int
crop_height
=
spu_scale_h
(
sys
->
crop
.
height
,
scale_size
);
/* Find the intersection */
if
(
i_crop_x
+
i_crop_width
<=
i_x_offset
||
i_x_offset
+
(
int
)
region_fmt
.
i_visible_width
<
i_crop_x
||
i_crop_y
+
i_crop_height
<=
i_y_offset
||
i_y_offset
+
(
int
)
region_fmt
.
i_visible_height
<
i_crop_y
)
{
if
(
crop_x
+
crop_width
<=
x_offset
||
x_offset
+
(
int
)
region_fmt
.
i_visible_width
<
crop_x
||
crop_y
+
crop_height
<=
y_offset
||
y_offset
+
(
int
)
region_fmt
.
i_visible_height
<
crop_y
)
{
/* No intersection */
region_fmt
.
i_visible_width
=
region_fmt
.
i_visible_width
=
region_fmt
.
i_visible_height
=
0
;
}
else
{
int
i_x
,
i_y
,
i_x_end
,
i_y_end
;
i_x
=
__MAX
(
i_crop_x
,
i_x_offset
);
i_y
=
__MAX
(
i_crop_y
,
i_y_offset
);
i_x_end
=
__MIN
(
i_crop_x
+
i_crop_width
,
i_x_offset
+
(
int
)
region_fmt
.
i_visible_width
);
i_y_end
=
__MIN
(
i_crop_y
+
i_crop_height
,
i_y_offset
+
(
int
)
region_fmt
.
i_visible_height
);
region_fmt
.
i_x_offset
=
i_x
-
i_x_offset
;
region_fmt
.
i_y_offset
=
i_y
-
i_y_offset
;
region_fmt
.
i_visible_width
=
i_x_end
-
i_x
;
region_fmt
.
i_visible_height
=
i_y_end
-
i_y
;
i_x_offset
=
__MAX
(
i_x
,
0
);
i_y_offset
=
__MAX
(
i_y
,
0
);
}
else
{
int
x
,
y
,
x_end
,
y_end
;
x
=
__MAX
(
crop_x
,
x_offset
);
y
=
__MAX
(
crop_y
,
y_offset
);
x_end
=
__MIN
(
crop_x
+
crop_width
,
x_offset
+
(
int
)
region_fmt
.
i_visible_width
);
y_end
=
__MIN
(
crop_y
+
crop_height
,
y_offset
+
(
int
)
region_fmt
.
i_visible_height
);
region_fmt
.
i_x_offset
=
x
-
x_offset
;
region_fmt
.
i_y_offset
=
y
-
y_offset
;
region_fmt
.
i_visible_width
=
x_end
-
x
;
region_fmt
.
i_visible_height
=
y_end
-
y
;
x_offset
=
__MAX
(
x
,
0
);
y_offset
=
__MAX
(
y
,
0
);
}
}
subpicture_region_t
*
p_dst
=
*
pp_dst
=
subpicture_region_New
(
&
region_fmt
);
if
(
p_dst
)
{
p_dst
->
i_x
=
i_x_offset
;
p_dst
->
i_y
=
i_y_offset
;
p_dst
->
i_align
=
0
;
if
(
p_dst
->
p_picture
)
picture_Release
(
p_dst
->
p_picture
);
p_dst
->
p_picture
=
picture_Hold
(
p_region_picture
);
int
i_fade_alpha
=
255
;
if
(
p_subpic
->
b_fade
)
{
mtime_t
fade_start
=
(
p_subpic
->
i_stop
+
p_subpic
->
i_start
)
/
2
;
if
(
fade_start
<=
render_date
&&
fade_start
<
p_subpic
->
i_stop
)
i_fade_alpha
=
255
*
(
p_subpic
->
i_stop
-
render_date
)
/
(
p_subpic
->
i_stop
-
fade_start
);
subpicture_region_t
*
dst
=
*
dst_ptr
=
subpicture_region_New
(
&
region_fmt
);
if
(
dst
)
{
dst
->
i_x
=
x_offset
;
dst
->
i_y
=
y_offset
;
dst
->
i_align
=
0
;
if
(
dst
->
p_picture
)
picture_Release
(
dst
->
p_picture
);
dst
->
p_picture
=
picture_Hold
(
region_picture
);
int
fade_alpha
=
255
;
if
(
subpic
->
b_fade
)
{
mtime_t
fade_start
=
(
subpic
->
i_stop
+
subpic
->
i_start
)
/
2
;
if
(
fade_start
<=
render_date
&&
fade_start
<
subpic
->
i_stop
)
fade_alpha
=
255
*
(
subpic
->
i_stop
-
render_date
)
/
(
subpic
->
i_stop
-
fade_start
);
}
p_dst
->
i_alpha
=
i_fade_alpha
*
p_subpic
->
i_alpha
*
p_
region
->
i_alpha
/
65025
;
dst
->
i_alpha
=
fade_alpha
*
subpic
->
i_alpha
*
region
->
i_alpha
/
65025
;
}
exit:
if
(
b_restore_text
)
{
if
(
restore_text
)
{
/* Some forms of subtitles need to be re-rendered more than
* once, eg. karaoke. We therefore restore the region to its
* pre-rendered state, so the next time through everything is
* calculated again.
*/
if
(
p_region
->
p_picture
)
{
picture_Release
(
p_region
->
p_picture
);
p_region
->
p_picture
=
NULL
;
if
(
region
->
p_picture
)
{
picture_Release
(
region
->
p_picture
);
region
->
p_picture
=
NULL
;
}
if
(
p_region
->
p_private
)
{
subpicture_region_private_Delete
(
p_region
->
p_private
);
p_region
->
p_private
=
NULL
;
if
(
region
->
p_private
)
{
subpicture_region_private_Delete
(
region
->
p_private
);
region
->
p_private
=
NULL
;
}
p_
region
->
fmt
=
fmt_original
;
region
->
fmt
=
fmt_original
;
}
}
/**
* This function renders all sub picture units in the list.
*/
static
subpicture_t
*
SpuRenderSubpictures
(
spu_t
*
p_
spu
,
unsigned
int
i_subpicture
,
subpicture_t
**
pp_subpicture
,
const
vlc_fourcc_t
*
p_
chroma_list
,
const
video_format_t
*
p_
fmt_dst
,
const
video_format_t
*
p_
fmt_src
,
mtime_t
render_subtitle_date
,
mtime_t
render_osd_date
)
static
subpicture_t
*
SpuRenderSubpictures
(
spu_t
*
spu
,
unsigned
int
i_subpicture
,
subpicture_t
**
pp_subpicture
,
const
vlc_fourcc_t
*
chroma_list
,
const
video_format_t
*
fmt_dst
,
const
video_format_t
*
fmt_src
,
mtime_t
render_subtitle_date
,
mtime_t
render_osd_date
)
{
spu_private_t
*
p_sys
=
p_
spu
->
p
;
spu_private_t
*
sys
=
spu
->
p
;
/* Count the number of regions and subtitle regions */
unsigned
int
i_subtitle_region_count
=
0
;
unsigned
int
i_region_count
=
0
;
for
(
unsigned
i
=
0
;
i
<
i_subpicture
;
i
++
)
{
const
subpicture_t
*
p_subpic
=
pp_subpicture
[
i
];
unsigned
i_count
=
0
;
for
(
subpicture_region_t
*
r
=
p_subpic
->
p_region
;
r
!=
NULL
;
r
=
r
->
p_next
)
i_count
++
;
if
(
p_subpic
->
b_subtitle
)
i_subtitle_region_count
+=
i_count
;
i_region_count
+=
i_count
;
unsigned
int
subtitle_region_count
=
0
;
unsigned
int
region_count
=
0
;
for
(
unsigned
i
=
0
;
i
<
i_subpicture
;
i
++
)
{
const
subpicture_t
*
subpic
=
pp_subpicture
[
i
];
unsigned
count
=
0
;
for
(
subpicture_region_t
*
r
=
subpic
->
p_region
;
r
!=
NULL
;
r
=
r
->
p_next
)
count
++
;
if
(
subpic
->
b_subtitle
)
subtitle_region_count
+=
count
;
region_count
+=
count
;
}
if
(
i_region_count
<=
0
)
if
(
region_count
<=
0
)
return
NULL
;
/* Create the output subpicture */
subpicture_t
*
p_output
=
subpicture_New
(
NULL
);
if
(
!
p_output
)
subpicture_t
*
output
=
subpicture_New
(
NULL
);
if
(
!
output
)
return
NULL
;
p_output
->
i_original_picture_width
=
p_
fmt_dst
->
i_width
;
p_output
->
i_original_picture_height
=
p_
fmt_dst
->
i_height
;
subpicture_region_t
**
pp_output_last
=
&
p_
output
->
p_region
;
output
->
i_original_picture_width
=
fmt_dst
->
i_width
;
output
->
i_original_picture_height
=
fmt_dst
->
i_height
;
subpicture_region_t
**
output_last_ptr
=
&
output
->
p_region
;
/* Allocate area array for subtitle overlap */
spu_area_t
p_
subtitle_area_buffer
[
VOUT_MAX_SUBPICTURES
];
spu_area_t
*
p_
subtitle_area
;
int
i_subtitle_area
;
spu_area_t
subtitle_area_buffer
[
VOUT_MAX_SUBPICTURES
];
spu_area_t
*
subtitle_area
;
int
subtitle_area_count
;
i_subtitle_area
=
0
;
p_subtitle_area
=
p_
subtitle_area_buffer
;
if
(
i_subtitle_region_count
>
sizeof
(
p_subtitle_area_buffer
)
/
sizeof
(
*
p_subtitle_area_buffer
)
)
p_subtitle_area
=
calloc
(
i_subtitle_region_count
,
sizeof
(
*
p_subtitle_area
)
);
subtitle_area_count
=
0
;
subtitle_area
=
subtitle_area_buffer
;
if
(
subtitle_region_count
>
sizeof
(
subtitle_area_buffer
)
/
sizeof
(
*
subtitle_area_buffer
)
)
subtitle_area
=
calloc
(
subtitle_region_count
,
sizeof
(
*
subtitle_area
)
);
/* Process all subpictures and regions (in the right order) */
for
(
unsigned
int
i_index
=
0
;
i_index
<
i_subpicture
;
i_index
++
)
{
subpicture_t
*
p_subpic
=
pp_subpicture
[
i_index
];
subpicture_region_t
*
p_region
;
for
(
unsigned
int
index
=
0
;
index
<
i_subpicture
;
index
++
)
{
subpicture_t
*
subpic
=
pp_subpicture
[
index
];
subpicture_region_t
*
region
;
if
(
!
p_subpic
->
p_region
)
if
(
!
subpic
->
p_region
)
continue
;
if
(
p_subpic
->
i_original_picture_width
<=
0
||
p_subpic
->
i_original_picture_height
<=
0
)
{
if
(
p_subpic
->
i_original_picture_width
>
0
||
p_subpic
->
i_original_picture_height
>
0
)
msg_Err
(
p_spu
,
"original picture size %dx%d is unsupported"
,
p_subpic
->
i_original_picture_width
,
p_subpic
->
i_original_picture_height
);
if
(
subpic
->
i_original_picture_width
<=
0
||
subpic
->
i_original_picture_height
<=
0
)
{
if
(
subpic
->
i_original_picture_width
>
0
||
subpic
->
i_original_picture_height
>
0
)
msg_Err
(
spu
,
"original picture size %dx%d is unsupported"
,
subpic
->
i_original_picture_width
,
subpic
->
i_original_picture_height
);
else
msg_Warn
(
p_spu
,
"original picture size is undefined"
);
msg_Warn
(
spu
,
"original picture size is undefined"
);
p_subpic
->
i_original_picture_width
=
p_
fmt_src
->
i_width
;
p_subpic
->
i_original_picture_height
=
p_
fmt_src
->
i_height
;
subpic
->
i_original_picture_width
=
fmt_src
->
i_width
;
subpic
->
i_original_picture_height
=
fmt_src
->
i_height
;
}
if
(
p_sys
->
p_text
)
{
if
(
sys
->
text
)
{
/* FIXME aspect ratio ? */
p_sys
->
p_
text
->
fmt_out
.
video
.
i_width
=
p_sys
->
p_text
->
fmt_out
.
video
.
i_visible_width
=
p_
subpic
->
i_original_picture_width
;
sys
->
text
->
fmt_out
.
video
.
i_width
=
sys
->
text
->
fmt_out
.
video
.
i_visible_width
=
subpic
->
i_original_picture_width
;
p_sys
->
p_
text
->
fmt_out
.
video
.
i_height
=
p_sys
->
p_text
->
fmt_out
.
video
.
i_visible_height
=
p_
subpic
->
i_original_picture_height
;
sys
->
text
->
fmt_out
.
video
.
i_height
=
sys
->
text
->
fmt_out
.
video
.
i_visible_height
=
subpic
->
i_original_picture_height
;
var_SetInteger
(
p_sys
->
p_text
,
"scale"
,
SCALE_UNIT
);
var_SetInteger
(
sys
->
text
,
"scale"
,
SCALE_UNIT
);
}
/* Render all regions
* We always transform non absolute subtitle into absolute one on the
* first rendering to allow good subtitle overlap support.
*/
for
(
p_region
=
p_subpic
->
p_region
;
p_region
!=
NULL
;
p_region
=
p_region
->
p_next
)
{
for
(
region
=
subpic
->
p_region
;
region
!=
NULL
;
region
=
region
->
p_next
)
{
spu_area_t
area
;
/* Compute region scale AR */
video_format_t
region_fmt
=
p_region
->
fmt
;
if
(
region_fmt
.
i_sar_num
<=
0
||
region_fmt
.
i_sar_den
<=
0
)
{
region_fmt
.
i_sar_num
=
p_fmt_src
->
i_sar_num
;
region_fmt
.
i_sar_den
=
p_fmt_src
->
i_sar_den
;
video_format_t
region_fmt
=
region
->
fmt
;
if
(
region_fmt
.
i_sar_num
<=
0
||
region_fmt
.
i_sar_den
<=
0
)
{
region_fmt
.
i_sar_num
=
fmt_src
->
i_sar_num
;
region_fmt
.
i_sar_den
=
fmt_src
->
i_sar_den
;
}
/* Compute scaling from original size to destination size
* FIXME The current scaling ensure that the heights match, the width being
* cropped.
*/
spu_scale_t
scale
=
spu_scale_createq
(
(
int64_t
)
p_fmt_dst
->
i_height
*
p_
fmt_dst
->
i_sar_den
*
region_fmt
.
i_sar_num
,
(
int64_t
)
p_subpic
->
i_original_picture_height
*
p_
fmt_dst
->
i_sar_num
*
region_fmt
.
i_sar_den
,
p_
fmt_dst
->
i_height
,
p_subpic
->
i_original_picture_height
);
spu_scale_t
scale
=
spu_scale_createq
((
int64_t
)
fmt_dst
->
i_height
*
fmt_dst
->
i_sar_den
*
region_fmt
.
i_sar_num
,
(
int64_t
)
subpic
->
i_original_picture_height
*
fmt_dst
->
i_sar_num
*
region_fmt
.
i_sar_den
,
fmt_dst
->
i_height
,
subpic
->
i_original_picture_height
);
/* Check scale validity */
if
(
scale
.
w
<=
0
||
scale
.
h
<=
0
)
if
(
scale
.
w
<=
0
||
scale
.
h
<=
0
)
continue
;
/* */
SpuRenderRegion
(
p_spu
,
pp_output_last
,
&
area
,
p_subpic
,
p_region
,
scale
,
p_chroma_list
,
p_fmt_dst
,
p_subtitle_area
,
i_subtitle_area
,
p_subpic
->
b_subtitle
?
render_subtitle_date
:
render_osd_date
);
if
(
*
pp_output_last
)
pp_output_last
=
&
(
*
pp_output_last
)
->
p_next
;
if
(
p_subpic
->
b_subtitle
)
{
area
=
spu_area_unscaled
(
area
,
scale
);
if
(
!
p_subpic
->
b_absolute
&&
area
.
i_width
>
0
&&
area
.
i_height
>
0
)
{
p_region
->
i_x
=
area
.
i_x
;
p_region
->
i_y
=
area
.
i_y
;
SpuRenderRegion
(
spu
,
output_last_ptr
,
&
area
,
subpic
,
region
,
scale
,
chroma_list
,
fmt_dst
,
subtitle_area
,
subtitle_area_count
,
subpic
->
b_subtitle
?
render_subtitle_date
:
render_osd_date
);
if
(
*
output_last_ptr
)
output_last_ptr
=
&
(
*
output_last_ptr
)
->
p_next
;
if
(
subpic
->
b_subtitle
)
{
area
=
spu_area_unscaled
(
area
,
scale
);
if
(
!
subpic
->
b_absolute
&&
area
.
width
>
0
&&
area
.
height
>
0
)
{
region
->
i_x
=
area
.
x
;
region
->
i_y
=
area
.
y
;
}
if
(
p_subtitle_area
)
p_subtitle_area
[
i_subtitle_area
++
]
=
area
;
if
(
subtitle_area
)
subtitle_area
[
subtitle_area_count
++
]
=
area
;
}
}
if
(
p_subpic
->
b_subtitle
&&
p_subpic
->
p_region
)
p_
subpic
->
b_absolute
=
true
;
if
(
subpic
->
b_subtitle
&&
subpic
->
p_region
)
subpic
->
b_absolute
=
true
;
}
/* */
if
(
p_subtitle_area
!=
p_subtitle_area_buffer
)
free
(
p_subtitle_area
);
if
(
subtitle_area
!=
subtitle_area_buffer
)
free
(
subtitle_area
);
return
p_
output
;
return
output
;
}
/*****************************************************************************
...
...
@@ -1188,39 +1104,37 @@ static subpicture_t *SpuRenderSubpictures( spu_t *p_spu,
* This function is called from CropCallback and at initialization time, to
* retrieve crop information from the input.
*****************************************************************************/
static
void
UpdateSPU
(
spu_t
*
p_spu
,
vlc_object_t
*
p_object
)
static
void
UpdateSPU
(
spu_t
*
spu
,
vlc_object_t
*
object
)
{
spu_private_t
*
p_sys
=
p_
spu
->
p
;
spu_private_t
*
sys
=
spu
->
p
;
vlc_value_t
val
;
vlc_mutex_lock
(
&
p_sys
->
lock
);
vlc_mutex_lock
(
&
sys
->
lock
);
p_sys
->
b_
force_palette
=
false
;
p_sys
->
b_
force_crop
=
false
;
sys
->
force_palette
=
false
;
sys
->
force_crop
=
false
;
if
(
var_Get
(
p_object
,
"highlight"
,
&
val
)
||
!
val
.
b_bool
)
{
vlc_mutex_unlock
(
&
p_sys
->
lock
);
if
(
var_Get
(
object
,
"highlight"
,
&
val
)
||
!
val
.
b_bool
)
{
vlc_mutex_unlock
(
&
sys
->
lock
);
return
;
}
p_sys
->
b_
force_crop
=
true
;
p_sys
->
i_crop_x
=
var_GetInteger
(
p_object
,
"x-start"
);
p_sys
->
i_crop_y
=
var_GetInteger
(
p_object
,
"y-start"
);
p_sys
->
i_crop_width
=
var_GetInteger
(
p_object
,
"x-end"
)
-
p_sys
->
i_crop_
x
;
p_sys
->
i_crop_height
=
var_GetInteger
(
p_object
,
"y-end"
)
-
p_sys
->
i_crop_
y
;
sys
->
force_crop
=
true
;
sys
->
crop
.
x
=
var_GetInteger
(
object
,
"x-start"
);
sys
->
crop
.
y
=
var_GetInteger
(
object
,
"y-start"
);
sys
->
crop
.
width
=
var_GetInteger
(
object
,
"x-end"
)
-
sys
->
crop
.
x
;
sys
->
crop
.
height
=
var_GetInteger
(
object
,
"y-end"
)
-
sys
->
crop
.
y
;
if
(
var_Get
(
p_object
,
"menu-palette"
,
&
val
)
==
VLC_SUCCESS
)
{
memcpy
(
p_sys
->
palette
,
val
.
p_address
,
16
);
p_sys
->
b_force_palette
=
true
;
if
(
var_Get
(
object
,
"menu-palette"
,
&
val
)
==
VLC_SUCCESS
)
{
memcpy
(
sys
->
palette
,
val
.
p_address
,
16
);
sys
->
force_palette
=
true
;
}
vlc_mutex_unlock
(
&
p_sys
->
lock
);
vlc_mutex_unlock
(
&
sys
->
lock
);
msg_Dbg
(
p_
object
,
"crop: %i,%i,%i,%i, palette forced: %i"
,
p_sys
->
i_crop_x
,
p_sys
->
i_crop_
y
,
p_sys
->
i_crop_width
,
p_sys
->
i_crop_
height
,
p_sys
->
b_force_palette
);
msg_Dbg
(
object
,
"crop: %i,%i,%i,%i, palette forced: %i"
,
sys
->
crop
.
x
,
sys
->
crop
.
y
,
sys
->
crop
.
width
,
sys
->
crop
.
height
,
sys
->
force_palette
);
}
/*****************************************************************************
...
...
@@ -1228,12 +1142,12 @@ static void UpdateSPU( spu_t *p_spu, vlc_object_t *p_object )
*****************************************************************************
* This callback is called from the input thread when we need cropping
*****************************************************************************/
static
int
CropCallback
(
vlc_object_t
*
p_object
,
char
const
*
psz_
var
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
p_data
)
static
int
CropCallback
(
vlc_object_t
*
object
,
char
const
*
var
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
data
)
{
VLC_UNUSED
(
oldval
);
VLC_UNUSED
(
newval
);
VLC_UNUSED
(
psz_
var
);
VLC_UNUSED
(
oldval
);
VLC_UNUSED
(
newval
);
VLC_UNUSED
(
var
);
UpdateSPU
(
(
spu_t
*
)
p_data
,
p_object
);
UpdateSPU
(
(
spu_t
*
)
data
,
object
);
return
VLC_SUCCESS
;
}
...
...
@@ -1241,45 +1155,45 @@ static int CropCallback( vlc_object_t *p_object, char const *psz_var,
* Buffers allocation callbacks for the filters
*****************************************************************************/
static
subpicture_t
*
sub_new_buffer
(
filter_t
*
p_filter
)
static
subpicture_t
*
sub_new_buffer
(
filter_t
*
filter
)
{
filter_owner_sys_t
*
p_sys
=
p_
filter
->
p_owner
;
filter_owner_sys_t
*
sys
=
filter
->
p_owner
;
subpicture_t
*
p_subpicture
=
subpicture_New
(
NULL
);
if
(
p_subpicture
)
p_subpicture
->
i_channel
=
p_sys
->
i_
channel
;
return
p_
subpicture
;
subpicture_t
*
subpicture
=
subpicture_New
(
NULL
);
if
(
subpicture
)
subpicture
->
i_channel
=
sys
->
channel
;
return
subpicture
;
}
static
void
sub_del_buffer
(
filter_t
*
p_filter
,
subpicture_t
*
p_subpic
)
static
void
sub_del_buffer
(
filter_t
*
filter
,
subpicture_t
*
subpic
)
{
VLC_UNUSED
(
p_filter
);
subpicture_Delete
(
p_subpic
);
VLC_UNUSED
(
filter
);
subpicture_Delete
(
subpic
);
}
static
int
SubSourceAllocationInit
(
filter_t
*
p_filter
,
void
*
p_data
)
static
int
SubSourceAllocationInit
(
filter_t
*
filter
,
void
*
data
)
{
spu_t
*
p_spu
=
p_
data
;
spu_t
*
spu
=
data
;
filter_owner_sys_t
*
p_sys
=
malloc
(
sizeof
(
filter_owner_sys_t
)
);
if
(
!
p_sys
)
filter_owner_sys_t
*
sys
=
malloc
(
sizeof
(
*
sys
)
);
if
(
!
sys
)
return
VLC_EGENERIC
;
p_
filter
->
pf_sub_buffer_new
=
sub_new_buffer
;
p_
filter
->
pf_sub_buffer_del
=
sub_del_buffer
;
filter
->
pf_sub_buffer_new
=
sub_new_buffer
;
filter
->
pf_sub_buffer_del
=
sub_del_buffer
;
p_filter
->
p_owner
=
p_
sys
;
p_sys
->
i_channel
=
spu_RegisterChannel
(
p_spu
);
p_sys
->
p_spu
=
p_
spu
;
filter
->
p_owner
=
sys
;
sys
->
channel
=
spu_RegisterChannel
(
spu
);
sys
->
spu
=
spu
;
return
VLC_SUCCESS
;
}
static
void
SubSourceAllocationClean
(
filter_t
*
p_filter
)
static
void
SubSourceAllocationClean
(
filter_t
*
filter
)
{
filter_owner_sys_t
*
p_sys
=
p_
filter
->
p_owner
;
filter_owner_sys_t
*
sys
=
filter
->
p_owner
;
spu_ClearChannel
(
p_sys
->
p_spu
,
p_sys
->
i_channel
);
free
(
p_filter
->
p_owner
);
spu_ClearChannel
(
sys
->
spu
,
sys
->
channel
);
free
(
filter
->
p_owner
);
}
/*****************************************************************************
...
...
@@ -1292,64 +1206,61 @@ static void SubSourceAllocationClean( filter_t *p_filter )
*
* \param p_this the parent object which creates the subpicture unit
*/
spu_t
*
spu_Create
(
vlc_object_t
*
p_this
)
spu_t
*
spu_Create
(
vlc_object_t
*
object
)
{
spu_t
*
p_spu
;
spu_private_t
*
p_sys
;
p_spu
=
vlc_custom_create
(
p_this
,
sizeof
(
spu_t
)
+
sizeof
(
spu_private_t
),
VLC_OBJECT_GENERIC
,
"subpicture"
);
if
(
!
p_spu
)
spu_t
*
spu
=
vlc_custom_create
(
object
,
sizeof
(
spu_t
)
+
sizeof
(
spu_private_t
),
VLC_OBJECT_GENERIC
,
"subpicture"
);
if
(
!
spu
)
return
NULL
;
vlc_object_attach
(
p_spu
,
p_this
);
vlc_object_attach
(
spu
,
object
);
/* Initialize spu fields */
p_spu
->
p
=
p_sys
=
(
spu_private_t
*
)
&
p_
spu
[
1
];
spu_private_t
*
sys
=
spu
->
p
=
(
spu_private_t
*
)
&
spu
[
1
];
/* Initialize private fields */
vlc_mutex_init
(
&
p_sys
->
lock
);
vlc_mutex_init
(
&
sys
->
lock
);
SpuHeapInit
(
&
p_sys
->
heap
);
SpuHeapInit
(
&
sys
->
heap
);
p_sys
->
p_
text
=
NULL
;
p_sys
->
p_
scale
=
NULL
;
p_sys
->
p_
scale_yuvp
=
NULL
;
sys
->
text
=
NULL
;
sys
->
scale
=
NULL
;
sys
->
scale_yuvp
=
NULL
;
p_sys
->
i_margin
=
var_InheritInteger
(
p_spu
,
"sub-margin"
);
sys
->
margin
=
var_InheritInteger
(
spu
,
"sub-margin"
);
/* Register the default subpicture channel */
p_sys
->
i_
channel
=
SPU_DEFAULT_CHANNEL
+
1
;
p_sys
->
psz_
source_chain_update
=
NULL
;
p_sys
->
psz_
filter_chain_update
=
NULL
;
vlc_mutex_init
(
&
p_sys
->
source_chain_lock
);
vlc_mutex_init
(
&
p_sys
->
filter_chain_lock
);
p_sys
->
p_source_chain
=
filter_chain_New
(
p_
spu
,
"sub source"
,
false
,
SubSourceAllocationInit
,
SubSourceAllocationClean
,
p_spu
);
p_sys
->
p_filter_chain
=
filter_chain_New
(
p_
spu
,
"sub filter"
,
false
,
NULL
,
NULL
,
p_spu
);
sys
->
channel
=
SPU_DEFAULT_CHANNEL
+
1
;
sys
->
source_chain_update
=
NULL
;
sys
->
filter_chain_update
=
NULL
;
vlc_mutex_init
(
&
sys
->
source_chain_lock
);
vlc_mutex_init
(
&
sys
->
filter_chain_lock
);
sys
->
source_chain
=
filter_chain_New
(
spu
,
"sub source"
,
false
,
SubSourceAllocationInit
,
SubSourceAllocationClean
,
spu
);
sys
->
filter_chain
=
filter_chain_New
(
spu
,
"sub filter"
,
false
,
NULL
,
NULL
,
spu
);
/* Load text and scale module */
p_sys
->
p_text
=
SpuRenderCreateAndLoadText
(
p_spu
);
sys
->
text
=
SpuRenderCreateAndLoadText
(
spu
);
/* XXX
p_
spu->p_scale is used for all conversion/scaling except yuvp to
/* XXX spu->p_scale is used for all conversion/scaling except yuvp to
* yuva/rgba */
p_sys
->
p_scale
=
SpuRenderCreateAndLoadScale
(
VLC_OBJECT
(
p_
spu
),
VLC_CODEC_YUVA
,
VLC_CODEC_RGBA
,
true
);
sys
->
scale
=
SpuRenderCreateAndLoadScale
(
VLC_OBJECT
(
spu
),
VLC_CODEC_YUVA
,
VLC_CODEC_RGBA
,
true
);
/* This one is used for YUVP to YUVA/RGBA without scaling
* FIXME rename it */
p_sys
->
p_scale_yuvp
=
SpuRenderCreateAndLoadScale
(
VLC_OBJECT
(
p_
spu
),
VLC_CODEC_YUVP
,
VLC_CODEC_YUVA
,
false
);
sys
->
scale_yuvp
=
SpuRenderCreateAndLoadScale
(
VLC_OBJECT
(
spu
),
VLC_CODEC_YUVP
,
VLC_CODEC_YUVA
,
false
);
/* */
p_sys
->
i_
last_sort_date
=
-
1
;
sys
->
last_sort_date
=
-
1
;
return
p_
spu
;
return
spu
;
}
/**
...
...
@@ -1357,32 +1268,32 @@ spu_t *spu_Create( vlc_object_t *p_this )
*
* \param p_this the parent object which destroys the subpicture unit
*/
void
spu_Destroy
(
spu_t
*
p_spu
)
void
spu_Destroy
(
spu_t
*
spu
)
{
spu_private_t
*
p_sys
=
p_
spu
->
p
;
spu_private_t
*
sys
=
spu
->
p
;
if
(
p_sys
->
p_text
)
FilterRelease
(
p_sys
->
p_text
);
if
(
sys
->
text
)
FilterRelease
(
sys
->
text
);
if
(
p_sys
->
p_scale_yuvp
)
FilterRelease
(
p_sys
->
p_scale_yuvp
);
if
(
sys
->
scale_yuvp
)
FilterRelease
(
sys
->
scale_yuvp
);
if
(
p_sys
->
p_scale
)
FilterRelease
(
p_sys
->
p_scale
);
if
(
sys
->
scale
)
FilterRelease
(
sys
->
scale
);
filter_chain_Delete
(
p_sys
->
p_source_chain
);
filter_chain_Delete
(
p_sys
->
p_filter_chain
);
vlc_mutex_destroy
(
&
p_sys
->
source_chain_lock
);
vlc_mutex_destroy
(
&
p_sys
->
filter_chain_lock
);
free
(
p_sys
->
psz_source_chain_update
);
free
(
p_sys
->
psz_filter_chain_update
);
filter_chain_Delete
(
sys
->
source_chain
);
filter_chain_Delete
(
sys
->
filter_chain
);
vlc_mutex_destroy
(
&
sys
->
source_chain_lock
);
vlc_mutex_destroy
(
&
sys
->
filter_chain_lock
);
free
(
sys
->
source_chain_update
);
free
(
sys
->
filter_chain_update
);
/* Destroy all remaining subpictures */
SpuHeapClean
(
&
p_sys
->
heap
);
SpuHeapClean
(
&
sys
->
heap
);
vlc_mutex_destroy
(
&
p_sys
->
lock
);
vlc_mutex_destroy
(
&
sys
->
lock
);
vlc_object_release
(
p_spu
);
vlc_object_release
(
spu
);
}
/**
...
...
@@ -1391,47 +1302,44 @@ void spu_Destroy( spu_t *p_spu )
* \param p_this the object in which to destroy the subpicture unit
* \param b_attach to select attach or detach
*/
void
spu_Attach
(
spu_t
*
p_spu
,
vlc_object_t
*
p_input
,
bool
b_attach
)
void
spu_Attach
(
spu_t
*
spu
,
vlc_object_t
*
input
,
bool
attach
)
{
if
(
b_attach
)
{
UpdateSPU
(
p_spu
,
p_input
);
var_Create
(
p_input
,
"highlight"
,
VLC_VAR_BOOL
);
var_AddCallback
(
p_input
,
"highlight"
,
CropCallback
,
p_spu
);
if
(
attach
)
{
UpdateSPU
(
spu
,
input
);
var_Create
(
input
,
"highlight"
,
VLC_VAR_BOOL
);
var_AddCallback
(
input
,
"highlight"
,
CropCallback
,
spu
);
vlc_mutex_lock
(
&
p_spu
->
p
->
lock
);
p_spu
->
p
->
p_input
=
p_
input
;
vlc_mutex_lock
(
&
spu
->
p
->
lock
);
spu
->
p
->
input
=
input
;
if
(
p_spu
->
p
->
p_text
)
FilterRelease
(
p_spu
->
p
->
p_text
);
p_spu
->
p
->
p_text
=
SpuRenderCreateAndLoadText
(
p_spu
);
if
(
spu
->
p
->
text
)
FilterRelease
(
spu
->
p
->
text
);
spu
->
p
->
text
=
SpuRenderCreateAndLoadText
(
spu
);
vlc_mutex_unlock
(
&
p_spu
->
p
->
lock
);
}
else
{
vlc_mutex_lock
(
&
p_spu
->
p
->
lock
);
p_spu
->
p
->
p_input
=
NULL
;
vlc_mutex_unlock
(
&
p_spu
->
p
->
lock
);
vlc_mutex_unlock
(
&
spu
->
p
->
lock
);
}
else
{
vlc_mutex_lock
(
&
spu
->
p
->
lock
);
spu
->
p
->
input
=
NULL
;
vlc_mutex_unlock
(
&
spu
->
p
->
lock
);
/* Delete callbacks */
var_DelCallback
(
p_input
,
"highlight"
,
CropCallback
,
p_spu
);
var_Destroy
(
p_input
,
"highlight"
);
var_DelCallback
(
input
,
"highlight"
,
CropCallback
,
spu
);
var_Destroy
(
input
,
"highlight"
);
}
}
/**
* Inform the SPU filters of mouse event
*/
int
spu_ProcessMouse
(
spu_t
*
p_
spu
,
const
vlc_mouse_t
*
p_
mouse
,
const
video_format_t
*
p_fmt
)
int
spu_ProcessMouse
(
spu_t
*
spu
,
const
vlc_mouse_t
*
mouse
,
const
video_format_t
*
fmt
)
{
spu_private_t
*
p_sys
=
p_
spu
->
p
;
spu_private_t
*
sys
=
spu
->
p
;
vlc_mutex_lock
(
&
p_sys
->
source_chain_lock
);
filter_chain_MouseEvent
(
p_sys
->
p_source_chain
,
p_mouse
,
p_fmt
);
vlc_mutex_unlock
(
&
p_sys
->
source_chain_lock
);
vlc_mutex_lock
(
&
sys
->
source_chain_lock
);
filter_chain_MouseEvent
(
sys
->
source_chain
,
mouse
,
fmt
);
vlc_mutex_unlock
(
&
sys
->
source_chain_lock
);
return
VLC_SUCCESS
;
}
...
...
@@ -1441,248 +1349,238 @@ int spu_ProcessMouse( spu_t *p_spu,
*
* Remove the reservation flag of a subpicture, which will cause it to be
* ready for display.
* \param
p_
spu the subpicture unit object
* \param
p_
subpic the subpicture to display
* \param spu the subpicture unit object
* \param subpic the subpicture to display
*/
void
spu_PutSubpicture
(
spu_t
*
p_spu
,
subpicture_t
*
p_subpic
)
void
spu_PutSubpicture
(
spu_t
*
spu
,
subpicture_t
*
subpic
)
{
spu_private_t
*
p_sys
=
p_
spu
->
p
;
spu_private_t
*
sys
=
spu
->
p
;
/* Update sub-filter chain */
vlc_mutex_lock
(
&
p_sys
->
lock
);
char
*
psz_chain_update
=
p_sys
->
psz_
filter_chain_update
;
p_sys
->
psz_
filter_chain_update
=
NULL
;
vlc_mutex_unlock
(
&
p_sys
->
lock
);
vlc_mutex_lock
(
&
sys
->
lock
);
char
*
chain_update
=
sys
->
filter_chain_update
;
sys
->
filter_chain_update
=
NULL
;
vlc_mutex_unlock
(
&
sys
->
lock
);
bool
b
_left_empty
=
false
;
bool
is
_left_empty
=
false
;
vlc_mutex_lock
(
&
p_sys
->
filter_chain_lock
);
if
(
psz_chain_update
)
{
filter_chain_Reset
(
p_sys
->
p_filter_chain
,
NULL
,
NULL
);
vlc_mutex_lock
(
&
sys
->
filter_chain_lock
);
if
(
chain_update
)
{
filter_chain_Reset
(
sys
->
filter_chain
,
NULL
,
NULL
);
filter_chain_AppendFromString
(
p_spu
->
p
->
p_filter_chain
,
psz_chain_update
);
filter_chain_AppendFromString
(
spu
->
p
->
filter_chain
,
chain_update
);
/* "sub-source" was formerly "sub-filter", so now the "sub-filter"
configuration may contain sub-filters or sub-sources configurations.
if the filters chain was left empty it may indicate that it's a sub-source configuration */
b_left_empty
=
(
filter_chain_GetLength
(
p_spu
->
p
->
p_filter_chain
)
==
0
);
is_left_empty
=
(
filter_chain_GetLength
(
spu
->
p
->
filter_chain
)
==
0
);
}
vlc_mutex_unlock
(
&
p_sys
->
filter_chain_lock
);
vlc_mutex_unlock
(
&
sys
->
filter_chain_lock
);
if
(
b_left_empty
)
{
if
(
is_left_empty
)
{
/* try to use the configuration as a sub-source configuration */
vlc_mutex_lock
(
&
p_sys
->
lock
);
if
(
!
p_sys
->
psz_source_chain_update
||
!*
p_sys
->
psz_source_chain_update
)
/* null or empty */
{
free
(
p_sys
->
psz_source_chain_update
);
p_sys
->
psz_source_chain_update
=
psz_chain_update
;
psz_chain_update
=
NULL
;
vlc_mutex_lock
(
&
sys
->
lock
);
if
(
!
sys
->
source_chain_update
||
!*
sys
->
source_chain_update
)
{
free
(
sys
->
source_chain_update
);
sys
->
source_chain_update
=
chain_update
;
chain_update
=
NULL
;
}
vlc_mutex_unlock
(
&
p_sys
->
lock
);
vlc_mutex_unlock
(
&
sys
->
lock
);
}
free
(
psz_chain_update
);
free
(
chain_update
);
/* Run filter chain on the new subpicture */
p_subpic
=
filter_chain_SubFilter
(
p_spu
->
p
->
p_filter_chain
,
p_
subpic
);
if
(
!
p_subpic
)
subpic
=
filter_chain_SubFilter
(
spu
->
p
->
filter_chain
,
subpic
);
if
(
!
subpic
)
return
;
/* SPU_DEFAULT_CHANNEL always reset itself */
if
(
p_subpic
->
i_channel
==
SPU_DEFAULT_CHANNEL
)
spu_ClearChannel
(
p_spu
,
SPU_DEFAULT_CHANNEL
);
if
(
subpic
->
i_channel
==
SPU_DEFAULT_CHANNEL
)
spu_ClearChannel
(
spu
,
SPU_DEFAULT_CHANNEL
);
/* p_private is for spu only and cannot be non NULL here */
for
(
subpicture_region_t
*
r
=
p_subpic
->
p_region
;
r
!=
NULL
;
r
=
r
->
p_next
)
assert
(
r
->
p_private
==
NULL
);
for
(
subpicture_region_t
*
r
=
subpic
->
p_region
;
r
!=
NULL
;
r
=
r
->
p_next
)
assert
(
r
->
p_private
==
NULL
);
/* */
vlc_mutex_lock
(
&
p_sys
->
lock
);
if
(
SpuHeapPush
(
&
p_sys
->
heap
,
p_subpic
)
)
{
vlc_mutex_unlock
(
&
p_sys
->
lock
);
msg_Err
(
p_spu
,
"subpicture heap full"
);
subpicture_Delete
(
p_subpic
);
vlc_mutex_lock
(
&
sys
->
lock
);
if
(
SpuHeapPush
(
&
sys
->
heap
,
subpic
))
{
vlc_mutex_unlock
(
&
sys
->
lock
);
msg_Err
(
spu
,
"subpicture heap full"
);
subpicture_Delete
(
subpic
);
return
;
}
vlc_mutex_unlock
(
&
p_sys
->
lock
);
vlc_mutex_unlock
(
&
sys
->
lock
);
}
subpicture_t
*
spu_Render
(
spu_t
*
p_
spu
,
const
vlc_fourcc_t
*
p_
chroma_list
,
const
video_format_t
*
p_
fmt_dst
,
const
video_format_t
*
p_
fmt_src
,
mtime_t
render_subtitle_date
,
mtime_t
render_osd_date
,
bool
b_subtitle_only
)
subpicture_t
*
spu_Render
(
spu_t
*
spu
,
const
vlc_fourcc_t
*
chroma_list
,
const
video_format_t
*
fmt_dst
,
const
video_format_t
*
fmt_src
,
mtime_t
render_subtitle_date
,
mtime_t
render_osd_date
,
bool
ignore_osd
)
{
spu_private_t
*
p_sys
=
p_
spu
->
p
;
spu_private_t
*
sys
=
spu
->
p
;
/* Update sub-source chain */
vlc_mutex_lock
(
&
p_sys
->
lock
);
char
*
psz_chain_update
=
p_sys
->
psz_
source_chain_update
;
p_sys
->
psz_
source_chain_update
=
NULL
;
vlc_mutex_unlock
(
&
p_sys
->
lock
);
vlc_mutex_lock
(
&
sys
->
lock
);
char
*
chain_update
=
sys
->
source_chain_update
;
sys
->
source_chain_update
=
NULL
;
vlc_mutex_unlock
(
&
sys
->
lock
);
vlc_mutex_lock
(
&
p_sys
->
source_chain_lock
);
if
(
psz_chain_update
)
{
filter_chain_Reset
(
p_sys
->
p_source_chain
,
NULL
,
NULL
);
vlc_mutex_lock
(
&
sys
->
source_chain_lock
);
if
(
chain_update
)
{
filter_chain_Reset
(
sys
->
source_chain
,
NULL
,
NULL
);
filter_chain_AppendFromString
(
p_spu
->
p
->
p_source_chain
,
psz_chain_update
);
filter_chain_AppendFromString
(
spu
->
p
->
source_chain
,
chain_update
);
free
(
psz_chain_update
);
free
(
chain_update
);
}
/* Run subpicture sources */
filter_chain_SubSource
(
p_sys
->
p_source_chain
,
render_osd_date
);
vlc_mutex_unlock
(
&
p_sys
->
source_chain_lock
);
filter_chain_SubSource
(
sys
->
source_chain
,
render_osd_date
);
vlc_mutex_unlock
(
&
sys
->
source_chain_lock
);
static
const
vlc_fourcc_t
p_
chroma_list_default_yuv
[]
=
{
static
const
vlc_fourcc_t
chroma_list_default_yuv
[]
=
{
VLC_CODEC_YUVA
,
VLC_CODEC_RGBA
,
VLC_CODEC_YUVP
,
0
,
};
static
const
vlc_fourcc_t
p_
chroma_list_default_rgb
[]
=
{
static
const
vlc_fourcc_t
chroma_list_default_rgb
[]
=
{
VLC_CODEC_RGBA
,
VLC_CODEC_YUVA
,
VLC_CODEC_YUVP
,
0
,
};
if
(
!
p_chroma_list
||
*
p_chroma_list
==
0
)
p_chroma_list
=
vlc_fourcc_IsYUV
(
p_fmt_dst
->
i_chroma
)
?
p_
chroma_list_default_yuv
:
p_
chroma_list_default_rgb
;
if
(
!
chroma_list
||
*
chroma_list
==
0
)
chroma_list
=
vlc_fourcc_IsYUV
(
fmt_dst
->
i_chroma
)
?
chroma_list_default_yuv
:
chroma_list_default_rgb
;
vlc_mutex_lock
(
&
p_sys
->
lock
);
vlc_mutex_lock
(
&
sys
->
lock
);
unsigned
int
i_subpicture
;
subpicture_t
*
pp_subpicture
[
VOUT_MAX_SUBPICTURES
];
unsigned
int
subpicture_count
;
subpicture_t
*
subpicture_array
[
VOUT_MAX_SUBPICTURES
];
/* Get an array of subpictures to render */
SpuSelectSubpictures
(
p_spu
,
&
i_subpicture
,
pp_subpicture
,
render_subtitle_date
,
render_osd_date
,
b_subtitle_only
);
if
(
i_subpicture
<=
0
)
{
vlc_mutex_unlock
(
&
p_sys
->
lock
);
SpuSelectSubpictures
(
spu
,
&
subpicture_count
,
subpicture_array
,
render_subtitle_date
,
render_osd_date
,
ignore_osd
);
if
(
subpicture_count
<=
0
)
{
vlc_mutex_unlock
(
&
sys
->
lock
);
return
NULL
;
}
/* Updates the subpictures */
for
(
unsigned
i
=
0
;
i
<
i_subpicture
;
i
++
)
{
subpicture_t
*
p_subpic
=
pp_subpicture
[
i
];
subpicture_Update
(
p_subpic
,
p_fmt_src
,
p_fmt_dst
,
p_subpic
->
b_subtitle
?
render_subtitle_date
:
render_osd_date
);
for
(
unsigned
i
=
0
;
i
<
subpicture_count
;
i
++
)
{
subpicture_t
*
subpic
=
subpicture_array
[
i
];
subpicture_Update
(
subpic
,
fmt_src
,
fmt_dst
,
subpic
->
b_subtitle
?
render_subtitle_date
:
render_osd_date
);
}
/* Now order the subpicture array
* XXX The order is *really* important for overlap subtitles positionning */
qsort
(
pp_subpicture
,
i_subpicture
,
sizeof
(
*
pp_subpicture
),
SubpictureCmp
);
qsort
(
subpicture_array
,
subpicture_count
,
sizeof
(
*
subpicture_array
),
SubpictureCmp
);
/* Render the subpictures */
subpicture_t
*
p_render
=
SpuRenderSubpictures
(
p_
spu
,
i_subpicture
,
pp_subpicture
,
p_
chroma_list
,
p_
fmt_dst
,
p_
fmt_src
,
render_subtitle_date
,
render_osd_date
);
vlc_mutex_unlock
(
&
p_sys
->
lock
);
return
p_
render
;
subpicture_t
*
render
=
SpuRenderSubpictures
(
spu
,
subpicture_count
,
subpicture_array
,
chroma_list
,
fmt_dst
,
fmt_src
,
render_subtitle_date
,
render_osd_date
);
vlc_mutex_unlock
(
&
sys
->
lock
);
return
render
;
}
void
spu_OffsetSubtitleDate
(
spu_t
*
p_spu
,
mtime_t
i_duration
)
void
spu_OffsetSubtitleDate
(
spu_t
*
spu
,
mtime_t
duration
)
{
spu_private_t
*
p_sys
=
p_spu
->
p
;
vlc_mutex_lock
(
&
p_sys
->
lock
);
for
(
int
i
=
0
;
i
<
VOUT_MAX_SUBPICTURES
;
i
++
)
{
spu_heap_entry_t
*
p_entry
=
&
p_sys
->
heap
.
p_entry
[
i
];
subpicture_t
*
p_current
=
p_entry
->
p_subpicture
;
if
(
p_current
&&
p_current
->
b_subtitle
)
{
if
(
p_current
->
i_start
>
0
)
p_current
->
i_start
+=
i_duration
;
if
(
p_current
->
i_stop
>
0
)
p_current
->
i_stop
+=
i_duration
;
spu_private_t
*
sys
=
spu
->
p
;
vlc_mutex_lock
(
&
sys
->
lock
);
for
(
int
i
=
0
;
i
<
VOUT_MAX_SUBPICTURES
;
i
++
)
{
spu_heap_entry_t
*
entry
=
&
sys
->
heap
.
entry
[
i
];
subpicture_t
*
current
=
entry
->
subpicture
;
if
(
current
&&
current
->
b_subtitle
)
{
if
(
current
->
i_start
>
0
)
current
->
i_start
+=
duration
;
if
(
current
->
i_stop
>
0
)
current
->
i_stop
+=
duration
;
}
}
vlc_mutex_unlock
(
&
p_sys
->
lock
);
vlc_mutex_unlock
(
&
sys
->
lock
);
}
int
spu_RegisterChannel
(
spu_t
*
p_spu
)
int
spu_RegisterChannel
(
spu_t
*
spu
)
{
spu_private_t
*
p_sys
=
p_
spu
->
p
;
spu_private_t
*
sys
=
spu
->
p
;
vlc_mutex_lock
(
&
p_sys
->
lock
);
int
i_channel
=
p_sys
->
i_
channel
++
;
vlc_mutex_unlock
(
&
p_sys
->
lock
);
vlc_mutex_lock
(
&
sys
->
lock
);
int
channel
=
sys
->
channel
++
;
vlc_mutex_unlock
(
&
sys
->
lock
);
return
i_
channel
;
return
channel
;
}
void
spu_ClearChannel
(
spu_t
*
p_spu
,
int
i_channel
)
void
spu_ClearChannel
(
spu_t
*
spu
,
int
channel
)
{
spu_private_t
*
p_sys
=
p_
spu
->
p
;
spu_private_t
*
sys
=
spu
->
p
;
vlc_mutex_lock
(
&
p_sys
->
lock
);
vlc_mutex_lock
(
&
sys
->
lock
);
for
(
int
i_subpic
=
0
;
i_subpic
<
VOUT_MAX_SUBPICTURES
;
i_subpic
++
)
{
spu_heap_entry_t
*
p_entry
=
&
p_sys
->
heap
.
p_entry
[
i_subpic
];
subpicture_t
*
p_subpic
=
p_entry
->
p_subpicture
;
for
(
int
i
=
0
;
i
<
VOUT_MAX_SUBPICTURES
;
i
++
)
{
spu_heap_entry_t
*
entry
=
&
sys
->
heap
.
entry
[
i
];
subpicture_t
*
subpic
=
entry
->
subpicture
;
if
(
!
p_subpic
)
if
(
!
subpic
)
continue
;
if
(
p_subpic
->
i_channel
!=
i_channel
&&
(
i_channel
!=
-
1
||
p_subpic
->
i_channel
==
SPU_DEFAULT_CHANNEL
)
)
if
(
subpic
->
i_channel
!=
channel
&&
(
channel
!=
-
1
||
subpic
->
i_channel
==
SPU_DEFAULT_CHANNEL
)
)
continue
;
/* You cannot delete subpicture outside of spu_SortSubpictures */
p_entry
->
b_
reject
=
true
;
entry
->
reject
=
true
;
}
vlc_mutex_unlock
(
&
p_sys
->
lock
);
vlc_mutex_unlock
(
&
sys
->
lock
);
}
void
spu_ChangeSources
(
spu_t
*
p_spu
,
const
char
*
psz_filters
)
void
spu_ChangeSources
(
spu_t
*
spu
,
const
char
*
filters
)
{
spu_private_t
*
p_sys
=
p_
spu
->
p
;
spu_private_t
*
sys
=
spu
->
p
;
vlc_mutex_lock
(
&
p_sys
->
lock
);
vlc_mutex_lock
(
&
sys
->
lock
);
free
(
p_sys
->
psz_source_chain_update
);
p_sys
->
psz_source_chain_update
=
strdup
(
psz_filters
);
free
(
sys
->
source_chain_update
);
sys
->
source_chain_update
=
strdup
(
filters
);
vlc_mutex_unlock
(
&
p_sys
->
lock
);
vlc_mutex_unlock
(
&
sys
->
lock
);
}
void
spu_ChangeFilters
(
spu_t
*
p_spu
,
const
char
*
psz_filters
)
void
spu_ChangeFilters
(
spu_t
*
spu
,
const
char
*
filters
)
{
spu_private_t
*
p_sys
=
p_
spu
->
p
;
spu_private_t
*
sys
=
spu
->
p
;
vlc_mutex_lock
(
&
p_sys
->
lock
);
vlc_mutex_lock
(
&
sys
->
lock
);
free
(
p_sys
->
psz_filter_chain_update
);
p_sys
->
psz_filter_chain_update
=
strdup
(
psz_filters
);
free
(
sys
->
filter_chain_update
);
sys
->
filter_chain_update
=
strdup
(
filters
);
vlc_mutex_unlock
(
&
p_sys
->
lock
);
vlc_mutex_unlock
(
&
sys
->
lock
);
}
void
spu_ChangeMargin
(
spu_t
*
p_spu
,
int
i_margin
)
void
spu_ChangeMargin
(
spu_t
*
spu
,
int
margin
)
{
spu_private_t
*
p_sys
=
p_
spu
->
p
;
spu_private_t
*
sys
=
spu
->
p
;
vlc_mutex_lock
(
&
p_sys
->
lock
);
p_sys
->
i_margin
=
i_
margin
;
vlc_mutex_unlock
(
&
p_sys
->
lock
);
vlc_mutex_lock
(
&
sys
->
lock
);
sys
->
margin
=
margin
;
vlc_mutex_unlock
(
&
sys
->
lock
);
}
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