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
24e00929
Commit
24e00929
authored
Mar 21, 2015
by
Rémi Denis-Courmont
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
decoder: reorder to avoid forward declation, no functional changes
parent
d4489a37
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
1249 additions
and
1266 deletions
+1249
-1266
src/input/decoder.c
src/input/decoder.c
+1249
-1266
No files found.
src/input/decoder.c
View file @
24e00929
...
@@ -53,25 +53,6 @@
...
@@ -53,25 +53,6 @@
#include "../video_output/vout_control.h"
#include "../video_output/vout_control.h"
static
decoder_t
*
CreateDecoder
(
vlc_object_t
*
,
input_thread_t
*
,
const
es_format_t
*
,
bool
,
input_resource_t
*
,
sout_instance_t
*
p_sout
);
static
void
DeleteDecoder
(
decoder_t
*
);
static
void
*
DecoderThread
(
void
*
);
static
void
DecoderProcess
(
decoder_t
*
,
block_t
*
);
static
void
DecoderFlush
(
decoder_t
*
);
static
void
DecoderSignalWait
(
decoder_t
*
);
static
void
DecoderUpdateFormatLocked
(
decoder_t
*
);
static
void
DecoderUnsupportedCodec
(
decoder_t
*
,
vlc_fourcc_t
);
/* Buffers allocation callbacks for the decoders */
static
int
vout_update_format
(
decoder_t
*
);
static
picture_t
*
vout_new_buffer
(
decoder_t
*
);
static
int
aout_update_format
(
decoder_t
*
);
static
subpicture_t
*
spu_new_buffer
(
decoder_t
*
,
const
subpicture_updater_t
*
);
struct
decoder_owner_sys_t
struct
decoder_owner_sys_t
{
{
int64_t
i_preroll_end
;
int64_t
i_preroll_end
;
...
@@ -151,847 +132,487 @@ struct decoder_owner_sys_t
...
@@ -151,847 +132,487 @@ struct decoder_owner_sys_t
/* */
/* */
#define DECODER_SPU_VOUT_WAIT_DURATION ((int)(0.200*CLOCK_FREQ))
#define DECODER_SPU_VOUT_WAIT_DURATION ((int)(0.200*CLOCK_FREQ))
static
void
DecoderUpdateFormatLocked
(
decoder_t
*
p_dec
)
/*****************************************************************************
* Public functions
*****************************************************************************/
picture_t
*
decoder_NewPicture
(
decoder_t
*
p_decoder
)
{
{
if
(
decoder_UpdateVideoFormat
(
p_decoder
)
)
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
return
NULL
;
picture_t
*
p_picture
=
p_decoder
->
pf_vout_buffer_new
(
p_decoder
);
vlc_assert_locked
(
&
p_owner
->
lock
);
if
(
!
p_picture
)
msg_Warn
(
p_decoder
,
"can't get output picture"
);
return
p_picture
;
}
block_t
*
decoder_NewAudioBuffer
(
decoder_t
*
dec
,
int
samples
)
p_owner
->
b_fmt_description
=
true
;
{
if
(
decoder_UpdateAudioFormat
(
dec
)
)
return
NULL
;
size_t
length
=
samples
*
dec
->
fmt_out
.
audio
.
i_bytes_per_frame
/* Move p_description */
/
dec
->
fmt_out
.
audio
.
i_frame_length
;
if
(
p_owner
->
p_description
&&
p_dec
->
p_description
)
block_t
*
block
=
block_Alloc
(
length
);
vlc_meta_Delete
(
p_owner
->
p_description
);
if
(
likely
(
block
!=
NULL
)
)
p_owner
->
p_description
=
p_dec
->
p_description
;
{
p_dec
->
p_description
=
NULL
;
block
->
i_nb_samples
=
samples
;
block
->
i_pts
=
block
->
i_length
=
0
;
}
return
block
;
}
}
subpicture_t
*
decoder_NewSubpicture
(
decoder_t
*
p_decoder
,
static
bool
DecoderIsFlushing
(
decoder_t
*
p_dec
)
const
subpicture_updater_t
*
p_dyn
)
{
{
subpicture_t
*
p_subpicture
=
p_decoder
->
pf_spu_buffer_new
(
p_decoder
,
p_dyn
);
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
if
(
!
p_subpicture
)
bool
b_flushing
;
msg_Warn
(
p_decoder
,
"can't get output subpicture"
);
return
p_subpicture
;
}
/* decoder_GetInputAttachments:
vlc_mutex_lock
(
&
p_owner
->
lock
);
*/
int
decoder_GetInputAttachments
(
decoder_t
*
p_dec
,
input_attachment_t
***
ppp_attachment
,
int
*
pi_attachment
)
{
if
(
!
p_dec
->
pf_get_attachments
)
return
VLC_EGENERIC
;
return
p_dec
->
pf_get_attachments
(
p_dec
,
ppp_attachment
,
pi_attachment
);
b_flushing
=
p_owner
->
b_flushing
;
}
/* decoder_GetDisplayDate:
*/
mtime_t
decoder_GetDisplayDate
(
decoder_t
*
p_dec
,
mtime_t
i_ts
)
{
if
(
!
p_dec
->
pf_get_display_date
)
return
VLC_TS_INVALID
;
return
p_dec
->
pf_get_display_date
(
p_dec
,
i_ts
);
vlc_mutex_unlock
(
&
p_owner
->
lock
);
}
/* decoder_GetDisplayRate:
*/
int
decoder_GetDisplayRate
(
decoder_t
*
p_dec
)
{
if
(
!
p_dec
->
pf_get_display_rate
)
return
INPUT_RATE_DEFAULT
;
return
p_dec
->
pf_get_display_rate
(
p_dec
)
;
return
b_flushing
;
}
}
/* TODO: pass p_sout through p_resource? -- Courmisch */
static
void
DecoderSignalWait
(
decoder_t
*
p_dec
)
static
decoder_t
*
decoder_New
(
vlc_object_t
*
p_parent
,
input_thread_t
*
p_input
,
const
es_format_t
*
fmt
,
input_clock_t
*
p_clock
,
input_resource_t
*
p_resource
,
sout_instance_t
*
p_sout
)
{
{
decoder_t
*
p_dec
=
NULL
;
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
const
char
*
psz_type
=
p_sout
?
N_
(
"packetizer"
)
:
N_
(
"decoder"
);
int
i_priority
;
/* Create the decoder configuration structure */
p_dec
=
CreateDecoder
(
p_parent
,
p_input
,
fmt
,
p_sout
!=
NULL
,
p_resource
,
p_sout
);
if
(
p_dec
==
NULL
)
{
msg_Err
(
p_parent
,
"could not create %s"
,
psz_type
);
dialog_Fatal
(
p_parent
,
_
(
"Streaming / Transcoding failed"
),
_
(
"VLC could not open the %s module."
),
vlc_gettext
(
psz_type
)
);
return
NULL
;
}
if
(
!
p_dec
->
p_module
)
{
DecoderUnsupportedCodec
(
p_dec
,
fmt
->
i_codec
);
DeleteDecoder
(
p_dec
);
return
NULL
;
}
p_dec
->
p_owner
->
p_clock
=
p_clock
;
assert
(
p_dec
->
fmt_out
.
i_cat
!=
UNKNOWN_ES
);
if
(
p_dec
->
fmt_out
.
i_cat
==
AUDIO_ES
)
vlc_mutex_lock
(
&
p_owner
->
lock
);
i_priority
=
VLC_THREAD_PRIORITY_AUDIO
;
else
i_priority
=
VLC_THREAD_PRIORITY_VIDEO
;
/* Spawn the decoder thread */
if
(
p_owner
->
b_waiting
)
if
(
vlc_clone
(
&
p_dec
->
p_owner
->
thread
,
DecoderThread
,
p_dec
,
i_priority
)
)
{
{
msg_Err
(
p_dec
,
"cannot spawn decoder thread"
);
p_owner
->
b_has_data
=
true
;
module_unneed
(
p_dec
,
p_dec
->
p_module
);
vlc_cond_signal
(
&
p_owner
->
wait_acknowledge
);
DeleteDecoder
(
p_dec
);
return
NULL
;
}
}
return
p_dec
;
vlc_mutex_unlock
(
&
p_owner
->
lock
)
;
}
}
static
block_t
*
DecoderBlockFlushNew
()
/**
* Spawns a new decoder thread from the input thread
*
* \param p_input the input thread
* \param p_es the es descriptor
* \return the spawned decoder object
*/
decoder_t
*
input_DecoderNew
(
input_thread_t
*
p_input
,
es_format_t
*
fmt
,
input_clock_t
*
p_clock
,
sout_instance_t
*
p_sout
)
{
{
return
decoder_New
(
VLC_OBJECT
(
p_input
),
p_input
,
fmt
,
p_clock
,
block_t
*
p_null
=
block_Alloc
(
128
);
p_input
->
p
->
p_resource
,
p_sout
);
if
(
!
p_null
)
}
return
NULL
;
/**
p_null
->
i_flags
|=
BLOCK_FLAG_DISCONTINUITY
|
* Spawn a decoder thread outside of the input thread.
BLOCK_FLAG_CORRUPTED
|
*/
BLOCK_FLAG_CORE_FLUSH
;
decoder_t
*
input_DecoderCreate
(
vlc_object_t
*
p_parent
,
const
es_format_t
*
fmt
,
memset
(
p_null
->
p_buffer
,
0
,
p_null
->
i_buffer
);
input_resource_t
*
p_resource
)
{
return
decoder_New
(
p_parent
,
NULL
,
fmt
,
NULL
,
p_resource
,
NULL
);
}
return
p_null
;
}
/**
/*****************************************************************************
* Kills a decoder thread and waits until it's finished
* Buffers allocation callbacks for the decoders
*
*****************************************************************************/
* \param p_input the input thread
static
vout_thread_t
*
aout_request_vout
(
void
*
p_private
,
* \param p_es the es descriptor
vout_thread_t
*
p_vout
,
video_format_t
*
p_fmt
,
bool
b_recyle
)
* \return nothing
*/
void
input_DecoderDelete
(
decoder_t
*
p_dec
)
{
{
decoder_t
*
p_dec
=
p_private
;
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
input_thread_t
*
p_input
=
p_owner
->
p_input
;
vlc_cancel
(
p_owner
->
thread
);
p_vout
=
input_resource_RequestVout
(
p_owner
->
p_resource
,
p_vout
,
p_fmt
,
1
,
b_recyle
);
/* Make sure we aren't paused/waiting/decoding anymore */
if
(
p_input
!=
NULL
)
vlc_mutex_lock
(
&
p_owner
->
lock
);
input_SendEventVout
(
p_input
);
p_owner
->
b_paused
=
false
;
p_owner
->
b_waiting
=
false
;
p_owner
->
b_flushing
=
true
;
vlc_cond_signal
(
&
p_owner
->
wait_request
);
vlc_mutex_unlock
(
&
p_owner
->
lock
);
vlc_join
(
p_owner
->
thread
,
NULL
);
module_unneed
(
p_dec
,
p_dec
->
p_module
);
/* */
if
(
p_dec
->
p_owner
->
cc
.
b_supported
)
{
int
i
;
for
(
i
=
0
;
i
<
4
;
i
++
)
input_DecoderSetCcState
(
p_dec
,
false
,
i
);
}
/* Delete decoder */
return
p_vout
;
DeleteDecoder
(
p_dec
);
}
}
/**
static
int
aout_update_format
(
decoder_t
*
p_dec
)
* Put a block_t in the decoder's fifo.
* Thread-safe w.r.t. the decoder. May be a cancellation point.
*
* \param p_dec the decoder object
* \param p_block the data block
*/
void
input_DecoderDecode
(
decoder_t
*
p_dec
,
block_t
*
p_block
,
bool
b_do_pace
)
{
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
vlc_fifo_Lock
(
p_owner
->
p_fifo
);
if
(
p_owner
->
p_aout
if
(
!
b_do_pace
)
&&
!
AOUT_FMTS_IDENTICAL
(
&
p_dec
->
fmt_out
.
audio
,
&
p_owner
->
fmt
.
audio
)
)
{
{
/* FIXME: ideally we would check the time amount of data
audio_output_t
*
p_aout
=
p_owner
->
p_aout
;
* in the FIFO instead of its size. */
/* 400 MiB, i.e. ~ 50mb/s for 60s */
if
(
vlc_fifo_GetBytes
(
p_owner
->
p_fifo
)
>
400
*
1024
*
1024
)
{
msg_Warn
(
p_dec
,
"decoder/packetizer fifo full (data not "
"consumed quickly enough), resetting fifo!"
);
block_ChainRelease
(
vlc_fifo_DequeueAllUnlocked
(
p_owner
->
p_fifo
)
);
}
}
else
if
(
!
p_owner
->
b_waiting
)
{
/* The FIFO is not consumed when waiting, so pacing would deadlock VLC.
* Locking is not necessary as b_waiting is only read, not written by
* the decoder thread. */
while
(
vlc_fifo_GetCount
(
p_owner
->
p_fifo
)
>=
10
)
vlc_fifo_WaitCond
(
p_owner
->
p_fifo
,
&
p_owner
->
wait_acknowledge
);
}
vlc_fifo_QueueUnlocked
(
p_owner
->
p_fifo
,
p_block
);
vlc_fifo_Unlock
(
p_owner
->
p_fifo
);
}
bool
input_DecoderIsEmpty
(
decoder_t
*
p_dec
)
/* Parameters changed, restart the aout */
{
vlc_mutex_lock
(
&
p_owner
->
lock
);
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
assert
(
!
p_owner
->
b_waiting
);
bool
b_empty
=
block_FifoCount
(
p_dec
->
p_owner
->
p_fifo
)
<=
0
;
aout_DecDelete
(
p_owner
->
p_aout
);
p_owner
->
p_aout
=
NULL
;
if
(
b_empty
)
{
vlc_mutex_lock
(
&
p_owner
->
lock
);
/* TODO subtitles support */
if
(
p_owner
->
fmt
.
i_cat
==
VIDEO_ES
&&
p_owner
->
p_vout
)
b_empty
=
vout_IsEmpty
(
p_owner
->
p_vout
);
else
if
(
p_owner
->
fmt
.
i_cat
==
AUDIO_ES
&&
p_owner
->
p_aout
)
b_empty
=
aout_DecIsEmpty
(
p_owner
->
p_aout
);
vlc_mutex_unlock
(
&
p_owner
->
lock
);
vlc_mutex_unlock
(
&
p_owner
->
lock
);
input_resource_PutAout
(
p_owner
->
p_resource
,
p_aout
);
}
}
return
b_empty
;
}
void
input_DecoderIsCcPresent
(
decoder_t
*
p_dec
,
bool
pb_present
[
4
]
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
int
i
;
vlc_mutex_lock
(
&
p_owner
->
lock
);
for
(
i
=
0
;
i
<
4
;
i
++
)
pb_present
[
i
]
=
p_owner
->
cc
.
pb_present
[
i
];
vlc_mutex_unlock
(
&
p_owner
->
lock
);
}
int
input_DecoderSetCcState
(
decoder_t
*
p_dec
,
bool
b_decode
,
int
i_channel
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
//msg_Warn( p_dec, "input_DecoderSetCcState: %d @%d", b_decode, i_channel );
if
(
i_channel
<
0
||
i_channel
>=
4
||
!
p_owner
->
cc
.
pb_present
[
i_channel
]
)
return
VLC_EGENERIC
;
if
(
b_decode
)
{
static
const
vlc_fourcc_t
fcc
[
4
]
=
{
VLC_FOURCC
(
'c'
,
'c'
,
'1'
,
' '
),
VLC_FOURCC
(
'c'
,
'c'
,
'2'
,
' '
),
VLC_FOURCC
(
'c'
,
'c'
,
'3'
,
' '
),
VLC_FOURCC
(
'c'
,
'c'
,
'4'
,
' '
),
};
decoder_t
*
p_cc
;
es_format_t
fmt
;
es_format_Init
(
&
fmt
,
SPU_ES
,
fcc
[
i_channel
]
);
p_cc
=
input_DecoderNew
(
p_owner
->
p_input
,
&
fmt
,
p_dec
->
p_owner
->
p_clock
,
p_owner
->
p_sout
);
if
(
!
p_cc
)
{
msg_Err
(
p_dec
,
"could not create decoder"
);
dialog_Fatal
(
p_dec
,
_
(
"Streaming / Transcoding failed"
),
"%s"
,
_
(
"VLC could not open the decoder module."
)
);
return
VLC_EGENERIC
;
}
else
if
(
!
p_cc
->
p_module
)
{
DecoderUnsupportedCodec
(
p_dec
,
fcc
[
i_channel
]
);
input_DecoderDelete
(
p_cc
);
return
VLC_EGENERIC
;
}
p_cc
->
p_owner
->
p_clock
=
p_owner
->
p_clock
;
vlc_mutex_lock
(
&
p_owner
->
lock
);
p_owner
->
cc
.
pp_decoder
[
i_channel
]
=
p_cc
;
vlc_mutex_unlock
(
&
p_owner
->
lock
);
}
else
{
decoder_t
*
p_cc
;
vlc_mutex_lock
(
&
p_owner
->
lock
);
p_cc
=
p_owner
->
cc
.
pp_decoder
[
i_channel
];
p_owner
->
cc
.
pp_decoder
[
i_channel
]
=
NULL
;
vlc_mutex_unlock
(
&
p_owner
->
lock
);
if
(
p_cc
)
input_DecoderDelete
(
p_cc
);
}
return
VLC_SUCCESS
;
}
int
input_DecoderGetCcState
(
decoder_t
*
p_dec
,
bool
*
pb_decode
,
int
i_channel
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
*
pb_decode
=
false
;
if
(
i_channel
<
0
||
i_channel
>=
4
||
!
p_owner
->
cc
.
pb_present
[
i_channel
]
)
return
VLC_EGENERIC
;
vlc_mutex_lock
(
&
p_owner
->
lock
);
*
pb_decode
=
p_owner
->
cc
.
pp_decoder
[
i_channel
]
!=
NULL
;
vlc_mutex_unlock
(
&
p_owner
->
lock
);
return
VLC_EGENERIC
;
}
void
input_DecoderChangePause
(
decoder_t
*
p_dec
,
bool
b_paused
,
mtime_t
i_date
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
vlc_mutex_lock
(
&
p_owner
->
lock
);
/* Normally, p_owner->b_paused != b_paused here. But if a track is added
* while the input is paused (e.g. add sub file), then b_paused is
* (incorrectly) false. */
if
(
likely
(
p_owner
->
b_paused
!=
b_paused
)
)
{
p_owner
->
b_paused
=
b_paused
;
p_owner
->
pause
.
i_date
=
i_date
;
p_owner
->
pause
.
i_ignore
=
0
;
vlc_cond_signal
(
&
p_owner
->
wait_request
);
/* XXX only audio and video output have to be paused.
* - for sout it is useless
* - for subs, it is done by the vout
*/
if
(
p_owner
->
fmt
.
i_cat
==
AUDIO_ES
)
{
if
(
p_owner
->
p_aout
)
aout_DecChangePause
(
p_owner
->
p_aout
,
b_paused
,
i_date
);
}
else
if
(
p_owner
->
fmt
.
i_cat
==
VIDEO_ES
)
{
if
(
p_owner
->
p_vout
)
vout_ChangePause
(
p_owner
->
p_vout
,
b_paused
,
i_date
);
}
}
vlc_mutex_unlock
(
&
p_owner
->
lock
);
}
void
input_DecoderChangeDelay
(
decoder_t
*
p_dec
,
mtime_t
i_delay
)
if
(
p_owner
->
p_aout
==
NULL
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
vlc_mutex_lock
(
&
p_owner
->
lock
);
p_owner
->
i_ts_delay
=
i_delay
;
vlc_mutex_unlock
(
&
p_owner
->
lock
);
}
/**
* Requests that the decoder immediately discard all pending buffers.
* This is useful at end of stream, when seeking or when deselecting a stream.
*/
void
input_DecoderFlush
(
decoder_t
*
p_dec
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
vlc_mutex_lock
(
&
p_owner
->
lock
);
DecoderFlush
(
p_dec
);
vlc_mutex_unlock
(
&
p_owner
->
lock
);
}
void
input_DecoderStartWait
(
decoder_t
*
p_dec
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
assert
(
!
p_owner
->
b_waiting
);
vlc_mutex_lock
(
&
p_owner
->
lock
);
p_owner
->
b_first
=
true
;
p_owner
->
b_has_data
=
false
;
p_owner
->
b_waiting
=
true
;
vlc_cond_signal
(
&
p_owner
->
wait_request
);
vlc_mutex_unlock
(
&
p_owner
->
lock
);
}
void
input_DecoderStopWait
(
decoder_t
*
p_dec
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
assert
(
p_owner
->
b_waiting
);
vlc_mutex_lock
(
&
p_owner
->
lock
);
p_owner
->
b_waiting
=
false
;
vlc_cond_signal
(
&
p_owner
->
wait_request
);
vlc_mutex_unlock
(
&
p_owner
->
lock
);
}
void
input_DecoderWait
(
decoder_t
*
p_dec
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
assert
(
p_owner
->
b_waiting
);
vlc_mutex_lock
(
&
p_owner
->
lock
);
while
(
!
p_owner
->
b_has_data
)
{
{
vlc_fifo_Lock
(
p_owner
->
p_fifo
);
p_dec
->
fmt_out
.
audio
.
i_format
=
p_dec
->
fmt_out
.
i_codec
;
p_owner
->
b_woken
=
true
;
vlc_fifo_Signal
(
p_owner
->
p_fifo
);
vlc_fifo_Unlock
(
p_owner
->
p_fifo
);
vlc_cond_wait
(
&
p_owner
->
wait_acknowledge
,
&
p_owner
->
lock
);
}
vlc_mutex_unlock
(
&
p_owner
->
lock
);
}
void
input_DecoderFrameNext
(
decoder_t
*
p_dec
,
mtime_t
*
pi_duration
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
*
pi_duration
=
0
;
audio_sample_format_t
format
=
p_dec
->
fmt_out
.
audio
;
aout_FormatPrepare
(
&
format
);
vlc_mutex_lock
(
&
p_owner
->
lock
);
const
int
i_force_dolby
=
var_InheritInteger
(
p_dec
,
"force-dolby-surround"
);
if
(
p_owner
->
fmt
.
i_cat
==
VIDEO_ES
)
if
(
i_force_dolby
&&
{
(
format
.
i_original_channels
&
AOUT_CHAN_PHYSMASK
)
==
if
(
p_owner
->
b_paused
&&
p_owner
->
p_vout
)
(
AOUT_CHAN_LEFT
|
AOUT_CHAN_RIGHT
)
)
{
{
vout_NextPicture
(
p_owner
->
p_vout
,
pi_duration
);
if
(
i_force_dolby
==
1
)
p_owner
->
pause
.
i_ignore
++
;
{
vlc_cond_signal
(
&
p_owner
->
wait_request
);
format
.
i_original_channels
=
format
.
i_original_channels
|
AOUT_CHAN_DOLBYSTEREO
;
}
else
/* i_force_dolby == 2 */
{
format
.
i_original_channels
=
format
.
i_original_channels
&
~
AOUT_CHAN_DOLBYSTEREO
;
}
}
}
}
else
{
/* TODO subtitle should not be flushed */
p_owner
->
b_waiting
=
false
;
DecoderFlush
(
p_dec
);
}
vlc_mutex_unlock
(
&
p_owner
->
lock
);
}
bool
input_DecoderHasFormatChanged
(
decoder_t
*
p_dec
,
es_format_t
*
p_fmt
,
vlc_meta_t
**
pp_meta
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
bool
b_changed
;
vlc_mutex_lock
(
&
p_owner
->
lock
);
aout_request_vout_t
request_vout
=
{
b_changed
=
p_owner
->
b_fmt_description
;
.
pf_request_vout
=
aout_request_vout
,
if
(
b_changed
)
.
p_private
=
p_dec
,
{
};
if
(
p_fmt
!=
NULL
)
audio_output_t
*
p_aout
;
es_format_Copy
(
p_fmt
,
&
p_owner
->
fmt
);
if
(
pp_meta
)
p_aout
=
input_resource_GetAout
(
p_owner
->
p_resource
);
if
(
p_aout
)
{
{
*
pp_meta
=
NULL
;
if
(
aout_DecNew
(
p_aout
,
&
format
,
if
(
p_owner
->
p_description
)
&
p_dec
->
fmt_out
.
audio_replay_gain
,
&
request_vout
)
)
{
{
*
pp_meta
=
vlc_meta_New
();
input_resource_PutAout
(
p_owner
->
p_resource
,
p_aout
);
if
(
*
pp_meta
)
p_aout
=
NULL
;
vlc_meta_Merge
(
*
pp_meta
,
p_owner
->
p_description
);
}
}
}
}
p_owner
->
b_fmt_description
=
false
;
}
vlc_mutex_unlock
(
&
p_owner
->
lock
);
return
b_changed
;
}
size_t
input_DecoderGetFifoSize
(
decoder_t
*
p_dec
)
vlc_mutex_lock
(
&
p_owner
->
lock
);
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
return
block_FifoSize
(
p_owner
->
p_fifo
);
}
void
input_DecoderGetObjects
(
decoder_t
*
p_dec
,
vout_thread_t
**
pp_vout
,
audio_output_t
**
pp_aout
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
vlc_mutex_lock
(
&
p_owner
->
lock
);
if
(
pp_vout
)
*
pp_vout
=
p_owner
->
p_vout
?
vlc_object_hold
(
p_owner
->
p_vout
)
:
NULL
;
if
(
pp_aout
)
*
pp_aout
=
p_owner
->
p_aout
?
vlc_object_hold
(
p_owner
->
p_aout
)
:
NULL
;
vlc_mutex_unlock
(
&
p_owner
->
lock
);
}
/*****************************************************************************
p_owner
->
p_aout
=
p_aout
;
* Internal functions
*****************************************************************************/
static
int
DecoderGetInputAttachments
(
decoder_t
*
p_dec
,
input_attachment_t
***
ppp_attachment
,
int
*
pi_attachment
)
{
input_thread_t
*
p_input
=
p_dec
->
p_owner
->
p_input
;
if
(
unlikely
(
p_input
==
NULL
)
)
es_format_Clean
(
&
p_owner
->
fmt
);
return
VLC_ENOOBJ
;
es_format_Copy
(
&
p_owner
->
fmt
,
&
p_dec
->
fmt_out
);
return
input_Control
(
p_input
,
INPUT_GET_ATTACHMENTS
,
aout_FormatPrepare
(
&
p_owner
->
fmt
.
audio
);
ppp_attachment
,
pi_attachment
);
}
static
mtime_t
DecoderGetDisplayDate
(
decoder_t
*
p_dec
,
mtime_t
i_ts
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
vlc_mutex_lock
(
&
p_owner
->
lock
);
DecoderUpdateFormatLocked
(
p_dec
);
if
(
p_owner
->
b_waiting
||
p_owner
->
b_paused
)
i_ts
=
VLC_TS_INVALID
;
vlc_mutex_unlock
(
&
p_owner
->
lock
);
if
(
!
p_owner
->
p_clock
||
i_ts
<=
VLC_TS_INVALID
)
if
(
unlikely
(
p_owner
->
b_paused
)
&&
p_aout
!=
NULL
)
return
i_ts
;
/* fake pause if needed */
aout_DecChangePause
(
p_aout
,
true
,
mdate
()
);
if
(
input_clock_ConvertTS
(
VLC_OBJECT
(
p_dec
),
p_owner
->
p_clock
,
NULL
,
&
i_ts
,
NULL
,
INT64_MAX
)
)
{
vlc_mutex_unlock
(
&
p_owner
->
lock
);
msg_Err
(
p_dec
,
"Could not get display date for timestamp %"
PRId64
""
,
i_ts
);
return
VLC_TS_INVALID
;
}
return
i_ts
;
if
(
p_owner
->
p_input
!=
NULL
)
}
input_SendEventAout
(
p_owner
->
p_input
);
static
int
DecoderGetDisplayRate
(
decoder_t
*
p_dec
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
if
(
!
p_owner
->
p_clock
)
if
(
p_aout
==
NULL
)
return
INPUT_RATE_DEFAULT
;
{
return
input_clock_GetRate
(
p_owner
->
p_clock
);
msg_Err
(
p_dec
,
"failed to create audio output"
);
}
p_dec
->
b_error
=
true
;
return
-
1
;
}
/* */
p_dec
->
fmt_out
.
audio
.
i_bytes_per_frame
=
static
void
DecoderUnsupportedCodec
(
decoder_t
*
p_dec
,
vlc_fourcc_t
codec
)
p_owner
->
fmt
.
audio
.
i_bytes_per_frame
;
{
p_dec
->
fmt_out
.
audio
.
i_frame_length
=
if
(
codec
!=
VLC_FOURCC
(
'u'
,
'n'
,
'd'
,
'f'
))
{
p_owner
->
fmt
.
audio
.
i_frame_length
;
const
char
*
desc
=
vlc_fourcc_GetDescription
(
p_dec
->
fmt_in
.
i_cat
,
codec
);
if
(
!
desc
||
!*
desc
)
desc
=
N_
(
"No description for this codec"
);
msg_Err
(
p_dec
,
"Codec `%4.4s' (%s) is not supported."
,
(
char
*
)
&
codec
,
desc
);
dialog_Fatal
(
p_dec
,
_
(
"Codec not supported"
),
_
(
"VLC could not decode the format
\"
%4.4s
\"
(%s)"
),
(
char
*
)
&
codec
,
desc
);
}
else
{
msg_Err
(
p_dec
,
"could not identify codec"
);
dialog_Fatal
(
p_dec
,
_
(
"Unidentified codec"
),
_
(
"VLC could not identify the audio or video codec"
)
);
}
}
return
0
;
}
}
static
int
vout_update_format
(
decoder_t
*
p_dec
)
/**
* Create a decoder object
*
* \param p_input the input thread
* \param p_es the es descriptor
* \param b_packetizer instead of a decoder
* \return the decoder object
*/
static
decoder_t
*
CreateDecoder
(
vlc_object_t
*
p_parent
,
input_thread_t
*
p_input
,
const
es_format_t
*
fmt
,
bool
b_packetizer
,
input_resource_t
*
p_resource
,
sout_instance_t
*
p_sout
)
{
{
decoder_t
*
p_dec
;
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
decoder_owner_sys_t
*
p_owner
;
es_format_t
null_es_format
;
p_dec
=
vlc_custom_create
(
p_parent
,
sizeof
(
*
p_dec
),
"decoder"
);
if
(
p_dec
==
NULL
)
return
NULL
;
p_dec
->
pf_decode_audio
=
NULL
;
p_dec
->
pf_decode_video
=
NULL
;
p_dec
->
pf_decode_sub
=
NULL
;
p_dec
->
pf_get_cc
=
NULL
;
p_dec
->
pf_packetize
=
NULL
;
/* Initialize the decoder */
p_dec
->
p_module
=
NULL
;
memset
(
&
null_es_format
,
0
,
sizeof
(
es_format_t
)
);
es_format_Copy
(
&
p_dec
->
fmt_in
,
fmt
);
es_format_Copy
(
&
p_dec
->
fmt_out
,
&
null_es_format
);
p_dec
->
p_description
=
NULL
;
/* Allocate our private structure for the decoder */
p_dec
->
p_owner
=
p_owner
=
malloc
(
sizeof
(
decoder_owner_sys_t
)
);
if
(
unlikely
(
p_owner
==
NULL
)
)
{
vlc_object_release
(
p_dec
);
return
NULL
;
}
p_owner
->
i_preroll_end
=
VLC_TS_INVALID
;
p_owner
->
i_last_rate
=
INPUT_RATE_DEFAULT
;
p_owner
->
p_input
=
p_input
;
p_owner
->
p_resource
=
p_resource
;
p_owner
->
p_aout
=
NULL
;
p_owner
->
p_vout
=
NULL
;
p_owner
->
p_spu_vout
=
NULL
;
p_owner
->
i_spu_channel
=
0
;
p_owner
->
i_spu_order
=
0
;
p_owner
->
p_sout
=
p_sout
;
p_owner
->
p_sout_input
=
NULL
;
p_owner
->
p_packetizer
=
NULL
;
p_owner
->
b_packetizer
=
b_packetizer
;
es_format_Init
(
&
p_owner
->
fmt
,
UNKNOWN_ES
,
0
);
/* decoder fifo */
p_owner
->
b_woken
=
false
;
p_owner
->
p_fifo
=
block_FifoNew
();
if
(
unlikely
(
p_owner
->
p_fifo
==
NULL
)
)
{
free
(
p_owner
);
vlc_object_release
(
p_dec
);
return
NULL
;
}
/* Set buffers allocation callbacks for the decoders */
p_dec
->
pf_aout_format_update
=
aout_update_format
;
p_dec
->
pf_vout_format_update
=
vout_update_format
;
p_dec
->
pf_vout_buffer_new
=
vout_new_buffer
;
p_dec
->
pf_spu_buffer_new
=
spu_new_buffer
;
/* */
p_dec
->
pf_get_attachments
=
DecoderGetInputAttachments
;
p_dec
->
pf_get_display_date
=
DecoderGetDisplayDate
;
p_dec
->
pf_get_display_rate
=
DecoderGetDisplayRate
;
/* Find a suitable decoder/packetizer module */
if
(
!
b_packetizer
)
p_dec
->
p_module
=
module_need
(
p_dec
,
"decoder"
,
"$codec"
,
false
);
else
p_dec
->
p_module
=
module_need
(
p_dec
,
"packetizer"
,
"$packetizer"
,
false
);
/* Check if decoder requires already packetized data */
if
(
p_owner
->
p_vout
==
NULL
if
(
!
b_packetizer
&&
||
p_dec
->
fmt_out
.
video
.
i_width
!=
p_owner
->
fmt
.
video
.
i_width
p_dec
->
b_need_packetized
&&
!
p_dec
->
fmt_in
.
b_packetized
)
||
p_dec
->
fmt_out
.
video
.
i_height
!=
p_owner
->
fmt
.
video
.
i_height
||
p_dec
->
fmt_out
.
video
.
i_visible_width
!=
p_owner
->
fmt
.
video
.
i_visible_width
||
p_dec
->
fmt_out
.
video
.
i_visible_height
!=
p_owner
->
fmt
.
video
.
i_visible_height
||
p_dec
->
fmt_out
.
video
.
i_x_offset
!=
p_owner
->
fmt
.
video
.
i_x_offset
||
p_dec
->
fmt_out
.
video
.
i_y_offset
!=
p_owner
->
fmt
.
video
.
i_y_offset
||
p_dec
->
fmt_out
.
i_codec
!=
p_owner
->
fmt
.
video
.
i_chroma
||
(
int64_t
)
p_dec
->
fmt_out
.
video
.
i_sar_num
*
p_owner
->
fmt
.
video
.
i_sar_den
!=
(
int64_t
)
p_dec
->
fmt_out
.
video
.
i_sar_den
*
p_owner
->
fmt
.
video
.
i_sar_num
||
p_dec
->
fmt_out
.
video
.
orientation
!=
p_owner
->
fmt
.
video
.
orientation
)
{
{
p_owner
->
p_packetizer
=
vout_thread_t
*
p_vout
;
vlc_custom_create
(
p_parent
,
sizeof
(
decoder_t
),
"packetizer"
);
if
(
p_owner
->
p_packetizer
)
{
es_format_Copy
(
&
p_owner
->
p_packetizer
->
fmt_in
,
&
p_dec
->
fmt_in
);
es_format_Copy
(
&
p_owner
->
p_packetizer
->
fmt_out
,
&
null_es_format
);
p_owner
->
p_packetizer
->
p_module
=
if
(
!
p_dec
->
fmt_out
.
video
.
i_width
||
module_need
(
p_owner
->
p_packetizer
,
!
p_dec
->
fmt_out
.
video
.
i_height
)
"packetizer"
,
"$packetizer"
,
false
);
{
/* Can't create a new vout without display size */
return
-
1
;
}
if
(
!
p_owner
->
p_packetizer
->
p_module
)
video_format_t
fmt
=
p_dec
->
fmt_out
.
video
;
fmt
.
i_chroma
=
p_dec
->
fmt_out
.
i_codec
;
if
(
vlc_fourcc_IsYUV
(
fmt
.
i_chroma
)
)
{
const
vlc_chroma_description_t
*
dsc
=
vlc_fourcc_GetChromaDescription
(
fmt
.
i_chroma
);
for
(
unsigned
int
i
=
0
;
dsc
&&
i
<
dsc
->
plane_count
;
i
++
)
{
{
es_format_Clean
(
&
p_owner
->
p_packetizer
->
fmt_in
);
while
(
fmt
.
i_width
%
dsc
->
p
[
i
].
w
.
den
)
vlc_object_release
(
p_owner
->
p_packetizer
);
fmt
.
i_width
++
;
p_owner
->
p_packetizer
=
NULL
;
while
(
fmt
.
i_height
%
dsc
->
p
[
i
].
h
.
den
)
fmt
.
i_height
++
;
}
}
}
}
}
/* Copy ourself the input replay gain */
if
(
!
fmt
.
i_visible_width
||
!
fmt
.
i_visible_height
)
if
(
fmt
->
i_cat
==
AUDIO_ES
)
{
for
(
unsigned
i
=
0
;
i
<
AUDIO_REPLAY_GAIN_MAX
;
i
++
)
{
{
if
(
!
p_dec
->
fmt_out
.
audio_replay_gain
.
pb_peak
[
i
]
)
if
(
p_dec
->
fmt_in
.
video
.
i_visible_width
&&
p_dec
->
fmt_in
.
video
.
i_visible_height
)
{
{
p_dec
->
fmt_out
.
audio_replay_gain
.
pb_peak
[
i
]
=
fmt
->
audio_replay_gain
.
pb_peak
[
i
];
fmt
.
i_visible_width
=
p_dec
->
fmt_in
.
video
.
i_visible_width
;
p_dec
->
fmt_out
.
audio_replay_gain
.
pf_peak
[
i
]
=
fmt
->
audio_replay_gain
.
pf_peak
[
i
];
fmt
.
i_visible_height
=
p_dec
->
fmt_in
.
video
.
i_visible_height
;
fmt
.
i_x_offset
=
p_dec
->
fmt_in
.
video
.
i_x_offset
;
fmt
.
i_y_offset
=
p_dec
->
fmt_in
.
video
.
i_y_offset
;
}
}
if
(
!
p_dec
->
fmt_out
.
audio_replay_gain
.
pb_gain
[
i
]
)
else
{
{
p_dec
->
fmt_out
.
audio_replay_gain
.
pb_gain
[
i
]
=
fmt
->
audio_replay_gain
.
pb_gain
[
i
];
fmt
.
i_visible_width
=
fmt
.
i_width
;
p_dec
->
fmt_out
.
audio_replay_gain
.
pf_gain
[
i
]
=
fmt
->
audio_replay_gain
.
pf_gain
[
i
];
fmt
.
i_visible_height
=
fmt
.
i_height
;
fmt
.
i_x_offset
=
0
;
fmt
.
i_y_offset
=
0
;
}
}
}
}
}
/* */
if
(
fmt
.
i_visible_height
==
1088
&&
vlc_mutex_init
(
&
p_owner
->
lock
);
var_CreateGetBool
(
p_dec
,
"hdtv-fix"
)
)
vlc_cond_init
(
&
p_owner
->
wait_request
);
{
vlc_cond_init
(
&
p_owner
->
wait_acknowledge
);
fmt
.
i_visible_height
=
1080
;
if
(
!
(
fmt
.
i_sar_num
%
136
))
{
fmt
.
i_sar_num
*=
135
;
fmt
.
i_sar_den
*=
136
;
}
msg_Warn
(
p_dec
,
"Fixing broken HDTV stream (display_height=1088)"
);
}
p_owner
->
b_fmt_description
=
false
;
if
(
!
fmt
.
i_sar_num
||
!
fmt
.
i_sar_den
)
p_owner
->
p_description
=
NULL
;
{
fmt
.
i_sar_num
=
1
;
fmt
.
i_sar_den
=
1
;
}
p_owner
->
b_paused
=
false
;
vlc_ureduce
(
&
fmt
.
i_sar_num
,
&
fmt
.
i_sar_den
,
p_owner
->
pause
.
i_date
=
VLC_TS_INVALID
;
fmt
.
i_sar_num
,
fmt
.
i_sar_den
,
50000
);
p_owner
->
pause
.
i_ignore
=
0
;
p_owner
->
b_waiting
=
false
;
vlc_mutex_lock
(
&
p_owner
->
lock
);
p_owner
->
b_first
=
true
;
p_owner
->
b_has_data
=
false
;
p_owner
->
b_flushing
=
false
;
p_vout
=
p_owner
->
p_vout
;
p_owner
->
p_vout
=
NULL
;
vlc_mutex_unlock
(
&
p_owner
->
lock
);
/* */
unsigned
dpb_size
;
p_owner
->
cc
.
b_supported
=
false
;
switch
(
p_dec
->
fmt_in
.
i_codec
)
if
(
!
b_packetizer
)
{
{
case
VLC_CODEC_HEVC
:
if
(
p_owner
->
p_packetizer
&&
p_owner
->
p_packetizer
->
pf_get_cc
)
case
VLC_CODEC_H264
:
p_owner
->
cc
.
b_supported
=
true
;
case
VLC_CODEC_DIRAC
:
/* FIXME valid ? */
if
(
p_dec
->
pf_get_cc
)
dpb_size
=
18
;
p_owner
->
cc
.
b_supported
=
true
;
break
;
}
case
VLC_CODEC_VP5
:
case
VLC_CODEC_VP6
:
case
VLC_CODEC_VP6F
:
case
VLC_CODEC_VP8
:
dpb_size
=
3
;
break
;
default:
dpb_size
=
2
;
break
;
}
p_vout
=
input_resource_RequestVout
(
p_owner
->
p_resource
,
p_vout
,
&
fmt
,
dpb_size
+
p_dec
->
i_extra_picture_buffers
+
1
,
true
);
vlc_mutex_lock
(
&
p_owner
->
lock
);
p_owner
->
p_vout
=
p_vout
;
for
(
unsigned
i
=
0
;
i
<
4
;
i
++
)
es_format_Clean
(
&
p_owner
->
fmt
);
{
es_format_Copy
(
&
p_owner
->
fmt
,
&
p_dec
->
fmt_out
);
p_owner
->
cc
.
pb_present
[
i
]
=
false
;
p_owner
->
fmt
.
video
.
i_chroma
=
p_dec
->
fmt_out
.
i_codec
;
p_owner
->
cc
.
pp_decoder
[
i
]
=
NULL
;
DecoderUpdateFormatLocked
(
p_dec
);
vlc_mutex_unlock
(
&
p_owner
->
lock
);
if
(
p_owner
->
p_input
!=
NULL
)
input_SendEventVout
(
p_owner
->
p_input
);
if
(
p_vout
==
NULL
)
{
msg_Err
(
p_dec
,
"failed to create video output"
);
p_dec
->
b_error
=
true
;
return
-
1
;
}
}
}
p_owner
->
i_ts_delay
=
0
;
return
0
;
return
p_dec
;
}
}
/**
static
picture_t
*
vout_new_buffer
(
decoder_t
*
p_dec
)
* The decoding main loop
*
* \param p_dec the decoder
*/
static
void
*
DecoderThread
(
void
*
p_data
)
{
{
decoder_t
*
p_dec
=
(
decoder_t
*
)
p_data
;
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
/* The decoder's main loop */
for
(
;;
)
for
(
;;
)
{
{
block_t
*
p_block
;
if
(
DecoderIsFlushing
(
p_dec
)
||
p_dec
->
b_error
)
return
NULL
;
vlc_fifo_Lock
(
p_owner
->
p_fifo
);
picture_t
*
p_picture
=
vout_GetPicture
(
p_owner
->
p_vout
);
vlc_fifo_CleanupPush
(
p_owner
->
p_fifo
);
if
(
p_picture
)
return
p_picture
;
while
(
vlc_fifo_IsEmpty
(
p_owner
->
p_fifo
)
)
/* */
{
DecoderSignalWait
(
p_dec
);
if
(
p_owner
->
b_woken
)
break
;
vlc_fifo_Wait
(
p_owner
->
p_fifo
);
/* Make sure there is no cancellation point other than this one^^.
* If you need one, be sure to push cleanup of p_block. */
}
p_block
=
vlc_fifo_DequeueUnlocked
(
p_owner
->
p_fifo
);
/* Check the decoder doesn't leak pictures */
if
(
p_block
!=
NULL
)
vout_FixLeaks
(
p_owner
->
p_vout
);
vlc_cond_signal
(
&
p_owner
->
wait_acknowledge
);
p_owner
->
b_woken
=
false
;
/* FIXME add a vout_WaitPictureAvailable (timedwait) */
vlc_cleanup_run
();
msleep
(
VOUT_OUTMEM_SLEEP
);
}
}
if
(
p_block
==
NULL
||
p_block
->
i_flags
&
BLOCK_FLAG_CORE_EOS
)
static
subpicture_t
*
spu_new_buffer
(
decoder_t
*
p_dec
,
DecoderSignalWait
(
p_dec
);
const
subpicture_updater_t
*
p_updater
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
vout_thread_t
*
p_vout
=
NULL
;
subpicture_t
*
p_subpic
;
int
i_attempts
=
30
;
if
(
p_block
)
while
(
i_attempts
--
)
{
{
int
canc
=
vlc_savecancel
();
if
(
DecoderIsFlushing
(
p_dec
)
||
p_dec
->
b_error
)
break
;
if
(
p_block
->
i_flags
&
BLOCK_FLAG_CORE_EOS
)
p_vout
=
input_resource_HoldVout
(
p_owner
->
p_resource
);
{
if
(
p_vout
)
/* calling DecoderProcess() with NULL block will make
break
;
* decoders/packetizers flush their buffers */
block_Release
(
p_block
);
p_block
=
NULL
;
}
DecoderProcess
(
p_dec
,
p_block
);
msleep
(
DECODER_SPU_VOUT_WAIT_DURATION
);
}
vlc_restorecancel
(
canc
);
if
(
!
p_vout
)
}
{
msg_Warn
(
p_dec
,
"no vout found, dropping subpicture"
);
return
NULL
;
}
}
return
NULL
;
if
(
p_owner
->
p_spu_vout
!=
p_vout
)
{
p_owner
->
i_spu_channel
=
vout_RegisterSubpictureChannel
(
p_vout
);
p_owner
->
i_spu_order
=
0
;
p_owner
->
p_spu_vout
=
p_vout
;
}
p_subpic
=
subpicture_New
(
p_updater
);
if
(
p_subpic
)
{
p_subpic
->
i_channel
=
p_owner
->
i_spu_channel
;
p_subpic
->
i_order
=
p_owner
->
i_spu_order
++
;
p_subpic
->
b_subtitle
=
true
;
}
vlc_object_release
(
p_vout
);
return
p_subpic
;
}
}
static
block_t
*
DecoderBlockFlushNew
()
static
int
DecoderGetInputAttachments
(
decoder_t
*
p_dec
,
input_attachment_t
***
ppp_attachment
,
int
*
pi_attachment
)
{
{
block_t
*
p_null
=
block_Alloc
(
128
);
input_thread_t
*
p_input
=
p_dec
->
p_owner
->
p_input
;
if
(
!
p_null
)
return
NULL
;
if
(
unlikely
(
p_input
==
NULL
)
)
return
VLC_ENOOBJ
;
return
input_Control
(
p_input
,
INPUT_GET_ATTACHMENTS
,
ppp_attachment
,
pi_attachment
);
}
static
mtime_t
DecoderGetDisplayDate
(
decoder_t
*
p_dec
,
mtime_t
i_ts
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
vlc_mutex_lock
(
&
p_owner
->
lock
);
if
(
p_owner
->
b_waiting
||
p_owner
->
b_paused
)
i_ts
=
VLC_TS_INVALID
;
vlc_mutex_unlock
(
&
p_owner
->
lock
);
p_null
->
i_flags
|=
BLOCK_FLAG_DISCONTINUITY
|
if
(
!
p_owner
->
p_clock
||
i_ts
<=
VLC_TS_INVALID
)
BLOCK_FLAG_CORRUPTED
|
return
i_ts
;
BLOCK_FLAG_CORE_FLUSH
;
memset
(
p_null
->
p_buffer
,
0
,
p_null
->
i_buffer
);
return
p_null
;
if
(
input_clock_ConvertTS
(
VLC_OBJECT
(
p_dec
),
p_owner
->
p_clock
,
NULL
,
&
i_ts
,
NULL
,
INT64_MAX
)
)
{
msg_Err
(
p_dec
,
"Could not get display date for timestamp %"
PRId64
""
,
i_ts
);
return
VLC_TS_INVALID
;
}
return
i_ts
;
}
}
static
void
DecoderFlush
(
decoder_t
*
p_dec
)
static
int
DecoderGetDisplayRate
(
decoder_t
*
p_dec
)
{
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
vlc_assert_locked
(
&
p_owner
->
lock
);
if
(
!
p_owner
->
p_clock
)
return
INPUT_RATE_DEFAULT
;
/* Empty the fifo */
return
input_clock_GetRate
(
p_owner
->
p_clock
);
block_FifoEmpty
(
p_owner
->
p_fifo
);
}
/* Monitor for flush end */
p_owner
->
b_flushing
=
true
;
vlc_cond_signal
(
&
p_owner
->
wait_request
);
/* Send a special block */
/*****************************************************************************
block_t
*
p_null
=
DecoderBlockFlushNew
();
* Public functions
if
(
!
p_null
)
*****************************************************************************/
return
;
picture_t
*
decoder_NewPicture
(
decoder_t
*
p_decoder
)
input_DecoderDecode
(
p_dec
,
p_null
,
false
);
{
if
(
decoder_UpdateVideoFormat
(
p_decoder
)
)
return
NULL
;
/* */
picture_t
*
p_picture
=
p_decoder
->
pf_vout_buffer_new
(
p_decoder
);
while
(
p_owner
->
b_flushing
)
if
(
!
p_picture
)
vlc_cond_wait
(
&
p_owner
->
wait_acknowledge
,
&
p_owner
->
lock
);
msg_Warn
(
p_decoder
,
"can't get output picture"
);
return
p_picture
;
}
}
static
void
DecoderSignalWait
(
decoder_t
*
p_dec
)
block_t
*
decoder_NewAudioBuffer
(
decoder_t
*
dec
,
int
samples
)
{
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
if
(
decoder_UpdateAudioFormat
(
dec
)
)
return
NULL
;
vlc_mutex_lock
(
&
p_owner
->
lock
);
if
(
p_owner
->
b_waiting
)
size_t
length
=
samples
*
dec
->
fmt_out
.
audio
.
i_bytes_per_frame
/
dec
->
fmt_out
.
audio
.
i_frame_length
;
block_t
*
block
=
block_Alloc
(
length
);
if
(
likely
(
block
!=
NULL
)
)
{
{
p_owner
->
b_has_data
=
true
;
block
->
i_nb_samples
=
samples
;
vlc_cond_signal
(
&
p_owner
->
wait_acknowledge
)
;
block
->
i_pts
=
block
->
i_length
=
0
;
}
}
return
block
;
vlc_mutex_unlock
(
&
p_owner
->
lock
);
}
}
static
bool
DecoderIsFlushing
(
decoder_t
*
p_dec
)
subpicture_t
*
decoder_NewSubpicture
(
decoder_t
*
p_decoder
,
const
subpicture_updater_t
*
p_dyn
)
{
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
subpicture_t
*
p_subpicture
=
p_decoder
->
pf_spu_buffer_new
(
p_decoder
,
p_dyn
);
bool
b_flushing
;
if
(
!
p_subpicture
)
msg_Warn
(
p_decoder
,
"can't get output subpicture"
);
return
p_subpicture
;
}
vlc_mutex_lock
(
&
p_owner
->
lock
);
/* decoder_GetInputAttachments:
*/
int
decoder_GetInputAttachments
(
decoder_t
*
p_dec
,
input_attachment_t
***
ppp_attachment
,
int
*
pi_attachment
)
{
if
(
!
p_dec
->
pf_get_attachments
)
return
VLC_EGENERIC
;
b_flushing
=
p_owner
->
b_flushing
;
return
p_dec
->
pf_get_attachments
(
p_dec
,
ppp_attachment
,
pi_attachment
);
}
/* decoder_GetDisplayDate:
*/
mtime_t
decoder_GetDisplayDate
(
decoder_t
*
p_dec
,
mtime_t
i_ts
)
{
if
(
!
p_dec
->
pf_get_display_date
)
return
VLC_TS_INVALID
;
vlc_mutex_unlock
(
&
p_owner
->
lock
);
return
p_dec
->
pf_get_display_date
(
p_dec
,
i_ts
);
}
/* decoder_GetDisplayRate:
*/
int
decoder_GetDisplayRate
(
decoder_t
*
p_dec
)
{
if
(
!
p_dec
->
pf_get_display_rate
)
return
INPUT_RATE_DEFAULT
;
return
b_flushing
;
return
p_dec
->
pf_get_display_rate
(
p_dec
)
;
}
}
static
bool
DecoderWaitUnblock
(
decoder_t
*
p_dec
)
static
bool
DecoderWaitUnblock
(
decoder_t
*
p_dec
)
...
@@ -1108,134 +729,107 @@ static void DecoderWaitDate( decoder_t *p_dec,
...
@@ -1108,134 +729,107 @@ static void DecoderWaitDate( decoder_t *p_dec,
i_deadline
)
==
0
);
i_deadline
)
==
0
);
}
}
static
void
DecoderPlayAudio
(
decoder_t
*
p_dec
,
block_t
*
p_audio
,
int
*
pi_played_sum
,
int
*
pi_lost_sum
)
#ifdef ENABLE_SOUT
static
int
DecoderPlaySout
(
decoder_t
*
p_dec
,
block_t
*
p_sout_block
)
{
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
audio_output_t
*
p_aout
=
p_owner
->
p_aout
;
/* */
assert
(
p_owner
->
p_clock
);
if
(
p_audio
&&
p_audio
->
i_pts
<=
VLC_TS_INVALID
)
// FIXME --VLC_TS_INVALID verify audio_output/*
assert
(
!
p_sout_block
->
p_next
);
{
msg_Warn
(
p_dec
,
"non-dated audio buffer received"
);
*
pi_lost_sum
+=
1
;
block_Release
(
p_audio
);
return
;
}
/* */
vlc_mutex_lock
(
&
p_owner
->
lock
);
vlc_mutex_lock
(
&
p_owner
->
lock
);
if
(
p_
audio
&&
p_
owner
->
b_waiting
)
if
(
p_owner
->
b_waiting
)
{
{
p_owner
->
b_has_data
=
true
;
p_owner
->
b_has_data
=
true
;
vlc_cond_signal
(
&
p_owner
->
wait_acknowledge
);
vlc_cond_signal
(
&
p_owner
->
wait_acknowledge
);
}
}
for
(
;;
)
bool
b_reject
=
DecoderWaitUnblock
(
p_dec
);
{
bool
b_paused
;
bool
b_reject
=
DecoderWaitUnblock
(
p_dec
);
b_paused
=
p_owner
->
b_paused
;
if
(
!
p_audio
)
break
;
/* */
int
i_rate
=
INPUT_RATE_DEFAULT
;
DecoderFixTs
(
p_dec
,
&
p_audio
->
i_pts
,
NULL
,
&
p_audio
->
i_length
,
&
i_rate
,
AOUT_MAX_ADVANCE_TIME
);
if
(
p_audio
->
i_pts
<=
VLC_TS_INVALID
||
i_rate
<
INPUT_RATE_DEFAULT
/
AOUT_MAX_INPUT_RATE
||
i_rate
>
INPUT_RATE_DEFAULT
*
AOUT_MAX_INPUT_RATE
)
b_reject
=
true
;
DecoderWaitDate
(
p_dec
,
&
b_reject
,
p_audio
->
i_pts
-
AOUT_MAX_PREPARE_TIME
);
if
(
unlikely
(
p_owner
->
b_paused
!=
b_paused
)
)
DecoderFixTs
(
p_dec
,
&
p_sout_block
->
i_dts
,
&
p_sout_block
->
i_pts
,
continue
;
/* race with input thread? retry... */
&
p_sout_block
->
i_length
,
NULL
,
INT64_MAX
);
if
(
p_aout
==
NULL
)
b_reject
=
true
;
if
(
!
b_reject
)
vlc_mutex_unlock
(
&
p_owner
->
lock
);
{
assert
(
!
p_owner
->
b_paused
);
if
(
!
aout_DecPlay
(
p_aout
,
p_audio
,
i_rate
)
)
*
pi_played_sum
+=
1
;
*
pi_lost_sum
+=
aout_DecGetResetLost
(
p_aout
);
}
else
{
msg_Dbg
(
p_dec
,
"discarded audio buffer"
);
*
pi_lost_sum
+=
1
;
block_Release
(
p_audio
);
}
break
;
if
(
!
b_reject
)
{
/* FIXME --VLC_TS_INVALID inspect stream_output*/
return
sout_InputSendBuffer
(
p_owner
->
p_sout_input
,
p_sout_block
);
}
else
{
block_Release
(
p_sout_block
);
return
VLC_EGENERIC
;
}
}
vlc_mutex_unlock
(
&
p_owner
->
lock
);
}
}
static
void
DecoderDecodeAudio
(
decoder_t
*
p_dec
,
block_t
*
p_block
)
/* This function process a block for sout
*/
static
void
DecoderProcessSout
(
decoder_t
*
p_dec
,
block_t
*
p_block
)
{
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
decoder_owner_sys_t
*
p_owner
=
(
decoder_owner_sys_t
*
)
p_dec
->
p_owner
;
block_t
*
p_aout_buf
;
block_t
*
p_sout_block
;
int
i_decoded
=
0
;
int
i_lost
=
0
;
int
i_played
=
0
;
if
(
!
p_block
)
{
while
(
(
p_sout_block
=
/* Play a NULL block to output buffered frames */
p_dec
->
pf_packetize
(
p_dec
,
p_block
?
&
p_block
:
NULL
)
)
)
DecoderPlayAudio
(
p_dec
,
NULL
,
&
i_played
,
&
i_lost
);
}
else
while
(
(
p_aout_buf
=
p_dec
->
pf_decode_audio
(
p_dec
,
&
p_block
))
)
{
{
if
(
DecoderIsFlushing
(
p_dec
)
)
if
(
p_owner
->
p_sout_input
==
NULL
)
{
{
/* It prevent freezing VLC in case of broken decoder */
vlc_mutex_lock
(
&
p_owner
->
lock
);
block_Release
(
p_aout_buf
);
es_format_Clean
(
&
p_owner
->
fmt
);
if
(
p_block
)
es_format_Copy
(
&
p_owner
->
fmt
,
&
p_dec
->
fmt_out
);
block_Release
(
p_block
);
DecoderUpdateFormatLocked
(
p_dec
);
break
;
vlc_mutex_unlock
(
&
p_owner
->
lock
);
}
i_decoded
++
;
if
(
p_owner
->
i_preroll_end
>
VLC_TS_INVALID
&&
p_owner
->
fmt
.
i_group
=
p_dec
->
fmt_in
.
i_group
;
p_aout_buf
->
i_pts
<
p_owner
->
i_preroll_end
)
p_owner
->
fmt
.
i_id
=
p_dec
->
fmt_in
.
i_id
;
{
if
(
p_dec
->
fmt_in
.
psz_language
)
block_Release
(
p_aout_buf
);
{
continue
;
free
(
p_owner
->
fmt
.
psz_language
);
p_owner
->
fmt
.
psz_language
=
strdup
(
p_dec
->
fmt_in
.
psz_language
);
}
p_owner
->
p_sout_input
=
sout_InputNew
(
p_owner
->
p_sout
,
&
p_owner
->
fmt
);
if
(
p_owner
->
p_sout_input
==
NULL
)
{
msg_Err
(
p_dec
,
"cannot create packetizer output (%4.4s)"
,
(
char
*
)
&
p_owner
->
fmt
.
i_codec
);
p_dec
->
b_error
=
true
;
block_ChainRelease
(
p_sout_block
);
break
;
}
}
}
if
(
p_owner
->
i_preroll_end
>
VLC_TS_INVALID
)
while
(
p_sout_block
)
{
{
msg_Dbg
(
p_dec
,
"End of audio preroll"
);
block_t
*
p_next
=
p_sout_block
->
p_next
;
if
(
p_owner
->
p_aout
)
aout_DecFlush
(
p_owner
->
p_aout
);
/* */
p_owner
->
i_preroll_end
=
VLC_TS_INVALID
;
}
DecoderPlayAudio
(
p_dec
,
p_aout_buf
,
&
i_played
,
&
i_lost
);
p_sout_block
->
p_next
=
NULL
;
}
if
(
DecoderPlaySout
(
p_dec
,
p_sout_block
)
==
VLC_EGENERIC
)
{
msg_Err
(
p_dec
,
"cannot continue streaming due to errors"
);
p_dec
->
b_error
=
true
;
/* Update ugly stat */
/* Cleanup */
input_thread_t
*
p_input
=
p_owner
->
p_input
;
block_ChainRelease
(
p_next
);
return
;
}
if
(
p_input
!=
NULL
&&
(
i_decoded
>
0
||
i_lost
>
0
||
i_played
>
0
)
)
p_sout_block
=
p_next
;
{
}
vlc_mutex_lock
(
&
p_input
->
p
->
counters
.
counters_lock
);
stats_Update
(
p_input
->
p
->
counters
.
p_lost_abuffers
,
i_lost
,
NULL
);
stats_Update
(
p_input
->
p
->
counters
.
p_played_abuffers
,
i_played
,
NULL
);
stats_Update
(
p_input
->
p
->
counters
.
p_decoded_audio
,
i_decoded
,
NULL
);
vlc_mutex_unlock
(
&
p_input
->
p
->
counters
.
counters_lock
);
}
}
}
}
#endif
static
void
DecoderGetCc
(
decoder_t
*
p_dec
,
decoder_t
*
p_dec_cc
)
static
void
DecoderGetCc
(
decoder_t
*
p_dec
,
decoder_t
*
p_dec_cc
)
{
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
...
@@ -1410,147 +1004,6 @@ static void DecoderDecodeVideo( decoder_t *p_dec, block_t *p_block )
...
@@ -1410,147 +1004,6 @@ static void DecoderDecodeVideo( decoder_t *p_dec, block_t *p_block )
}
}
}
}
static
void
DecoderPlaySpu
(
decoder_t
*
p_dec
,
subpicture_t
*
p_subpic
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
vout_thread_t
*
p_vout
=
p_owner
->
p_spu_vout
;
/* */
if
(
p_subpic
->
i_start
<=
VLC_TS_INVALID
)
{
msg_Warn
(
p_dec
,
"non-dated spu buffer received"
);
subpicture_Delete
(
p_subpic
);
return
;
}
/* */
vlc_mutex_lock
(
&
p_owner
->
lock
);
if
(
p_owner
->
b_waiting
)
{
p_owner
->
b_has_data
=
true
;
vlc_cond_signal
(
&
p_owner
->
wait_acknowledge
);
}
bool
b_reject
=
DecoderWaitUnblock
(
p_dec
);
DecoderFixTs
(
p_dec
,
&
p_subpic
->
i_start
,
&
p_subpic
->
i_stop
,
NULL
,
NULL
,
INT64_MAX
);
if
(
p_subpic
->
i_start
<=
VLC_TS_INVALID
)
b_reject
=
true
;
DecoderWaitDate
(
p_dec
,
&
b_reject
,
p_subpic
->
i_start
-
SPU_MAX_PREPARE_TIME
);
vlc_mutex_unlock
(
&
p_owner
->
lock
);
if
(
!
b_reject
)
vout_PutSubpicture
(
p_vout
,
p_subpic
);
else
subpicture_Delete
(
p_subpic
);
}
#ifdef ENABLE_SOUT
static
int
DecoderPlaySout
(
decoder_t
*
p_dec
,
block_t
*
p_sout_block
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
assert
(
p_owner
->
p_clock
);
assert
(
!
p_sout_block
->
p_next
);
vlc_mutex_lock
(
&
p_owner
->
lock
);
if
(
p_owner
->
b_waiting
)
{
p_owner
->
b_has_data
=
true
;
vlc_cond_signal
(
&
p_owner
->
wait_acknowledge
);
}
bool
b_reject
=
DecoderWaitUnblock
(
p_dec
);
DecoderFixTs
(
p_dec
,
&
p_sout_block
->
i_dts
,
&
p_sout_block
->
i_pts
,
&
p_sout_block
->
i_length
,
NULL
,
INT64_MAX
);
vlc_mutex_unlock
(
&
p_owner
->
lock
);
if
(
!
b_reject
)
{
/* FIXME --VLC_TS_INVALID inspect stream_output*/
return
sout_InputSendBuffer
(
p_owner
->
p_sout_input
,
p_sout_block
);
}
else
{
block_Release
(
p_sout_block
);
return
VLC_EGENERIC
;
}
}
#endif
#ifdef ENABLE_SOUT
/* This function process a block for sout
*/
static
void
DecoderProcessSout
(
decoder_t
*
p_dec
,
block_t
*
p_block
)
{
decoder_owner_sys_t
*
p_owner
=
(
decoder_owner_sys_t
*
)
p_dec
->
p_owner
;
block_t
*
p_sout_block
;
while
(
(
p_sout_block
=
p_dec
->
pf_packetize
(
p_dec
,
p_block
?
&
p_block
:
NULL
)
)
)
{
if
(
p_owner
->
p_sout_input
==
NULL
)
{
vlc_mutex_lock
(
&
p_owner
->
lock
);
es_format_Clean
(
&
p_owner
->
fmt
);
es_format_Copy
(
&
p_owner
->
fmt
,
&
p_dec
->
fmt_out
);
DecoderUpdateFormatLocked
(
p_dec
);
vlc_mutex_unlock
(
&
p_owner
->
lock
);
p_owner
->
fmt
.
i_group
=
p_dec
->
fmt_in
.
i_group
;
p_owner
->
fmt
.
i_id
=
p_dec
->
fmt_in
.
i_id
;
if
(
p_dec
->
fmt_in
.
psz_language
)
{
free
(
p_owner
->
fmt
.
psz_language
);
p_owner
->
fmt
.
psz_language
=
strdup
(
p_dec
->
fmt_in
.
psz_language
);
}
p_owner
->
p_sout_input
=
sout_InputNew
(
p_owner
->
p_sout
,
&
p_owner
->
fmt
);
if
(
p_owner
->
p_sout_input
==
NULL
)
{
msg_Err
(
p_dec
,
"cannot create packetizer output (%4.4s)"
,
(
char
*
)
&
p_owner
->
fmt
.
i_codec
);
p_dec
->
b_error
=
true
;
block_ChainRelease
(
p_sout_block
);
break
;
}
}
while
(
p_sout_block
)
{
block_t
*
p_next
=
p_sout_block
->
p_next
;
p_sout_block
->
p_next
=
NULL
;
if
(
DecoderPlaySout
(
p_dec
,
p_sout_block
)
==
VLC_EGENERIC
)
{
msg_Err
(
p_dec
,
"cannot continue streaming due to errors"
);
p_dec
->
b_error
=
true
;
/* Cleanup */
block_ChainRelease
(
p_next
);
return
;
}
p_sout_block
=
p_next
;
}
}
}
#endif
/* This function process a video block
/* This function process a video block
*/
*/
static
void
DecoderProcessVideo
(
decoder_t
*
p_dec
,
block_t
*
p_block
,
bool
b_flush
)
static
void
DecoderProcessVideo
(
decoder_t
*
p_dec
,
block_t
*
p_block
,
bool
b_flush
)
...
@@ -1593,27 +1046,156 @@ static void DecoderProcessVideo( decoder_t *p_dec, block_t *p_block, bool b_flus
...
@@ -1593,27 +1046,156 @@ static void DecoderProcessVideo( decoder_t *p_dec, block_t *p_block, bool b_flus
block_t
*
p_next
=
p_packetized_block
->
p_next
;
block_t
*
p_next
=
p_packetized_block
->
p_next
;
p_packetized_block
->
p_next
=
NULL
;
p_packetized_block
->
p_next
=
NULL
;
DecoderDecodeVideo
(
p_dec
,
p_packetized_block
);
DecoderDecodeVideo
(
p_dec
,
p_packetized_block
);
p_packetized_block
=
p_next
;
}
}
/* The packetizer does not output a block that tell the decoder to flush
* do it ourself */
if
(
b_flush
)
{
block_t
*
p_null
=
DecoderBlockFlushNew
();
if
(
p_null
)
DecoderDecodeVideo
(
p_dec
,
p_null
);
}
}
else
{
DecoderDecodeVideo
(
p_dec
,
p_block
);
}
if
(
b_flush
&&
p_owner
->
p_vout
)
vout_Flush
(
p_owner
->
p_vout
,
VLC_TS_INVALID
+
1
);
}
static
void
DecoderPlayAudio
(
decoder_t
*
p_dec
,
block_t
*
p_audio
,
int
*
pi_played_sum
,
int
*
pi_lost_sum
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
audio_output_t
*
p_aout
=
p_owner
->
p_aout
;
/* */
if
(
p_audio
&&
p_audio
->
i_pts
<=
VLC_TS_INVALID
)
// FIXME --VLC_TS_INVALID verify audio_output/*
{
msg_Warn
(
p_dec
,
"non-dated audio buffer received"
);
*
pi_lost_sum
+=
1
;
block_Release
(
p_audio
);
return
;
}
/* */
vlc_mutex_lock
(
&
p_owner
->
lock
);
if
(
p_audio
&&
p_owner
->
b_waiting
)
{
p_owner
->
b_has_data
=
true
;
vlc_cond_signal
(
&
p_owner
->
wait_acknowledge
);
}
for
(
;;
)
{
bool
b_paused
;
bool
b_reject
=
DecoderWaitUnblock
(
p_dec
);
b_paused
=
p_owner
->
b_paused
;
if
(
!
p_audio
)
break
;
/* */
int
i_rate
=
INPUT_RATE_DEFAULT
;
DecoderFixTs
(
p_dec
,
&
p_audio
->
i_pts
,
NULL
,
&
p_audio
->
i_length
,
&
i_rate
,
AOUT_MAX_ADVANCE_TIME
);
if
(
p_audio
->
i_pts
<=
VLC_TS_INVALID
||
i_rate
<
INPUT_RATE_DEFAULT
/
AOUT_MAX_INPUT_RATE
||
i_rate
>
INPUT_RATE_DEFAULT
*
AOUT_MAX_INPUT_RATE
)
b_reject
=
true
;
DecoderWaitDate
(
p_dec
,
&
b_reject
,
p_audio
->
i_pts
-
AOUT_MAX_PREPARE_TIME
);
if
(
unlikely
(
p_owner
->
b_paused
!=
b_paused
)
)
continue
;
/* race with input thread? retry... */
if
(
p_aout
==
NULL
)
b_reject
=
true
;
if
(
!
b_reject
)
{
assert
(
!
p_owner
->
b_paused
);
if
(
!
aout_DecPlay
(
p_aout
,
p_audio
,
i_rate
)
)
*
pi_played_sum
+=
1
;
*
pi_lost_sum
+=
aout_DecGetResetLost
(
p_aout
);
}
else
{
msg_Dbg
(
p_dec
,
"discarded audio buffer"
);
*
pi_lost_sum
+=
1
;
block_Release
(
p_audio
);
}
break
;
}
vlc_mutex_unlock
(
&
p_owner
->
lock
);
}
static
void
DecoderDecodeAudio
(
decoder_t
*
p_dec
,
block_t
*
p_block
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
block_t
*
p_aout_buf
;
int
i_decoded
=
0
;
int
i_lost
=
0
;
int
i_played
=
0
;
if
(
!
p_block
)
{
/* Play a NULL block to output buffered frames */
DecoderPlayAudio
(
p_dec
,
NULL
,
&
i_played
,
&
i_lost
);
}
else
while
(
(
p_aout_buf
=
p_dec
->
pf_decode_audio
(
p_dec
,
&
p_block
))
)
{
if
(
DecoderIsFlushing
(
p_dec
)
)
{
/* It prevent freezing VLC in case of broken decoder */
block_Release
(
p_aout_buf
);
if
(
p_block
)
block_Release
(
p_block
);
break
;
}
i_decoded
++
;
p_packetized_block
=
p_next
;
if
(
p_owner
->
i_preroll_end
>
VLC_TS_INVALID
&&
}
p_aout_buf
->
i_pts
<
p_owner
->
i_preroll_end
)
{
block_Release
(
p_aout_buf
);
continue
;
}
}
/* The packetizer does not output a block that tell the decoder to flush
* do it ourself */
if
(
p_owner
->
i_preroll_end
>
VLC_TS_INVALID
)
if
(
b_flush
)
{
{
block_t
*
p_null
=
DecoderBlockFlushNew
();
msg_Dbg
(
p_dec
,
"End of audio preroll"
);
if
(
p_null
)
if
(
p_owner
->
p_aout
)
DecoderDecodeVideo
(
p_dec
,
p_null
);
aout_DecFlush
(
p_owner
->
p_aout
);
/* */
p_owner
->
i_preroll_end
=
VLC_TS_INVALID
;
}
}
DecoderPlayAudio
(
p_dec
,
p_aout_buf
,
&
i_played
,
&
i_lost
);
}
}
else
/* Update ugly stat */
input_thread_t
*
p_input
=
p_owner
->
p_input
;
if
(
p_input
!=
NULL
&&
(
i_decoded
>
0
||
i_lost
>
0
||
i_played
>
0
)
)
{
{
DecoderDecodeVideo
(
p_dec
,
p_block
);
vlc_mutex_lock
(
&
p_input
->
p
->
counters
.
counters_lock
);
stats_Update
(
p_input
->
p
->
counters
.
p_lost_abuffers
,
i_lost
,
NULL
);
stats_Update
(
p_input
->
p
->
counters
.
p_played_abuffers
,
i_played
,
NULL
);
stats_Update
(
p_input
->
p
->
counters
.
p_decoded_audio
,
i_decoded
,
NULL
);
vlc_mutex_unlock
(
&
p_input
->
p
->
counters
.
counters_lock
);
}
}
if
(
b_flush
&&
p_owner
->
p_vout
)
vout_Flush
(
p_owner
->
p_vout
,
VLC_TS_INVALID
+
1
);
}
}
/* This function process a audio block
/* This function process a audio block
...
@@ -1664,6 +1246,46 @@ static void DecoderProcessAudio( decoder_t *p_dec, block_t *p_block, bool b_flus
...
@@ -1664,6 +1246,46 @@ static void DecoderProcessAudio( decoder_t *p_dec, block_t *p_block, bool b_flus
aout_DecFlush
(
p_owner
->
p_aout
);
aout_DecFlush
(
p_owner
->
p_aout
);
}
}
static
void
DecoderPlaySpu
(
decoder_t
*
p_dec
,
subpicture_t
*
p_subpic
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
vout_thread_t
*
p_vout
=
p_owner
->
p_spu_vout
;
/* */
if
(
p_subpic
->
i_start
<=
VLC_TS_INVALID
)
{
msg_Warn
(
p_dec
,
"non-dated spu buffer received"
);
subpicture_Delete
(
p_subpic
);
return
;
}
/* */
vlc_mutex_lock
(
&
p_owner
->
lock
);
if
(
p_owner
->
b_waiting
)
{
p_owner
->
b_has_data
=
true
;
vlc_cond_signal
(
&
p_owner
->
wait_acknowledge
);
}
bool
b_reject
=
DecoderWaitUnblock
(
p_dec
);
DecoderFixTs
(
p_dec
,
&
p_subpic
->
i_start
,
&
p_subpic
->
i_stop
,
NULL
,
NULL
,
INT64_MAX
);
if
(
p_subpic
->
i_start
<=
VLC_TS_INVALID
)
b_reject
=
true
;
DecoderWaitDate
(
p_dec
,
&
b_reject
,
p_subpic
->
i_start
-
SPU_MAX_PREPARE_TIME
);
vlc_mutex_unlock
(
&
p_owner
->
lock
);
if
(
!
b_reject
)
vout_PutSubpicture
(
p_vout
,
p_subpic
);
else
subpicture_Delete
(
p_subpic
);
}
/* This function process a subtitle block
/* This function process a subtitle block
*/
*/
static
void
DecoderProcessSpu
(
decoder_t
*
p_dec
,
block_t
*
p_block
,
bool
b_flush
)
static
void
DecoderProcessSpu
(
decoder_t
*
p_dec
,
block_t
*
p_block
,
bool
b_flush
)
...
@@ -1745,66 +1367,291 @@ static void DecoderProcess( decoder_t *p_dec, block_t *p_block )
...
@@ -1745,66 +1367,291 @@ static void DecoderProcess( decoder_t *p_dec, block_t *p_block )
decoder_owner_sys_t
*
p_owner
=
(
decoder_owner_sys_t
*
)
p_dec
->
p_owner
;
decoder_owner_sys_t
*
p_owner
=
(
decoder_owner_sys_t
*
)
p_dec
->
p_owner
;
const
bool
b_flush_request
=
p_block
&&
(
p_block
->
i_flags
&
BLOCK_FLAG_CORE_FLUSH
);
const
bool
b_flush_request
=
p_block
&&
(
p_block
->
i_flags
&
BLOCK_FLAG_CORE_FLUSH
);
if
(
p_dec
->
b_error
)
if
(
p_dec
->
b_error
)
{
if
(
p_block
)
block_Release
(
p_block
);
goto
flush
;
}
if
(
p_block
&&
p_block
->
i_buffer
<=
0
)
{
assert
(
!
b_flush_request
);
block_Release
(
p_block
);
return
;
}
#ifdef ENABLE_SOUT
if
(
p_owner
->
b_packetizer
)
{
if
(
p_block
)
p_block
->
i_flags
&=
~
BLOCK_FLAG_CORE_PRIVATE_MASK
;
DecoderProcessSout
(
p_dec
,
p_block
);
}
else
#endif
{
bool
b_flush
=
false
;
if
(
p_block
)
{
const
bool
b_flushing
=
p_owner
->
i_preroll_end
==
INT64_MAX
;
DecoderUpdatePreroll
(
&
p_owner
->
i_preroll_end
,
p_block
);
b_flush
=
!
b_flushing
&&
b_flush_request
;
p_block
->
i_flags
&=
~
BLOCK_FLAG_CORE_PRIVATE_MASK
;
}
if
(
p_dec
->
fmt_out
.
i_cat
==
AUDIO_ES
)
{
DecoderProcessAudio
(
p_dec
,
p_block
,
b_flush
);
}
else
if
(
p_dec
->
fmt_out
.
i_cat
==
VIDEO_ES
)
{
DecoderProcessVideo
(
p_dec
,
p_block
,
b_flush
);
}
else
if
(
p_dec
->
fmt_out
.
i_cat
==
SPU_ES
)
{
DecoderProcessSpu
(
p_dec
,
p_block
,
b_flush
);
}
else
{
msg_Err
(
p_dec
,
"unknown ES format"
);
p_dec
->
b_error
=
true
;
}
}
/* */
flush:
if
(
b_flush_request
)
DecoderProcessOnFlush
(
p_dec
);
}
/**
* The decoding main loop
*
* \param p_dec the decoder
*/
static
void
*
DecoderThread
(
void
*
p_data
)
{
decoder_t
*
p_dec
=
(
decoder_t
*
)
p_data
;
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
/* The decoder's main loop */
for
(
;;
)
{
block_t
*
p_block
;
vlc_fifo_Lock
(
p_owner
->
p_fifo
);
vlc_fifo_CleanupPush
(
p_owner
->
p_fifo
);
while
(
vlc_fifo_IsEmpty
(
p_owner
->
p_fifo
)
)
{
if
(
p_owner
->
b_woken
)
break
;
vlc_fifo_Wait
(
p_owner
->
p_fifo
);
/* Make sure there is no cancellation point other than this one^^.
* If you need one, be sure to push cleanup of p_block. */
}
p_block
=
vlc_fifo_DequeueUnlocked
(
p_owner
->
p_fifo
);
if
(
p_block
!=
NULL
)
vlc_cond_signal
(
&
p_owner
->
wait_acknowledge
);
p_owner
->
b_woken
=
false
;
vlc_cleanup_run
();
if
(
p_block
==
NULL
||
p_block
->
i_flags
&
BLOCK_FLAG_CORE_EOS
)
DecoderSignalWait
(
p_dec
);
if
(
p_block
)
{
int
canc
=
vlc_savecancel
();
if
(
p_block
->
i_flags
&
BLOCK_FLAG_CORE_EOS
)
{
/* calling DecoderProcess() with NULL block will make
* decoders/packetizers flush their buffers */
block_Release
(
p_block
);
p_block
=
NULL
;
}
DecoderProcess
(
p_dec
,
p_block
);
vlc_restorecancel
(
canc
);
}
}
return
NULL
;
}
/**
* Create a decoder object
*
* \param p_input the input thread
* \param p_es the es descriptor
* \param b_packetizer instead of a decoder
* \return the decoder object
*/
static
decoder_t
*
CreateDecoder
(
vlc_object_t
*
p_parent
,
input_thread_t
*
p_input
,
const
es_format_t
*
fmt
,
bool
b_packetizer
,
input_resource_t
*
p_resource
,
sout_instance_t
*
p_sout
)
{
decoder_t
*
p_dec
;
decoder_owner_sys_t
*
p_owner
;
es_format_t
null_es_format
;
p_dec
=
vlc_custom_create
(
p_parent
,
sizeof
(
*
p_dec
),
"decoder"
);
if
(
p_dec
==
NULL
)
return
NULL
;
p_dec
->
pf_decode_audio
=
NULL
;
p_dec
->
pf_decode_video
=
NULL
;
p_dec
->
pf_decode_sub
=
NULL
;
p_dec
->
pf_get_cc
=
NULL
;
p_dec
->
pf_packetize
=
NULL
;
/* Initialize the decoder */
p_dec
->
p_module
=
NULL
;
memset
(
&
null_es_format
,
0
,
sizeof
(
es_format_t
)
);
es_format_Copy
(
&
p_dec
->
fmt_in
,
fmt
);
es_format_Copy
(
&
p_dec
->
fmt_out
,
&
null_es_format
);
p_dec
->
p_description
=
NULL
;
/* Allocate our private structure for the decoder */
p_dec
->
p_owner
=
p_owner
=
malloc
(
sizeof
(
decoder_owner_sys_t
)
);
if
(
unlikely
(
p_owner
==
NULL
)
)
{
{
if
(
p_block
)
vlc_object_release
(
p_dec
);
block_Release
(
p_block
);
return
NULL
;
goto
flush
;
}
}
p_owner
->
i_preroll_end
=
VLC_TS_INVALID
;
p_owner
->
i_last_rate
=
INPUT_RATE_DEFAULT
;
p_owner
->
p_input
=
p_input
;
p_owner
->
p_resource
=
p_resource
;
p_owner
->
p_aout
=
NULL
;
p_owner
->
p_vout
=
NULL
;
p_owner
->
p_spu_vout
=
NULL
;
p_owner
->
i_spu_channel
=
0
;
p_owner
->
i_spu_order
=
0
;
p_owner
->
p_sout
=
p_sout
;
p_owner
->
p_sout_input
=
NULL
;
p_owner
->
p_packetizer
=
NULL
;
p_owner
->
b_packetizer
=
b_packetizer
;
es_format_Init
(
&
p_owner
->
fmt
,
UNKNOWN_ES
,
0
);
if
(
p_block
&&
p_block
->
i_buffer
<=
0
)
/* decoder fifo */
p_owner
->
b_woken
=
false
;
p_owner
->
p_fifo
=
block_FifoNew
();
if
(
unlikely
(
p_owner
->
p_fifo
==
NULL
)
)
{
{
assert
(
!
b_flush_request
);
free
(
p_owner
);
block_Release
(
p_block
);
vlc_object_release
(
p_dec
);
return
;
return
NULL
;
}
}
#ifdef ENABLE_SOUT
/* Set buffers allocation callbacks for the decoders */
if
(
p_owner
->
b_packetizer
)
p_dec
->
pf_aout_format_update
=
aout_update_format
;
{
p_dec
->
pf_vout_format_update
=
vout_update_format
;
if
(
p_block
)
p_dec
->
pf_vout_buffer_new
=
vout_new_buffer
;
p_block
->
i_flags
&=
~
BLOCK_FLAG_CORE_PRIVATE_MASK
;
p_dec
->
pf_spu_buffer_new
=
spu_new_buffer
;
/* */
p_dec
->
pf_get_attachments
=
DecoderGetInputAttachments
;
p_dec
->
pf_get_display_date
=
DecoderGetDisplayDate
;
p_dec
->
pf_get_display_rate
=
DecoderGetDisplayRate
;
DecoderProcessSout
(
p_dec
,
p_block
);
/* Find a suitable decoder/packetizer module */
}
if
(
!
b_packetizer
)
p_dec
->
p_module
=
module_need
(
p_dec
,
"decoder"
,
"$codec"
,
false
);
else
else
#endif
p_dec
->
p_module
=
module_need
(
p_dec
,
"packetizer"
,
"$packetizer"
,
false
);
{
bool
b_flush
=
false
;
if
(
p_block
)
/* Check if decoder requires already packetized data */
if
(
!
b_packetizer
&&
p_dec
->
b_need_packetized
&&
!
p_dec
->
fmt_in
.
b_packetized
)
{
p_owner
->
p_packetizer
=
vlc_custom_create
(
p_parent
,
sizeof
(
decoder_t
),
"packetizer"
);
if
(
p_owner
->
p_packetizer
)
{
{
const
bool
b_flushing
=
p_owner
->
i_preroll_end
==
INT64_MAX
;
es_format_Copy
(
&
p_owner
->
p_packetizer
->
fmt_in
,
DecoderUpdatePreroll
(
&
p_owner
->
i_preroll_end
,
p_block
);
&
p_dec
->
fmt_in
);
b_flush
=
!
b_flushing
&&
b_flush_request
;
es_format_Copy
(
&
p_owner
->
p_packetizer
->
fmt_out
,
&
null_es_format
);
p_block
->
i_flags
&=
~
BLOCK_FLAG_CORE_PRIVATE_MASK
;
p_owner
->
p_packetizer
->
p_module
=
}
module_need
(
p_owner
->
p_packetizer
,
"packetizer"
,
"$packetizer"
,
false
);
if
(
p_dec
->
fmt_out
.
i_cat
==
AUDIO_ES
)
if
(
!
p_owner
->
p_packetizer
->
p_module
)
{
{
DecoderProcessAudio
(
p_dec
,
p_block
,
b_flush
);
es_format_Clean
(
&
p_owner
->
p_packetizer
->
fmt_in
);
}
vlc_object_release
(
p_owner
->
p_packetizer
);
else
if
(
p_dec
->
fmt_out
.
i_cat
==
VIDEO_ES
)
p_owner
->
p_packetizer
=
NULL
;
{
}
DecoderProcessVideo
(
p_dec
,
p_block
,
b_flush
);
}
else
if
(
p_dec
->
fmt_out
.
i_cat
==
SPU_ES
)
{
DecoderProcessSpu
(
p_dec
,
p_block
,
b_flush
);
}
}
else
}
/* Copy ourself the input replay gain */
if
(
fmt
->
i_cat
==
AUDIO_ES
)
{
for
(
unsigned
i
=
0
;
i
<
AUDIO_REPLAY_GAIN_MAX
;
i
++
)
{
{
msg_Err
(
p_dec
,
"unknown ES format"
);
if
(
!
p_dec
->
fmt_out
.
audio_replay_gain
.
pb_peak
[
i
]
)
p_dec
->
b_error
=
true
;
{
p_dec
->
fmt_out
.
audio_replay_gain
.
pb_peak
[
i
]
=
fmt
->
audio_replay_gain
.
pb_peak
[
i
];
p_dec
->
fmt_out
.
audio_replay_gain
.
pf_peak
[
i
]
=
fmt
->
audio_replay_gain
.
pf_peak
[
i
];
}
if
(
!
p_dec
->
fmt_out
.
audio_replay_gain
.
pb_gain
[
i
]
)
{
p_dec
->
fmt_out
.
audio_replay_gain
.
pb_gain
[
i
]
=
fmt
->
audio_replay_gain
.
pb_gain
[
i
];
p_dec
->
fmt_out
.
audio_replay_gain
.
pf_gain
[
i
]
=
fmt
->
audio_replay_gain
.
pf_gain
[
i
];
}
}
}
}
}
/* */
/* */
flush:
vlc_mutex_init
(
&
p_owner
->
lock
);
if
(
b_flush_request
)
vlc_cond_init
(
&
p_owner
->
wait_request
);
DecoderProcessOnFlush
(
p_dec
);
vlc_cond_init
(
&
p_owner
->
wait_acknowledge
);
p_owner
->
b_fmt_description
=
false
;
p_owner
->
p_description
=
NULL
;
p_owner
->
b_paused
=
false
;
p_owner
->
pause
.
i_date
=
VLC_TS_INVALID
;
p_owner
->
pause
.
i_ignore
=
0
;
p_owner
->
b_waiting
=
false
;
p_owner
->
b_first
=
true
;
p_owner
->
b_has_data
=
false
;
p_owner
->
b_flushing
=
false
;
/* */
p_owner
->
cc
.
b_supported
=
false
;
if
(
!
b_packetizer
)
{
if
(
p_owner
->
p_packetizer
&&
p_owner
->
p_packetizer
->
pf_get_cc
)
p_owner
->
cc
.
b_supported
=
true
;
if
(
p_dec
->
pf_get_cc
)
p_owner
->
cc
.
b_supported
=
true
;
}
for
(
unsigned
i
=
0
;
i
<
4
;
i
++
)
{
p_owner
->
cc
.
pb_present
[
i
]
=
false
;
p_owner
->
cc
.
pp_decoder
[
i
]
=
NULL
;
}
p_owner
->
i_ts_delay
=
0
;
return
p_dec
;
}
}
/**
/**
...
@@ -1893,331 +1740,467 @@ static void DeleteDecoder( decoder_t * p_dec )
...
@@ -1893,331 +1740,467 @@ static void DeleteDecoder( decoder_t * p_dec )
free
(
p_owner
);
free
(
p_owner
);
}
}
/*****************************************************************************
/* */
* Buffers allocation callbacks for the decoders
static
void
DecoderUnsupportedCodec
(
decoder_t
*
p_dec
,
vlc_fourcc_t
codec
)
*****************************************************************************/
static
void
DecoderUpdateFormatLocked
(
decoder_t
*
p_dec
)
{
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
if
(
codec
!=
VLC_FOURCC
(
'u'
,
'n'
,
'd'
,
'f'
))
{
const
char
*
desc
=
vlc_fourcc_GetDescription
(
p_dec
->
fmt_in
.
i_cat
,
codec
);
if
(
!
desc
||
!*
desc
)
desc
=
N_
(
"No description for this codec"
);
msg_Err
(
p_dec
,
"Codec `%4.4s' (%s) is not supported."
,
(
char
*
)
&
codec
,
desc
);
dialog_Fatal
(
p_dec
,
_
(
"Codec not supported"
),
_
(
"VLC could not decode the format
\"
%4.4s
\"
(%s)"
),
(
char
*
)
&
codec
,
desc
);
}
else
{
msg_Err
(
p_dec
,
"could not identify codec"
);
dialog_Fatal
(
p_dec
,
_
(
"Unidentified codec"
),
_
(
"VLC could not identify the audio or video codec"
)
);
}
}
vlc_assert_locked
(
&
p_owner
->
lock
);
/* TODO: pass p_sout through p_resource? -- Courmisch */
static
decoder_t
*
decoder_New
(
vlc_object_t
*
p_parent
,
input_thread_t
*
p_input
,
const
es_format_t
*
fmt
,
input_clock_t
*
p_clock
,
input_resource_t
*
p_resource
,
sout_instance_t
*
p_sout
)
{
decoder_t
*
p_dec
=
NULL
;
const
char
*
psz_type
=
p_sout
?
N_
(
"packetizer"
)
:
N_
(
"decoder"
);
int
i_priority
;
p_owner
->
b_fmt_description
=
true
;
/* Create the decoder configuration structure */
p_dec
=
CreateDecoder
(
p_parent
,
p_input
,
fmt
,
p_sout
!=
NULL
,
p_resource
,
p_sout
);
if
(
p_dec
==
NULL
)
{
msg_Err
(
p_parent
,
"could not create %s"
,
psz_type
);
dialog_Fatal
(
p_parent
,
_
(
"Streaming / Transcoding failed"
),
_
(
"VLC could not open the %s module."
),
vlc_gettext
(
psz_type
)
);
return
NULL
;
}
/* Move p_description */
if
(
!
p_dec
->
p_module
)
if
(
p_owner
->
p_description
&&
p_dec
->
p_description
)
{
vlc_meta_Delete
(
p_owner
->
p_description
);
DecoderUnsupportedCodec
(
p_dec
,
fmt
->
i_codec
);
p_owner
->
p_description
=
p_dec
->
p_description
;
p_dec
->
p_description
=
NULL
;
DeleteDecoder
(
p_dec
);
return
NULL
;
}
p_dec
->
p_owner
->
p_clock
=
p_clock
;
assert
(
p_dec
->
fmt_out
.
i_cat
!=
UNKNOWN_ES
);
if
(
p_dec
->
fmt_out
.
i_cat
==
AUDIO_ES
)
i_priority
=
VLC_THREAD_PRIORITY_AUDIO
;
else
i_priority
=
VLC_THREAD_PRIORITY_VIDEO
;
/* Spawn the decoder thread */
if
(
vlc_clone
(
&
p_dec
->
p_owner
->
thread
,
DecoderThread
,
p_dec
,
i_priority
)
)
{
msg_Err
(
p_dec
,
"cannot spawn decoder thread"
);
module_unneed
(
p_dec
,
p_dec
->
p_module
);
DeleteDecoder
(
p_dec
);
return
NULL
;
}
return
p_dec
;
}
}
static
vout_thread_t
*
aout_request_vout
(
void
*
p_private
,
vout_thread_t
*
p_vout
,
video_format_t
*
p_fmt
,
bool
b_recyle
)
{
decoder_t
*
p_dec
=
p_private
;
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
input_thread_t
*
p_input
=
p_owner
->
p_input
;
p_vout
=
input_resource_RequestVout
(
p_owner
->
p_resource
,
p_vout
,
p_fmt
,
1
,
b_recyle
);
if
(
p_input
!=
NULL
)
input_SendEventVout
(
p_input
);
return
p_vout
;
/**
* Spawns a new decoder thread from the input thread
*
* \param p_input the input thread
* \param p_es the es descriptor
* \return the spawned decoder object
*/
decoder_t
*
input_DecoderNew
(
input_thread_t
*
p_input
,
es_format_t
*
fmt
,
input_clock_t
*
p_clock
,
sout_instance_t
*
p_sout
)
{
return
decoder_New
(
VLC_OBJECT
(
p_input
),
p_input
,
fmt
,
p_clock
,
p_input
->
p
->
p_resource
,
p_sout
);
}
/**
* Spawn a decoder thread outside of the input thread.
*/
decoder_t
*
input_DecoderCreate
(
vlc_object_t
*
p_parent
,
const
es_format_t
*
fmt
,
input_resource_t
*
p_resource
)
{
return
decoder_New
(
p_parent
,
NULL
,
fmt
,
NULL
,
p_resource
,
NULL
);
}
}
static
int
aout_update_format
(
decoder_t
*
p_dec
)
/**
* Kills a decoder thread and waits until it's finished
*
* \param p_input the input thread
* \param p_es the es descriptor
* \return nothing
*/
void
input_DecoderDelete
(
decoder_t
*
p_dec
)
{
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
if
(
p_owner
->
p_aout
vlc_cancel
(
p_owner
->
thread
);
&&
!
AOUT_FMTS_IDENTICAL
(
&
p_dec
->
fmt_out
.
audio
,
&
p_owner
->
fmt
.
audio
)
)
{
audio_output_t
*
p_aout
=
p_owner
->
p_aout
;
/* Parameters changed, restart the aout */
/* Make sure we aren't paused/waiting/decoding anymore */
vlc_mutex_lock
(
&
p_owner
->
lock
);
vlc_mutex_lock
(
&
p_owner
->
lock
);
p_owner
->
b_paused
=
false
;
p_owner
->
b_waiting
=
false
;
p_owner
->
b_flushing
=
true
;
vlc_cond_signal
(
&
p_owner
->
wait_request
);
vlc_mutex_unlock
(
&
p_owner
->
lock
);
aout_DecDelete
(
p_owner
->
p_aout
);
vlc_join
(
p_owner
->
thread
,
NULL
);
p_owner
->
p_aout
=
NULL
;
vlc_mutex_unlock
(
&
p_owner
->
lock
);
module_unneed
(
p_dec
,
p_dec
->
p_module
);
input_resource_PutAout
(
p_owner
->
p_resource
,
p_aout
);
}
if
(
p_owner
->
p_aout
==
NULL
)
/* */
if
(
p_dec
->
p_owner
->
cc
.
b_supported
)
{
{
p_dec
->
fmt_out
.
audio
.
i_format
=
p_dec
->
fmt_out
.
i_codec
;
int
i
;
for
(
i
=
0
;
i
<
4
;
i
++
)
input_DecoderSetCcState
(
p_dec
,
false
,
i
);
}
audio_sample_format_t
format
=
p_dec
->
fmt_out
.
audio
;
/* Delete decoder */
aout_FormatPrepare
(
&
format
);
DeleteDecoder
(
p_dec
);
}
const
int
i_force_dolby
=
var_InheritInteger
(
p_dec
,
"force-dolby-surround"
);
/**
if
(
i_force_dolby
&&
* Put a block_t in the decoder's fifo.
(
format
.
i_original_channels
&
AOUT_CHAN_PHYSMASK
)
==
* Thread-safe w.r.t. the decoder. May be a cancellation point.
(
AOUT_CHAN_LEFT
|
AOUT_CHAN_RIGHT
)
)
*
* \param p_dec the decoder object
* \param p_block the data block
*/
void
input_DecoderDecode
(
decoder_t
*
p_dec
,
block_t
*
p_block
,
bool
b_do_pace
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
vlc_fifo_Lock
(
p_owner
->
p_fifo
);
if
(
!
b_do_pace
)
{
/* FIXME: ideally we would check the time amount of data
* in the FIFO instead of its size. */
/* 400 MiB, i.e. ~ 50mb/s for 60s */
if
(
vlc_fifo_GetBytes
(
p_owner
->
p_fifo
)
>
400
*
1024
*
1024
)
{
{
if
(
i_force_dolby
==
1
)
msg_Warn
(
p_dec
,
"decoder/packetizer fifo full (data not "
{
"consumed quickly enough), resetting fifo!"
);
format
.
i_original_channels
=
format
.
i_original_channels
|
block_ChainRelease
(
vlc_fifo_DequeueAllUnlocked
(
p_owner
->
p_fifo
)
);
AOUT_CHAN_DOLBYSTEREO
;
}
else
/* i_force_dolby == 2 */
{
format
.
i_original_channels
=
format
.
i_original_channels
&
~
AOUT_CHAN_DOLBYSTEREO
;
}
}
}
}
else
if
(
!
p_owner
->
b_waiting
)
{
/* The FIFO is not consumed when waiting, so pacing would deadlock VLC.
* Locking is not necessary as b_waiting is only read, not written by
* the decoder thread. */
while
(
vlc_fifo_GetCount
(
p_owner
->
p_fifo
)
>=
10
)
vlc_fifo_WaitCond
(
p_owner
->
p_fifo
,
&
p_owner
->
wait_acknowledge
);
}
aout_request_vout_t
request_vout
=
{
vlc_fifo_QueueUnlocked
(
p_owner
->
p_fifo
,
p_block
);
.
pf_request_vout
=
aout_request_vout
,
vlc_fifo_Unlock
(
p_owner
->
p_fifo
);
.
p_private
=
p_dec
,
}
};
audio_output_t
*
p_aout
;
p_aout
=
input_resource_GetAout
(
p_owner
->
p_resource
);
bool
input_DecoderIsEmpty
(
decoder_t
*
p_dec
)
if
(
p_aout
)
{
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
if
(
aout_DecNew
(
p_aout
,
&
format
,
assert
(
!
p_owner
->
b_waiting
);
&
p_dec
->
fmt_out
.
audio_replay_gain
,
&
request_vout
)
)
{
input_resource_PutAout
(
p_owner
->
p_resource
,
p_aout
);
p_aout
=
NULL
;
}
}
bool
b_empty
=
block_FifoCount
(
p_dec
->
p_owner
->
p_fifo
)
<=
0
;
if
(
b_empty
)
{
vlc_mutex_lock
(
&
p_owner
->
lock
);
vlc_mutex_lock
(
&
p_owner
->
lock
);
/* TODO subtitles support */
if
(
p_owner
->
fmt
.
i_cat
==
VIDEO_ES
&&
p_owner
->
p_vout
)
b_empty
=
vout_IsEmpty
(
p_owner
->
p_vout
);
else
if
(
p_owner
->
fmt
.
i_cat
==
AUDIO_ES
&&
p_owner
->
p_aout
)
b_empty
=
aout_DecIsEmpty
(
p_owner
->
p_aout
);
vlc_mutex_unlock
(
&
p_owner
->
lock
);
}
return
b_empty
;
}
p_owner
->
p_aout
=
p_aout
;
static
void
DecoderFlush
(
decoder_t
*
p_dec
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
es_format_Clean
(
&
p_owner
->
fmt
);
vlc_assert_locked
(
&
p_owner
->
lock
);
es_format_Copy
(
&
p_owner
->
fmt
,
&
p_dec
->
fmt_out
);
aout_FormatPrepare
(
&
p_owner
->
fmt
.
audio
);
DecoderUpdateFormatLocked
(
p_dec
);
/* Empty the fifo */
block_FifoEmpty
(
p_owner
->
p_fifo
);
if
(
unlikely
(
p_owner
->
b_paused
)
&&
p_aout
!=
NULL
)
/* Monitor for flush end */
/* fake pause if needed */
p_owner
->
b_flushing
=
true
;
aout_DecChangePause
(
p_aout
,
true
,
mdate
()
);
vlc_cond_signal
(
&
p_owner
->
wait_request
);
vlc_mutex_unlock
(
&
p_owner
->
lock
);
/* Send a special block */
block_t
*
p_null
=
DecoderBlockFlushNew
();
if
(
!
p_null
)
return
;
input_DecoderDecode
(
p_dec
,
p_null
,
false
);
if
(
p_owner
->
p_input
!=
NULL
)
/* */
input_SendEventAout
(
p_owner
->
p_input
);
while
(
p_owner
->
b_flushing
)
vlc_cond_wait
(
&
p_owner
->
wait_acknowledge
,
&
p_owner
->
lock
);
}
if
(
p_aout
==
NULL
)
/**
{
* Requests that the decoder immediately discard all pending buffers.
msg_Err
(
p_dec
,
"failed to create audio output"
);
* This is useful at end of stream, when seeking or when deselecting a stream.
p_dec
->
b_error
=
true
;
*/
return
-
1
;
void
input_DecoderFlush
(
decoder_t
*
p_dec
)
}
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
p_dec
->
fmt_out
.
audio
.
i_bytes_per_frame
=
vlc_mutex_lock
(
&
p_owner
->
lock
);
p_owner
->
fmt
.
audio
.
i_bytes_per_frame
;
DecoderFlush
(
p_dec
);
p_dec
->
fmt_out
.
audio
.
i_frame_length
=
vlc_mutex_unlock
(
&
p_owner
->
lock
);
p_owner
->
fmt
.
audio
.
i_frame_length
;
}
return
0
;
}
}
static
int
vout_update_format
(
decoder_t
*
p_dec
)
void
input_DecoderIsCcPresent
(
decoder_t
*
p_dec
,
bool
pb_present
[
4
]
)
{
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
int
i
;
if
(
p_owner
->
p_vout
==
NULL
vlc_mutex_lock
(
&
p_owner
->
lock
);
||
p_dec
->
fmt_out
.
video
.
i_width
!=
p_owner
->
fmt
.
video
.
i_width
for
(
i
=
0
;
i
<
4
;
i
++
)
||
p_dec
->
fmt_out
.
video
.
i_height
!=
p_owner
->
fmt
.
video
.
i_height
pb_present
[
i
]
=
p_owner
->
cc
.
pb_present
[
i
];
||
p_dec
->
fmt_out
.
video
.
i_visible_width
!=
p_owner
->
fmt
.
video
.
i_visible_width
vlc_mutex_unlock
(
&
p_owner
->
lock
);
||
p_dec
->
fmt_out
.
video
.
i_visible_height
!=
p_owner
->
fmt
.
video
.
i_visible_height
}
||
p_dec
->
fmt_out
.
video
.
i_x_offset
!=
p_owner
->
fmt
.
video
.
i_x_offset
||
p_dec
->
fmt_out
.
video
.
i_y_offset
!=
p_owner
->
fmt
.
video
.
i_y_offset
||
p_dec
->
fmt_out
.
i_codec
!=
p_owner
->
fmt
.
video
.
i_chroma
||
(
int64_t
)
p_dec
->
fmt_out
.
video
.
i_sar_num
*
p_owner
->
fmt
.
video
.
i_sar_den
!=
(
int64_t
)
p_dec
->
fmt_out
.
video
.
i_sar_den
*
p_owner
->
fmt
.
video
.
i_sar_num
||
p_dec
->
fmt_out
.
video
.
orientation
!=
p_owner
->
fmt
.
video
.
orientation
)
{
vout_thread_t
*
p_vout
;
if
(
!
p_dec
->
fmt_out
.
video
.
i_width
||
int
input_DecoderSetCcState
(
decoder_t
*
p_dec
,
bool
b_decode
,
int
i_channel
)
!
p_dec
->
fmt_out
.
video
.
i_height
)
{
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
/* Can't create a new vout without display size */
return
-
1
;
}
video_format_t
fmt
=
p_dec
->
fmt_out
.
video
;
//msg_Warn( p_dec, "input_DecoderSetCcState: %d @%d", b_decode, i_channel );
fmt
.
i_chroma
=
p_dec
->
fmt_out
.
i_codec
;
if
(
vlc_fourcc_IsYUV
(
fmt
.
i_chroma
)
)
if
(
i_channel
<
0
||
i_channel
>=
4
||
!
p_owner
->
cc
.
pb_present
[
i_channel
]
)
{
return
VLC_EGENERIC
;
const
vlc_chroma_description_t
*
dsc
=
vlc_fourcc_GetChromaDescription
(
fmt
.
i_chroma
);
for
(
unsigned
int
i
=
0
;
dsc
&&
i
<
dsc
->
plane_count
;
i
++
)
{
while
(
fmt
.
i_width
%
dsc
->
p
[
i
].
w
.
den
)
fmt
.
i_width
++
;
while
(
fmt
.
i_height
%
dsc
->
p
[
i
].
h
.
den
)
fmt
.
i_height
++
;
}
}
if
(
!
fmt
.
i_visible_width
||
!
fmt
.
i_visible_height
)
if
(
b_decode
)
{
{
if
(
p_dec
->
fmt_in
.
video
.
i_visible_width
&&
static
const
vlc_fourcc_t
fcc
[
4
]
=
{
p_dec
->
fmt_in
.
video
.
i_visible_height
)
VLC_FOURCC
(
'c'
,
'c'
,
'1'
,
' '
),
{
VLC_FOURCC
(
'c'
,
'c'
,
'2'
,
' '
),
fmt
.
i_visible_width
=
p_dec
->
fmt_in
.
video
.
i_visible_width
;
VLC_FOURCC
(
'c'
,
'c'
,
'3'
,
' '
),
fmt
.
i_visible_height
=
p_dec
->
fmt_in
.
video
.
i_visible_height
;
VLC_FOURCC
(
'c'
,
'c'
,
'4'
,
' '
),
fmt
.
i_x_offset
=
p_dec
->
fmt_in
.
video
.
i_x_offset
;
};
fmt
.
i_y_offset
=
p_dec
->
fmt_in
.
video
.
i_y_offset
;
decoder_t
*
p_cc
;
}
es_format_t
fmt
;
else
{
fmt
.
i_visible_width
=
fmt
.
i_width
;
fmt
.
i_visible_height
=
fmt
.
i_height
;
fmt
.
i_x_offset
=
0
;
fmt
.
i_y_offset
=
0
;
}
}
if
(
fmt
.
i_visible_height
==
1088
&&
es_format_Init
(
&
fmt
,
SPU_ES
,
fcc
[
i_channel
]
);
var_CreateGetBool
(
p_dec
,
"hdtv-fix"
)
)
p_cc
=
input_DecoderNew
(
p_owner
->
p_input
,
&
fmt
,
p_dec
->
p_owner
->
p_clock
,
p_owner
->
p_sout
);
if
(
!
p_cc
)
{
{
fmt
.
i_visible_height
=
1080
;
msg_Err
(
p_dec
,
"could not create decoder"
);
if
(
!
(
fmt
.
i_sar_num
%
136
))
dialog_Fatal
(
p_dec
,
_
(
"Streaming / Transcoding failed"
),
"%s"
,
{
_
(
"VLC could not open the decoder module."
)
);
fmt
.
i_sar_num
*=
135
;
return
VLC_EGENERIC
;
fmt
.
i_sar_den
*=
136
;
}
msg_Warn
(
p_dec
,
"Fixing broken HDTV stream (display_height=1088)"
);
}
}
else
if
(
!
p_cc
->
p_module
)
if
(
!
fmt
.
i_sar_num
||
!
fmt
.
i_sar_den
)
{
{
fmt
.
i_sar_num
=
1
;
DecoderUnsupportedCodec
(
p_dec
,
fcc
[
i_channel
]
);
fmt
.
i_sar_den
=
1
;
input_DecoderDelete
(
p_cc
);
return
VLC_EGENERIC
;
}
}
p_cc
->
p_owner
->
p_clock
=
p_owner
->
p_clock
;
vlc_ureduce
(
&
fmt
.
i_sar_num
,
&
fmt
.
i_sar_den
,
fmt
.
i_sar_num
,
fmt
.
i_sar_den
,
50000
);
vlc_mutex_lock
(
&
p_owner
->
lock
);
vlc_mutex_lock
(
&
p_owner
->
lock
);
p_owner
->
cc
.
pp_decoder
[
i_channel
]
=
p_cc
;
p_vout
=
p_owner
->
p_vout
;
p_owner
->
p_vout
=
NULL
;
vlc_mutex_unlock
(
&
p_owner
->
lock
);
vlc_mutex_unlock
(
&
p_owner
->
lock
);
}
else
{
decoder_t
*
p_cc
;
unsigned
dpb_size
;
switch
(
p_dec
->
fmt_in
.
i_codec
)
{
case
VLC_CODEC_HEVC
:
case
VLC_CODEC_H264
:
case
VLC_CODEC_DIRAC
:
/* FIXME valid ? */
dpb_size
=
18
;
break
;
case
VLC_CODEC_VP5
:
case
VLC_CODEC_VP6
:
case
VLC_CODEC_VP6F
:
case
VLC_CODEC_VP8
:
dpb_size
=
3
;
break
;
default:
dpb_size
=
2
;
break
;
}
p_vout
=
input_resource_RequestVout
(
p_owner
->
p_resource
,
p_vout
,
&
fmt
,
dpb_size
+
p_dec
->
i_extra_picture_buffers
+
1
,
true
);
vlc_mutex_lock
(
&
p_owner
->
lock
);
vlc_mutex_lock
(
&
p_owner
->
lock
);
p_owner
->
p_vout
=
p_vout
;
p_cc
=
p_owner
->
cc
.
pp_decoder
[
i_channel
];
p_owner
->
cc
.
pp_decoder
[
i_channel
]
=
NULL
;
vlc_mutex_unlock
(
&
p_owner
->
lock
);
es_format_Clean
(
&
p_owner
->
fmt
);
if
(
p_cc
)
es_format_Copy
(
&
p_owner
->
fmt
,
&
p_dec
->
fmt_out
);
input_DecoderDelete
(
p_cc
);
p_owner
->
fmt
.
video
.
i_chroma
=
p_dec
->
fmt_out
.
i_codec
;
}
return
VLC_SUCCESS
;
}
DecoderUpdateFormatLocked
(
p_dec
);
int
input_DecoderGetCcState
(
decoder_t
*
p_dec
,
bool
*
pb_decode
,
int
i_channel
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
vlc_mutex_unlock
(
&
p_owner
->
lock
);
*
pb_decode
=
false
;
if
(
i_channel
<
0
||
i_channel
>=
4
||
!
p_owner
->
cc
.
pb_present
[
i_channel
]
)
return
VLC_EGENERIC
;
if
(
p_owner
->
p_input
!=
NULL
)
vlc_mutex_lock
(
&
p_owner
->
lock
);
input_SendEventVout
(
p_owner
->
p_input
);
*
pb_decode
=
p_owner
->
cc
.
pp_decoder
[
i_channel
]
!=
NULL
;
if
(
p_vout
==
NULL
)
vlc_mutex_unlock
(
&
p_owner
->
lock
);
return
VLC_EGENERIC
;
}
void
input_DecoderChangePause
(
decoder_t
*
p_dec
,
bool
b_paused
,
mtime_t
i_date
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
vlc_mutex_lock
(
&
p_owner
->
lock
);
/* Normally, p_owner->b_paused != b_paused here. But if a track is added
* while the input is paused (e.g. add sub file), then b_paused is
* (incorrectly) false. */
if
(
likely
(
p_owner
->
b_paused
!=
b_paused
)
)
{
p_owner
->
b_paused
=
b_paused
;
p_owner
->
pause
.
i_date
=
i_date
;
p_owner
->
pause
.
i_ignore
=
0
;
vlc_cond_signal
(
&
p_owner
->
wait_request
);
/* XXX only audio and video output have to be paused.
* - for sout it is useless
* - for subs, it is done by the vout
*/
if
(
p_owner
->
fmt
.
i_cat
==
AUDIO_ES
)
{
{
msg_Err
(
p_dec
,
"failed to create video output"
);
if
(
p_owner
->
p_aout
)
p_dec
->
b_error
=
true
;
aout_DecChangePause
(
p_owner
->
p_aout
,
b_paused
,
i_date
);
return
-
1
;
}
else
if
(
p_owner
->
fmt
.
i_cat
==
VIDEO_ES
)
{
if
(
p_owner
->
p_vout
)
vout_ChangePause
(
p_owner
->
p_vout
,
b_paused
,
i_date
);
}
}
}
}
return
0
;
vlc_mutex_unlock
(
&
p_owner
->
lock
)
;
}
}
static
picture_t
*
vout_new_buffer
(
decoder_t
*
p_dec
)
void
input_DecoderChangeDelay
(
decoder_t
*
p_dec
,
mtime_t
i_delay
)
{
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
for
(
;;
)
vlc_mutex_lock
(
&
p_owner
->
lock
);
{
p_owner
->
i_ts_delay
=
i_delay
;
if
(
DecoderIsFlushing
(
p_dec
)
||
p_dec
->
b_error
)
vlc_mutex_unlock
(
&
p_owner
->
lock
);
return
NULL
;
}
picture_t
*
p_picture
=
vout_GetPicture
(
p_owner
->
p_vout
);
void
input_DecoderStartWait
(
decoder_t
*
p_dec
)
if
(
p_picture
)
{
return
p_picture
;
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
/* */
assert
(
!
p_owner
->
b_waiting
);
DecoderSignalWait
(
p_dec
);
/* Check the decoder doesn't leak pictures */
vlc_mutex_lock
(
&
p_owner
->
lock
);
vout_FixLeaks
(
p_owner
->
p_vout
);
p_owner
->
b_first
=
true
;
p_owner
->
b_has_data
=
false
;
p_owner
->
b_waiting
=
true
;
vlc_cond_signal
(
&
p_owner
->
wait_request
);
vlc_mutex_unlock
(
&
p_owner
->
lock
);
}
/* FIXME add a vout_WaitPictureAvailable (timedwait) */
void
input_DecoderStopWait
(
decoder_t
*
p_dec
)
msleep
(
VOUT_OUTMEM_SLEEP
);
{
}
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
assert
(
p_owner
->
b_waiting
);
vlc_mutex_lock
(
&
p_owner
->
lock
);
p_owner
->
b_waiting
=
false
;
vlc_cond_signal
(
&
p_owner
->
wait_request
);
vlc_mutex_unlock
(
&
p_owner
->
lock
);
}
}
static
subpicture_t
*
spu_new_buffer
(
decoder_t
*
p_dec
,
void
input_DecoderWait
(
decoder_t
*
p_dec
)
const
subpicture_updater_t
*
p_updater
)
{
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
vout_thread_t
*
p_vout
=
NULL
;
subpicture_t
*
p_subpic
;
int
i_attempts
=
30
;
while
(
i_attempts
--
)
assert
(
p_owner
->
b_waiting
);
vlc_mutex_lock
(
&
p_owner
->
lock
);
while
(
!
p_owner
->
b_has_data
)
{
{
if
(
DecoderIsFlushing
(
p_dec
)
||
p_dec
->
b_error
)
vlc_fifo_Lock
(
p_owner
->
p_fifo
);
break
;
p_owner
->
b_woken
=
true
;
vlc_fifo_Signal
(
p_owner
->
p_fifo
);
vlc_fifo_Unlock
(
p_owner
->
p_fifo
);
vlc_cond_wait
(
&
p_owner
->
wait_acknowledge
,
&
p_owner
->
lock
);
}
vlc_mutex_unlock
(
&
p_owner
->
lock
);
}
p_vout
=
input_resource_HoldVout
(
p_owner
->
p_resource
);
void
input_DecoderFrameNext
(
decoder_t
*
p_dec
,
mtime_t
*
pi_duration
)
if
(
p_vout
)
{
break
;
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
msleep
(
DECODER_SPU_VOUT_WAIT_DURATION
);
*
pi_duration
=
0
;
}
if
(
!
p_vout
)
vlc_mutex_lock
(
&
p_owner
->
lock
);
if
(
p_owner
->
fmt
.
i_cat
==
VIDEO_ES
)
{
{
msg_Warn
(
p_dec
,
"no vout found, dropping subpicture"
);
if
(
p_owner
->
b_paused
&&
p_owner
->
p_vout
)
return
NULL
;
{
vout_NextPicture
(
p_owner
->
p_vout
,
pi_duration
);
p_owner
->
pause
.
i_ignore
++
;
vlc_cond_signal
(
&
p_owner
->
wait_request
);
}
}
}
else
if
(
p_owner
->
p_spu_vout
!=
p_vout
)
{
{
p_owner
->
i_spu_channel
=
vout_RegisterSubpictureChannel
(
p_vout
);
/* TODO subtitle should not be flushed */
p_owner
->
i_spu_order
=
0
;
p_owner
->
b_waiting
=
false
;
p_owner
->
p_spu_vout
=
p_vout
;
DecoderFlush
(
p_dec
)
;
}
}
vlc_mutex_unlock
(
&
p_owner
->
lock
);
}
p_subpic
=
subpicture_New
(
p_updater
);
bool
input_DecoderHasFormatChanged
(
decoder_t
*
p_dec
,
es_format_t
*
p_fmt
,
vlc_meta_t
**
pp_meta
)
if
(
p_subpic
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
bool
b_changed
;
vlc_mutex_lock
(
&
p_owner
->
lock
);
b_changed
=
p_owner
->
b_fmt_description
;
if
(
b_changed
)
{
{
p_subpic
->
i_channel
=
p_owner
->
i_spu_channel
;
if
(
p_fmt
!=
NULL
)
p_subpic
->
i_order
=
p_owner
->
i_spu_order
++
;
es_format_Copy
(
p_fmt
,
&
p_owner
->
fmt
);
p_subpic
->
b_subtitle
=
true
;
if
(
pp_meta
)
{
*
pp_meta
=
NULL
;
if
(
p_owner
->
p_description
)
{
*
pp_meta
=
vlc_meta_New
();
if
(
*
pp_meta
)
vlc_meta_Merge
(
*
pp_meta
,
p_owner
->
p_description
);
}
}
p_owner
->
b_fmt_description
=
false
;
}
}
vlc_mutex_unlock
(
&
p_owner
->
lock
);
return
b_changed
;
}
vlc_object_release
(
p_vout
);
size_t
input_DecoderGetFifoSize
(
decoder_t
*
p_dec
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
return
p_subpic
;
return
block_FifoSize
(
p_owner
->
p_fifo
);
}
void
input_DecoderGetObjects
(
decoder_t
*
p_dec
,
vout_thread_t
**
pp_vout
,
audio_output_t
**
pp_aout
)
{
decoder_owner_sys_t
*
p_owner
=
p_dec
->
p_owner
;
vlc_mutex_lock
(
&
p_owner
->
lock
);
if
(
pp_vout
)
*
pp_vout
=
p_owner
->
p_vout
?
vlc_object_hold
(
p_owner
->
p_vout
)
:
NULL
;
if
(
pp_aout
)
*
pp_aout
=
p_owner
->
p_aout
?
vlc_object_hold
(
p_owner
->
p_aout
)
:
NULL
;
vlc_mutex_unlock
(
&
p_owner
->
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