Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc
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
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