Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc-1.1
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-1.1
Commits
68d21786
Commit
68d21786
authored
Jun 22, 2004
by
Laurent Aimar
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
* all: rework of the input.
parent
7d01a7e7
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
2984 additions
and
3945 deletions
+2984
-3945
src/input/access.c
src/input/access.c
+1
-27
src/input/clock.c
src/input/clock.c
+81
-87
src/input/control.c
src/input/control.c
+36
-39
src/input/decoder.c
src/input/decoder.c
+56
-160
src/input/demux.c
src/input/demux.c
+280
-144
src/input/es_out.c
src/input/es_out.c
+539
-249
src/input/input.c
src/input/input.c
+1036
-918
src/input/input_ext-plugins.c
src/input/input_ext-plugins.c
+0
-658
src/input/input_programs.c
src/input/input_programs.c
+0
-1268
src/input/stream.c
src/input/stream.c
+955
-393
src/input/subtitles.c
src/input/subtitles.c
+0
-2
No files found.
src/input/access.c
View file @
68d21786
...
@@ -25,33 +25,7 @@
...
@@ -25,33 +25,7 @@
#include <vlc/vlc.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#include <vlc/input.h>
#include "ninput.h"
#include "input_internal.h"
int
access_vaControl
(
input_thread_t
*
p_input
,
int
i_query
,
va_list
args
)
{
if
(
p_input
->
pf_access_control
)
{
return
p_input
->
pf_access_control
(
p_input
,
i_query
,
args
);
}
return
VLC_EGENERIC
;
}
int
access_Control
(
input_thread_t
*
p_input
,
int
i_query
,
...
)
{
va_list
args
;
int
i_result
;
va_start
(
args
,
i_query
);
i_result
=
access_vaControl
(
p_input
,
i_query
,
args
);
va_end
(
args
);
return
i_result
;
}
int
access_vaControlDefault
(
input_thread_t
*
p_input
,
int
i_query
,
va_list
args
)
{
return
VLC_EGENERIC
;
}
/*****************************************************************************
/*****************************************************************************
* access2_New:
* access2_New:
...
...
src/input/
input_
clock.c
→
src/input/clock.c
View file @
68d21786
...
@@ -24,14 +24,11 @@
...
@@ -24,14 +24,11 @@
/*****************************************************************************
/*****************************************************************************
* Preamble
* Preamble
*****************************************************************************/
*****************************************************************************/
#include <string.h>
/* memcpy(), memset() */
#include <stdlib.h>
#include <vlc/vlc.h>
#include <vlc/vlc.h>
#include "stream_control.h"
#include <vlc/input.h>
#include "input_ext-intf.h"
#include "input_internal.h"
#include "input_ext-dec.h"
#include "input_ext-plugins.h"
/*
/*
* DISCUSSION : SYNCHRONIZATION METHOD
* DISCUSSION : SYNCHRONIZATION METHOD
...
@@ -67,7 +64,8 @@
...
@@ -67,7 +64,8 @@
* new_average = (old_average * c_average + new_sample_value) / (c_average +1)
* new_average = (old_average * c_average + new_sample_value) / (c_average +1)
*/
*/
static
void
ClockNewRef
(
pgrm_descriptor_t
*
p_pgrm
,
static
void
ClockNewRef
(
input_clock_t
*
p_pgrm
,
mtime_t
i_clock
,
mtime_t
i_sysdate
);
mtime_t
i_clock
,
mtime_t
i_sysdate
);
/*****************************************************************************
/*****************************************************************************
...
@@ -84,19 +82,19 @@ static void ClockNewRef( pgrm_descriptor_t * p_pgrm,
...
@@ -84,19 +82,19 @@ static void ClockNewRef( pgrm_descriptor_t * p_pgrm,
/*****************************************************************************
/*****************************************************************************
* ClockToSysdate: converts a movie clock to system date
* ClockToSysdate: converts a movie clock to system date
*****************************************************************************/
*****************************************************************************/
static
mtime_t
ClockToSysdate
(
input_thread_t
*
p_input
,
static
mtime_t
ClockToSysdate
(
input_thread_t
*
p_input
,
pgrm_descriptor_t
*
p_pgrm
,
mtime_t
i_clock
)
input_clock_t
*
cl
,
mtime_t
i_clock
)
{
{
mtime_t
i_sysdate
=
0
;
mtime_t
i_sysdate
=
0
;
if
(
p_pgrm
->
i_synchro_state
==
SYNCHRO_OK
)
if
(
cl
->
i_synchro_state
==
SYNCHRO_OK
)
{
{
i_sysdate
=
(
mtime_t
)(
i_clock
-
p_pgrm
->
cr_ref
)
i_sysdate
=
(
mtime_t
)(
i_clock
-
cl
->
cr_ref
)
*
(
mtime_t
)
p_input
->
stream
.
control
.
i_rate
*
(
mtime_t
)
p_input
->
i_rate
*
(
mtime_t
)
300
;
*
(
mtime_t
)
300
;
i_sysdate
/=
27
;
i_sysdate
/=
27
;
i_sysdate
/=
1000
;
i_sysdate
/=
1000
;
i_sysdate
+=
(
mtime_t
)
p_pgrm
->
sysdate_ref
;
i_sysdate
+=
(
mtime_t
)
cl
->
sysdate_ref
;
}
}
return
(
i_sysdate
);
return
(
i_sysdate
);
...
@@ -107,46 +105,54 @@ static mtime_t ClockToSysdate( input_thread_t * p_input,
...
@@ -107,46 +105,54 @@ static mtime_t ClockToSysdate( input_thread_t * p_input,
*****************************************************************************
*****************************************************************************
* Caution : the synchro state must be SYNCHRO_OK for this to operate.
* Caution : the synchro state must be SYNCHRO_OK for this to operate.
*****************************************************************************/
*****************************************************************************/
static
mtime_t
ClockCurrent
(
input_thread_t
*
p_input
,
static
mtime_t
ClockCurrent
(
input_thread_t
*
p_input
,
pgrm_descriptor_t
*
p_pgrm
)
input_clock_t
*
cl
)
{
{
return
(
(
mdate
()
-
p_pgrm
->
sysdate_ref
)
*
27
*
DEFAULT_RATE
return
(
(
mdate
()
-
cl
->
sysdate_ref
)
*
27
*
INPUT_RATE_DEFAULT
/
p_input
->
stream
.
control
.
i_rate
/
300
/
p_input
->
i_rate
/
300
+
p_pgrm
->
cr_ref
);
+
cl
->
cr_ref
);
}
}
/*****************************************************************************
/*****************************************************************************
* ClockNewRef: writes a new clock reference
* ClockNewRef: writes a new clock reference
*****************************************************************************/
*****************************************************************************/
static
void
ClockNewRef
(
pgrm_descriptor_t
*
p_pgrm
,
static
void
ClockNewRef
(
input_clock_t
*
cl
,
mtime_t
i_clock
,
mtime_t
i_sysdate
)
mtime_t
i_clock
,
mtime_t
i_sysdate
)
{
{
p_pgrm
->
cr_ref
=
i_clock
;
cl
->
cr_ref
=
i_clock
;
p_pgrm
->
sysdate_ref
=
i_sysdate
;
cl
->
sysdate_ref
=
i_sysdate
;
}
}
/*****************************************************************************
/*****************************************************************************
* input_ClockInit: reinitializes the clock reference after a stream
* input_ClockInit: reinitializes the clock reference after a stream
* discontinuity
* discontinuity
*****************************************************************************/
*****************************************************************************/
void
input_ClockInit
(
pgrm_descriptor_t
*
p_pgrm
)
void
input_ClockInit
(
input_clock_t
*
cl
,
vlc_bool_t
b_master
,
int
i_cr_average
)
{
{
p_pgrm
->
last_cr
=
0
;
cl
->
i_synchro_state
=
SYNCHRO_START
;
p_pgrm
->
last_pts
=
0
;
p_pgrm
->
cr_ref
=
0
;
cl
->
last_cr
=
0
;
p_pgrm
->
sysdate_ref
=
0
;
cl
->
last_pts
=
0
;
p_pgrm
->
delta_cr
=
0
;
cl
->
cr_ref
=
0
;
p_pgrm
->
c_average_count
=
0
;
cl
->
sysdate_ref
=
0
;
cl
->
delta_cr
=
0
;
cl
->
c_average_count
=
0
;
cl
->
i_cr_average
=
i_cr_average
;
cl
->
b_master
=
b_master
;
}
}
#if 0
/*****************************************************************************
/*****************************************************************************
* input_ClockManageControl: handles the messages from the interface
* input_ClockManageControl: handles the messages from the interface
*****************************************************************************
*****************************************************************************
* Returns UNDEF_S if nothing happened, PAUSE_S if the stream was paused
* Returns UNDEF_S if nothing happened, PAUSE_S if the stream was paused
*****************************************************************************/
*****************************************************************************/
int input_ClockManageControl( input_thread_t * p_input,
int input_ClockManageControl( input_thread_t * p_input,
pgrm_descriptor_t
*
p_pgrm
,
mtime_t
i_clock
)
input_clock_t *cl
, mtime_t i_clock )
{
{
#if 0
vlc_value_t val;
vlc_value_t val;
int i_return_value = UNDEF_S;
int i_return_value = UNDEF_S;
...
@@ -221,36 +227,32 @@ int input_ClockManageControl( input_thread_t * p_input,
...
@@ -221,36 +227,32 @@ int input_ClockManageControl( input_thread_t * p_input,
vlc_mutex_unlock( &p_input->stream.stream_lock );
vlc_mutex_unlock( &p_input->stream.stream_lock );
return( i_return_value );
return( i_return_value );
#endif
return UNDEF_S;
}
}
#endif
/*****************************************************************************
/*****************************************************************************
* input_Clock
ManageRef
: manages a clock reference
* input_Clock
SetPCR
: manages a clock reference
*****************************************************************************/
*****************************************************************************/
void
input_Clock
ManageRef
(
input_thread_t
*
p_input
,
void
input_Clock
SetPCR
(
input_thread_t
*
p_input
,
pgrm_descriptor_t
*
p_pgrm
,
mtime_t
i_clock
)
input_clock_t
*
cl
,
mtime_t
i_clock
)
{
{
/* take selected program if none specified */
if
(
(
cl
->
i_synchro_state
!=
SYNCHRO_OK
)
||
if
(
!
p_pgrm
)
(
i_clock
==
0
&&
cl
->
last_cr
!=
0
)
)
{
p_pgrm
=
p_input
->
stream
.
p_selected_program
;
}
if
(
(
p_pgrm
->
i_synchro_state
!=
SYNCHRO_OK
)
||
(
i_clock
==
0
&&
p_pgrm
->
last_cr
!=
0
)
)
{
{
/* Feed synchro with a new reference point. */
/* Feed synchro with a new reference point. */
ClockNewRef
(
p_pgrm
,
i_clock
,
ClockNewRef
(
cl
,
i_clock
,
p_pgrm
->
last_pts
+
CR_MEAN_PTS_GAP
>
mdate
()
?
cl
->
last_pts
+
CR_MEAN_PTS_GAP
>
mdate
()
?
p_pgrm
->
last_pts
+
CR_MEAN_PTS_GAP
:
mdate
()
);
cl
->
last_pts
+
CR_MEAN_PTS_GAP
:
mdate
()
);
p_pgrm
->
i_synchro_state
=
SYNCHRO_OK
;
cl
->
i_synchro_state
=
SYNCHRO_OK
;
if
(
p_input
->
stream
.
b_pace_control
if
(
p_input
->
b_can_pace_control
&&
cl
->
b_master
)
&&
p_input
->
stream
.
p_selected_program
==
p_pgrm
)
{
{
p_pgrm
->
last_cr
=
i_clock
;
cl
->
last_cr
=
i_clock
;
if
(
!
p_input
->
b_out_pace_control
)
if
(
!
p_input
->
b_out_pace_control
)
{
{
mtime_t
i_wakeup
=
ClockToSysdate
(
p_input
,
p_pgrm
,
i_clock
);
mtime_t
i_wakeup
=
ClockToSysdate
(
p_input
,
cl
,
i_clock
);
while
(
(
i_wakeup
-
mdate
())
/
CLOCK_FREQ
>
1
)
while
(
(
i_wakeup
-
mdate
())
/
CLOCK_FREQ
>
1
)
{
{
msleep
(
CLOCK_FREQ
);
msleep
(
CLOCK_FREQ
);
...
@@ -261,37 +263,38 @@ void input_ClockManageRef( input_thread_t * p_input,
...
@@ -261,37 +263,38 @@ void input_ClockManageRef( input_thread_t * p_input,
}
}
else
else
{
{
p_pgrm
->
last_cr
=
0
;
cl
->
last_cr
=
0
;
p_pgrm
->
delta_cr
=
0
;
cl
->
delta_cr
=
0
;
p_pgrm
->
c_average_count
=
0
;
cl
->
c_average_count
=
0
;
}
}
}
}
else
else
{
{
if
(
p_pgrm
->
last_cr
!=
0
&&
if
(
cl
->
last_cr
!=
0
&&
(
(
p_pgrm
->
last_cr
-
i_clock
)
>
CR_MAX_GAP
(
(
cl
->
last_cr
-
i_clock
)
>
CR_MAX_GAP
||
(
p_pgrm
->
last_cr
-
i_clock
)
<
-
CR_MAX_GAP
)
)
||
(
cl
->
last_cr
-
i_clock
)
<
-
CR_MAX_GAP
)
)
{
{
/* Stream discontinuity, for which we haven't received a
/* Stream discontinuity, for which we haven't received a
* warning from the stream control facilities (dd-edited
* warning from the stream control facilities (dd-edited
* stream ?). */
* stream ?). */
msg_Warn
(
p_input
,
"clock gap, unexpected stream discontinuity"
);
msg_Warn
(
p_input
,
"clock gap, unexpected stream discontinuity"
);
input_ClockInit
(
p_pgrm
);
input_ClockInit
(
cl
,
cl
->
b_master
,
cl
->
i_cr_average
);
p_pgrm
->
i_synchro_state
=
SYNCHRO_START
;
/* FIXME needed ? */
#if 0
input_EscapeDiscontinuity( p_input );
input_EscapeDiscontinuity( p_input );
#endif
}
}
p_pgrm
->
last_cr
=
i_clock
;
cl
->
last_cr
=
i_clock
;
if
(
p_input
->
stream
.
b_pace_control
if
(
p_input
->
b_can_pace_control
&&
cl
->
b_master
)
&&
p_input
->
stream
.
p_selected_program
==
p_pgrm
)
{
{
/* Wait a while before delivering the packets to the decoder.
/* Wait a while before delivering the packets to the decoder.
* In case of multiple programs, we arbitrarily follow the
* In case of multiple programs, we arbitrarily follow the
* clock of the selected program. */
* clock of the selected program. */
if
(
!
p_input
->
b_out_pace_control
)
if
(
!
p_input
->
b_out_pace_control
)
{
{
mtime_t
i_wakeup
=
ClockToSysdate
(
p_input
,
p_pgrm
,
i_clock
);
mtime_t
i_wakeup
=
ClockToSysdate
(
p_input
,
cl
,
i_clock
);
while
(
(
i_wakeup
-
mdate
())
/
CLOCK_FREQ
>
1
)
while
(
(
i_wakeup
-
mdate
())
/
CLOCK_FREQ
>
1
)
{
{
msleep
(
CLOCK_FREQ
);
msleep
(
CLOCK_FREQ
);
...
@@ -299,30 +302,32 @@ void input_ClockManageRef( input_thread_t * p_input,
...
@@ -299,30 +302,32 @@ void input_ClockManageRef( input_thread_t * p_input,
}
}
mwait
(
i_wakeup
);
mwait
(
i_wakeup
);
}
}
/* FIXME Not needed anymore ? */
#if 0
/* Now take into account interface changes. */
/* Now take into account interface changes. */
input_ClockManageControl
(
p_input
,
p_pgrm
,
i_clock
);
input_ClockManageControl( p_input, cl, i_clock );
#endif
}
}
else
else
{
{
/* Smooth clock reference variations. */
/* Smooth clock reference variations. */
mtime_t
i_extrapoled_clock
=
ClockCurrent
(
p_input
,
p_pgrm
);
mtime_t
i_extrapoled_clock
=
ClockCurrent
(
p_input
,
cl
);
/* Bresenham algorithm to smooth variations. */
/* Bresenham algorithm to smooth variations. */
if
(
p_pgrm
->
c_average_count
==
p_input
->
i_cr_average
)
if
(
cl
->
c_average_count
==
cl
->
i_cr_average
)
{
{
p_pgrm
->
delta_cr
=
(
p_pgrm
->
delta_cr
cl
->
delta_cr
=
(
cl
->
delta_cr
*
(
p_input
->
i_cr_average
-
1
)
*
(
cl
->
i_cr_average
-
1
)
+
(
i_extrapoled_clock
-
i_clock
)
)
+
(
i_extrapoled_clock
-
i_clock
)
)
/
p_input
->
i_cr_average
;
/
cl
->
i_cr_average
;
}
}
else
else
{
{
p_pgrm
->
delta_cr
=
(
p_pgrm
->
delta_cr
cl
->
delta_cr
=
(
cl
->
delta_cr
*
p_pgrm
->
c_average_count
*
cl
->
c_average_count
+
(
i_extrapoled_clock
-
i_clock
)
)
+
(
i_extrapoled_clock
-
i_clock
)
)
/
(
p_pgrm
->
c_average_count
+
1
);
/
(
cl
->
c_average_count
+
1
);
p_pgrm
->
c_average_count
++
;
cl
->
c_average_count
++
;
}
}
}
}
}
}
...
@@ -332,23 +337,12 @@ void input_ClockManageRef( input_thread_t * p_input,
...
@@ -332,23 +337,12 @@ void input_ClockManageRef( input_thread_t * p_input,
* input_ClockGetTS: manages a PTS or DTS
* input_ClockGetTS: manages a PTS or DTS
*****************************************************************************/
*****************************************************************************/
mtime_t
input_ClockGetTS
(
input_thread_t
*
p_input
,
mtime_t
input_ClockGetTS
(
input_thread_t
*
p_input
,
pgrm_descriptor_t
*
p_pgrm
,
mtime_t
i_ts
)
input_clock_t
*
cl
,
mtime_t
i_ts
)
{
{
/* take selected program if none specified */
if
(
cl
->
i_synchro_state
!=
SYNCHRO_OK
)
if
(
!
p_pgrm
)
{
p_pgrm
=
p_input
->
stream
.
p_selected_program
;
}
if
(
p_pgrm
->
i_synchro_state
==
SYNCHRO_OK
)
{
p_pgrm
->
last_pts
=
ClockToSysdate
(
p_input
,
p_pgrm
,
i_ts
+
p_pgrm
->
delta_cr
);
return
(
p_pgrm
->
last_pts
+
p_input
->
i_pts_delay
);
}
else
{
return
0
;
return
0
;
}
cl
->
last_pts
=
ClockToSysdate
(
p_input
,
cl
,
i_ts
+
cl
->
delta_cr
);
return
cl
->
last_pts
+
p_input
->
i_pts_delay
;
}
}
src/input/control.c
View file @
68d21786
...
@@ -22,22 +22,12 @@
...
@@ -22,22 +22,12 @@
*****************************************************************************/
*****************************************************************************/
#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <vlc/vlc.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#include <vlc/input.h>
#include "input_internal.h"
#include "vlc_playlist.h"
#include "vlc_playlist.h"
#include "ninput.h"
#include "../../modules/demux/util/sub.h"
struct
input_thread_sys_t
{
/* subtitles */
int
i_sub
;
subtitle_demux_t
**
sub
;
int64_t
i_stop_time
;
};
static
void
UpdateBookmarksOption
(
input_thread_t
*
);
static
void
UpdateBookmarksOption
(
input_thread_t
*
);
...
@@ -64,7 +54,6 @@ int input_Control( input_thread_t *p_input, int i_query, ... )
...
@@ -64,7 +54,6 @@ int input_Control( input_thread_t *p_input, int i_query, ... )
int
input_vaControl
(
input_thread_t
*
p_input
,
int
i_query
,
va_list
args
)
int
input_vaControl
(
input_thread_t
*
p_input
,
int
i_query
,
va_list
args
)
{
{
int
i_ret
;
seekpoint_t
*
p_bkmk
,
***
ppp_bkmk
;
seekpoint_t
*
p_bkmk
,
***
ppp_bkmk
;
int
i_bkmk
=
0
;
int
i_bkmk
=
0
;
int
*
pi_bkmk
;
int
*
pi_bkmk
;
...
@@ -75,54 +64,50 @@ int input_vaControl( input_thread_t *p_input, int i_query, va_list args )
...
@@ -75,54 +64,50 @@ int input_vaControl( input_thread_t *p_input, int i_query, va_list args )
double
f
,
*
pf
;
double
f
,
*
pf
;
int64_t
i_64
,
*
pi_64
;
int64_t
i_64
,
*
pi_64
;
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
switch
(
i_query
)
switch
(
i_query
)
{
{
case
INPUT_GET_POSITION
:
case
INPUT_GET_POSITION
:
pf
=
(
double
*
)
va_arg
(
args
,
double
*
);
pf
=
(
double
*
)
va_arg
(
args
,
double
*
);
*
pf
=
var_GetFloat
(
p_input
,
"position"
);
*
pf
=
var_GetFloat
(
p_input
,
"position"
);
i_ret
=
VLC_SUCCESS
;
return
VLC_SUCCESS
;
break
;
case
INPUT_SET_POSITION
:
case
INPUT_SET_POSITION
:
f
=
(
double
)
va_arg
(
args
,
double
);
f
=
(
double
)
va_arg
(
args
,
double
);
i_ret
=
var_SetFloat
(
p_input
,
"position"
,
f
);
return
var_SetFloat
(
p_input
,
"position"
,
f
);
break
;
case
INPUT_GET_LENGTH
:
case
INPUT_GET_LENGTH
:
pi_64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
pi_64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
*
pi_64
=
var_GetTime
(
p_input
,
"length"
);
*
pi_64
=
var_GetTime
(
p_input
,
"length"
);
i_ret
=
VLC_SUCCESS
;
return
VLC_SUCCESS
;
break
;
case
INPUT_GET_TIME
:
case
INPUT_GET_TIME
:
pi_64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
pi_64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
*
pi_64
=
var_GetTime
(
p_input
,
"time"
);
*
pi_64
=
var_GetTime
(
p_input
,
"time"
);
i_ret
=
VLC_SUCCESS
;
return
VLC_SUCCESS
;
break
;
case
INPUT_SET_TIME
:
case
INPUT_SET_TIME
:
i_64
=
(
int64_t
)
va_arg
(
args
,
int64_t
);
i_64
=
(
int64_t
)
va_arg
(
args
,
int64_t
);
i_ret
=
var_SetTime
(
p_input
,
"time"
,
i_64
);
return
var_SetTime
(
p_input
,
"time"
,
i_64
);
break
;
case
INPUT_GET_RATE
:
case
INPUT_GET_RATE
:
pi_int
=
(
int
*
)
va_arg
(
args
,
int
*
);
pi_int
=
(
int
*
)
va_arg
(
args
,
int
*
);
*
pi_int
=
var_GetInteger
(
p_input
,
"rate"
);
*
pi_int
=
var_GetInteger
(
p_input
,
"rate"
);
i_ret
=
VLC_SUCCESS
;
return
VLC_SUCCESS
;
break
;
case
INPUT_SET_RATE
:
case
INPUT_SET_RATE
:
i_int
=
(
int
)
va_arg
(
args
,
int
);
i_int
=
(
int
)
va_arg
(
args
,
int
);
i_ret
=
var_SetInteger
(
p_input
,
"rate"
,
i_int
);
return
var_SetInteger
(
p_input
,
"rate"
,
i_int
);
break
;
case
INPUT_GET_STATE
:
case
INPUT_GET_STATE
:
pi_int
=
(
int
*
)
va_arg
(
args
,
int
*
);
pi_int
=
(
int
*
)
va_arg
(
args
,
int
*
);
*
pi_int
=
var_GetInteger
(
p_input
,
"state"
);
*
pi_int
=
var_GetInteger
(
p_input
,
"state"
);
i_ret
=
VLC_SUCCESS
;
return
VLC_SUCCESS
;
break
;
case
INPUT_SET_STATE
:
case
INPUT_SET_STATE
:
i_int
=
(
int
)
va_arg
(
args
,
int
);
i_int
=
(
int
)
va_arg
(
args
,
int
);
i_ret
=
var_SetInteger
(
p_input
,
"state"
,
i_int
);
return
var_SetInteger
(
p_input
,
"state"
,
i_int
);
break
;
#if 0
case INPUT_ADD_OPTION:
case INPUT_ADD_OPTION:
{
{
psz_option = (char *)va_arg( args, char * );
psz_option = (char *)va_arg( args, char * );
...
@@ -130,7 +115,7 @@ int input_vaControl( input_thread_t *p_input, int i_query, va_list args )
...
@@ -130,7 +115,7 @@ int input_vaControl( input_thread_t *p_input, int i_query, va_list args )
i_ret = VLC_EGENERIC;
i_ret = VLC_EGENERIC;
vlc_mutex_lock( &p_input->p_item->lock );
vlc_mutex_lock( &p_input->p_item->lock );
/* Check if option already exists */
/* Check if option already exists */
for( i = 0; i < p_input->p_item->i_options; i++ )
for( i = 0; i < p_input->p_item->i_options; i++ )
{
{
if( !strncmp( p_input->p_item->ppsz_options[i], psz_option,
if( !strncmp( p_input->p_item->ppsz_options[i], psz_option,
...
@@ -500,22 +485,33 @@ int input_vaControl( input_thread_t *p_input, int i_query, va_list args )
...
@@ -500,22 +485,33 @@ int input_vaControl( input_thread_t *p_input, int i_query, va_list args )
i_ret = VLC_EGENERIC;
i_ret = VLC_EGENERIC;
}
}
break;
break;
#endif
case
INPUT_GET_BOOKMARKS
:
case
INPUT_CLEAR_BOOKMARKS
:
case
INPUT_ADD_BOOKMARK
:
case
INPUT_CHANGE_BOOKMARK
:
case
INPUT_DEL_BOOKMARK
:
case
INPUT_SET_BOOKMARK
:
case
INPUT_ADD_OPTION
:
case
INPUT_ADD_INFO
:
case
INPUT_GET_INFO
:
case
INPUT_SET_NAME
:
case
INPUT_GET_SUBDELAY
:
case
INPUT_SET_SUBDELAY
:
/* FIXME */
msg_Err
(
p_input
,
"unimplemented query in input_vaControl"
);
default:
default:
msg_Err
(
p_input
,
"unknown query in input_vaControl"
);
msg_Err
(
p_input
,
"unknown query in input_vaControl"
);
i_ret
=
VLC_EGENERIC
;
return
VLC_EGENERIC
;
break
;
}
}
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
return
i_ret
;
}
}
static
void
UpdateBookmarksOption
(
input_thread_t
*
p_input
)
static
void
UpdateBookmarksOption
(
input_thread_t
*
p_input
)
{
{
int
i
,
i_len
=
0
;
int
i
,
i_len
=
0
;
char
*
psz_value
=
NULL
,
*
psz_next
=
NULL
;
char
*
psz_value
=
NULL
,
*
psz_next
=
NULL
;
/* FIXME */
#if 0
vlc_mutex_unlock( &p_input->stream.stream_lock );
vlc_mutex_unlock( &p_input->stream.stream_lock );
for( i = 0; i < p_input->i_bookmarks; i++ )
for( i = 0; i < p_input->i_bookmarks; i++ )
...
@@ -546,4 +542,5 @@ static void UpdateBookmarksOption( input_thread_t *p_input )
...
@@ -546,4 +542,5 @@ static void UpdateBookmarksOption( input_thread_t *p_input )
psz_value ? psz_value : "" );
psz_value ? psz_value : "" );
vlc_mutex_lock( &p_input->stream.stream_lock );
vlc_mutex_lock( &p_input->stream.stream_lock );
#endif
}
}
src/input/
input_dec
.c
→
src/input/
decoder
.c
View file @
68d21786
/*****************************************************************************
/*****************************************************************************
*
input_dec
.c: Functions for the management of decoders
*
decoder
.c: Functions for the management of decoders
*****************************************************************************
*****************************************************************************
* Copyright (C) 1999-2004 VideoLAN
* Copyright (C) 1999-2004 VideoLAN
* $Id$
* $Id$
*
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Gildas Bazin <gbazin@netcourrier.com>
* Gildas Bazin <gbazin@netcourrier.com>
* Laurent Aimar <fenrir@via.ecp.fr>
*
*
* This program is free software; you can redistribute it and/or modify
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* it under the terms of the GNU General Public License as published by
...
@@ -26,25 +27,20 @@
...
@@ -26,25 +27,20 @@
* Preamble
* Preamble
*****************************************************************************/
*****************************************************************************/
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
/* memcpy(), memset() */
#include <vlc/vlc.h>
#include <vlc/vlc.h>
#include <vlc/decoder.h>
#include <vlc/decoder.h>
#include <vlc/vout.h>
#include <vlc/vout.h>
#include <vlc/input.h>
#include "stream_output.h"
#include "stream_output.h"
#include "input_internal.h"
#include "input_ext-intf.h"
static
decoder_t
*
CreateDecoder
(
input_thread_t
*
,
es_format_t
*
,
int
);
#include "input_ext-plugins.h"
static
void
DeleteDecoder
(
decoder_t
*
);
#include "codecs.h"
static
void
input_NullPacket
(
input_thread_t
*
,
es_descriptor_t
*
);
static
decoder_t
*
CreateDecoder
(
input_thread_t
*
,
es_descriptor_t
*
,
int
);
static
int
DecoderThread
(
decoder_t
*
);
static
int
DecoderThread
(
decoder_t
*
);
static
int
DecoderDecode
(
decoder_t
*
p_dec
,
block_t
*
p_block
);
static
int
DecoderDecode
(
decoder_t
*
p_dec
,
block_t
*
p_block
);
static
void
DeleteDecoder
(
decoder_t
*
);
/* Buffers allocation callbacks for the decoders */
/* Buffers allocation callbacks for the decoders */
static
aout_buffer_t
*
aout_new_buffer
(
decoder_t
*
,
int
);
static
aout_buffer_t
*
aout_new_buffer
(
decoder_t
*
,
int
);
...
@@ -81,10 +77,6 @@ struct decoder_owner_sys_t
...
@@ -81,10 +77,6 @@ struct decoder_owner_sys_t
/* fifo */
/* fifo */
block_fifo_t
*
p_fifo
;
block_fifo_t
*
p_fifo
;
/* */
input_buffers_t
*
p_method_data
;
es_descriptor_t
*
p_es_descriptor
;
};
};
...
@@ -95,16 +87,17 @@ struct decoder_owner_sys_t
...
@@ -95,16 +87,17 @@ struct decoder_owner_sys_t
* \param p_es the es descriptor
* \param p_es the es descriptor
* \return the spawned decoder object
* \return the spawned decoder object
*/
*/
decoder_t
*
input_RunDecoder
(
input_thread_t
*
p_input
,
es_descriptor_t
*
p_es
)
decoder_t
*
input_DecoderNew
(
input_thread_t
*
p_input
,
es_format_t
*
fmt
,
vlc_bool_t
b_force_decoder
)
{
{
decoder_t
*
p_dec
=
NULL
;
decoder_t
*
p_dec
=
NULL
;
vlc_value_t
val
;
vlc_value_t
val
;
/* If we are in sout mode, search for packetizer module */
/* If we are in sout mode, search for packetizer module */
if
(
!
p_es
->
b_force_decoder
&&
p_input
->
stream
.
p_sout
)
if
(
p_input
->
p_sout
&&
!
b_force_decoder
)
{
{
/* Create the decoder configuration structure */
/* Create the decoder configuration structure */
p_dec
=
CreateDecoder
(
p_input
,
p_es
,
VLC_OBJECT_PACKETIZER
);
p_dec
=
CreateDecoder
(
p_input
,
fmt
,
VLC_OBJECT_PACKETIZER
);
if
(
p_dec
==
NULL
)
if
(
p_dec
==
NULL
)
{
{
msg_Err
(
p_input
,
"could not create packetizer"
);
msg_Err
(
p_input
,
"could not create packetizer"
);
...
@@ -114,7 +107,7 @@ decoder_t * input_RunDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
...
@@ -114,7 +107,7 @@ decoder_t * input_RunDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
else
else
{
{
/* Create the decoder configuration structure */
/* Create the decoder configuration structure */
p_dec
=
CreateDecoder
(
p_input
,
p_es
,
VLC_OBJECT_DECODER
);
p_dec
=
CreateDecoder
(
p_input
,
fmt
,
VLC_OBJECT_DECODER
);
if
(
p_dec
==
NULL
)
if
(
p_dec
==
NULL
)
{
{
msg_Err
(
p_input
,
"could not create decoder"
);
msg_Err
(
p_input
,
"could not create decoder"
);
...
@@ -133,7 +126,8 @@ decoder_t * input_RunDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
...
@@ -133,7 +126,8 @@ decoder_t * input_RunDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
return
NULL
;
return
NULL
;
}
}
if
(
!
p_es
->
b_force_decoder
&&
p_input
->
stream
.
p_sout
&&
p_input
->
stream
.
b_pace_control
)
if
(
p_input
->
p_sout
&&
p_input
->
input
.
b_can_pace_control
&&
!
b_force_decoder
)
{
{
msg_Dbg
(
p_input
,
"stream out mode -> no decoder thread"
);
msg_Dbg
(
p_input
,
"stream out mode -> no decoder thread"
);
p_dec
->
p_owner
->
b_own_thread
=
VLC_FALSE
;
p_dec
->
p_owner
->
b_own_thread
=
VLC_FALSE
;
...
@@ -147,14 +141,10 @@ decoder_t * input_RunDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
...
@@ -147,14 +141,10 @@ decoder_t * input_RunDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
if
(
p_dec
->
p_owner
->
b_own_thread
)
if
(
p_dec
->
p_owner
->
b_own_thread
)
{
{
int
i_priority
;
int
i_priority
;
if
(
p_es
->
i_cat
==
AUDIO_ES
)
if
(
fmt
->
i_cat
==
AUDIO_ES
)
{
i_priority
=
VLC_THREAD_PRIORITY_AUDIO
;
i_priority
=
VLC_THREAD_PRIORITY_AUDIO
;
}
else
else
{
i_priority
=
VLC_THREAD_PRIORITY_VIDEO
;
i_priority
=
VLC_THREAD_PRIORITY_VIDEO
;
}
/* Spawn the decoder thread */
/* Spawn the decoder thread */
if
(
vlc_thread_create
(
p_dec
,
"decoder"
,
DecoderThread
,
if
(
vlc_thread_create
(
p_dec
,
"decoder"
,
DecoderThread
,
...
@@ -169,14 +159,6 @@ decoder_t * input_RunDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
...
@@ -169,14 +159,6 @@ decoder_t * input_RunDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
}
}
}
}
/* Select a new ES */
INSERT_ELEM
(
p_input
->
stream
.
pp_selected_es
,
p_input
->
stream
.
i_selected_es_number
,
p_input
->
stream
.
i_selected_es_number
,
p_es
);
p_input
->
stream
.
b_changed
=
1
;
return
p_dec
;
return
p_dec
;
}
}
...
@@ -187,10 +169,8 @@ decoder_t * input_RunDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
...
@@ -187,10 +169,8 @@ decoder_t * input_RunDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
* \param p_es the es descriptor
* \param p_es the es descriptor
* \return nothing
* \return nothing
*/
*/
void
input_
EndDecoder
(
input_thread_t
*
p_input
,
es_descriptor_t
*
p_es
)
void
input_
DecoderDelete
(
decoder_t
*
p_dec
)
{
{
decoder_t
*
p_dec
=
p_es
->
p_dec
;
p_dec
->
b_die
=
VLC_TRUE
;
p_dec
->
b_die
=
VLC_TRUE
;
if
(
p_dec
->
p_owner
->
b_own_thread
)
if
(
p_dec
->
p_owner
->
b_own_thread
)
...
@@ -198,7 +178,7 @@ void input_EndDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
...
@@ -198,7 +178,7 @@ void input_EndDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
/* Make sure the thread leaves the function by
/* Make sure the thread leaves the function by
* sending it an empty block. */
* sending it an empty block. */
block_t
*
p_block
=
block_New
(
p_dec
,
0
);
block_t
*
p_block
=
block_New
(
p_dec
,
0
);
input_Decode
Block
(
p_dec
,
p_block
);
input_Decode
rDecode
(
p_dec
,
p_block
);
vlc_thread_join
(
p_dec
);
vlc_thread_join
(
p_dec
);
...
@@ -215,55 +195,6 @@ void input_EndDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
...
@@ -215,55 +195,6 @@ void input_EndDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
/* Delete the decoder */
/* Delete the decoder */
vlc_object_destroy
(
p_dec
);
vlc_object_destroy
(
p_dec
);
/* Tell the input there is no more decoder */
p_es
->
p_dec
=
NULL
;
p_input
->
stream
.
b_changed
=
1
;
}
/**
* Put a PES in the decoder's fifo.
*
* \param p_dec the decoder object
* \param p_pes the pes packet
* \return nothing
*/
void
input_DecodePES
(
decoder_t
*
p_dec
,
pes_packet_t
*
p_pes
)
{
data_packet_t
*
p_data
;
int
i_size
=
0
;
for
(
p_data
=
p_pes
->
p_first
;
p_data
!=
NULL
;
p_data
=
p_data
->
p_next
)
{
i_size
+=
p_data
->
p_payload_end
-
p_data
->
p_payload_start
;
}
if
(
i_size
>
0
)
{
block_t
*
p_block
=
block_New
(
p_dec
,
i_size
);
if
(
p_block
)
{
uint8_t
*
p_buffer
=
p_block
->
p_buffer
;
for
(
p_data
=
p_pes
->
p_first
;
p_data
;
p_data
=
p_data
->
p_next
)
{
int
i_copy
=
p_data
->
p_payload_end
-
p_data
->
p_payload_start
;
memcpy
(
p_buffer
,
p_data
->
p_payload_start
,
i_copy
);
p_buffer
+=
i_copy
;
}
p_block
->
i_pts
=
p_pes
->
i_pts
;
p_block
->
i_dts
=
p_pes
->
i_dts
;
if
(
p_pes
->
b_discontinuity
)
p_block
->
i_flags
|=
BLOCK_FLAG_DISCONTINUITY
;
p_block
->
i_rate
=
p_pes
->
i_rate
;
input_DecodeBlock
(
p_dec
,
p_block
);
}
}
input_DeletePES
(
p_dec
->
p_owner
->
p_method_data
,
p_pes
);
}
}
/**
/**
...
@@ -272,7 +203,7 @@ void input_DecodePES( decoder_t * p_dec, pes_packet_t * p_pes )
...
@@ -272,7 +203,7 @@ void input_DecodePES( decoder_t * p_dec, pes_packet_t * p_pes )
* \param p_dec the decoder object
* \param p_dec the decoder object
* \param p_block the data block
* \param p_block the data block
*/
*/
void
input_Decode
Block
(
decoder_t
*
p_dec
,
block_t
*
p_block
)
void
input_Decode
rDecode
(
decoder_t
*
p_dec
,
block_t
*
p_block
)
{
{
if
(
p_dec
->
p_owner
->
b_own_thread
)
if
(
p_dec
->
p_owner
->
b_own_thread
)
{
{
...
@@ -301,6 +232,25 @@ void input_DecodeBlock( decoder_t * p_dec, block_t *p_block )
...
@@ -301,6 +232,25 @@ void input_DecodeBlock( decoder_t * p_dec, block_t *p_block )
}
}
}
}
void
input_DecoderDiscontinuity
(
decoder_t
*
p_dec
)
{
block_t
*
p_null
;
/* Empty the fifo */
if
(
p_dec
->
p_owner
->
b_own_thread
)
{
block_FifoEmpty
(
p_dec
->
p_owner
->
p_fifo
);
}
/* Send a special block */
p_null
=
block_New
(
p_dec
,
128
);
p_null
->
i_flags
|=
BLOCK_FLAG_DISCONTINUITY
;
memset
(
p_null
->
p_buffer
,
0
,
p_null
->
i_buffer
);
input_DecoderDecode
(
p_dec
,
p_null
);
}
#if 0
/**
/**
* Create a NULL packet for padding in case of a data loss
* Create a NULL packet for padding in case of a data loss
*
*
...
@@ -311,6 +261,7 @@ void input_DecodeBlock( decoder_t * p_dec, block_t *p_block )
...
@@ -311,6 +261,7 @@ void input_DecodeBlock( decoder_t * p_dec, block_t *p_block )
static void input_NullPacket( input_thread_t * p_input,
static void input_NullPacket( input_thread_t * p_input,
es_descriptor_t * p_es )
es_descriptor_t * p_es )
{
{
#if 0
block_t *p_block = block_New( p_input, PADDING_PACKET_SIZE );
block_t *p_block = block_New( p_input, PADDING_PACKET_SIZE );
if( p_block )
if( p_block )
{
{
...
@@ -319,6 +270,7 @@ static void input_NullPacket( input_thread_t * p_input,
...
@@ -319,6 +270,7 @@ static void input_NullPacket( input_thread_t * p_input,
block_FifoPut( p_es->p_dec->p_owner->p_fifo, p_block );
block_FifoPut( p_es->p_dec->p_owner->p_fifo, p_block );
}
}
#endif
}
}
/**
/**
...
@@ -329,6 +281,7 @@ static void input_NullPacket( input_thread_t * p_input,
...
@@ -329,6 +281,7 @@ static void input_NullPacket( input_thread_t * p_input,
*/
*/
void input_EscapeDiscontinuity( input_thread_t * p_input )
void input_EscapeDiscontinuity( input_thread_t * p_input )
{
{
#if 0
unsigned int i_es, i;
unsigned int i_es, i;
for( i_es = 0; i_es < p_input->stream.i_selected_es_number; i_es++ )
for( i_es = 0; i_es < p_input->stream.i_selected_es_number; i_es++ )
...
@@ -343,6 +296,7 @@ void input_EscapeDiscontinuity( input_thread_t * p_input )
...
@@ -343,6 +296,7 @@ void input_EscapeDiscontinuity( input_thread_t * p_input )
}
}
}
}
}
}
#endif
}
}
/**
/**
...
@@ -353,6 +307,7 @@ void input_EscapeDiscontinuity( input_thread_t * p_input )
...
@@ -353,6 +307,7 @@ void input_EscapeDiscontinuity( input_thread_t * p_input )
*/
*/
void input_EscapeAudioDiscontinuity( input_thread_t * p_input )
void input_EscapeAudioDiscontinuity( input_thread_t * p_input )
{
{
#if 0
unsigned int i_es, i;
unsigned int i_es, i;
for( i_es = 0; i_es < p_input->stream.i_selected_es_number; i_es++ )
for( i_es = 0; i_es < p_input->stream.i_selected_es_number; i_es++ )
...
@@ -367,7 +322,9 @@ void input_EscapeAudioDiscontinuity( input_thread_t * p_input )
...
@@ -367,7 +322,9 @@ void input_EscapeAudioDiscontinuity( input_thread_t * p_input )
}
}
}
}
}
}
#endif
}
}
#endif
/**
/**
* Create a decoder object
* Create a decoder object
...
@@ -377,8 +334,8 @@ void input_EscapeAudioDiscontinuity( input_thread_t * p_input )
...
@@ -377,8 +334,8 @@ void input_EscapeAudioDiscontinuity( input_thread_t * p_input )
* \param i_object_type Object type as define in include/vlc_objects.h
* \param i_object_type Object type as define in include/vlc_objects.h
* \return the decoder object
* \return the decoder object
*/
*/
static
decoder_t
*
CreateDecoder
(
input_thread_t
*
p_input
,
static
decoder_t
*
CreateDecoder
(
input_thread_t
*
p_input
,
es_
descriptor_t
*
p_es
,
int
i_object_type
)
es_
format_t
*
fmt
,
int
i_object_type
)
{
{
decoder_t
*
p_dec
;
decoder_t
*
p_dec
;
...
@@ -397,67 +354,12 @@ static decoder_t * CreateDecoder( input_thread_t * p_input,
...
@@ -397,67 +354,12 @@ static decoder_t * CreateDecoder( input_thread_t * p_input,
/* Initialize the decoder fifo */
/* Initialize the decoder fifo */
p_dec
->
p_module
=
NULL
;
p_dec
->
p_module
=
NULL
;
es_format_Copy
(
&
p_dec
->
fmt_in
,
&
p_es
->
fmt
);
if
(
p_es
->
p_waveformatex
)
es_format_Copy
(
&
p_dec
->
fmt_in
,
fmt
);
{
es_format_Copy
(
&
p_dec
->
fmt_out
,
&
null_es_format
);
#define p_wf ((WAVEFORMATEX *)p_es->p_waveformatex)
p_dec
->
fmt_in
.
audio
.
i_channels
=
p_wf
->
nChannels
;
p_dec
->
fmt_in
.
audio
.
i_rate
=
p_wf
->
nSamplesPerSec
;
p_dec
->
fmt_in
.
i_bitrate
=
p_wf
->
nAvgBytesPerSec
*
8
;
p_dec
->
fmt_in
.
audio
.
i_blockalign
=
p_wf
->
nBlockAlign
;
p_dec
->
fmt_in
.
audio
.
i_bitspersample
=
p_wf
->
wBitsPerSample
;
p_dec
->
fmt_in
.
i_extra
=
p_wf
->
cbSize
;
p_dec
->
fmt_in
.
p_extra
=
NULL
;
if
(
p_wf
->
cbSize
)
{
p_dec
->
fmt_in
.
p_extra
=
malloc
(
p_wf
->
cbSize
);
memcpy
(
p_dec
->
fmt_in
.
p_extra
,
&
p_wf
[
1
],
p_wf
->
cbSize
);
}
}
if
(
p_es
->
p_bitmapinfoheader
)
{
#define p_bih ((BITMAPINFOHEADER *) p_es->p_bitmapinfoheader)
p_dec
->
fmt_in
.
i_extra
=
p_bih
->
biSize
-
sizeof
(
BITMAPINFOHEADER
);
p_dec
->
fmt_in
.
p_extra
=
NULL
;
if
(
p_dec
->
fmt_in
.
i_extra
)
{
p_dec
->
fmt_in
.
p_extra
=
malloc
(
p_dec
->
fmt_in
.
i_extra
);
memcpy
(
p_dec
->
fmt_in
.
p_extra
,
&
p_bih
[
1
],
p_dec
->
fmt_in
.
i_extra
);
}
p_dec
->
fmt_in
.
video
.
i_width
=
p_bih
->
biWidth
;
p_dec
->
fmt_in
.
video
.
i_height
=
p_bih
->
biHeight
;
}
/* FIXME
* - 1: beurk
* - 2: I'm not sure there isn't any endian problem here (spu)... */
if
(
p_es
->
i_cat
==
SPU_ES
&&
p_es
->
p_demux_data
)
{
if
(
(
p_es
->
i_fourcc
==
VLC_FOURCC
(
's'
,
'p'
,
'u'
,
' '
)
||
p_es
->
i_fourcc
==
VLC_FOURCC
(
's'
,
'p'
,
'u'
,
'b'
)
)
&&
*
((
uint32_t
*
)
p_es
->
p_demux_data
)
==
0xBeef
)
{
memcpy
(
p_dec
->
fmt_in
.
subs
.
spu
.
palette
,
p_es
->
p_demux_data
,
17
*
4
);
}
else
if
(
p_es
->
i_fourcc
==
VLC_FOURCC
(
'd'
,
'v'
,
'b'
,
's'
)
&&
p_es
->
p_spuinfo
)
{
dvb_spuinfo_t
*
p_dvbs
=
(
dvb_spuinfo_t
*
)
p_es
->
p_spuinfo
;
p_dec
->
fmt_in
.
subs
.
dvb
.
i_id
=
p_dvbs
->
i_id
;
}
}
p_dec
->
fmt_in
.
i_cat
=
p_es
->
i_cat
;
p_dec
->
fmt_in
.
i_codec
=
p_es
->
i_fourcc
;
p_dec
->
fmt_out
=
null_es_format
;
/* Allocate our private structure for the decoder */
/* Allocate our private structure for the decoder */
p_dec
->
p_owner
=
(
decoder_owner_sys_t
*
)
malloc
(
sizeof
(
decoder_owner_sys_t
)
);
p_dec
->
p_owner
=
malloc
(
sizeof
(
decoder_owner_sys_t
)
);
if
(
p_dec
->
p_owner
==
NULL
)
if
(
p_dec
->
p_owner
==
NULL
)
{
{
msg_Err
(
p_dec
,
"out of memory"
);
msg_Err
(
p_dec
,
"out of memory"
);
...
@@ -468,10 +370,9 @@ static decoder_t * CreateDecoder( input_thread_t * p_input,
...
@@ -468,10 +370,9 @@ static decoder_t * CreateDecoder( input_thread_t * p_input,
p_dec
->
p_owner
->
p_aout
=
NULL
;
p_dec
->
p_owner
->
p_aout
=
NULL
;
p_dec
->
p_owner
->
p_aout_input
=
NULL
;
p_dec
->
p_owner
->
p_aout_input
=
NULL
;
p_dec
->
p_owner
->
p_vout
=
NULL
;
p_dec
->
p_owner
->
p_vout
=
NULL
;
p_dec
->
p_owner
->
p_sout
=
p_input
->
stream
.
p_sout
;
p_dec
->
p_owner
->
p_sout
=
p_input
->
p_sout
;
p_dec
->
p_owner
->
p_sout_input
=
NULL
;
p_dec
->
p_owner
->
p_sout_input
=
NULL
;
p_dec
->
p_owner
->
p_packetizer
=
NULL
;
p_dec
->
p_owner
->
p_packetizer
=
NULL
;
p_dec
->
p_owner
->
p_es_descriptor
=
p_es
;
/* decoder fifo */
/* decoder fifo */
...
@@ -480,8 +381,6 @@ static decoder_t * CreateDecoder( input_thread_t * p_input,
...
@@ -480,8 +381,6 @@ static decoder_t * CreateDecoder( input_thread_t * p_input,
msg_Err
(
p_dec
,
"out of memory"
);
msg_Err
(
p_dec
,
"out of memory"
);
return
NULL
;
return
NULL
;
}
}
p_dec
->
p_owner
->
p_method_data
=
p_input
->
p_method_data
;
/* Set buffers allocation callbacks for the decoders */
/* Set buffers allocation callbacks for the decoders */
p_dec
->
pf_aout_buffer_new
=
aout_new_buffer
;
p_dec
->
pf_aout_buffer_new
=
aout_new_buffer
;
p_dec
->
pf_aout_buffer_del
=
aout_del_buffer
;
p_dec
->
pf_aout_buffer_del
=
aout_del_buffer
;
...
@@ -506,11 +405,12 @@ static decoder_t * CreateDecoder( input_thread_t * p_input,
...
@@ -506,11 +405,12 @@ static decoder_t * CreateDecoder( input_thread_t * p_input,
vlc_object_create
(
p_input
,
VLC_OBJECT_PACKETIZER
);
vlc_object_create
(
p_input
,
VLC_OBJECT_PACKETIZER
);
if
(
p_dec
->
p_owner
->
p_packetizer
)
if
(
p_dec
->
p_owner
->
p_packetizer
)
{
{
p_dec
->
p_owner
->
p_packetizer
->
fmt_in
=
null_es_format
;
p_dec
->
p_owner
->
p_packetizer
->
fmt_out
=
null_es_format
;
es_format_Copy
(
&
p_dec
->
p_owner
->
p_packetizer
->
fmt_in
,
es_format_Copy
(
&
p_dec
->
p_owner
->
p_packetizer
->
fmt_in
,
&
p_dec
->
fmt_in
);
&
p_dec
->
fmt_in
);
es_format_Copy
(
&
p_dec
->
p_owner
->
p_packetizer
->
fmt_out
,
&
null_es_format
);
vlc_object_attach
(
p_dec
->
p_owner
->
p_packetizer
,
p_input
);
vlc_object_attach
(
p_dec
->
p_owner
->
p_packetizer
,
p_input
);
p_dec
->
p_owner
->
p_packetizer
->
p_module
=
p_dec
->
p_owner
->
p_packetizer
->
p_module
=
...
@@ -591,13 +491,9 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
...
@@ -591,13 +491,9 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
if
(
!
p_dec
->
p_owner
->
p_sout_input
)
if
(
!
p_dec
->
p_owner
->
p_sout_input
)
{
{
es_format_Copy
(
&
p_dec
->
p_owner
->
sout
,
&
p_dec
->
fmt_out
);
es_format_Copy
(
&
p_dec
->
p_owner
->
sout
,
&
p_dec
->
fmt_out
);
if
(
p_dec
->
p_owner
->
p_es_descriptor
->
p_pgrm
)
{
p_dec
->
p_owner
->
sout
.
i_group
=
p_dec
->
fmt_in
.
i_group
;
p_dec
->
p_owner
->
sout
.
i_group
=
p_dec
->
p_owner
->
sout
.
i_id
=
p_dec
->
fmt_in
.
i_id
;
p_dec
->
p_owner
->
p_es_descriptor
->
p_pgrm
->
i_number
;
}
p_dec
->
p_owner
->
sout
.
i_id
=
p_dec
->
p_owner
->
p_es_descriptor
->
i_id
-
1
;
if
(
p_dec
->
fmt_in
.
psz_language
)
if
(
p_dec
->
fmt_in
.
psz_language
)
{
{
p_dec
->
p_owner
->
sout
.
psz_language
=
p_dec
->
p_owner
->
sout
.
psz_language
=
...
...
src/input/demux.c
View file @
68d21786
...
@@ -25,148 +25,11 @@
...
@@ -25,148 +25,11 @@
#include <vlc/vlc.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#include <vlc/input.h>
#include "ninput.h"
#include "input_internal.h"
int
demux_vaControl
(
input_thread_t
*
p_input
,
int
i_query
,
va_list
args
)
{
if
(
p_input
->
pf_demux_control
)
{
return
p_input
->
pf_demux_control
(
p_input
,
i_query
,
args
);
}
return
VLC_EGENERIC
;
}
int
demux_Control
(
input_thread_t
*
p_input
,
int
i_query
,
...
)
{
va_list
args
;
int
i_result
;
va_start
(
args
,
i_query
);
i_result
=
demux_vaControl
(
p_input
,
i_query
,
args
);
va_end
(
args
);
return
i_result
;
}
static
void
SeekOffset
(
input_thread_t
*
p_input
,
int64_t
i_pos
);
int
demux_vaControlDefault
(
input_thread_t
*
p_input
,
int
i_query
,
va_list
args
)
{
int
i_ret
;
double
f
,
*
pf
;
int64_t
i64
,
*
pi64
;
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
switch
(
i_query
)
{
case
DEMUX_GET_POSITION
:
pf
=
(
double
*
)
va_arg
(
args
,
double
*
);
if
(
p_input
->
stream
.
p_selected_area
->
i_size
<=
0
)
{
*
pf
=
0
.
0
;
}
else
{
*
pf
=
(
double
)
p_input
->
stream
.
p_selected_area
->
i_tell
/
(
double
)
p_input
->
stream
.
p_selected_area
->
i_size
;
}
i_ret
=
VLC_SUCCESS
;
break
;
case
DEMUX_SET_POSITION
:
f
=
(
double
)
va_arg
(
args
,
double
);
if
(
p_input
->
stream
.
b_seekable
&&
p_input
->
pf_seek
!=
NULL
&&
f
>=
0
.
0
&&
f
<=
1
.
0
)
{
SeekOffset
(
p_input
,
(
int64_t
)(
f
*
(
double
)
p_input
->
stream
.
p_selected_area
->
i_size
)
);
i_ret
=
VLC_SUCCESS
;
}
else
{
i_ret
=
VLC_EGENERIC
;
}
break
;
case
DEMUX_GET_TIME
:
pi64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
if
(
p_input
->
stream
.
i_mux_rate
>
0
)
{
*
pi64
=
(
int64_t
)
1000000
*
(
p_input
->
stream
.
p_selected_area
->
i_tell
/
50
)
/
p_input
->
stream
.
i_mux_rate
;
i_ret
=
VLC_SUCCESS
;
}
else
{
*
pi64
=
0
;
i_ret
=
VLC_EGENERIC
;
}
break
;
case
DEMUX_SET_TIME
:
i64
=
(
int64_t
)
va_arg
(
args
,
int64_t
);
if
(
p_input
->
stream
.
i_mux_rate
>
0
&&
p_input
->
stream
.
b_seekable
&&
p_input
->
pf_seek
!=
NULL
&&
i64
>=
0
)
{
SeekOffset
(
p_input
,
i64
*
50
*
(
int64_t
)
p_input
->
stream
.
i_mux_rate
/
(
int64_t
)
1000000
);
i_ret
=
VLC_SUCCESS
;
}
else
{
i_ret
=
VLC_EGENERIC
;
}
break
;
case
DEMUX_GET_LENGTH
:
pi64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
if
(
p_input
->
stream
.
i_mux_rate
>
0
)
{
*
pi64
=
(
int64_t
)
1000000
*
(
p_input
->
stream
.
p_selected_area
->
i_size
/
50
)
/
p_input
->
stream
.
i_mux_rate
;
i_ret
=
VLC_SUCCESS
;
}
else
{
*
pi64
=
0
;
i_ret
=
VLC_EGENERIC
;
}
break
;
case
DEMUX_GET_FPS
:
i_ret
=
VLC_EGENERIC
;
break
;
case
DEMUX_GET_META
:
i_ret
=
VLC_EGENERIC
;
break
;
default:
msg_Err
(
p_input
,
"unknown query in demux_vaControlDefault"
);
i_ret
=
VLC_EGENERIC
;
break
;
}
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
return
i_ret
;
}
static
void
SeekOffset
(
input_thread_t
*
p_input
,
int64_t
i_pos
)
{
/* Reinitialize buffer manager. */
input_AccessReinit
(
p_input
);
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
p_input
->
pf_seek
(
p_input
,
i_pos
);
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
}
/*****************************************************************************
/*****************************************************************************
* demux2_New:
* demux2_New:
* if s is NULL then load a access_demux
*****************************************************************************/
*****************************************************************************/
demux_t
*
__demux2_New
(
vlc_object_t
*
p_obj
,
demux_t
*
__demux2_New
(
vlc_object_t
*
p_obj
,
char
*
psz_access
,
char
*
psz_demux
,
char
*
psz_path
,
char
*
psz_access
,
char
*
psz_demux
,
char
*
psz_path
,
...
@@ -198,8 +61,12 @@ demux_t *__demux2_New( vlc_object_t *p_obj,
...
@@ -198,8 +61,12 @@ demux_t *__demux2_New( vlc_object_t *p_obj,
p_demux
->
info
.
i_title
=
0
;
p_demux
->
info
.
i_title
=
0
;
p_demux
->
info
.
i_seekpoint
=
0
;
p_demux
->
info
.
i_seekpoint
=
0
;
psz_module
=
p_demux
->
psz_demux
;
if
(
s
)
if
(
*
psz_module
==
'\0'
&&
strrchr
(
p_demux
->
psz_path
,
'.'
)
)
psz_module
=
p_demux
->
psz_demux
;
else
psz_module
=
p_demux
->
psz_access
;
if
(
s
&&
*
psz_module
==
'\0'
&&
strrchr
(
p_demux
->
psz_path
,
'.'
)
)
{
{
/* XXX: add only file without any problem here and with strong detection.
/* XXX: add only file without any problem here and with strong detection.
* - no .mp3, .a52, ... (aac is added as it works only by file ext anyway
* - no .mp3, .a52, ... (aac is added as it works only by file ext anyway
...
@@ -241,9 +108,18 @@ demux_t *__demux2_New( vlc_object_t *p_obj,
...
@@ -241,9 +108,18 @@ demux_t *__demux2_New( vlc_object_t *p_obj,
/* Before module_Need (for var_Create...) */
/* Before module_Need (for var_Create...) */
vlc_object_attach
(
p_demux
,
p_obj
);
vlc_object_attach
(
p_demux
,
p_obj
);
p_demux
->
p_module
=
if
(
s
)
module_Need
(
p_demux
,
"demux2"
,
psz_module
,
{
!
strcmp
(
psz_module
,
p_demux
->
psz_demux
)
?
VLC_TRUE
:
VLC_FALSE
);
p_demux
->
p_module
=
module_Need
(
p_demux
,
"demux2"
,
psz_module
,
!
strcmp
(
psz_module
,
p_demux
->
psz_demux
)
?
VLC_TRUE
:
VLC_FALSE
);
}
else
{
p_demux
->
p_module
=
module_Need
(
p_demux
,
"access_demux"
,
psz_module
,
!
strcmp
(
psz_module
,
p_demux
->
psz_access
)
?
VLC_TRUE
:
VLC_FALSE
);
}
if
(
p_demux
->
p_module
==
NULL
)
if
(
p_demux
->
p_module
==
NULL
)
{
{
...
@@ -358,3 +234,263 @@ int demux2_vaControlHelper( stream_t *s,
...
@@ -358,3 +234,263 @@ int demux2_vaControlHelper( stream_t *s,
}
}
}
}
/****************************************************************************
* stream_Demux*: create a demuxer for an outpout stream (allow demuxer chain)
****************************************************************************/
typedef
struct
{
/* Data buffer */
vlc_mutex_t
lock
;
int
i_buffer
;
int
i_buffer_size
;
uint8_t
*
p_buffer
;
int64_t
i_pos
;
/* Demuxer */
char
*
psz_name
;
es_out_t
*
out
;
demux_t
*
p_demux
;
}
d_stream_sys_t
;
static
int
DStreamRead
(
stream_t
*
,
void
*
p_read
,
int
i_read
);
static
int
DStreamPeek
(
stream_t
*
,
uint8_t
**
pp_peek
,
int
i_peek
);
static
int
DStreamControl
(
stream_t
*
,
int
i_query
,
va_list
);
static
int
DStreamThread
(
stream_t
*
);
stream_t
*
__stream_DemuxNew
(
vlc_object_t
*
p_obj
,
char
*
psz_demux
,
es_out_t
*
out
)
{
/* We create a stream reader, and launch a thread */
stream_t
*
s
;
d_stream_sys_t
*
p_sys
;
if
(
psz_demux
==
NULL
||
*
psz_demux
==
'\0'
)
{
return
NULL
;
}
s
=
vlc_object_create
(
p_obj
,
VLC_OBJECT_STREAM
);
s
->
pf_block
=
NULL
;
s
->
pf_read
=
DStreamRead
;
s
->
pf_peek
=
DStreamPeek
;
s
->
pf_control
=
DStreamControl
;
s
->
p_sys
=
malloc
(
sizeof
(
d_stream_sys_t
)
);
p_sys
=
(
d_stream_sys_t
*
)
s
->
p_sys
;
vlc_mutex_init
(
s
,
&
p_sys
->
lock
);
p_sys
->
i_buffer
=
0
;
p_sys
->
i_buffer_size
=
1000000
;
p_sys
->
p_buffer
=
malloc
(
p_sys
->
i_buffer_size
);
p_sys
->
i_pos
=
0
;
p_sys
->
psz_name
=
strdup
(
psz_demux
);
p_sys
->
out
=
out
;
p_sys
->
p_demux
=
NULL
;
if
(
vlc_thread_create
(
s
,
"stream out"
,
DStreamThread
,
VLC_THREAD_PRIORITY_INPUT
,
VLC_FALSE
)
)
{
vlc_mutex_destroy
(
&
p_sys
->
lock
);
vlc_object_destroy
(
s
);
free
(
p_sys
);
return
NULL
;
}
return
s
;
}
void
stream_DemuxSend
(
stream_t
*
s
,
block_t
*
p_block
)
{
d_stream_sys_t
*
p_sys
=
(
d_stream_sys_t
*
)
s
->
p_sys
;
if
(
p_block
->
i_buffer
>
0
)
{
vlc_mutex_lock
(
&
p_sys
->
lock
);
/* Realloc if needed */
if
(
p_sys
->
i_buffer
+
p_block
->
i_buffer
>
p_sys
->
i_buffer_size
)
{
if
(
p_sys
->
i_buffer_size
>
5000000
)
{
vlc_mutex_unlock
(
&
p_sys
->
lock
);
msg_Err
(
s
,
"stream_DemuxSend: buffer size > 5000000"
);
block_Release
(
p_block
);
return
;
}
/* I know, it's more than needed but that's perfect */
p_sys
->
i_buffer_size
+=
p_block
->
i_buffer
;
/* FIXME won't work with PEEK -> segfault */
p_sys
->
p_buffer
=
realloc
(
p_sys
->
p_buffer
,
p_sys
->
i_buffer_size
);
msg_Dbg
(
s
,
"stream_DemuxSend: realloc to %d"
,
p_sys
->
i_buffer_size
);
}
/* copy data */
memcpy
(
&
p_sys
->
p_buffer
[
p_sys
->
i_buffer
],
p_block
->
p_buffer
,
p_block
->
i_buffer
);
p_sys
->
i_buffer
+=
p_block
->
i_buffer
;
vlc_mutex_unlock
(
&
p_sys
->
lock
);
}
block_Release
(
p_block
);
}
void
stream_DemuxDelete
(
stream_t
*
s
)
{
d_stream_sys_t
*
p_sys
=
(
d_stream_sys_t
*
)
s
->
p_sys
;
s
->
b_die
=
VLC_TRUE
;
vlc_mutex_lock
(
&
p_sys
->
lock
);
if
(
p_sys
->
p_demux
)
{
p_sys
->
p_demux
->
b_die
=
VLC_TRUE
;
}
vlc_mutex_unlock
(
&
p_sys
->
lock
);
vlc_thread_join
(
s
);
if
(
p_sys
->
p_demux
)
{
demux2_Delete
(
p_sys
->
p_demux
);
}
vlc_mutex_destroy
(
&
p_sys
->
lock
);
free
(
p_sys
->
psz_name
);
free
(
p_sys
->
p_buffer
);
free
(
p_sys
);
vlc_object_destroy
(
s
);
}
static
int
DStreamRead
(
stream_t
*
s
,
void
*
p_read
,
int
i_read
)
{
d_stream_sys_t
*
p_sys
=
(
d_stream_sys_t
*
)
s
->
p_sys
;
int
i_copy
;
//msg_Dbg( s, "DStreamRead: wanted %d bytes", i_read );
for
(
;;
)
{
vlc_mutex_lock
(
&
p_sys
->
lock
);
//msg_Dbg( s, "DStreamRead: buffer %d", p_sys->i_buffer );
if
(
p_sys
->
i_buffer
>=
i_read
||
s
->
b_die
)
{
break
;
}
vlc_mutex_unlock
(
&
p_sys
->
lock
);
msleep
(
10000
);
}
//msg_Dbg( s, "DStreamRead: read %d buffer %d", i_read, p_sys->i_buffer );
i_copy
=
__MIN
(
i_read
,
p_sys
->
i_buffer
);
if
(
i_copy
>
0
)
{
if
(
p_read
)
{
memcpy
(
p_read
,
p_sys
->
p_buffer
,
i_copy
);
}
p_sys
->
i_buffer
-=
i_copy
;
p_sys
->
i_pos
+=
i_copy
;
if
(
p_sys
->
i_buffer
>
0
)
{
memmove
(
p_sys
->
p_buffer
,
&
p_sys
->
p_buffer
[
i_copy
],
p_sys
->
i_buffer
);
}
}
vlc_mutex_unlock
(
&
p_sys
->
lock
);
return
i_copy
;
}
static
int
DStreamPeek
(
stream_t
*
s
,
uint8_t
**
pp_peek
,
int
i_peek
)
{
d_stream_sys_t
*
p_sys
=
(
d_stream_sys_t
*
)
s
->
p_sys
;
int
i_copy
;
//msg_Dbg( s, "DStreamPeek: wanted %d bytes", i_peek );
for
(
;;
)
{
vlc_mutex_lock
(
&
p_sys
->
lock
);
//msg_Dbg( s, "DStreamPeek: buffer %d", p_sys->i_buffer );
if
(
p_sys
->
i_buffer
>=
i_peek
||
s
->
b_die
)
{
break
;
}
vlc_mutex_unlock
(
&
p_sys
->
lock
);
msleep
(
10000
);
}
*
pp_peek
=
p_sys
->
p_buffer
;
i_copy
=
__MIN
(
i_peek
,
p_sys
->
i_buffer
);
vlc_mutex_unlock
(
&
p_sys
->
lock
);
return
i_copy
;
}
static
int
DStreamControl
(
stream_t
*
s
,
int
i_query
,
va_list
args
)
{
d_stream_sys_t
*
p_sys
=
(
d_stream_sys_t
*
)
s
->
p_sys
;
int64_t
*
p_i64
;
vlc_bool_t
*
p_b
;
int
*
p_int
;
switch
(
i_query
)
{
case
STREAM_GET_SIZE
:
p_i64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
*
p_i64
=
0
;
return
VLC_SUCCESS
;
case
STREAM_CAN_SEEK
:
p_b
=
(
vlc_bool_t
*
)
va_arg
(
args
,
vlc_bool_t
*
);
*
p_b
=
VLC_FALSE
;
return
VLC_SUCCESS
;
case
STREAM_CAN_FASTSEEK
:
p_b
=
(
vlc_bool_t
*
)
va_arg
(
args
,
vlc_bool_t
*
);
*
p_b
=
VLC_FALSE
;
return
VLC_SUCCESS
;
case
STREAM_GET_POSITION
:
p_i64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
*
p_i64
=
p_sys
->
i_pos
;
return
VLC_SUCCESS
;
case
STREAM_SET_POSITION
:
return
VLC_EGENERIC
;
case
STREAM_GET_MTU
:
p_int
=
(
int
*
)
va_arg
(
args
,
int
*
);
*
p_int
=
0
;
return
VLC_SUCCESS
;
default:
msg_Err
(
s
,
"invalid DStreamControl query=0x%x"
,
i_query
);
return
VLC_EGENERIC
;
}
}
static
int
DStreamThread
(
stream_t
*
s
)
{
d_stream_sys_t
*
p_sys
=
(
d_stream_sys_t
*
)
s
->
p_sys
;
demux_t
*
p_demux
;
/* Create the demuxer */
if
(
(
p_demux
=
demux2_New
(
s
,
""
,
p_sys
->
psz_name
,
""
,
s
,
p_sys
->
out
)
)
==
NULL
)
{
return
VLC_EGENERIC
;
}
vlc_mutex_lock
(
&
p_sys
->
lock
);
p_sys
->
p_demux
=
p_demux
;
vlc_mutex_unlock
(
&
p_sys
->
lock
);
/* Main loop */
while
(
!
s
->
b_die
&&
!
p_demux
->
b_die
)
{
if
(
p_demux
->
pf_demux
(
p_demux
)
<=
0
)
{
break
;
}
}
p_demux
->
b_die
=
VLC_TRUE
;
return
VLC_SUCCESS
;
}
src/input/es_out.c
View file @
68d21786
...
@@ -30,26 +30,53 @@
...
@@ -30,26 +30,53 @@
#include <vlc/input.h>
#include <vlc/input.h>
#include <vlc/decoder.h>
#include <vlc/decoder.h>
#include "input_internal.h"
#include "vlc_playlist.h"
#include "vlc_playlist.h"
#include "codecs.h"
#include "iso_lang.h"
#include "iso_lang.h"
/*****************************************************************************
/*****************************************************************************
* Local prototypes
* Local prototypes
*****************************************************************************/
*****************************************************************************/
typedef
struct
{
/* Program ID */
int
i_id
;
/* Number of es for this pgrm */
int
i_es
;
vlc_bool_t
b_selected
;
/* Clock for this program */
input_clock_t
clock
;
}
es_out_pgrm_t
;
struct
es_out_id_t
struct
es_out_id_t
{
{
int
i_channel
;
/* ES ID */
es_descriptor_t
*
p_es
;
int
i_id
;
es_out_pgrm_t
*
p_pgrm
;
/* Channel in the track type */
int
i_channel
;
es_format_t
fmt
;
char
*
psz_description
;
decoder_t
*
p_dec
;
};
};
struct
es_out_sys_t
struct
es_out_sys_t
{
{
input_thread_t
*
p_input
;
input_thread_t
*
p_input
;
/* all programs */
int
i_pgrm
;
es_out_pgrm_t
**
pgrm
;
es_out_pgrm_t
*
p_pgrm
;
/* Master program */
/* all es */
/* all es */
int
i_id
;
int
i_id
;
int
i_es
;
int
i_es
;
es_out_id_t
**
es
;
es_out_id_t
**
es
;
...
@@ -75,16 +102,17 @@ struct es_out_sys_t
...
@@ -75,16 +102,17 @@ struct es_out_sys_t
static
es_out_id_t
*
EsOutAdd
(
es_out_t
*
,
es_format_t
*
);
static
es_out_id_t
*
EsOutAdd
(
es_out_t
*
,
es_format_t
*
);
static
int
EsOutSend
(
es_out_t
*
,
es_out_id_t
*
,
block_t
*
);
static
int
EsOutSend
(
es_out_t
*
,
es_out_id_t
*
,
block_t
*
);
static
void
EsOutDel
(
es_out_t
*
,
es_out_id_t
*
);
static
void
EsOutDel
(
es_out_t
*
,
es_out_id_t
*
);
static
void
EsOutSelect
(
es_out_t
*
out
,
es_out_id_t
*
es
,
vlc_bool_t
b_force
);
static
int
EsOutControl
(
es_out_t
*
,
int
i_query
,
va_list
);
static
int
EsOutControl
(
es_out_t
*
,
int
i_query
,
va_list
);
static
void
EsSelect
(
es_out_t
*
out
,
es_out_id_t
*
es
);
static
void
EsUnselect
(
es_out_t
*
out
,
es_out_id_t
*
es
,
vlc_bool_t
b_update
);
static
char
*
LanguageGetName
(
const
char
*
psz_code
);
static
char
*
LanguageGetName
(
const
char
*
psz_code
);
/**
/*****************************************************************************
* Create a new es_out structure
* input_EsOutNew:
*
*****************************************************************************/
* \param p_input The related input thread
* \return the new es_out_t
*/
es_out_t
*
input_EsOutNew
(
input_thread_t
*
p_input
)
es_out_t
*
input_EsOutNew
(
input_thread_t
*
p_input
)
{
{
es_out_t
*
out
=
malloc
(
sizeof
(
es_out_t
)
);
es_out_t
*
out
=
malloc
(
sizeof
(
es_out_t
)
);
...
@@ -102,8 +130,12 @@ es_out_t *input_EsOutNew( input_thread_t *p_input )
...
@@ -102,8 +130,12 @@ es_out_t *input_EsOutNew( input_thread_t *p_input )
p_sys
->
b_active
=
VLC_FALSE
;
p_sys
->
b_active
=
VLC_FALSE
;
p_sys
->
i_mode
=
ES_OUT_MODE_AUTO
;
p_sys
->
i_mode
=
ES_OUT_MODE_AUTO
;
p_sys
->
i_id
=
1
;
p_sys
->
i_pgrm
=
0
;
p_sys
->
pgrm
=
NULL
;
p_sys
->
p_pgrm
=
NULL
;
p_sys
->
i_id
=
0
;
p_sys
->
i_es
=
0
;
p_sys
->
i_es
=
0
;
p_sys
->
es
=
NULL
;
p_sys
->
es
=
NULL
;
...
@@ -124,12 +156,9 @@ es_out_t *input_EsOutNew( input_thread_t *p_input )
...
@@ -124,12 +156,9 @@ es_out_t *input_EsOutNew( input_thread_t *p_input )
return
out
;
return
out
;
}
}
/**
/*****************************************************************************
* Deletes an es_out structure
* input_EsOutDelete:
*
*****************************************************************************/
* \param out the es_out structure to destroy
* \return nothing
*/
void
input_EsOutDelete
(
es_out_t
*
out
)
void
input_EsOutDelete
(
es_out_t
*
out
)
{
{
es_out_sys_t
*
p_sys
=
out
->
p_sys
;
es_out_sys_t
*
p_sys
=
out
->
p_sys
;
...
@@ -137,191 +166,249 @@ void input_EsOutDelete( es_out_t *out )
...
@@ -137,191 +166,249 @@ void input_EsOutDelete( es_out_t *out )
for
(
i
=
0
;
i
<
p_sys
->
i_es
;
i
++
)
for
(
i
=
0
;
i
<
p_sys
->
i_es
;
i
++
)
{
{
if
(
p_sys
->
es
[
i
]
->
p_dec
)
{
input_DecoderDelete
(
p_sys
->
es
[
i
]
->
p_dec
);
}
if
(
p_sys
->
es
[
i
]
->
psz_description
)
free
(
p_sys
->
es
[
i
]
->
psz_description
);
es_format_Clean
(
&
p_sys
->
es
[
i
]
->
fmt
);
free
(
p_sys
->
es
[
i
]
);
free
(
p_sys
->
es
[
i
]
);
}
}
if
(
p_sys
->
es
)
if
(
p_sys
->
es
)
{
free
(
p_sys
->
es
);
free
(
p_sys
->
es
);
for
(
i
=
0
;
i
<
p_sys
->
i_pgrm
;
i
++
)
{
free
(
p_sys
->
pgrm
[
i
]
);
}
}
if
(
p_sys
->
pgrm
)
free
(
p_sys
->
pgrm
);
free
(
p_sys
);
free
(
p_sys
);
free
(
out
);
free
(
out
);
}
}
/**
es_out_id_t
*
input_EsOutGetFromID
(
es_out_t
*
out
,
int
i_id
)
* Add a program
*
* \param out the es_out
* \param i_group ...
* \return a program descriptor for the new program
*/
static
pgrm_descriptor_t
*
EsOutAddProgram
(
es_out_t
*
out
,
int
i_group
)
{
{
input_thread_t
*
p_input
=
out
->
p_sys
->
p_input
;
int
i
;
pgrm_descriptor_t
*
p_pgrm
;
if
(
i_id
<
0
)
es_descriptor_t
*
p_pmt
;
{
/* Special HACK, -i_id is tha cat of the stream */
/* FIXME we should use a object variable but a lot of place in src/input
return
(
es_out_id_t
*
)((
uint8_t
*
)
NULL
-
i_id
);
* have to be changed */
}
int
i_select
=
config_GetInt
(
p_input
,
"program"
);
/* create it */
for
(
i
=
0
;
i
<
out
->
p_sys
->
i_es
;
i
++
)
p_pgrm
=
input_AddProgram
(
p_input
,
i_group
,
0
);
{
if
(
out
->
p_sys
->
es
[
i
]
->
i_id
==
i_id
)
return
out
->
p_sys
->
es
[
i
];
}
return
NULL
;
}
/* XXX welcome to kludge, add a dummy es, if you want to understand
void
input_EsOutDiscontinuity
(
es_out_t
*
out
,
vlc_bool_t
b_audio
)
* why have a look at input_SetProgram. Basicaly, it assume the first
{
* es to be the PMT, how that is stupid, nevertheless it is needed for
es_out_sys_t
*
p_sys
=
out
->
p_sys
;
* the old ts demuxer */
int
i
;
p_pmt
=
input_AddES
(
p_input
,
p_pgrm
,
0
,
UNKNOWN_ES
,
NULL
,
0
);
p_pmt
->
i_fourcc
=
VLC_FOURCC
(
'n'
,
'u'
,
'l'
,
'l'
);
/* Select i_select or the first by default */
for
(
i
=
0
;
i
<
p_sys
->
i_es
;
i
++
)
if
(
p_input
->
stream
.
p_selected_program
==
NULL
&&
(
i_select
<=
0
||
i_select
==
i_group
)
)
{
{
p_input
->
stream
.
p_selected_program
=
p_pgrm
;
es_out_id_t
*
es
=
p_sys
->
es
[
i
];
}
return
p_pgrm
;
/* Send a dummy block to let decoder know that
* there is a discontinuity */
if
(
es
->
p_dec
&&
(
!
b_audio
||
es
->
fmt
.
i_cat
==
AUDIO_ES
)
)
{
input_DecoderDiscontinuity
(
es
->
p_dec
);
}
}
}
}
/**
/*****************************************************************************
* Select an ES given the current mode
* XXX: you need to take a the lock before (stream.stream_lock)
*
*
* \param out The es_out structure
*****************************************************************************/
* \param es es_out_id structure
static
void
EsOutESVarUpdate
(
es_out_t
*
out
,
es_out_id_t
*
es
)
* \param b_force ...
* \return nothing
*/
static
void
EsOutSelect
(
es_out_t
*
out
,
es_out_id_t
*
es
,
vlc_bool_t
b_force
)
{
{
es_out_sys_t
*
p_sys
=
out
->
p_sys
;
es_out_sys_t
*
p_sys
=
out
->
p_sys
;
input_thread_t
*
p_input
=
p_sys
->
p_input
;
input_thread_t
*
p_input
=
p_sys
->
p_input
;
vlc_value_t
val
,
text
;
int
i_cat
=
es
->
p_es
->
i_cat
;
char
*
psz_var
;
if
(
!
p_sys
->
b_active
||
if
(
es
->
fmt
.
i_cat
==
AUDIO_ES
)
(
!
b_force
&&
es
->
p_es
->
fmt
.
i_priority
<
0
)
)
psz_var
=
"audio-es"
;
{
else
if
(
es
->
fmt
.
i_cat
==
VIDEO_ES
)
psz_var
=
"video-es"
;
else
if
(
es
->
fmt
.
i_cat
==
SPU_ES
)
psz_var
=
"spu-es"
;
else
return
;
return
;
/* Get the number of ES already added */
var_Change
(
p_input
,
psz_var
,
VLC_VAR_CHOICESCOUNT
,
&
val
,
NULL
);
if
(
val
.
i_int
==
0
)
{
vlc_value_t
val2
;
/* First one, we need to add the "Disable" choice */
val2
.
i_int
=
-
1
;
text
.
psz_string
=
_
(
"Disable"
);
var_Change
(
p_input
,
psz_var
,
VLC_VAR_ADDCHOICE
,
&
val2
,
&
text
);
val
.
i_int
++
;
}
}
if
(
p_sys
->
i_mode
==
ES_OUT_MODE_ALL
||
b_force
)
/* Take care of the ES description */
if
(
es
->
psz_description
&&
*
es
->
psz_description
)
{
{
if
(
!
es
->
p_es
->
p_dec
)
text
.
psz_string
=
strdup
(
es
->
psz_description
);
{
input_SelectES
(
p_input
,
es
->
p_es
);
}
}
}
else
if
(
p_sys
->
i_mode
==
ES_OUT_MODE_AUTO
)
else
{
{
int
i_wanted
=
-
1
;
text
.
psz_string
=
malloc
(
strlen
(
_
(
"Track %i"
)
)
+
20
);
sprintf
(
text
.
psz_string
,
_
(
"Track %i"
),
val
.
i_int
);
}
if
(
es
->
p_es
->
p_pgrm
!=
NULL
&&
val
.
i_int
=
es
->
i_id
;
es
->
p_es
->
p_pgrm
!=
p_input
->
stream
.
p_selected_program
)
var_Change
(
p_input
,
psz_var
,
VLC_VAR_ADDCHOICE
,
&
val
,
&
text
);
{
return
;
}
if
(
i_cat
==
AUDIO_ES
)
free
(
text
.
psz_string
);
{
if
(
p_sys
->
p_es_audio
&&
var_SetBool
(
p_sys
->
p_input
,
"intf-change"
,
VLC_TRUE
);
p_sys
->
p_es_audio
->
p_es
->
fmt
.
i_priority
>=
}
es
->
p_es
->
fmt
.
i_priority
)
{
/* EsOutProgramSelect:
return
;
* Select a program and update the object variable
}
*/
i_wanted
=
p_sys
->
i_audio_last
>=
0
?
static
void
EsOutProgramSelect
(
es_out_t
*
out
,
es_out_pgrm_t
*
p_pgrm
)
p_sys
->
i_audio_last
:
es
->
i_channel
;
{
}
es_out_sys_t
*
p_sys
=
out
->
p_sys
;
else
if
(
i_cat
==
SPU_ES
)
input_thread_t
*
p_input
=
p_sys
->
p_input
;
{
vlc_value_t
val
;
if
(
p_sys
->
p_es_sub
&&
int
i
;
p_sys
->
p_es_sub
->
p_es
->
fmt
.
i_priority
>=
es
->
p_es
->
fmt
.
i_priority
)
if
(
p_sys
->
p_pgrm
==
p_pgrm
)
{
return
;
/* Nothing to do */
return
;
}
if
(
p_sys
->
p_pgrm
)
i_wanted
=
p_sys
->
i_sub_last
;
{
}
es_out_pgrm_t
*
old
=
p_sys
->
p_pgrm
;
else
if
(
i_cat
==
VIDEO_ES
)
msg_Dbg
(
p_input
,
"Unselecting program id=%d"
,
old
->
i_id
);
{
i_wanted
=
es
->
i_channel
;
}
if
(
i_wanted
==
es
->
i_channel
&&
es
->
p_es
->
p_dec
==
NULL
)
for
(
i
=
0
;
i
<
p_sys
->
i_es
;
i
++
)
{
{
input_SelectES
(
p_input
,
es
->
p_es
);
if
(
p_sys
->
es
[
i
]
->
p_pgrm
==
old
&&
p_sys
->
es
[
i
]
->
p_dec
&&
p_sys
->
i_mode
!=
ES_OUT_MODE_ALL
)
EsUnselect
(
out
,
p_sys
->
es
[
i
],
VLC_TRUE
);
}
}
}
}
/* FIXME TODO handle priority here */
msg_Dbg
(
p_input
,
"Selecting program id=%d"
,
p_pgrm
->
i_id
);
if
(
es
->
p_es
->
p_dec
)
/* Mark it selected */
p_pgrm
->
b_selected
=
VLC_TRUE
;
/* Switch master stream */
if
(
p_sys
->
p_pgrm
&&
p_sys
->
p_pgrm
->
clock
.
b_master
)
{
{
if
(
i_cat
==
AUDIO_ES
)
p_sys
->
p_pgrm
->
clock
.
b_master
=
VLC_FALSE
;
{
}
if
(
p_sys
->
i_mode
==
ES_OUT_MODE_AUTO
&&
p_pgrm
->
clock
.
b_master
=
VLC_TRUE
;
p_sys
->
p_es_audio
&&
p_sys
->
p_es_audio
->
p_es
->
p_dec
)
p_sys
->
p_pgrm
=
p_pgrm
;
{
input_UnselectES
(
p_input
,
p_sys
->
p_es_audio
->
p_es
);
/* Update "program" */
}
val
.
i_int
=
p_pgrm
->
i_id
;
p_sys
->
p_es_audio
=
es
;
var_Change
(
p_input
,
"program"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
}
else
if
(
i_cat
==
SPU_ES
)
/* Update "es-*" */
{
var_Change
(
p_input
,
"audio-es"
,
VLC_VAR_CLEARCHOICES
,
NULL
,
NULL
);
if
(
p_sys
->
i_mode
==
ES_OUT_MODE_AUTO
&&
var_Change
(
p_input
,
"video-es"
,
VLC_VAR_CLEARCHOICES
,
NULL
,
NULL
);
p_sys
->
p_es_sub
&&
p_sys
->
p_es_sub
->
p_es
->
p_dec
)
var_Change
(
p_input
,
"spu-es"
,
VLC_VAR_CLEARCHOICES
,
NULL
,
NULL
);
{
for
(
i
=
0
;
i
<
p_sys
->
i_es
;
i
++
)
input_UnselectES
(
p_input
,
p_sys
->
p_es_sub
->
p_es
);
{
}
EsOutESVarUpdate
(
out
,
p_sys
->
es
[
i
]
);
p_sys
->
p_es_sub
=
es
;
EsOutSelect
(
out
,
p_sys
->
es
[
i
],
VLC_FALSE
);
}
}
else
if
(
i_cat
==
VIDEO_ES
)
{
var_SetBool
(
p_sys
->
p_input
,
"intf-change"
,
VLC_TRUE
);
p_sys
->
p_es_video
=
es
;
}
}
/* EsOutAddProgram:
* Add a program
*/
static
es_out_pgrm_t
*
EsOutProgramAdd
(
es_out_t
*
out
,
int
i_group
)
{
es_out_sys_t
*
p_sys
=
out
->
p_sys
;
input_thread_t
*
p_input
=
p_sys
->
p_input
;
vlc_value_t
val
;
es_out_pgrm_t
*
p_pgrm
=
malloc
(
sizeof
(
es_out_pgrm_t
)
);
/* Init */
p_pgrm
->
i_id
=
i_group
;
p_pgrm
->
i_es
=
0
;
p_pgrm
->
b_selected
=
VLC_FALSE
;
input_ClockInit
(
&
p_pgrm
->
clock
,
VLC_FALSE
,
p_input
->
input
.
i_cr_average
);
/* Append it */
TAB_APPEND
(
p_sys
->
i_pgrm
,
p_sys
->
pgrm
,
p_pgrm
);
/* Update "program" variable */
val
.
i_int
=
i_group
;
var_Change
(
p_input
,
"program"
,
VLC_VAR_ADDCHOICE
,
&
val
,
NULL
);
if
(
i_group
==
var_GetInteger
(
p_input
,
"program"
)
)
{
EsOutProgramSelect
(
out
,
p_pgrm
);
}
else
{
var_SetBool
(
p_sys
->
p_input
,
"intf-change"
,
VLC_TRUE
);
}
}
return
p_pgrm
;
}
}
/**
/* EsOutAdd:
* Add an es_out
* Add an es_out
*
* \param out the es_out to add
* \param fmt the es_format of the es_out
* \return an es_out id
*/
*/
static
es_out_id_t
*
EsOutAdd
(
es_out_t
*
out
,
es_format_t
*
fmt
)
static
es_out_id_t
*
EsOutAdd
(
es_out_t
*
out
,
es_format_t
*
fmt
)
{
{
es_out_sys_t
*
p_sys
=
out
->
p_sys
;
es_out_sys_t
*
p_sys
=
out
->
p_sys
;
input_thread_t
*
p_input
=
p_sys
->
p_input
;
input_thread_t
*
p_input
=
p_sys
->
p_input
;
es_out_id_t
*
es
=
malloc
(
sizeof
(
es_out_id_t
)
);
es_out_id_t
*
es
=
malloc
(
sizeof
(
es_out_id_t
)
);
pgrm_descriptor_t
*
p_pgrm
=
NULL
;
es_out_pgrm_t
*
p_pgrm
=
NULL
;
char
psz_cat
[
sizeof
(
_
(
"Stream "
)
)
+
10
];
int
i
;
char
*
psz_description
;
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
if
(
fmt
->
i_group
<
0
)
if
(
fmt
->
i_group
>=
0
)
{
{
/* search program */
msg_Err
(
p_input
,
"invakud group number"
);
p_pgrm
=
input_FindProgram
(
p_input
,
fmt
->
i_group
);
return
NULL
;
}
if
(
p_pgrm
==
NULL
)
/* Search the program */
for
(
i
=
0
;
i
<
p_sys
->
i_pgrm
;
i
++
)
{
if
(
fmt
->
i_group
==
p_sys
->
pgrm
[
i
]
->
i_id
)
{
{
/* Create it */
p_pgrm
=
p_sys
->
pgrm
[
i
];
p_pgrm
=
EsOutAddProgram
(
out
,
fmt
->
i_group
)
;
break
;
}
}
}
}
if
(
fmt
->
i_id
<
0
)
if
(
p_pgrm
==
NULL
)
{
{
fmt
->
i_id
=
out
->
p_sys
->
i_id
-
1
;
/* Create a new one */
p_pgrm
=
EsOutProgramAdd
(
out
,
fmt
->
i_group
);
}
}
psz_description
=
LanguageGetName
(
fmt
->
psz_language
);
/* Increase ref count for program */
es
->
p_es
=
input_AddES
(
p_input
,
p_pgrm
,
fmt
->
i_id
+
1
,
p_pgrm
->
i_es
++
;
fmt
->
i_cat
,
psz_description
,
0
);
es
->
p_es
->
i_stream_id
=
fmt
->
i_id
;
es
->
p_es
->
i_fourcc
=
fmt
->
i_codec
;
/* Set up ES */
if
(
fmt
->
i_id
<
0
)
fmt
->
i_id
=
out
->
p_sys
->
i_id
;
es
->
i_id
=
fmt
->
i_id
;
es
->
p_pgrm
=
p_pgrm
;
es_format_Copy
(
&
es
->
fmt
,
fmt
);
switch
(
fmt
->
i_cat
)
switch
(
fmt
->
i_cat
)
{
{
case
AUDIO_ES
:
case
AUDIO_ES
:
...
@@ -340,9 +427,14 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
...
@@ -340,9 +427,14 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
es
->
i_channel
=
0
;
es
->
i_channel
=
0
;
break
;
break
;
}
}
es
->
psz_description
=
LanguageGetName
(
fmt
->
psz_language
);
es
->
p_dec
=
NULL
;
if
(
es
->
p_pgrm
==
p_sys
->
p_pgrm
)
EsOutESVarUpdate
(
out
,
es
);
#if 0
/* Add stream info */
/* Add stream info */
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
sprintf( psz_cat, _("Stream %d"), out->p_sys->i_id - 1 );
sprintf( psz_cat, _("Stream %d"), out->p_sys->i_id - 1 );
input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Codec"),
input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Codec"),
...
@@ -406,19 +498,12 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
...
@@ -406,19 +498,12 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
default:
default:
break;
break;
}
}
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
free( psz_description );
free( psz_description );
#endif
es_format_Copy
(
&
es
->
p_es
->
fmt
,
fmt
);
/* Select it if needed */
EsOutSelect
(
out
,
es
,
VLC_FALSE
);
/* Apply mode
* XXX change that when we do group too */
if
(
1
)
{
EsOutSelect
(
out
,
es
,
VLC_FALSE
);
}
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
TAB_APPEND
(
out
->
p_sys
->
i_es
,
out
->
p_sys
->
es
,
es
);
TAB_APPEND
(
out
->
p_sys
->
i_es
,
out
->
p_sys
->
es
,
es
);
p_sys
->
i_id
++
;
/* always incremented */
p_sys
->
i_id
++
;
/* always incremented */
...
@@ -438,6 +523,186 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
...
@@ -438,6 +523,186 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
return
es
;
return
es
;
}
}
static
void
EsSelect
(
es_out_t
*
out
,
es_out_id_t
*
es
)
{
es_out_sys_t
*
p_sys
=
out
->
p_sys
;
input_thread_t
*
p_input
=
p_sys
->
p_input
;
vlc_value_t
val
;
char
*
psz_var
;
if
(
es
->
p_dec
)
{
msg_Warn
(
p_input
,
"ES 0x%x is already selected"
,
es
->
i_id
);
return
;
}
if
(
es
->
fmt
.
i_cat
==
VIDEO_ES
||
es
->
fmt
.
i_cat
==
SPU_ES
)
{
if
(
!
var_GetBool
(
p_input
,
"video"
)
||
(
p_input
->
p_sout
&&
!
var_GetBool
(
p_input
,
"sout-video"
)
)
)
{
msg_Dbg
(
p_input
,
"video is disabled, not selecting ES 0x%x"
,
es
->
i_id
);
return
;
}
}
else
if
(
es
->
fmt
.
i_cat
==
AUDIO_ES
)
{
var_Get
(
p_input
,
"audio"
,
&
val
);
if
(
!
var_GetBool
(
p_input
,
"audio"
)
||
(
p_input
->
p_sout
&&
!
var_GetBool
(
p_input
,
"sout-audio"
)
)
)
{
msg_Dbg
(
p_input
,
"audio is disabled, not selecting ES 0x%x"
,
es
->
i_id
);
return
;
}
}
es
->
p_dec
=
input_DecoderNew
(
p_input
,
&
es
->
fmt
,
VLC_FALSE
);
if
(
es
->
p_dec
==
NULL
||
es
->
p_pgrm
!=
p_sys
->
p_pgrm
)
return
;
if
(
es
->
fmt
.
i_cat
==
VIDEO_ES
)
psz_var
=
"video-es"
;
else
if
(
es
->
fmt
.
i_cat
==
AUDIO_ES
)
psz_var
=
"audio-es"
;
else
if
(
es
->
fmt
.
i_cat
==
SPU_ES
)
psz_var
=
"spu-es"
;
else
return
;
/* Mark it as selected */
val
.
i_int
=
es
->
i_id
;
var_Change
(
p_input
,
psz_var
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
var_SetBool
(
p_sys
->
p_input
,
"intf-change"
,
VLC_TRUE
);
}
static
void
EsUnselect
(
es_out_t
*
out
,
es_out_id_t
*
es
,
vlc_bool_t
b_update
)
{
es_out_sys_t
*
p_sys
=
out
->
p_sys
;
input_thread_t
*
p_input
=
p_sys
->
p_input
;
vlc_value_t
val
;
char
*
psz_var
;
if
(
es
->
p_dec
==
NULL
)
{
msg_Warn
(
p_input
,
"ES 0x%x is already unselected"
,
es
->
i_id
);
return
;
}
input_DecoderDelete
(
es
->
p_dec
);
es
->
p_dec
=
NULL
;
if
(
!
b_update
)
return
;
/* Update var */
if
(
es
->
p_dec
==
NULL
)
return
;
if
(
es
->
fmt
.
i_cat
==
VIDEO_ES
)
psz_var
=
"video-es"
;
else
if
(
es
->
fmt
.
i_cat
==
AUDIO_ES
)
psz_var
=
"audio-es"
;
else
if
(
es
->
fmt
.
i_cat
==
SPU_ES
)
psz_var
=
"spu-es"
;
else
return
;
/* Mark it as selected */
val
.
i_int
=
-
1
;
var_Change
(
p_input
,
psz_var
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
var_SetBool
(
p_sys
->
p_input
,
"intf-change"
,
VLC_TRUE
);
}
/**
* Select an ES given the current mode
* XXX: you need to take a the lock before (stream.stream_lock)
*
* \param out The es_out structure
* \param es es_out_id structure
* \param b_force ...
* \return nothing
*/
static
void
EsOutSelect
(
es_out_t
*
out
,
es_out_id_t
*
es
,
vlc_bool_t
b_force
)
{
es_out_sys_t
*
p_sys
=
out
->
p_sys
;
int
i_cat
=
es
->
fmt
.
i_cat
;
if
(
!
p_sys
->
b_active
||
(
!
b_force
&&
es
->
fmt
.
i_priority
<
0
)
)
{
return
;
}
if
(
p_sys
->
i_mode
==
ES_OUT_MODE_ALL
||
b_force
)
{
if
(
!
es
->
p_dec
)
EsSelect
(
out
,
es
);
}
else
if
(
p_sys
->
i_mode
==
ES_OUT_MODE_AUTO
)
{
int
i_wanted
=
-
1
;
if
(
es
->
p_pgrm
!=
p_sys
->
p_pgrm
)
return
;
if
(
i_cat
==
AUDIO_ES
)
{
if
(
p_sys
->
p_es_audio
&&
p_sys
->
p_es_audio
->
fmt
.
i_priority
>=
es
->
fmt
.
i_priority
)
{
return
;
}
i_wanted
=
p_sys
->
i_audio_last
>=
0
?
p_sys
->
i_audio_last
:
es
->
i_channel
;
}
else
if
(
i_cat
==
SPU_ES
)
{
if
(
p_sys
->
p_es_sub
&&
p_sys
->
p_es_sub
->
fmt
.
i_priority
>=
es
->
fmt
.
i_priority
)
{
return
;
}
i_wanted
=
p_sys
->
i_sub_last
;
}
else
if
(
i_cat
==
VIDEO_ES
)
{
i_wanted
=
es
->
i_channel
;
}
if
(
i_wanted
==
es
->
i_channel
&&
es
->
p_dec
==
NULL
)
EsSelect
(
out
,
es
);
}
/* FIXME TODO handle priority here */
if
(
es
->
p_dec
)
{
if
(
i_cat
==
AUDIO_ES
)
{
if
(
p_sys
->
i_mode
==
ES_OUT_MODE_AUTO
&&
p_sys
->
p_es_audio
&&
p_sys
->
p_es_audio
->
p_dec
)
{
EsUnselect
(
out
,
p_sys
->
p_es_audio
,
VLC_FALSE
);
}
p_sys
->
p_es_audio
=
es
;
}
else
if
(
i_cat
==
SPU_ES
)
{
if
(
p_sys
->
i_mode
==
ES_OUT_MODE_AUTO
&&
p_sys
->
p_es_sub
&&
p_sys
->
p_es_sub
->
p_dec
)
{
EsUnselect
(
out
,
p_sys
->
p_es_sub
,
VLC_FALSE
);
}
p_sys
->
p_es_sub
=
es
;
}
else
if
(
i_cat
==
VIDEO_ES
)
{
p_sys
->
p_es_video
=
es
;
}
}
}
/**
/**
* Send a block for the given es_out
* Send a block for the given es_out
*
*
...
@@ -448,37 +713,30 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
...
@@ -448,37 +713,30 @@ static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
static
int
EsOutSend
(
es_out_t
*
out
,
es_out_id_t
*
es
,
block_t
*
p_block
)
static
int
EsOutSend
(
es_out_t
*
out
,
es_out_id_t
*
es
,
block_t
*
p_block
)
{
{
es_out_sys_t
*
p_sys
=
out
->
p_sys
;
es_out_sys_t
*
p_sys
=
out
->
p_sys
;
pgrm_descriptor_t
*
p_pgrm
=
es
->
p_es
->
p_pgrm
;
input_thread_t
*
p_input
=
p_sys
->
p_input
;
input_thread_t
*
p_input
=
p_sys
->
p_input
;
es_out_pgrm_t
*
p_pgrm
=
es
->
p_pgrm
;
if
(
p_pgrm
==
NULL
)
{
p_pgrm
=
p_sys
->
p_input
->
stream
.
p_selected_program
;
}
/* +11 -> avoid null value with non null dts/pts */
/* +11 -> avoid null value with non null dts/pts */
if
(
p_block
->
i_dts
>
0
&&
p_pgrm
)
if
(
p_block
->
i_dts
>
0
)
{
{
p_block
->
i_dts
=
p_block
->
i_dts
=
input_ClockGetTS
(
p_input
,
p_pgrm
,
(
p_block
->
i_dts
+
11
)
*
9
/
100
);
input_ClockGetTS
(
p_input
,
&
p_pgrm
->
clock
,
(
p_block
->
i_dts
+
11
)
*
9
/
100
);
}
}
if
(
p_block
->
i_pts
>
0
&&
p_pgrm
)
if
(
p_block
->
i_pts
>
0
)
{
{
p_block
->
i_pts
=
p_block
->
i_pts
=
input_ClockGetTS
(
p_input
,
p_pgrm
,
(
p_block
->
i_pts
+
11
)
*
9
/
100
);
input_ClockGetTS
(
p_input
,
&
p_pgrm
->
clock
,
(
p_block
->
i_pts
+
11
)
*
9
/
100
);
}
}
vlc_mutex_lock
(
&
out
->
p_sys
->
p_input
->
stream
.
stream_lock
)
;
p_block
->
i_rate
=
p_input
->
i_rate
;
p_block
->
i_rate
=
out
->
p_sys
->
p_input
->
stream
.
control
.
i_rate
;
if
(
es
->
p_es
->
p_dec
&&
/* TODO handle mute */
(
es
->
p_es
->
i_cat
!=
AUDIO_ES
||
!
p_sys
->
p_input
->
stream
.
control
.
b_mute
)
)
if
(
es
->
p_dec
&&
(
es
->
fmt
.
i_cat
!=
AUDIO_ES
||
p_input
->
i_rate
==
INPUT_RATE_DEFAULT
)
)
{
{
vlc_mutex_unlock
(
&
out
->
p_sys
->
p_input
->
stream
.
stream_lock
);
input_DecoderDecode
(
es
->
p_dec
,
p_block
);
input_DecodeBlock
(
es
->
p_es
->
p_dec
,
p_block
);
}
}
else
else
{
{
vlc_mutex_unlock
(
&
out
->
p_sys
->
p_input
->
stream
.
stream_lock
);
block_Release
(
p_block
);
block_Release
(
p_block
);
}
}
...
@@ -492,9 +750,23 @@ static void EsOutDel( es_out_t *out, es_out_id_t *es )
...
@@ -492,9 +750,23 @@ static void EsOutDel( es_out_t *out, es_out_id_t *es )
{
{
es_out_sys_t
*
p_sys
=
out
->
p_sys
;
es_out_sys_t
*
p_sys
=
out
->
p_sys
;
/* We don't try to reselect */
if
(
es
->
p_dec
)
EsUnselect
(
out
,
es
,
es
->
p_pgrm
==
p_sys
->
p_pgrm
);
TAB_REMOVE
(
p_sys
->
i_es
,
p_sys
->
es
,
es
);
TAB_REMOVE
(
p_sys
->
i_es
,
p_sys
->
es
,
es
);
switch
(
es
->
p_es
->
i_cat
)
es
->
p_pgrm
->
i_es
--
;
if
(
es
->
p_pgrm
->
i_es
==
0
)
{
msg_Err
(
p_sys
->
p_input
,
"Program doesn't have es anymore, clenaing TODO ?"
);
}
if
(
p_sys
->
p_es_audio
==
es
)
p_sys
->
p_es_audio
=
NULL
;
if
(
p_sys
->
p_es_video
==
es
)
p_sys
->
p_es_video
=
NULL
;
if
(
p_sys
->
p_es_sub
==
es
)
p_sys
->
p_es_sub
=
NULL
;
switch
(
es
->
fmt
.
i_cat
)
{
{
case
AUDIO_ES
:
case
AUDIO_ES
:
p_sys
->
i_audio
--
;
p_sys
->
i_audio
--
;
...
@@ -507,30 +779,10 @@ static void EsOutDel( es_out_t *out, es_out_id_t *es )
...
@@ -507,30 +779,10 @@ static void EsOutDel( es_out_t *out, es_out_id_t *es )
break
;
break
;
}
}
/* We don't try to reselect */
if
(
es
->
psz_description
)
vlc_mutex_lock
(
&
p_sys
->
p_input
->
stream
.
stream_lock
);
free
(
es
->
psz_description
);
if
(
es
->
p_es
->
p_dec
)
{
input_UnselectES
(
p_sys
->
p_input
,
es
->
p_es
);
}
if
(
es
->
p_es
->
p_waveformatex
)
{
free
(
es
->
p_es
->
p_waveformatex
);
es
->
p_es
->
p_waveformatex
=
NULL
;
}
if
(
es
->
p_es
->
p_bitmapinfoheader
)
{
free
(
es
->
p_es
->
p_bitmapinfoheader
);
es
->
p_es
->
p_bitmapinfoheader
=
NULL
;
}
input_DelES
(
p_sys
->
p_input
,
es
->
p_es
);
if
(
p_sys
->
p_es_audio
==
es
)
p_sys
->
p_es_audio
=
NULL
;
es_format_Clean
(
&
es
->
fmt
);
if
(
p_sys
->
p_es_video
==
es
)
p_sys
->
p_es_video
=
NULL
;
if
(
p_sys
->
p_es_sub
==
es
)
p_sys
->
p_es_sub
=
NULL
;
vlc_mutex_unlock
(
&
p_sys
->
p_input
->
stream
.
stream_lock
);
free
(
es
);
free
(
es
);
}
}
...
@@ -554,42 +806,34 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args )
...
@@ -554,42 +806,34 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args )
switch
(
i_query
)
switch
(
i_query
)
{
{
case
ES_OUT_SET_ES_STATE
:
case
ES_OUT_SET_ES_STATE
:
vlc_mutex_lock
(
&
p_sys
->
p_input
->
stream
.
stream_lock
);
es
=
(
es_out_id_t
*
)
va_arg
(
args
,
es_out_id_t
*
);
es
=
(
es_out_id_t
*
)
va_arg
(
args
,
es_out_id_t
*
);
b
=
(
vlc_bool_t
)
va_arg
(
args
,
vlc_bool_t
);
b
=
(
vlc_bool_t
)
va_arg
(
args
,
vlc_bool_t
);
if
(
b
&&
es
->
p_
es
->
p_
dec
==
NULL
)
if
(
b
&&
es
->
p_dec
==
NULL
)
{
{
input_SelectES
(
p_sys
->
p_input
,
es
->
p_es
);
EsSelect
(
out
,
es
);
vlc_mutex_unlock
(
&
p_sys
->
p_input
->
stream
.
stream_lock
);
return
es
->
p_dec
?
VLC_SUCCESS
:
VLC_EGENERIC
;
return
es
->
p_es
->
p_dec
?
VLC_SUCCESS
:
VLC_EGENERIC
;
}
}
else
if
(
!
b
&&
es
->
p_
es
->
p_
dec
)
else
if
(
!
b
&&
es
->
p_dec
)
{
{
input_UnselectES
(
p_sys
->
p_input
,
es
->
p_es
);
EsUnselect
(
out
,
es
,
es
->
p_pgrm
==
p_sys
->
p_pgrm
);
vlc_mutex_unlock
(
&
p_sys
->
p_input
->
stream
.
stream_lock
);
return
VLC_SUCCESS
;
return
VLC_SUCCESS
;
}
}
vlc_mutex_unlock
(
&
p_sys
->
p_input
->
stream
.
stream_lock
);
return
VLC_SUCCESS
;
return
VLC_SUCCESS
;
case
ES_OUT_GET_ES_STATE
:
case
ES_OUT_GET_ES_STATE
:
es
=
(
es_out_id_t
*
)
va_arg
(
args
,
es_out_id_t
*
);
es
=
(
es_out_id_t
*
)
va_arg
(
args
,
es_out_id_t
*
);
pb
=
(
vlc_bool_t
*
)
va_arg
(
args
,
vlc_bool_t
*
);
pb
=
(
vlc_bool_t
*
)
va_arg
(
args
,
vlc_bool_t
*
);
*
pb
=
es
->
p_
es
->
p_
dec
?
VLC_TRUE
:
VLC_FALSE
;
*
pb
=
es
->
p_dec
?
VLC_TRUE
:
VLC_FALSE
;
return
VLC_SUCCESS
;
return
VLC_SUCCESS
;
case
ES_OUT_SET_ACTIVE
:
case
ES_OUT_SET_ACTIVE
:
{
{
b
=
(
vlc_bool_t
)
va_arg
(
args
,
vlc_bool_t
);
b
=
(
vlc_bool_t
)
va_arg
(
args
,
vlc_bool_t
);
p_sys
->
b_active
=
b
;
p_sys
->
b_active
=
b
;
/* Needed ? */
if
(
b
)
if
(
b
)
{
var_SetBool
(
p_sys
->
p_input
,
"intf-change"
,
VLC_TRUE
);
vlc_value_t
val
;
val
.
b_bool
=
VLC_TRUE
;
var_Set
(
p_sys
->
p_input
,
"intf-change"
,
val
);
}
return
VLC_SUCCESS
;
return
VLC_SUCCESS
;
}
}
...
@@ -603,28 +847,20 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args )
...
@@ -603,28 +847,20 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args )
if
(
i
==
ES_OUT_MODE_NONE
||
i
==
ES_OUT_MODE_ALL
||
if
(
i
==
ES_OUT_MODE_NONE
||
i
==
ES_OUT_MODE_ALL
||
i
==
ES_OUT_MODE_AUTO
)
i
==
ES_OUT_MODE_AUTO
)
{
{
vlc_value_t
val
;
p_sys
->
i_mode
=
i
;
p_sys
->
i_mode
=
i
;
/* Reapply policy mode */
/* Reapply policy mode */
vlc_mutex_lock
(
&
p_sys
->
p_input
->
stream
.
stream_lock
);
for
(
i
=
0
;
i
<
p_sys
->
i_es
;
i
++
)
for
(
i
=
0
;
i
<
p_sys
->
i_es
;
i
++
)
{
{
if
(
p_sys
->
es
[
i
]
->
p_
es
->
p_
dec
)
if
(
p_sys
->
es
[
i
]
->
p_dec
)
{
{
input_UnselectES
(
p_sys
->
p_input
,
p_sys
->
es
[
i
]
->
p_es
);
EsUnselect
(
out
,
p_sys
->
es
[
i
],
p_sys
->
es
[
i
]
->
p_pgrm
==
p_sys
->
p_pgrm
);
}
}
}
}
for
(
i
=
0
;
i
<
p_sys
->
i_es
;
i
++
)
for
(
i
=
0
;
i
<
p_sys
->
i_es
;
i
++
)
{
{
EsOutSelect
(
out
,
p_sys
->
es
[
i
],
VLC_FALSE
);
EsOutSelect
(
out
,
p_sys
->
es
[
i
],
VLC_FALSE
);
}
}
vlc_mutex_unlock
(
&
p_sys
->
p_input
->
stream
.
stream_lock
);
val
.
b_bool
=
VLC_TRUE
;
var_Set
(
p_sys
->
p_input
,
"intf-change"
,
val
);
return
VLC_SUCCESS
;
return
VLC_SUCCESS
;
}
}
return
VLC_EGENERIC
;
return
VLC_EGENERIC
;
...
@@ -636,65 +872,119 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args )
...
@@ -636,65 +872,119 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args )
case
ES_OUT_SET_ES
:
case
ES_OUT_SET_ES
:
es
=
(
es_out_id_t
*
)
va_arg
(
args
,
es_out_id_t
*
);
es
=
(
es_out_id_t
*
)
va_arg
(
args
,
es_out_id_t
*
);
/* Special case NULL, NULL+i_cat */
if
(
es
==
NULL
)
if
(
es
==
NULL
)
{
{
for
(
i
=
0
;
i
<
p_sys
->
i_es
;
i
++
)
for
(
i
=
0
;
i
<
p_sys
->
i_es
;
i
++
)
{
{
vlc_mutex_lock
(
&
p_sys
->
p_input
->
stream
.
stream_lock
);
if
(
p_sys
->
es
[
i
]
->
p_dec
)
if
(
p_sys
->
es
[
i
]
->
p_es
->
p_dec
)
EsUnselect
(
out
,
p_sys
->
es
[
i
],
{
p_sys
->
es
[
i
]
->
p_pgrm
==
p_sys
->
p_pgrm
);
input_UnselectES
(
p_sys
->
p_input
,
p_sys
->
es
[
i
]
->
p_es
);
}
}
}
vlc_mutex_unlock
(
&
p_sys
->
p_input
->
stream
.
stream_lock
);
else
if
(
es
==
(
es_out_id_t
*
)((
uint8_t
*
)
NULL
+
AUDIO_ES
)
)
{
for
(
i
=
0
;
i
<
p_sys
->
i_es
;
i
++
)
{
if
(
p_sys
->
es
[
i
]
->
p_dec
&&
p_sys
->
es
[
i
]
->
fmt
.
i_cat
==
AUDIO_ES
)
EsUnselect
(
out
,
p_sys
->
es
[
i
],
p_sys
->
es
[
i
]
->
p_pgrm
==
p_sys
->
p_pgrm
);
}
}
else
if
(
es
==
(
es_out_id_t
*
)((
uint8_t
*
)
NULL
+
VIDEO_ES
)
)
{
for
(
i
=
0
;
i
<
p_sys
->
i_es
;
i
++
)
{
if
(
p_sys
->
es
[
i
]
->
p_dec
&&
p_sys
->
es
[
i
]
->
fmt
.
i_cat
==
VIDEO_ES
)
EsUnselect
(
out
,
p_sys
->
es
[
i
],
p_sys
->
es
[
i
]
->
p_pgrm
==
p_sys
->
p_pgrm
);
}
}
else
if
(
es
==
(
es_out_id_t
*
)((
uint8_t
*
)
NULL
+
SPU_ES
)
)
{
for
(
i
=
0
;
i
<
p_sys
->
i_es
;
i
++
)
{
if
(
p_sys
->
es
[
i
]
->
p_dec
&&
p_sys
->
es
[
i
]
->
fmt
.
i_cat
==
SPU_ES
)
EsUnselect
(
out
,
p_sys
->
es
[
i
],
p_sys
->
es
[
i
]
->
p_pgrm
==
p_sys
->
p_pgrm
);
}
}
}
}
else
else
{
{
vlc_mutex_lock
(
&
p_sys
->
p_input
->
stream
.
stream_lock
);
for
(
i
=
0
;
i
<
p_sys
->
i_es
;
i
++
)
EsOutSelect
(
out
,
es
,
VLC_TRUE
);
{
vlc_mutex_unlock
(
&
p_sys
->
p_input
->
stream
.
stream_lock
);
if
(
es
==
p_sys
->
es
[
i
]
)
{
EsOutSelect
(
out
,
es
,
VLC_TRUE
);
break
;
}
}
}
}
return
VLC_SUCCESS
;
return
VLC_SUCCESS
;
case
ES_OUT_SET_PCR
:
case
ES_OUT_SET_PCR
:
case
ES_OUT_SET_GROUP_PCR
:
case
ES_OUT_SET_GROUP_PCR
:
{
{
pgrm_descriptor_t
*
p_pgrm
=
NULL
;
es_out_pgrm_t
*
p_pgrm
=
NULL
;
int64_t
i_pcr
;
int
i_group
=
0
;
int64_t
i_pcr
;
if
(
i_query
==
ES_OUT_SET_PCR
)
if
(
i_query
==
ES_OUT_SET_PCR
)
{
{
p_pgrm
=
p_sys
->
p_
input
->
stream
.
p_selected_progra
m
;
p_pgrm
=
p_sys
->
p_
pgr
m
;
}
}
else
else
{
{
int
i
_group
=
(
int
)
va_arg
(
args
,
int
)
;
int
i
;
p_pgrm
=
input_FindProgram
(
p_sys
->
p_input
,
i_group
);
i_group
=
(
int
)
va_arg
(
args
,
int
);
if
(
p_pgrm
==
NULL
)
for
(
i
=
0
;
i
<
p_sys
->
i_pgrm
;
i
++
)
{
{
/* we create the requested program */
if
(
p_sys
->
pgrm
[
i
]
->
i_id
==
i_group
)
p_pgrm
=
EsOutAddProgram
(
out
,
i_group
);
{
p_pgrm
=
p_sys
->
pgrm
[
i
];
break
;
}
}
}
}
}
if
(
p_pgrm
==
NULL
)
p_pgrm
=
EsOutProgramAdd
(
out
,
i_group
);
/* Create it */
i_pcr
=
(
int64_t
)
va_arg
(
args
,
int64_t
);
i_pcr
=
(
int64_t
)
va_arg
(
args
,
int64_t
);
/* search program */
/* search program */
if
(
p_pgrm
)
{
/* 11 is a vodoo trick to avoid non_pcr*9/100 to be null */
/* 11 is a vodoo trick to avoid non_pcr*9/100 to be null */
input_ClockManageRef
(
p_sys
->
p_input
,
p_pgrm
,
(
i_pcr
+
11
)
*
9
/
100
);
input_ClockSetPCR
(
p_sys
->
p_input
,
&
p_pgrm
->
clock
,
(
i_pcr
+
11
)
*
9
/
100
);
}
return
VLC_SUCCESS
;
return
VLC_SUCCESS
;
}
}
case
ES_OUT_RESET_PCR
:
case
ES_OUT_RESET_PCR
:
for
(
i
=
0
;
i
<
p_sys
->
p_input
->
stream
.
i_pgrm_number
;
i
++
)
for
(
i
=
0
;
i
<
p_sys
->
i_pgrm
;
i
++
)
{
{
p_sys
->
p_input
->
stream
.
pp_programs
[
i
]
->
i_synchro_state
=
p_sys
->
pgrm
[
i
]
->
clock
.
i_synchro_state
=
SYNCHRO_REINIT
;
SYNCHRO_REINIT
;
p_sys
->
pgrm
[
i
]
->
clock
.
last_pts
=
0
;
p_sys
->
p_input
->
stream
.
pp_programs
[
i
]
->
last_pts
=
0
;
}
}
return
VLC_SUCCESS
;
return
VLC_SUCCESS
;
case
ES_OUT_GET_GROUP
:
pi
=
(
int
*
)
va_arg
(
args
,
int
*
);
if
(
p_sys
->
p_pgrm
)
*
pi
=
p_sys
->
p_pgrm
->
i_id
;
else
*
pi
=
-
1
;
/* FIXME */
return
VLC_SUCCESS
;
case
ES_OUT_SET_GROUP
:
{
int
j
;
i
=
(
int
)
va_arg
(
args
,
int
);
for
(
j
=
0
;
j
<
p_sys
->
i_pgrm
;
j
++
)
{
es_out_pgrm_t
*
p_pgrm
=
p_sys
->
pgrm
[
j
];
if
(
p_pgrm
->
i_id
==
i
)
{
EsOutProgramSelect
(
out
,
p_pgrm
);
return
VLC_SUCCESS
;
}
}
return
VLC_EGENERIC
;
}
default:
default:
msg_Err
(
p_sys
->
p_input
,
"unknown query in es_out_Control"
);
msg_Err
(
p_sys
->
p_input
,
"unknown query in es_out_Control"
);
return
VLC_EGENERIC
;
return
VLC_EGENERIC
;
...
...
src/input/input.c
View file @
68d21786
/*****************************************************************************
/*****************************************************************************
* input.c: input thread
* input.c: input thread
* Read a stream, demultiplex and parse it before sending it to
* decoders.
*****************************************************************************
*****************************************************************************
* Copyright (C) 1998-2004 VideoLAN
* Copyright (C) 1998-2004 VideoLAN
* $Id$
* $Id$
*
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Laurent Aimar <fenrir@via.ecp.fr>
*
*
* This program is free software; you can redistribute it and/or modify
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* it under the terms of the GNU General Public License as published by
...
@@ -33,64 +32,63 @@
...
@@ -33,64 +32,63 @@
#include <vlc/decoder.h>
#include <vlc/decoder.h>
#include <vlc/vout.h>
#include <vlc/vout.h>
#ifdef HAVE_SYS_TIMES_H
#include "input_internal.h"
# include <sys/times.h>
#endif
#include "stream_output.h"
#include "stream_output.h"
#include "vlc_interface.h"
#include "vlc_interface.h"
#include "codecs.h"
#include "vlc_meta.h"
#include "vlc_meta.h"
#include "../../modules/demux/util/sub.h"
/*****************************************************************************
/*****************************************************************************
* Local prototypes
* Local prototypes
*****************************************************************************/
*****************************************************************************/
struct
input_thread_sys_t
static
int
Run
(
input_thread_t
*
p_input
);
{
/* subtitles */
static
int
Init
(
input_thread_t
*
p_input
);
int
i_sub
;
static
void
Error
(
input_thread_t
*
p_input
);
subtitle_demux_t
**
sub
;
static
void
End
(
input_thread_t
*
p_input
);
static
inline
int
ControlPopNoLock
(
input_thread_t
*
,
int
*
,
vlc_value_t
*
);
static
void
ControlReduce
(
input_thread_t
*
);
static
vlc_bool_t
Control
(
input_thread_t
*
,
int
,
vlc_value_t
);
int64_t
i_stop_time
;
};
static
int
RunThread
(
input_thread_t
*
p_input
);
static
void
UpdateFromAccess
(
input_thread_t
*
);
static
int
InitThread
(
input_thread_t
*
p_input
);
static
void
UpdateFromDemux
(
input_thread_t
*
);
static
void
ErrorThread
(
input_thread_t
*
p_input
);
static
void
EndThread
(
input_thread_t
*
p_input
);
static
void
ParseOption
(
input_thread_t
*
p_input
,
const
char
*
psz_option
);
static
void
ParseOption
(
input_thread_t
*
p_input
,
const
char
*
psz_option
);
static
void
DecodeUrl
(
char
*
);
static
void
DecodeUrl
(
char
*
);
/*****************************************************************************
* Callbacks
*****************************************************************************/
static
int
PositionCallback
(
vlc_object_t
*
p_this
,
char
const
*
psz_cmd
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
p_data
);
static
int
TimeCallback
(
vlc_object_t
*
p_this
,
char
const
*
psz_cmd
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
p_data
);
static
int
StateCallback
(
vlc_object_t
*
p_this
,
char
const
*
psz_cmd
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
p_data
);
static
int
RateCallback
(
vlc_object_t
*
p_this
,
char
const
*
psz_cmd
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
p_data
);
static
int
BookmarkCallback
(
vlc_object_t
*
p_this
,
char
const
*
psz_cmd
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
p_data
);
/*****************************************************************************
/*****************************************************************************
* input_CreateThread: creates a new input thread
* input_CreateThread: creates a new input thread
*****************************************************************************
*****************************************************************************
* This function creates a new input, and returns a pointer
* This function creates a new input, and returns a pointer
* to its description. On error, it returns NULL.
* to its description. On error, it returns NULL.
*
* Variables for _public_ use:
* * Get and Set:
* - state
* - rate,rate-slower, rate-faster
* - position, position-offset
* - time, time-offset
* - title,title-next,title-prev
* - chapter,chapter-next, chapter-prev
* - program, audio-es, video-es, spu-es
* - bookmark
* * Get only:
* - length
* - bookmarks
* * For intf callback upon changes
* - intf-change
* TODO explain when Callback is called
* TODO complete this list (?)
*****************************************************************************/
*****************************************************************************/
input_thread_t
*
__input_CreateThread
(
vlc_object_t
*
p_parent
,
input_thread_t
*
__input_CreateThread
(
vlc_object_t
*
p_parent
,
input_item_t
*
p_item
)
input_item_t
*
p_item
)
{
{
input_thread_t
*
p_input
;
/* thread descriptor */
input_thread_t
*
p_input
;
/* thread descriptor */
vlc_value_t
val
;
int
i
;
int
i
;
/* Allocate descriptor */
/* Allocate descriptor */
...
@@ -101,8 +99,40 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
...
@@ -101,8 +99,40 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
return
NULL
;
return
NULL
;
}
}
/* Store pointer to input item descriptor */
/* Init Common fields */
p_input
->
p_item
=
p_item
;
p_input
->
b_eof
=
VLC_FALSE
;
p_input
->
b_can_pace_control
=
VLC_TRUE
;
p_input
->
i_start
=
0
;
p_input
->
i_time
=
0
;
p_input
->
i_stop
=
0
;
p_input
->
i_title
=
0
;
p_input
->
title
=
NULL
;
p_input
->
i_state
=
INIT_S
;
p_input
->
i_rate
=
INPUT_RATE_DEFAULT
;
p_input
->
i_bookmark
=
0
;
p_input
->
bookmark
=
NULL
;
p_input
->
p_es_out
=
NULL
;
p_input
->
p_sout
=
NULL
;
p_input
->
b_out_pace_control
=
VLC_FALSE
;
p_input
->
i_pts_delay
=
0
;
/* Init Input fields */
p_input
->
input
.
p_item
=
p_item
;
p_input
->
input
.
p_access
=
NULL
;
p_input
->
input
.
p_stream
=
NULL
;
p_input
->
input
.
p_demux
=
NULL
;
p_input
->
input
.
b_title_demux
=
VLC_FALSE
;
p_input
->
input
.
i_title
=
0
;
p_input
->
input
.
title
=
NULL
;
p_input
->
input
.
b_can_pace_control
=
VLC_TRUE
;
p_input
->
input
.
b_eof
=
VLC_FALSE
;
p_input
->
input
.
i_cr_average
=
0
;
/* Init control buffer */
vlc_mutex_init
(
p_input
,
&
p_input
->
lock_control
);
p_input
->
i_control
=
0
;
p_input
->
p_sys
=
NULL
;
/* Parse input options */
/* Parse input options */
vlc_mutex_lock
(
&
p_item
->
lock
);
vlc_mutex_lock
(
&
p_item
->
lock
);
...
@@ -113,166 +143,15 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
...
@@ -113,166 +143,15 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
}
}
vlc_mutex_unlock
(
&
p_item
->
lock
);
vlc_mutex_unlock
(
&
p_item
->
lock
);
/* Create a few object variables we'll need later on */
/* Create Object Variables for private use only */
var_Create
(
p_input
,
"video"
,
VLC_VAR_BOOL
|
VLC_VAR_DOINHERIT
);
input_ConfigVarInit
(
p_input
);
var_Create
(
p_input
,
"audio"
,
VLC_VAR_BOOL
|
VLC_VAR_DOINHERIT
);
var_Create
(
p_input
,
"audio-channel"
,
VLC_VAR_INTEGER
|
VLC_VAR_DOINHERIT
);
var_Create
(
p_input
,
"spu-channel"
,
VLC_VAR_INTEGER
|
VLC_VAR_DOINHERIT
);
var_Create
(
p_input
,
"sub-file"
,
VLC_VAR_FILE
|
VLC_VAR_DOINHERIT
);
var_Create
(
p_input
,
"sub-autodetect-file"
,
VLC_VAR_BOOL
|
VLC_VAR_DOINHERIT
);
var_Create
(
p_input
,
"sub-autodetect-path"
,
VLC_VAR_STRING
|
VLC_VAR_DOINHERIT
);
var_Create
(
p_input
,
"sub-autodetect-fuzzy"
,
VLC_VAR_INTEGER
|
VLC_VAR_DOINHERIT
);
var_Create
(
p_input
,
"sout"
,
VLC_VAR_STRING
|
VLC_VAR_DOINHERIT
);
var_Create
(
p_input
,
"sout-all"
,
VLC_VAR_BOOL
|
VLC_VAR_DOINHERIT
);
var_Create
(
p_input
,
"sout-audio"
,
VLC_VAR_BOOL
|
VLC_VAR_DOINHERIT
);
var_Create
(
p_input
,
"sout-video"
,
VLC_VAR_BOOL
|
VLC_VAR_DOINHERIT
);
var_Create
(
p_input
,
"sout-keep"
,
VLC_VAR_BOOL
|
VLC_VAR_DOINHERIT
);
/* repeat variable */
var_Create
(
p_input
,
"input-repeat"
,
VLC_VAR_INTEGER
|
VLC_VAR_DOINHERIT
);
/* start/stop time */
var_Create
(
p_input
,
"start-time"
,
VLC_VAR_INTEGER
|
VLC_VAR_DOINHERIT
);
var_Create
(
p_input
,
"stop-time"
,
VLC_VAR_INTEGER
|
VLC_VAR_DOINHERIT
);
/* decoders */
var_Create
(
p_input
,
"minimize-threads"
,
VLC_VAR_BOOL
|
VLC_VAR_DOINHERIT
);
/* play status */
/* position variable */
var_Create
(
p_input
,
"position"
,
VLC_VAR_FLOAT
);
/* position 0.0->1.0 */
var_Create
(
p_input
,
"position-offset"
,
VLC_VAR_FLOAT
);
/* relative */
val
.
f_float
=
0
.
0
;
var_Change
(
p_input
,
"position"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
var_AddCallback
(
p_input
,
"position"
,
PositionCallback
,
NULL
);
var_AddCallback
(
p_input
,
"position-offset"
,
PositionCallback
,
NULL
);
/* time variable */
var_Create
(
p_input
,
"time"
,
VLC_VAR_TIME
);
var_Create
(
p_input
,
"time-offset"
,
VLC_VAR_TIME
);
/* relative */
val
.
i_time
=
0
;
var_Change
(
p_input
,
"time"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
var_AddCallback
(
p_input
,
"time"
,
TimeCallback
,
NULL
);
var_AddCallback
(
p_input
,
"time-offset"
,
TimeCallback
,
NULL
);
/* length variable */
var_Create
(
p_input
,
"length"
,
VLC_VAR_TIME
);
val
.
i_time
=
0
;
var_Change
(
p_input
,
"length"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
/* rate variable */
var_Create
(
p_input
,
"rate"
,
VLC_VAR_INTEGER
);
var_Create
(
p_input
,
"rate-slower"
,
VLC_VAR_VOID
);
var_Create
(
p_input
,
"rate-faster"
,
VLC_VAR_VOID
);
val
.
i_int
=
DEFAULT_RATE
;
var_Change
(
p_input
,
"rate"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
var_AddCallback
(
p_input
,
"rate"
,
RateCallback
,
NULL
);
var_AddCallback
(
p_input
,
"rate-slower"
,
RateCallback
,
NULL
);
var_AddCallback
(
p_input
,
"rate-faster"
,
RateCallback
,
NULL
);
/* state variable */
var_Create
(
p_input
,
"state"
,
VLC_VAR_INTEGER
);
val
.
i_int
=
INIT_S
;
var_Change
(
p_input
,
"state"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
var_AddCallback
(
p_input
,
"state"
,
StateCallback
,
NULL
);
/* state variable */
var_Create
(
p_input
,
"demuxed-id3"
,
VLC_VAR_BOOL
);
val
.
b_bool
=
VLC_FALSE
;
var_Change
(
p_input
,
"demuxed-id3"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
/* Initialize thread properties */
p_input
->
b_eof
=
0
;
p_input
->
b_out_pace_control
=
VLC_FALSE
;
p_input
->
p_sys
=
NULL
;
/* Set target */
vlc_mutex_lock
(
&
p_item
->
lock
);
p_input
->
psz_source
=
strdup
(
p_item
->
psz_uri
);
vlc_mutex_unlock
(
&
p_item
->
lock
);
/* Stream */
p_input
->
s
=
NULL
;
/* es out */
p_input
->
p_es_out
=
NULL
;
/* Demux */
p_input
->
p_demux
=
NULL
;
p_input
->
pf_demux
=
NULL
;
p_input
->
pf_rewind
=
NULL
;
p_input
->
pf_demux_control
=
demux_vaControlDefault
;
p_input
->
i_cr_average
=
config_GetInt
(
p_input
,
"cr-average"
);
/* Access */
p_input
->
p_access
=
NULL
;
p_input
->
pf_access_control
=
NULL
;
p_input
->
i_bufsize
=
0
;
p_input
->
i_mtu
=
0
;
p_input
->
i_pts_delay
=
DEFAULT_PTS_DELAY
;
/* Initialize statistics */
p_input
->
c_loops
=
0
;
p_input
->
stream
.
c_packets_read
=
0
;
p_input
->
stream
.
c_packets_trashed
=
0
;
/* Set locks. */
vlc_mutex_init
(
p_input
,
&
p_input
->
stream
.
stream_lock
);
vlc_cond_init
(
p_input
,
&
p_input
->
stream
.
stream_wait
);
vlc_mutex_init
(
p_input
,
&
p_input
->
stream
.
control
.
control_lock
);
/* Initialize stream description */
p_input
->
stream
.
b_changed
=
0
;
p_input
->
stream
.
i_es_number
=
0
;
p_input
->
stream
.
i_selected_es_number
=
0
;
p_input
->
stream
.
i_pgrm_number
=
0
;
p_input
->
stream
.
i_new_status
=
p_input
->
stream
.
i_new_rate
=
0
;
p_input
->
stream
.
b_new_mute
=
MUTE_NO_CHANGE
;
p_input
->
stream
.
i_mux_rate
=
0
;
p_input
->
stream
.
b_seekable
=
0
;
p_input
->
stream
.
p_sout
=
NULL
;
/* no stream, no program, no area, no es */
p_input
->
stream
.
p_new_program
=
NULL
;
p_input
->
stream
.
i_area_nb
=
0
;
p_input
->
stream
.
pp_areas
=
NULL
;
p_input
->
stream
.
p_selected_area
=
NULL
;
p_input
->
stream
.
p_new_area
=
NULL
;
p_input
->
stream
.
pp_selected_es
=
NULL
;
p_input
->
stream
.
p_removed_es
=
NULL
;
p_input
->
stream
.
p_newly_selected_es
=
NULL
;
/* By default there is one area in a stream */
input_AddArea
(
p_input
,
0
,
1
);
p_input
->
stream
.
p_selected_area
=
p_input
->
stream
.
pp_areas
[
0
];
/* Initialize stream control properties. */
p_input
->
stream
.
control
.
i_status
=
INIT_S
;
p_input
->
stream
.
control
.
i_rate
=
DEFAULT_RATE
;
p_input
->
stream
.
control
.
b_mute
=
0
;
p_input
->
stream
.
control
.
b_grayscale
=
config_GetInt
(
p_input
,
"grayscale"
);
msg_Info
(
p_input
,
"playlist item `%s'"
,
p_input
->
psz_source
);
/* Bookmarks */
/* Create Objects variables for public Get and Set */
var_Create
(
p_input
,
"bookmarks"
,
VLC_VAR_STRING
|
VLC_VAR_DOINHERIT
);
input_ControlVarInit
(
p_input
);
var_Create
(
p_input
,
"bookmark"
,
VLC_VAR_INTEGER
|
VLC_VAR_HASCHOICE
|
p_input
->
input
.
i_cr_average
=
var_GetInteger
(
p_input
,
"cr-average"
);
VLC_VAR_ISCOMMAND
);
val
.
psz_string
=
_
(
"Bookmark"
);
var_Change
(
p_input
,
"bookmark"
,
VLC_VAR_SETTEXT
,
&
val
,
NULL
);
var_AddCallback
(
p_input
,
"bookmark"
,
BookmarkCallback
,
NULL
);
p_input
->
i_bookmarks
=
0
;
p_input
->
pp_bookmarks
=
NULL
;
#if 0
/* TODO */
var_Get( p_input, "bookmarks", &val );
var_Get( p_input, "bookmarks", &val );
if( val.psz_string )
if( val.psz_string )
{
{
...
@@ -319,15 +198,18 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
...
@@ -319,15 +198,18 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
}
}
free( val.psz_string );
free( val.psz_string );
}
}
#endif
/* Now we can attach our new input */
vlc_object_attach
(
p_input
,
p_parent
);
vlc_object_attach
(
p_input
,
p_parent
);
/* Create thread and wait for its readiness. */
/* Create thread and wait for its readiness. */
if
(
vlc_thread_create
(
p_input
,
"input"
,
Run
Thread
,
if
(
vlc_thread_create
(
p_input
,
"input"
,
Run
,
VLC_THREAD_PRIORITY_INPUT
,
VLC_TRUE
)
)
VLC_THREAD_PRIORITY_INPUT
,
VLC_TRUE
)
)
{
{
msg_Err
(
p_input
,
"cannot create input thread"
);
msg_Err
(
p_input
,
"cannot create input thread"
);
free
(
p_input
);
vlc_object_detach
(
p_input
);
vlc_object_destroy
(
p_input
);
return
NULL
;
return
NULL
;
}
}
...
@@ -341,34 +223,40 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
...
@@ -341,34 +223,40 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
*****************************************************************************/
*****************************************************************************/
void
input_StopThread
(
input_thread_t
*
p_input
)
void
input_StopThread
(
input_thread_t
*
p_input
)
{
{
demux_t
*
p_demux
;
vlc_list_t
*
p_list
;
access_t
*
p_access
;
int
i
;
/*
Make the thread exit from a possible vlc_cond_wait()
*/
/*
Set die for input
*/
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
)
;
p_input
->
b_die
=
VLC_TRUE
;
/* Request thread destruction */
/* We cannot touch p_input fields directly (we can from another thread),
* so use the vlc_object_find way, it's perfectly safe */
/*
Temporary demux2 hack
*/
/*
Set die for all access
*/
p_
demux
=
(
demux_t
*
)
vlc_object_find
(
p_input
,
VLC_OBJECT_DEMUX
,
FIND_CHILD
);
p_
list
=
vlc_list_find
(
p_input
,
VLC_OBJECT_ACCESS
,
FIND_CHILD
);
if
(
p_demux
)
for
(
i
=
0
;
i
<
p_list
->
i_count
;
i
++
)
{
{
p_demux
->
b_die
=
1
;
p_list
->
p_values
[
i
].
p_object
->
b_die
=
VLC_TRUE
;
vlc_object_release
(
p_demux
);
}
}
vlc_list_release
(
p_list
);
/*
Temporary access2 hack
*/
/*
Set die for all stream
*/
p_
access
=
(
access_t
*
)
vlc_object_find
(
p_input
,
VLC_OBJECT_ACCESS
,
FIND_CHILD
);
p_
list
=
vlc_list_find
(
p_input
,
VLC_OBJECT_STREAM
,
FIND_CHILD
);
if
(
p_access
)
for
(
i
=
0
;
i
<
p_list
->
i_count
;
i
++
)
{
{
p_access
->
b_die
=
1
;
p_list
->
p_values
[
i
].
p_object
->
b_die
=
VLC_TRUE
;
vlc_object_release
(
p_access
);
}
}
vlc_list_release
(
p_list
);
p_input
->
b_die
=
1
;
/* Set die for all demux */
p_list
=
vlc_list_find
(
p_input
,
VLC_OBJECT_DEMUX
,
FIND_CHILD
);
for
(
i
=
0
;
i
<
p_list
->
i_count
;
i
++
)
{
p_list
->
p_values
[
i
].
p_object
->
b_die
=
VLC_TRUE
;
}
vlc_list_release
(
p_list
);
vlc_cond_signal
(
&
p_input
->
stream
.
stream_wait
);
input_ControlPush
(
p_input
,
INPUT_CONTROL_SET_DIE
,
NULL
);
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
}
}
/*****************************************************************************
/*****************************************************************************
...
@@ -381,106 +269,192 @@ void input_DestroyThread( input_thread_t *p_input )
...
@@ -381,106 +269,192 @@ void input_DestroyThread( input_thread_t *p_input )
/* Join the thread */
/* Join the thread */
vlc_thread_join
(
p_input
);
vlc_thread_join
(
p_input
);
/* Destroy Mutex locks */
/* Delete input lock (only after thread joined) */
vlc_mutex_destroy
(
&
p_input
->
stream
.
control
.
control_lock
);
vlc_mutex_destroy
(
&
p_input
->
lock_control
);
vlc_cond_destroy
(
&
p_input
->
stream
.
stream_wait
);
vlc_mutex_destroy
(
&
p_input
->
stream
.
stream_lock
);
/* TODO: maybe input_DestroyThread should also delete p_input instead
* of the playlist but I'm not sure if it's possible */
}
}
/*****************************************************************************
/*****************************************************************************
* Run
Thread
: main thread loop
* Run: main thread loop
*****************************************************************************
*****************************************************************************
* Thread in charge of processing the network packets and demultiplexing.
* Thread in charge of processing the network packets and demultiplexing.
*****************************************************************************/
*****************************************************************************/
static
int
Run
Thread
(
input_thread_t
*
p_input
)
static
int
Run
(
input_thread_t
*
p_input
)
{
{
vlc_value_t
val
;
int64_t
i_intf_update
=
0
;
mtime_t
i_update_next
=
-
1
;
/* Signal
right now, otherwise we'll get stuck in a peek
*/
/* Signal
that the thread is launched
*/
vlc_thread_ready
(
p_input
);
vlc_thread_ready
(
p_input
);
if
(
Init
Thread
(
p_input
)
)
if
(
Init
(
p_input
)
)
{
{
/* If we failed, wait before we are killed, and exit */
/* If we failed, wait before we are killed, and exit */
p_input
->
b_error
=
1
;
p_input
->
b_error
=
VLC_TRUE
;
Error
Thread
(
p_input
);
Error
(
p_input
);
/* Tell we're dead */
/* Tell we're dead */
p_input
->
b_dead
=
1
;
p_input
->
b_dead
=
VLC_TRUE
;
return
0
;
return
0
;
}
}
/* initialization is complete */
/* Main loop */
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
p_input
->
stream
.
b_changed
=
1
;
p_input
->
stream
.
control
.
i_status
=
PLAYING_S
;
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
val
.
i_int
=
PLAYING_S
;
var_Change
(
p_input
,
"state"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
while
(
!
p_input
->
b_die
&&
!
p_input
->
b_error
&&
!
p_input
->
b_eof
)
while
(
!
p_input
->
b_die
&&
!
p_input
->
b_error
&&
!
p_input
->
b_eof
)
{
{
unsigned
int
i
,
i_count
;
vlc_bool_t
b_force_update
=
VLC_FALSE
;
int
i_ret
;
p_input
->
c_loops
++
;
int
i_type
;
vlc_value_t
val
;
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
if
(
p_input
->
stream
.
p_new_program
)
/* Do the read */
if
(
p_input
->
i_state
!=
PAUSE_S
)
{
{
if
(
p_input
->
pf_set_program
!=
NULL
)
if
(
p_input
->
i_stop
<=
0
||
p_input
->
i_time
<
p_input
->
i_stop
)
{
i_ret
=
p_input
->
input
.
p_demux
->
pf_demux
(
p_input
->
input
.
p_demux
);
else
/* Reinitialize buffer manager. */
i_ret
=
0
;
/* EOF */
input_AccessReinit
(
p_input
);
p_input
->
pf_set_program
(
p_input
,
p_input
->
stream
.
p_new_program
);
/* Escape all decoders for the stream discontinuity they
if
(
i_ret
>
0
)
* will encounter. */
{
input_EscapeDiscontinuity
(
p_input
);
/* TODO */
if
(
p_input
->
input
.
b_title_demux
&&
p_input
->
input
.
p_demux
->
info
.
i_update
)
{
UpdateFromDemux
(
p_input
);
b_force_update
=
VLC_TRUE
;
}
else
if
(
!
p_input
->
input
.
b_title_demux
&&
p_input
->
input
.
p_access
&&
p_input
->
input
.
p_access
->
info
.
i_update
)
{
UpdateFromAccess
(
p_input
);
b_force_update
=
VLC_TRUE
;
}
}
else
if
(
i_ret
==
0
)
/* EOF */
{
vlc_value_t
repeat
;
for
(
i
=
0
;
i
<
p_input
->
stream
.
i_pgrm_number
;
i
++
)
var_Get
(
p_input
,
"input-repeat"
,
&
repeat
);
if
(
repeat
.
i_int
==
0
)
{
/* End of file - we do not set b_die because only the
* playlist is allowed to do so. */
msg_Dbg
(
p_input
,
"EOF reached"
);
p_input
->
b_eof
=
VLC_TRUE
;
p_input
->
input
.
b_eof
=
VLC_TRUE
;
}
else
{
{
pgrm_descriptor_t
*
p_pgrm
msg_Dbg
(
p_input
,
"repeating the same input (%d)"
,
repeat
.
i_int
);
=
p_input
->
stream
.
pp_programs
[
i
];
if
(
repeat
.
i_int
>
0
)
{
repeat
.
i_int
--
;
var_Set
(
p_input
,
"input-repeat"
,
repeat
);
}
/* Reinitialize synchro. */
/* Seek to title 0 position 0(start) */
p_pgrm
->
i_synchro_state
=
SYNCHRO_REINIT
;
val
.
i_int
=
0
;
input_ControlPush
(
p_input
,
INPUT_CONTROL_SET_TITLE
,
&
val
);
if
(
p_input
->
i_start
>
0
)
{
val
.
i_time
=
p_input
->
i_start
;
input_ControlPush
(
p_input
,
INPUT_CONTROL_SET_TIME
,
&
val
);
}
else
{
val
.
f_float
=
0
.
0
;
input_ControlPush
(
p_input
,
INPUT_CONTROL_SET_POSITION
,
&
val
);
}
}
}
}
}
p_input
->
stream
.
p_new_program
=
NULL
;
else
if
(
i_ret
<
0
)
{
p_input
->
b_error
=
VLC_TRUE
;
}
}
}
else
if
(
p_input
->
stream
.
p_new_area
)
{
{
if
(
p_input
->
stream
.
b_seekable
&&
p_input
->
pf_set_area
!=
NULL
)
/* Small wait */
{
msleep
(
10
*
1000
);
input_AccessReinit
(
p_input
);
}
p_input
->
pf_set_area
(
p_input
,
p_input
->
stream
.
p_new_area
);
/* Handle control */
vlc_mutex_lock
(
&
p_input
->
lock_control
);
ControlReduce
(
p_input
);
while
(
!
ControlPopNoLock
(
p_input
,
&
i_type
,
&
val
)
)
{
msg_Dbg
(
p_input
,
"control type=%d"
,
i_type
);
if
(
Control
(
p_input
,
i_type
,
val
)
)
b_force_update
=
VLC_TRUE
;
}
vlc_mutex_unlock
(
&
p_input
->
lock_control
);
/* Escape all decoders for the stream discontinuity they
if
(
b_force_update
||
* will encounter. */
i_intf_update
<
mdate
()
)
input_EscapeDiscontinuity
(
p_input
);
{
vlc_value_t
val
;
double
f_pos
;
int64_t
i_time
,
i_length
;
/* update input status variables */
if
(
!
demux2_Control
(
p_input
->
input
.
p_demux
,
DEMUX_GET_POSITION
,
&
f_pos
)
)
{
val
.
f_float
=
(
float
)
f_pos
;
var_Change
(
p_input
,
"position"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
}
if
(
!
demux2_Control
(
p_input
->
input
.
p_demux
,
DEMUX_GET_TIME
,
&
i_time
)
)
{
p_input
->
i_time
=
i_time
;
val
.
i_time
=
i_time
;
var_Change
(
p_input
,
"time"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
}
if
(
!
demux2_Control
(
p_input
->
input
.
p_demux
,
DEMUX_GET_LENGTH
,
&
i_length
)
)
{
vlc_value_t
old_val
;
var_Get
(
p_input
,
"length"
,
&
old_val
);
val
.
i_time
=
i_length
;
var_Change
(
p_input
,
"length"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
for
(
i
=
0
;
i
<
p_input
->
stream
.
i_pgrm_number
;
i
++
)
if
(
old_val
.
i_time
!=
val
.
i_time
)
{
{
pgrm_descriptor_t
*
p_pgrm
/* TODO */
=
p_input
->
stream
.
pp_programs
[
i
];
#if 0
char psz_buffer[MSTRTIME_MAX_SIZE];
/* Reinitialize synchro. */
vlc_mutex_lock( &p_input->p_item->lock );
p_pgrm
->
i_synchro_state
=
SYNCHRO_REINIT
;
p_input->p_item->i_duration = i_length;
vlc_mutex_unlock( &p_input->p_item->lock );
input_Control( p_input, INPUT_ADD_INFO, _("General"), _("Duration"),
msecstotimestr( psz_buffer, i_length / 1000 ) );
#endif
}
}
}
}
p_input
->
stream
.
p_new_area
=
NULL
;
var_SetBool
(
p_input
,
"intf-change"
,
VLC_TRUE
);
i_intf_update
=
mdate
()
+
I64C
(
150000
);
}
}
}
/* Wait we are asked to die */
if
(
!
p_input
->
b_die
)
{
Error
(
p_input
);
}
/* Clean up */
End
(
p_input
);
return
0
;
#if 0
while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
{
if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
{
{
if( p_input->stream.p_selected_area->i_size > 0 )
if( p_input->stream.p_selected_area->i_size > 0 )
...
@@ -532,66 +506,10 @@ static int RunThread( input_thread_t *p_input )
...
@@ -532,66 +506,10 @@ static int RunThread( input_thread_t *p_input )
p_input->stream.p_selected_area->i_seek = NO_SEEK;
p_input->stream.p_selected_area->i_seek = NO_SEEK;
}
}
if
(
p_input
->
stream
.
p_removed_es
)
{
input_UnselectES
(
p_input
,
p_input
->
stream
.
p_removed_es
);
p_input
->
stream
.
p_removed_es
=
NULL
;
}
if
(
p_input
->
stream
.
p_newly_selected_es
)
{
input_SelectES
(
p_input
,
p_input
->
stream
.
p_newly_selected_es
);
p_input
->
stream
.
p_newly_selected_es
=
NULL
;
}
if
(
p_input
->
stream
.
b_new_mute
!=
MUTE_NO_CHANGE
)
{
if
(
p_input
->
stream
.
b_new_mute
)
{
input_EscapeAudioDiscontinuity
(
p_input
);
}
vlc_mutex_lock
(
&
p_input
->
stream
.
control
.
control_lock
);
p_input
->
stream
.
control
.
b_mute
=
p_input
->
stream
.
b_new_mute
;
vlc_mutex_unlock
(
&
p_input
->
stream
.
control
.
control_lock
);
p_input
->
stream
.
b_new_mute
=
MUTE_NO_CHANGE
;
}
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
/* Read and demultiplex some data. */
/* Read and demultiplex some data. */
i_count = p_input->pf_demux( p_input );
i_count = p_input->pf_demux( p_input );
if
(
i_count
==
0
)
XXXXX
{
vlc_value_t
repeat
;
var_Get
(
p_input
,
"input-repeat"
,
&
repeat
);
if
(
repeat
.
i_int
==
0
||
p_input
->
stream
.
i_area_nb
<=
0
)
{
/* End of file - we do not set b_die because only the
* playlist is allowed to do so. */
msg_Info
(
p_input
,
"EOF reached"
);
p_input
->
b_eof
=
1
;
}
else
{
msg_Dbg
(
p_input
,
"repeating the same input (%d)"
,
repeat
.
i_int
);
if
(
repeat
.
i_int
>
0
)
{
repeat
.
i_int
--
;
var_Set
(
p_input
,
"input-repeat"
,
repeat
);
}
p_input
->
stream
.
p_new_area
=
p_input
->
stream
.
pp_areas
[
0
];
p_input
->
stream
.
p_new_area
->
i_seek
=
0
;
}
}
else
if
(
i_count
<
0
)
{
p_input
->
b_error
=
1
;
}
if( !p_input->b_error && !p_input->b_eof && i_update_next < mdate() )
if( !p_input->b_error && !p_input->b_eof && i_update_next < mdate() )
{
{
...
@@ -655,285 +573,363 @@ static int RunThread( input_thread_t *p_input )
...
@@ -655,285 +573,363 @@ static int RunThread( input_thread_t *p_input )
EndThread( p_input );
EndThread( p_input );
return 0;
return 0;
#endif
}
}
/*****************************************************************************
/*****************************************************************************
* Init
Thread
: init the input Thread
* Init: init the input Thread
*****************************************************************************/
*****************************************************************************/
static
int
Init
Thread
(
input_thread_t
*
p_input
)
static
int
Init
(
input_thread_t
*
p_input
)
{
{
vlc_meta_t
*
p_meta
=
NULL
,
*
p_meta_user
=
NULL
;
char
*
psz_dup
=
strdup
(
p_input
->
input
.
p_item
->
psz_uri
);
// float f_fps;
char
*
psz_access
=
NULL
;
double
f_fps
;
char
*
psz_demux
=
NULL
;
mtime_t
i_length
;
char
*
psz_path
=
NULL
;
char
*
psz
;
/* Parse source string. Syntax : [[<access>][/<demux>]:][<source>] */
vlc_value_t
val
;
char
*
psz_parser
=
p_input
->
psz_dupsource
=
strdup
(
p_input
->
psz_source
);
vlc_value_t
val
,
val1
;
int64_t
i_microsecondperframe
;
subtitle_demux_t
*
p_sub_toselect
=
NULL
;
char
*
psz_sub_file
=
NULL
;
/* Skip the plug-in names */
/* Open access/stream/demux */
while
(
*
psz_parser
&&
*
psz_parser
!=
':'
)
psz
=
strchr
(
psz_dup
,
':'
);
{
psz_parser
++
;
}
#if defined( WIN32 ) || defined( UNDER_CE )
#if defined( WIN32 ) || defined( UNDER_CE )
if
(
psz_parser
-
p_input
->
psz_dupsource
==
1
)
if
(
psz
-
psz_dup
==
1
)
{
msg_Warn
(
p_input
,
"drive letter %c: found in source string"
,
p_input
->
psz_dupsource
[
0
]
)
;
psz_parser
=
""
;
}
#endif
if
(
!*
psz_parser
)
{
{
p_input
->
psz_access
=
p_input
->
psz_demux
=
""
;
msg_Warn
(
p_input
,
"drive letter %c: found in source string"
,
psz_dup
[
0
]
);
p_input
->
psz_name
=
p_input
->
psz_source
;
free
(
p_input
->
psz_dupsource
);
p_input
->
psz_dupsource
=
NULL
;
}
}
else
else
#endif
if
(
psz
)
{
{
*
psz_parser
++
=
'\0'
;
*
psz
++
=
'\0'
;
if
(
psz
[
0
]
==
'/'
&&
psz
[
1
]
==
'/'
)
/* let's skip '//' */
psz
+=
2
;
if
(
psz_parser
[
0
]
==
'/'
&&
psz_parser
[
1
]
==
'/'
)
{
psz_parser
+=
2
;
}
p
_input
->
psz_name
=
psz_parser
;
p
sz_path
=
psz
;
/* Come back to parse the access and demux plug-ins */
psz
=
strchr
(
psz_dup
,
'/'
);
psz_parser
=
p_input
->
psz_dupsource
;
if
(
psz
)
if
(
!*
psz_parser
)
{
/* No access */
p_input
->
psz_access
=
""
;
}
else
if
(
*
psz_parser
==
'/'
)
{
/* No access */
p_input
->
psz_access
=
""
;
psz_parser
++
;
}
else
{
{
p_input
->
psz_access
=
psz_parser
;
*
psz
++
=
'\0'
;
psz_demux
=
psz
;
while
(
*
psz_parser
&&
*
psz_parser
!=
'/'
)
{
psz_parser
++
;
}
if
(
*
psz_parser
==
'/'
)
{
*
psz_parser
++
=
'\0'
;
}
}
}
if
(
!*
psz_parser
)
psz_access
=
psz_dup
;
{
/* No demux */
p_input
->
psz_demux
=
""
;
}
else
{
p_input
->
psz_demux
=
psz_parser
;
}
}
}
else
msg_Dbg
(
p_input
,
"access `%s', demux `%s', name `%s'"
,
p_input
->
psz_access
,
p_input
->
psz_demux
,
p_input
->
psz_name
);
if
(
input_AccessInit
(
p_input
)
==
-
1
)
{
{
free
(
p_input
->
psz_source
);
psz_path
=
psz_dup
;
if
(
p_input
->
psz_dupsource
!=
NULL
)
{
free
(
p_input
->
psz_dupsource
);
}
return
VLC_EGENERIC
;
}
}
/* Initialize optional stream output. (before demuxer)*/
if
(
psz_access
==
NULL
)
psz_access
=
""
;
var_Get
(
p_input
,
"sout"
,
&
val
);
if
(
psz_demux
==
NULL
)
psz_demux
=
""
;
if
(
val
.
psz_string
!=
NULL
)
if
(
psz_path
==
NULL
)
psz_path
=
""
;
msg_Dbg
(
p_input
,
"`%s' gives access `%s' demux `%s' path `%s'"
,
p_input
->
input
.
p_item
->
psz_uri
,
psz_access
,
psz_demux
,
psz_path
);
/* Initialize optional stream output. (before access/demuxer) */
psz
=
var_GetString
(
p_input
,
"sout"
);
if
(
*
psz
)
{
{
if
(
*
val
.
psz_string
&&
(
p_input
->
stream
.
p_sout
=
p_input
->
p_sout
=
sout_NewInstance
(
p_input
,
psz
);
sout_NewInstance
(
p_input
,
val
.
psz_string
))
==
NULL
)
if
(
p_input
->
p_sout
==
NULL
)
{
{
msg_Err
(
p_input
,
"cannot start stream output instance, aborting"
);
msg_Err
(
p_input
,
"cannot start stream output instance, aborting"
);
free
(
val
.
psz_string
);
free
(
psz
);
free
(
psz_dup
);
input_AccessEnd
(
p_input
);
free
(
p_input
->
psz_source
);
if
(
p_input
->
psz_dupsource
!=
NULL
)
{
free
(
p_input
->
psz_dupsource
);
}
return
VLC_EGENERIC
;
return
VLC_EGENERIC
;
}
}
free
(
val
.
psz_string
);
}
}
free
(
psz
);
/* Create es out */
p_input
->
p_es_out
=
input_EsOutNew
(
p_input
);
p_input
->
p_es_out
=
input_EsOutNew
(
p_input
);
es_out_Control
(
p_input
->
p_es_out
,
ES_OUT_SET_ACTIVE
,
VLC_FALSE
);
es_out_Control
(
p_input
->
p_es_out
,
ES_OUT_SET_ACTIVE
,
VLC_FALSE
);
es_out_Control
(
p_input
->
p_es_out
,
ES_OUT_SET_MODE
,
ES_OUT_MODE_NONE
);
es_out_Control
(
p_input
->
p_es_out
,
ES_OUT_SET_MODE
,
ES_OUT_MODE_NONE
);
/* Find and open appropriate access module */
/* Try access_demux if no demux given */
p_input
->
p_access
=
module_Need
(
p_input
,
"access"
,
if
(
*
psz_access
&&
*
psz_demux
==
'\0'
)
p_input
->
psz_access
,
VLC_TRUE
);
/* Maybe we had an encoded url */
if
(
!
p_input
->
p_access
&&
strchr
(
p_input
->
psz_name
,
'%'
)
)
{
{
DecodeUrl
(
p_input
->
psz_name
);
p_input
->
input
.
p_demux
=
demux2_New
(
p_input
,
psz_access
,
psz_demux
,
psz_path
,
NULL
,
p_input
->
p_es_out
);
}
msg_Dbg
(
p_input
,
"retying with %s"
,
p_input
->
psz_name
);
if
(
p_input
->
input
.
p_demux
)
p_input
->
p_access
=
module_Need
(
p_input
,
"access"
,
{
p_input
->
psz_access
,
VLC_TRUE
);
/* Get infos from access_demux */
demux2_Control
(
p_input
->
input
.
p_demux
,
DEMUX_GET_PTS_DELAY
,
&
p_input
->
i_pts_delay
);
p_input
->
input
.
b_title_demux
=
VLC_TRUE
;
if
(
demux2_Control
(
p_input
->
input
.
p_demux
,
DEMUX_GET_TITLE_INFO
,
&
p_input
->
input
.
title
,
&
p_input
->
input
.
i_title
)
)
{
p_input
->
input
.
i_title
=
0
;
p_input
->
input
.
title
=
NULL
;
}
demux2_Control
(
p_input
->
input
.
p_demux
,
DEMUX_CAN_CONTROL_PACE
,
&
p_input
->
input
.
b_can_pace_control
);
demux2_Control
(
p_input
->
input
.
p_demux
,
DEMUX_CAN_PAUSE
,
&
p_input
->
input
.
b_can_pause
);
}
}
else
{
/* Now try a real access */
p_input
->
input
.
p_access
=
access2_New
(
p_input
,
psz_access
,
psz_demux
,
psz_path
);
/* Access failed, URL encoded ? */
if
(
p_input
->
input
.
p_access
==
NULL
&&
strchr
(
psz_path
,
'%'
)
)
{
DecodeUrl
(
psz_path
);
msg_Dbg
(
p_input
,
"retying with access `%s' demux `%s' path `%s'"
,
psz_access
,
psz_demux
,
psz_path
);
p_input
->
input
.
p_access
=
access2_New
(
p_input
,
psz_access
,
psz_demux
,
psz_path
);
}
#ifndef WIN32
/* Remove this gross hack from the win32 build as colons
#ifndef WIN32
/* Remove this gross hack from the win32 build as colons
* are forbidden in filenames on Win32. */
* are forbidden in filenames on Win32. */
/* Maybe we got something like: /Volumes/toto:titi/gabu.mpg */
/* Maybe we got something like: /Volumes/toto:titi/gabu.mpg */
if
(
p_input
->
p_access
==
NULL
if
(
p_input
->
input
.
p_access
==
NULL
&&
&&
(
*
p_input
->
psz_demux
||
*
p_input
->
psz_access
)
)
*
psz_access
==
'\0'
&&
(
*
psz_demux
||
*
psz_path
)
)
{
{
p_input
->
psz_access
=
p_input
->
psz_demux
=
""
;
free
(
psz_dup
);
p_input
->
psz_name
=
p_input
->
psz_source
;
psz_dup
=
strdup
(
p_input
->
input
.
p_item
->
psz_uri
);
free
(
p_input
->
psz_dupsource
);
psz_access
=
""
;
p_input
->
psz_dupsource
=
NULL
;
psz_demux
=
""
;
psz_path
=
psz_dup
;
p_input
->
p_access
=
module_Need
(
p_input
,
"access"
,
p_input
->
input
.
p_access
=
access2_New
(
p_input
,
psz_access
,
psz_demux
,
psz_path
);
p_input
->
psz_access
,
VLC_TRUE
);
}
}
#endif
#endif
if
(
p_input
->
p_access
==
NULL
)
{
if
(
p_input
->
input
.
p_access
==
NULL
)
msg_Err
(
p_input
,
"no suitable access module for `%s/%s://%s'"
,
p_input
->
psz_access
,
p_input
->
psz_demux
,
p_input
->
psz_name
);
if
(
p_input
->
stream
.
p_sout
!=
NULL
)
{
{
sout_DeleteInstance
(
p_input
->
stream
.
p_sout
);
msg_Err
(
p_input
,
"no suitable access module for `%s'"
,
p_input
->
input
.
p_item
->
psz_uri
);
goto
error
;
}
}
input_AccessEnd
(
p_input
);
/* Get infos from access */
free
(
p_input
->
psz_source
);
access2_Control
(
p_input
->
input
.
p_access
,
if
(
p_input
->
psz_dupsource
!=
NULL
)
ACCESS_GET_PTS_DELAY
,
&
p_input
->
i_pts_delay
);
p_input
->
input
.
b_title_demux
=
VLC_FALSE
;
if
(
access2_Control
(
p_input
->
input
.
p_access
,
ACCESS_GET_TITLE_INFO
,
&
p_input
->
input
.
title
,
&
p_input
->
input
.
i_title
)
)
{
{
free
(
p_input
->
psz_dupsource
);
p_input
->
input
.
i_title
=
0
;
p_input
->
input
.
title
=
NULL
;
}
access2_Control
(
p_input
->
input
.
p_access
,
ACCESS_CAN_CONTROL_PACE
,
&
p_input
->
input
.
b_can_pace_control
);
access2_Control
(
p_input
->
input
.
p_access
,
ACCESS_CAN_PAUSE
,
&
p_input
->
input
.
b_can_pace_control
);
/* Create the stream_t */
p_input
->
input
.
p_stream
=
stream_AccessNew
(
p_input
->
input
.
p_access
);
if
(
p_input
->
input
.
p_stream
==
NULL
)
{
msg_Warn
(
p_input
,
"cannot create a stream_t from access"
);
goto
error
;
}
}
input_EsOutDelete
(
p_input
->
p_es_out
);
return
VLC_EGENERIC
;
}
/* Waiting for stream. */
/* Open a demuxer */
if
(
p_input
->
i_mtu
)
if
(
*
psz_demux
==
'\0'
&&
*
p_input
->
input
.
p_access
->
psz_demux
)
{
{
p_input
->
i_bufsize
=
p_input
->
i_mtu
;
psz_demux
=
p_input
->
input
.
p_access
->
psz_demux
;
}
p_input
->
input
.
p_demux
=
demux2_New
(
p_input
,
psz_access
,
psz_demux
,
psz_path
,
p_input
->
input
.
p_stream
,
p_input
->
p_es_out
);
if
(
p_input
->
input
.
p_demux
==
NULL
)
{
msg_Err
(
p_input
,
"no suitable demux module for `%s/%s://%s'"
,
psz_access
,
psz_demux
,
psz_path
);
goto
error
;
}
/* TODO get title from demux */
if
(
p_input
->
input
.
i_title
<=
0
)
{
if
(
demux2_Control
(
p_input
->
input
.
p_demux
,
DEMUX_GET_TITLE_INFO
,
&
p_input
->
input
.
title
,
&
p_input
->
input
.
i_title
)
)
{
p_input
->
input
.
i_title
=
0
;
p_input
->
input
.
title
=
NULL
;
}
else
{
p_input
->
input
.
b_title_demux
=
VLC_TRUE
;
}
}
}
}
else
/* Create global title (for now, just a copy) */
p_input
->
i_title
=
p_input
->
input
.
i_title
;
if
(
p_input
->
i_title
>
0
)
{
{
p_input
->
i_bufsize
=
INPUT_DEFAULT_BUFSIZE
;
int
i
;
p_input
->
title
=
malloc
(
sizeof
(
input_title_t
*
)
*
p_input
->
i_title
);
for
(
i
=
0
;
i
<
p_input
->
i_title
;
i
++
)
{
p_input
->
title
[
i
]
=
vlc_input_title_Duplicate
(
p_input
->
input
.
title
[
i
]
);
}
/* Setup variables */
input_ControlVarNavigation
(
p_input
);
input_ControlVarTitle
(
p_input
,
0
);
}
}
/* Global flag */
p_input
->
b_can_pace_control
=
p_input
->
input
.
b_can_pace_control
;
p_input
->
b_can_pause
=
p_input
->
input
.
b_can_pause
;
/* Fix pts delay */
if
(
p_input
->
i_pts_delay
<=
0
)
p_input
->
i_pts_delay
=
DEFAULT_PTS_DELAY
;
/* If the desynchronisation requested by the user is < 0, we need to
/* If the desynchronisation requested by the user is < 0, we need to
* cache more data. */
* cache more data. */
var_Create
(
p_input
,
"audio-desync"
,
VLC_VAR_INTEGER
|
VLC_VAR_DOINHERIT
);
var_Get
(
p_input
,
"audio-desync"
,
&
val
);
var_Get
(
p_input
,
"audio-desync"
,
&
val
);
if
(
val
.
i_int
<
0
)
if
(
val
.
i_int
<
0
)
p_input
->
i_pts_delay
-=
(
val
.
i_int
*
1000
);
p_input
->
i_pts_delay
-=
(
val
.
i_int
*
1000
);
if
(
p_input
->
p_current_data
==
NULL
&&
p_input
->
pf_read
!=
NULL
)
/* Init input_thread_sys_t */
{
p_input
->
p_sys
=
malloc
(
sizeof
(
input_thread_sys_t
)
);
while
(
!
input_FillBuffer
(
p_input
)
)
p_input
->
p_sys
->
i_sub
=
0
;
{
p_input
->
p_sys
->
sub
=
NULL
;
if
(
p_input
->
b_die
||
p_input
->
b_error
||
p_input
->
b_eof
)
{
module_Unneed
(
p_input
,
p_input
->
p_access
);
if
(
p_input
->
stream
.
p_sout
!=
NULL
)
{
sout_DeleteInstance
(
p_input
->
stream
.
p_sout
);
}
input_AccessEnd
(
p_input
);
free
(
p_input
->
psz_source
);
if
(
p_input
->
psz_dupsource
!=
NULL
)
{
free
(
p_input
->
psz_dupsource
);
}
input_EsOutDelete
(
p_input
->
p_es_out
);
return
VLC_EGENERIC
;
}
}
}
/* Create the stream_t facilities */
/* TODO: check meta data from users */
p_input
->
s
=
input_StreamNew
(
p_input
);
if
(
p_input
->
s
==
NULL
)
{
/* should never occur yet */
msg_Err
(
p_input
,
"cannot create stream_t"
);
/* TODO: get meta data from demuxer */
module_Unneed
(
p_input
,
p_input
->
p_access
);
/* Init length */
if
(
p_input
->
stream
.
p_sout
!=
NULL
)
if
(
!
demux2_Control
(
p_input
->
input
.
p_demux
,
DEMUX_GET_LENGTH
,
&
val
.
i_time
)
&&
val
.
i_time
>
0
)
{
var_Change
(
p_input
,
"length"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
/* TODO update playlist meta data */
}
/* Start time*/
/* Set start time */
p_input
->
i_start
=
(
int64_t
)
var_GetInteger
(
p_input
,
"start-time"
)
*
I64C
(
1000000
);
p_input
->
i_stop
=
(
int64_t
)
var_GetInteger
(
p_input
,
"stop-time"
)
*
I64C
(
1000000
);
if
(
p_input
->
i_start
>
0
)
{
if
(
p_input
->
i_start
>=
val
.
i_time
)
{
{
sout_DeleteInstance
(
p_input
->
stream
.
p_sout
);
msg_Warn
(
p_input
,
"invalid start-time ignored"
);
}
}
input_AccessEnd
(
p_input
);
else
free
(
p_input
->
psz_source
);
if
(
p_input
->
psz_dupsource
!=
NULL
)
{
{
free
(
p_input
->
psz_dupsource
);
vlc_value_t
s
;
msg_Dbg
(
p_input
,
"start-time: %ds"
,
(
int
)(
p_input
->
i_start
/
I64C
(
1000000
)
)
);
s
.
i_time
=
p_input
->
i_start
;
input_ControlPush
(
p_input
,
INPUT_CONTROL_SET_TIME
,
&
s
);
}
}
input_EsOutDelete
(
p_input
->
p_es_out
);
}
return
VLC_EGENERIC
;
if
(
p_input
->
i_stop
>
0
&&
p_input
->
i_stop
<=
p_input
->
i_start
)
{
msg_Warn
(
p_input
,
"invalid stop-time ignored"
);
p_input
->
i_stop
=
0
;
}
}
/* Find and open appropriate demux module */
p_input
->
p_demux
=
module_Need
(
p_input
,
"demux"
,
(
p_input
->
psz_demux
&&
*
p_input
->
psz_demux
)
?
p_input
->
psz_demux
:
"$demux"
,
(
p_input
->
psz_demux
&&
*
p_input
->
psz_demux
)
?
VLC_TRUE
:
VLC_FALSE
);
if
(
p_input
->
p_demux
==
NULL
)
/* TODO: do subtitle loading */
{
msg_Err
(
p_input
,
"no suitable demux module for `%s/%s://%s'"
,
p_input
->
psz_access
,
p_input
->
psz_demux
,
p_input
->
psz_name
);
input_StreamDelete
(
p_input
->
s
);
module_Unneed
(
p_input
,
p_input
->
p_access
);
/* Set up es_out */
if
(
p_input
->
stream
.
p_sout
!=
NULL
)
es_out_Control
(
p_input
->
p_es_out
,
ES_OUT_SET_ACTIVE
,
VLC_TRUE
);
{
val
.
b_bool
=
VLC_FALSE
;
sout_DeleteInstance
(
p_input
->
stream
.
p_sout
);
if
(
p_input
->
p_sout
)
}
{
input_AccessEnd
(
p_input
);
var_Get
(
p_input
,
"sout-all"
,
&
val
);
free
(
p_input
->
psz_source
);
}
if
(
p_input
->
psz_dupsource
!=
NULL
)
es_out_Control
(
p_input
->
p_es_out
,
ES_OUT_SET_MODE
,
{
val
.
b_bool
?
ES_OUT_MODE_ALL
:
ES_OUT_MODE_AUTO
);
free
(
p_input
->
psz_dupsource
);
/* TODO select forced subs */
#if 0
if( p_sub_toselect )
{
es_out_Control( p_input->p_es_out, ES_OUT_SET_ES,
p_sub_toselect->p_es, VLC_TRUE );
}
#endif
if
(
p_input
->
p_sout
)
{
if
(
p_input
->
p_sout
->
i_out_pace_nocontrol
>
0
)
{
p_input
->
b_out_pace_control
=
VLC_FALSE
;
}
}
input_EsOutDelete
(
p_input
->
p_es_out
);
else
return
VLC_EGENERIC
;
{
p_input
->
b_out_pace_control
=
VLC_TRUE
;
}
msg_Dbg
(
p_input
,
"starting in %s mode"
,
p_input
->
b_out_pace_control
?
"asynch"
:
"synch"
);
}
}
msg_Dbg
(
p_input
,
"`%s' sucessfully opened"
,
p_input
->
input
.
p_item
->
psz_uri
);
/* initialization is complete */
p_input
->
i_state
=
PLAYING_S
;
val
.
i_int
=
PLAYING_S
;
var_Change
(
p_input
,
"state"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
return
VLC_SUCCESS
;
error:
if
(
p_input
->
input
.
p_demux
)
demux2_Delete
(
p_input
->
input
.
p_demux
);
if
(
p_input
->
input
.
p_stream
)
stream_AccessDelete
(
p_input
->
input
.
p_stream
);
if
(
p_input
->
input
.
p_access
)
access2_Delete
(
p_input
->
input
.
p_access
);
if
(
p_input
->
p_es_out
)
input_EsOutDelete
(
p_input
->
p_es_out
);
if
(
p_input
->
p_sout
)
sout_DeleteInstance
(
p_input
->
p_sout
);
/* Mark them deleted */
p_input
->
input
.
p_demux
=
NULL
;
p_input
->
input
.
p_stream
=
NULL
;
p_input
->
input
.
p_access
=
NULL
;
p_input
->
p_es_out
=
NULL
;
p_input
->
p_sout
=
NULL
;
return
VLC_EGENERIC
;
#if 0
vlc_meta_t *p_meta = NULL, *p_meta_user = NULL;
// float f_fps;
double f_fps;
mtime_t i_length;
FIXME
p_input->input.i_cr_average = config_GetInt( p_input, "cr-average" );
p_input->stream.control.i_status = INIT_S;
p_input->stream.control.i_rate = DEFAULT_RATE;
/* Init input_thread_sys_t */
/* Init input_thread_sys_t */
p_input->p_sys = malloc( sizeof( input_thread_sys_t ) );
p_input->p_sys = malloc( sizeof( input_thread_sys_t ) );
p_input->p_sys->i_sub = 0;
p_input->p_sys->i_sub = 0;
p_input->p_sys->sub = NULL;
p_input->p_sys->sub = NULL;
p_input
->
p_sys
->
i_stop_time
=
0
;
/* Get meta information from user */
/* Get meta information from user */
var_Create( p_input, "meta-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
var_Create( p_input, "meta-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
var_Create( p_input, "meta-author", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
var_Create( p_input, "meta-author", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
...
@@ -948,37 +944,37 @@ static int InitThread( input_thread_t * p_input )
...
@@ -948,37 +944,37 @@ static int InitThread( input_thread_t * p_input )
vlc_value_t val;
vlc_value_t val;
var_Get( p_input, "meta-title", &val );
var_Get( p_input, "meta-title", &val );
if
(
val
.
psz_string
&&
*
val
.
psz_string
)
if( *val.psz_string )
vlc_meta_Add( p_meta_user, VLC_META_TITLE, val.psz_string );
vlc_meta_Add( p_meta_user, VLC_META_TITLE, val.psz_string );
if
(
val
.
psz_string
)
free
(
val
.
psz_string
);
free( val.psz_string );
var_Get( p_input, "meta-author", &val );
var_Get( p_input, "meta-author", &val );
if
(
val
.
psz_string
&&
*
val
.
psz_string
)
if( *val.psz_string )
vlc_meta_Add( p_meta_user, VLC_META_AUTHOR, val.psz_string );
vlc_meta_Add( p_meta_user, VLC_META_AUTHOR, val.psz_string );
if
(
val
.
psz_string
)
free
(
val
.
psz_string
);
free( val.psz_string );
var_Get( p_input, "meta-artist", &val );
var_Get( p_input, "meta-artist", &val );
if
(
val
.
psz_string
&&
*
val
.
psz_string
)
if( *val.psz_string )
vlc_meta_Add( p_meta_user, VLC_META_ARTIST, val.psz_string );
vlc_meta_Add( p_meta_user, VLC_META_ARTIST, val.psz_string );
if
(
val
.
psz_string
)
free
(
val
.
psz_string
);
free( val.psz_string );
var_Get( p_input, "meta-genre", &val );
var_Get( p_input, "meta-genre", &val );
if
(
val
.
psz_string
&&
*
val
.
psz_string
)
if( *val.psz_string )
vlc_meta_Add( p_meta_user, VLC_META_GENRE, val.psz_string );
vlc_meta_Add( p_meta_user, VLC_META_GENRE, val.psz_string );
if
(
val
.
psz_string
)
free
(
val
.
psz_string
);
free( val.psz_string );
var_Get( p_input, "meta-copyright", &val );
var_Get( p_input, "meta-copyright", &val );
if
(
val
.
psz_string
&&
*
val
.
psz_string
)
if( *val.psz_string )
vlc_meta_Add( p_meta_user, VLC_META_COPYRIGHT, val.psz_string );
vlc_meta_Add( p_meta_user, VLC_META_COPYRIGHT, val.psz_string );
if
(
val
.
psz_string
)
free
(
val
.
psz_string
);
free( val.psz_string );
var_Get( p_input, "meta-description", &val );
var_Get( p_input, "meta-description", &val );
if
(
val
.
psz_string
&&
*
val
.
psz_string
)
if( *val.psz_string )
vlc_meta_Add( p_meta_user, VLC_META_DESCRIPTION, val.psz_string );
vlc_meta_Add( p_meta_user, VLC_META_DESCRIPTION, val.psz_string );
if
(
val
.
psz_string
)
free
(
val
.
psz_string
);
free( val.psz_string );
var_Get( p_input, "meta-date", &val );
var_Get( p_input, "meta-date", &val );
if
(
val
.
psz_string
&&
*
val
.
psz_string
)
if( *val.psz_string )
vlc_meta_Add( p_meta_user, VLC_META_DATE, val.psz_string );
vlc_meta_Add( p_meta_user, VLC_META_DATE, val.psz_string );
if
(
val
.
psz_string
)
free
(
val
.
psz_string
);
free( val.psz_string );
var_Get( p_input, "meta-url", &val );
var_Get( p_input, "meta-url", &val );
if
(
val
.
psz_string
&&
*
val
.
psz_string
)
if( *val.psz_string )
vlc_meta_Add( p_meta_user, VLC_META_URL, val.psz_string );
vlc_meta_Add( p_meta_user, VLC_META_URL, val.psz_string );
if
(
val
.
psz_string
)
free
(
val
.
psz_string
);
free( val.psz_string );
}
}
/* Get meta informations from demuxer */
/* Get meta informations from demuxer */
...
@@ -1077,25 +1073,6 @@ static int InitThread( input_thread_t * p_input )
...
@@ -1077,25 +1073,6 @@ static int InitThread( input_thread_t * p_input )
}
}
}
}
/* Set stop-time and check validity */
var_Get
(
p_input
,
"stop-time"
,
&
val
);
if
(
val
.
i_int
>
0
)
{
vlc_value_t
start
;
var_Get
(
p_input
,
"start-time"
,
&
start
);
if
(
start
.
i_int
>=
val
.
i_int
)
{
msg_Warn
(
p_input
,
"invalid stop-time, ignored (stop-time < "
"start-time)"
);
}
else
{
p_input
->
p_sys
->
i_stop_time
=
(
int64_t
)
val
.
i_int
*
I64C
(
1000000
);
msg_Dbg
(
p_input
,
"stop-time %ds"
,
val
.
i_int
);
}
}
/* Get fps */
/* Get fps */
if( demux_Control( p_input, DEMUX_GET_FPS, &f_fps ) || f_fps < 0.1 )
if( demux_Control( p_input, DEMUX_GET_FPS, &f_fps ) || f_fps < 0.1 )
{
{
...
@@ -1161,30 +1138,15 @@ static int InitThread( input_thread_t * p_input )
...
@@ -1161,30 +1138,15 @@ static int InitThread( input_thread_t * p_input )
es_out_Control( p_input->p_es_out, ES_OUT_SET_ES,
es_out_Control( p_input->p_es_out, ES_OUT_SET_ES,
p_sub_toselect->p_es, VLC_TRUE );
p_sub_toselect->p_es, VLC_TRUE );
}
}
#endif
if
(
p_input
->
stream
.
p_sout
)
{
if
(
p_input
->
stream
.
p_sout
->
i_out_pace_nocontrol
>
0
)
{
p_input
->
b_out_pace_control
=
VLC_FALSE
;
}
else
{
p_input
->
b_out_pace_control
=
VLC_TRUE
;
}
msg_Dbg
(
p_input
,
"starting in %s mode"
,
p_input
->
b_out_pace_control
?
"asynch"
:
"synch"
);
}
return
VLC_SUCCESS
;
}
}
/*****************************************************************************
/*****************************************************************************
* Error
Thread
: RunThread() error loop
* Error: RunThread() error loop
*****************************************************************************
*****************************************************************************
* This function is called when an error occured during thread main's loop.
* This function is called when an error occured during thread main's loop.
*****************************************************************************/
*****************************************************************************/
static
void
Error
Thread
(
input_thread_t
*
p_input
)
static
void
Error
(
input_thread_t
*
p_input
)
{
{
while
(
!
p_input
->
b_die
)
while
(
!
p_input
->
b_die
)
{
{
...
@@ -1194,55 +1156,39 @@ static void ErrorThread( input_thread_t *p_input )
...
@@ -1194,55 +1156,39 @@ static void ErrorThread( input_thread_t *p_input )
}
}
/*****************************************************************************
/*****************************************************************************
* End
Thread
: end the input thread
* End: end the input thread
*****************************************************************************/
*****************************************************************************/
static
void
End
Thread
(
input_thread_t
*
p_input
)
static
void
End
(
input_thread_t
*
p_input
)
{
{
int
i
,
j
;
vlc_value_t
val
;
#ifdef HAVE_SYS_TIMES_H
/* Display statistics */
struct
tms
cpu_usage
;
times
(
&
cpu_usage
);
msg_Dbg
(
p_input
,
"%ld loops consuming user: %ld, system: %ld"
,
p_input
->
c_loops
,
cpu_usage
.
tms_utime
,
cpu_usage
.
tms_stime
);
#else
msg_Dbg
(
p_input
,
"%ld loops"
,
p_input
->
c_loops
);
#endif
msg_Dbg
(
p_input
,
"closing `%s'"
,
p_input
->
input
.
p_item
->
psz_uri
);
/* DumpStream: printf some info for debugging purpose */
/* We are at the end */
#define S p_input->stream
p_input
->
i_state
=
END_S
;
msg_Dbg
(
p_input
,
"dumping stream ID 0x%x [OK:%ld/D:%ld]"
,
S
.
i_stream_id
,
S
.
c_packets_read
,
S
.
c_packets_trashed
);
val
.
i_int
=
END_S
;
#undef S
var_Change
(
p_input
,
"state"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
for
(
i
=
0
;
i
<
p_input
->
stream
.
i_pgrm_number
;
i
++
)
{
/* Clean control variables */
#define P p_input->stream.pp_programs[i]
input_ControlVarClean
(
p_input
);
msg_Dbg
(
p_input
,
"dumping program 0x%x, version %d (%s)"
,
P
->
i_number
,
P
->
i_version
,
P
->
b_is_ok
?
"complete"
:
"partial"
);
#undef P
for
(
j
=
0
;
j
<
p_input
->
stream
.
pp_programs
[
i
]
->
i_es_number
;
j
++
)
{
#define ES p_input->stream.pp_programs[i]->pp_es[j]
msg_Dbg
(
p_input
,
"ES 0x%x, "
"stream 0x%x, fourcc `%4.4s', %s [OK:%ld/ERR:%ld]"
,
ES
->
i_id
,
ES
->
i_stream_id
,
(
char
*
)
&
ES
->
i_fourcc
,
ES
->
p_dec
!=
NULL
?
"selected"
:
"not selected"
,
ES
->
c_packets
,
ES
->
c_invalid_packets
);
#undef ES
}
}
/* Free demultiplexer's data */
/* Unload all modules */
if
(
p_input
->
p_demux
)
module_Unneed
(
p_input
,
p_input
->
p_demux
);
if
(
p_input
->
input
.
p_demux
)
demux2_Delete
(
p_input
->
input
.
p_demux
);
/* Free all ES and destroy all decoder threads */
if
(
p_input
->
input
.
p_stream
)
input_EndStream
(
p_input
);
stream_AccessDelete
(
p_input
->
input
.
p_stream
);
if
(
p_input
->
input
.
p_access
)
access2_Delete
(
p_input
->
input
.
p_access
);
if
(
p_input
->
p_es_out
)
input_EsOutDelete
(
p_input
->
p_es_out
);
/* Close optional stream output instance */
/* Close optional stream output instance */
if
(
p_input
->
stream
.
p_sout
)
if
(
p_input
->
p_sout
)
{
{
vlc_object_t
*
p_pl
=
vlc_object_t
*
p_pl
=
vlc_object_find
(
p_input
,
VLC_OBJECT_PLAYLIST
,
FIND_ANYWHERE
);
vlc_object_find
(
p_input
,
VLC_OBJECT_PLAYLIST
,
FIND_ANYWHERE
);
...
@@ -1252,20 +1198,20 @@ static void EndThread( input_thread_t * p_input )
...
@@ -1252,20 +1198,20 @@ static void EndThread( input_thread_t * p_input )
{
{
/* attach sout to the playlist */
/* attach sout to the playlist */
msg_Warn
(
p_input
,
"keeping sout"
);
msg_Warn
(
p_input
,
"keeping sout"
);
vlc_object_detach
(
p_input
->
stream
.
p_sout
);
vlc_object_detach
(
p_input
->
p_sout
);
vlc_object_attach
(
p_input
->
stream
.
p_sout
,
p_pl
);
vlc_object_attach
(
p_input
->
p_sout
,
p_pl
);
}
}
else
else
{
{
msg_Warn
(
p_input
,
"destroying sout"
);
msg_Warn
(
p_input
,
"destroying sout"
);
sout_DeleteInstance
(
p_input
->
stream
.
p_sout
);
sout_DeleteInstance
(
p_input
->
p_sout
);
}
}
if
(
p_pl
)
if
(
p_pl
)
{
vlc_object_release
(
p_pl
);
vlc_object_release
(
p_pl
);
}
}
}
/* TODO subs */
#if 0
/* Destroy subtitles demuxers */
/* Destroy subtitles demuxers */
if( p_input->p_sys )
if( p_input->p_sys )
{
{
...
@@ -1278,30 +1224,471 @@ static void EndThread( input_thread_t * p_input )
...
@@ -1278,30 +1224,471 @@ static void EndThread( input_thread_t * p_input )
free( p_input->p_sys->sub );
free( p_input->p_sys->sub );
}
}
/* Free input_thread_sys_t */
free
(
p_input
->
p_sys
);
}
}
#endif
/* Free input_thread_sys_t */
free
(
p_input
->
p_sys
);
/* Destroy the stream_t facilities */
/* Tell we're dead */
if
(
p_input
->
s
)
input_StreamDelete
(
p_input
->
s
);
p_input
->
b_dead
=
VLC_TRUE
;
}
/* Destroy es out */
/*****************************************************************************
if
(
p_input
->
p_es_out
)
input_EsOutDelete
(
p_input
->
p_es_out
);
* Control
*****************************************************************************/
static
inline
int
ControlPopNoLock
(
input_thread_t
*
p_input
,
int
*
pi_type
,
vlc_value_t
*
p_val
)
{
if
(
p_input
->
i_control
<=
0
)
{
return
VLC_EGENERIC
;
}
/* Close the access plug-in */
*
pi_type
=
p_input
->
control
[
0
].
i_type
;
if
(
p_input
->
p_access
)
module_Unneed
(
p_input
,
p_input
->
p_access
)
;
*
p_val
=
p_input
->
control
[
0
].
val
;
input_AccessEnd
(
p_input
);
p_input
->
i_control
--
;
if
(
p_input
->
i_control
>
0
)
{
int
i
;
/* Free info structures XXX destroy es before 'cause vorbis */
for
(
i
=
0
;
i
<
p_input
->
i_control
;
i
++
)
msg_Dbg
(
p_input
,
"freeing info structures..."
);
{
p_input
->
control
[
i
].
i_type
=
p_input
->
control
[
i
+
1
].
i_type
;
p_input
->
control
[
i
].
val
=
p_input
->
control
[
i
+
1
].
val
;
}
}
free
(
p_input
->
psz_source
)
;
return
VLC_SUCCESS
;
if
(
p_input
->
psz_dupsource
!=
NULL
)
free
(
p_input
->
psz_dupsource
);
}
/* Tell we're dead */
static
void
ControlReduce
(
input_thread_t
*
p_input
)
p_input
->
b_dead
=
1
;
{
int
i
;
for
(
i
=
1
;
i
<
p_input
->
i_control
;
i
++
)
{
const
int
i_lt
=
p_input
->
control
[
i
-
1
].
i_type
;
const
int
i_ct
=
p_input
->
control
[
i
].
i_type
;
/* XXX We can't merge INPUT_CONTROL_SET_ES */
msg_Dbg
(
p_input
,
"[%d/%d] l=%d c=%d"
,
i
,
p_input
->
i_control
,
i_lt
,
i_ct
);
if
(
i_lt
==
i_ct
&&
(
i_ct
==
INPUT_CONTROL_SET_STATE
||
i_ct
==
INPUT_CONTROL_SET_RATE
||
i_ct
==
INPUT_CONTROL_SET_POSITION
||
i_ct
==
INPUT_CONTROL_SET_TIME
||
i_ct
==
INPUT_CONTROL_SET_PROGRAM
||
i_ct
==
INPUT_CONTROL_SET_TITLE
||
i_ct
==
INPUT_CONTROL_SET_SEEKPOINT
||
i_ct
==
INPUT_CONTROL_SET_BOOKMARK
)
)
{
int
j
;
msg_Dbg
(
p_input
,
"merged at %d"
,
i
);
/* Remove the i-1 */
for
(
j
=
i
;
j
<
p_input
->
i_control
;
j
++
)
p_input
->
control
[
j
-
1
]
=
p_input
->
control
[
j
];
p_input
->
i_control
--
;
}
else
{
/* TODO but that's not that important
- merge SET_X with SET_X_CMD
- remove SET_SEEKPOINT/SET_POSITION/SET_TIME before a SET_TITLE
- remove SET_SEEKPOINT/SET_POSITION/SET_TIME before another among them
- ?
*/
}
}
}
}
static
vlc_bool_t
Control
(
input_thread_t
*
p_input
,
int
i_type
,
vlc_value_t
val
)
{
vlc_bool_t
b_force_update
=
VLC_FALSE
;
switch
(
i_type
)
{
case
INPUT_CONTROL_SET_DIE
:
msg_Dbg
(
p_input
,
"control: INPUT_CONTROL_SET_DIE proceed"
);
/* Mark all submodules to die */
if
(
p_input
->
input
.
p_access
)
p_input
->
input
.
p_access
->
b_die
=
VLC_TRUE
;
if
(
p_input
->
input
.
p_stream
)
p_input
->
input
.
p_stream
->
b_die
=
VLC_TRUE
;
p_input
->
input
.
p_demux
->
b_die
=
VLC_TRUE
;
p_input
->
b_die
=
VLC_TRUE
;
break
;
case
INPUT_CONTROL_SET_POSITION
:
case
INPUT_CONTROL_SET_POSITION_OFFSET
:
{
double
f_pos
;
if
(
i_type
==
INPUT_CONTROL_SET_POSITION
)
{
f_pos
=
val
.
f_float
;
}
else
{
/* Should not fail */
demux2_Control
(
p_input
->
input
.
p_demux
,
DEMUX_GET_POSITION
,
&
f_pos
);
f_pos
+=
val
.
f_float
;
}
if
(
f_pos
<
0
.
0
)
f_pos
=
0
.
0
;
if
(
f_pos
>
1
.
0
)
f_pos
=
1
.
0
;
if
(
demux2_Control
(
p_input
->
input
.
p_demux
,
DEMUX_SET_POSITION
,
f_pos
)
)
{
msg_Err
(
p_input
,
"INPUT_CONTROL_SET_POSITION(_OFFSET) %2.1f%% failed"
,
f_pos
*
100
);
}
else
{
input_EsOutDiscontinuity
(
p_input
->
p_es_out
,
VLC_FALSE
);
es_out_Control
(
p_input
->
p_es_out
,
ES_OUT_RESET_PCR
);
b_force_update
=
VLC_TRUE
;
}
break
;
}
case
INPUT_CONTROL_SET_TIME
:
case
INPUT_CONTROL_SET_TIME_OFFSET
:
{
int64_t
i_time
;
int
i_ret
;
if
(
i_type
==
INPUT_CONTROL_SET_TIME
)
{
i_time
=
val
.
i_time
;
}
else
{
/* Should not fail */
demux2_Control
(
p_input
->
input
.
p_demux
,
DEMUX_GET_TIME
,
&
i_time
);
i_time
+=
val
.
i_time
;
}
if
(
i_time
<
0
)
i_time
=
0
;
i_ret
=
demux2_Control
(
p_input
->
input
.
p_demux
,
DEMUX_SET_TIME
,
i_time
);
if
(
i_ret
)
{
int64_t
i_length
;
/* Emulate it with a SET_POS */
demux2_Control
(
p_input
->
input
.
p_demux
,
DEMUX_GET_LENGTH
,
&
i_length
);
if
(
i_length
>
0
)
{
double
f_pos
=
(
double
)
i_time
/
(
double
)
i_length
;
i_ret
=
demux2_Control
(
p_input
->
input
.
p_demux
,
DEMUX_SET_POSITION
,
f_pos
);
}
}
if
(
i_ret
)
{
msg_Err
(
p_input
,
"INPUT_CONTROL_SET_TIME(_OFFSET) %lld failed"
,
i_time
);
}
else
{
input_EsOutDiscontinuity
(
p_input
->
p_es_out
,
VLC_FALSE
);
es_out_Control
(
p_input
->
p_es_out
,
ES_OUT_RESET_PCR
);
b_force_update
=
VLC_TRUE
;
}
break
;
}
case
INPUT_CONTROL_SET_STATE
:
if
(
(
val
.
i_int
==
PLAYING_S
&&
p_input
->
i_state
==
PAUSE_S
)
||
(
val
.
i_int
==
PAUSE_S
&&
p_input
->
i_state
==
PAUSE_S
)
)
{
int
i_ret
;
if
(
p_input
->
input
.
p_access
)
i_ret
=
access2_Control
(
p_input
->
input
.
p_access
,
ACCESS_SET_PAUSE_STATE
,
VLC_FALSE
);
else
i_ret
=
demux2_Control
(
p_input
->
input
.
p_demux
,
DEMUX_SET_PAUSE_STATE
,
VLC_FALSE
);
if
(
i_ret
)
{
/* FIXME What to do ? */
msg_Warn
(
p_input
,
"cannot unset pause -> EOF"
);
input_ControlPush
(
p_input
,
INPUT_CONTROL_SET_DIE
,
NULL
);
}
b_force_update
=
VLC_TRUE
;
/* Switch to play */
p_input
->
i_state
=
PLAYING_S
;
val
.
i_int
=
PLAYING_S
;
var_Change
(
p_input
,
"state"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
/* Reset clock */
es_out_Control
(
p_input
->
p_es_out
,
ES_OUT_RESET_PCR
);
}
else
if
(
val
.
i_int
==
PAUSE_S
&&
p_input
->
i_state
==
PLAYING_S
&&
p_input
->
b_can_pause
)
{
int
i_ret
;
if
(
p_input
->
input
.
p_access
)
i_ret
=
access2_Control
(
p_input
->
input
.
p_access
,
ACCESS_SET_PAUSE_STATE
,
VLC_TRUE
);
else
i_ret
=
demux2_Control
(
p_input
->
input
.
p_demux
,
DEMUX_SET_PAUSE_STATE
,
VLC_TRUE
);
b_force_update
=
VLC_TRUE
;
if
(
i_ret
)
{
msg_Warn
(
p_input
,
"cannot set pause state"
);
val
.
i_int
=
p_input
->
i_state
;
}
else
{
val
.
i_int
=
PAUSE_S
;
}
/* Switch to new state */
p_input
->
i_state
=
val
.
i_int
;
var_Change
(
p_input
,
"state"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
}
else
if
(
val
.
i_int
==
PAUSE_S
&&
!
p_input
->
b_can_pause
)
{
b_force_update
=
VLC_TRUE
;
/* Correct "state" value */
val
.
i_int
=
p_input
->
i_state
;
var_Change
(
p_input
,
"state"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
}
else
if
(
val
.
i_int
!=
PLAYING_S
&&
val
.
i_int
!=
PAUSE_S
)
{
msg_Err
(
p_input
,
"invalid state in INPUT_CONTROL_SET_STATE"
);
}
break
;
case
INPUT_CONTROL_SET_RATE
:
case
INPUT_CONTROL_SET_RATE_SLOWER
:
case
INPUT_CONTROL_SET_RATE_FASTER
:
{
int
i_rate
;
if
(
i_type
==
INPUT_CONTROL_SET_RATE_SLOWER
)
i_rate
=
p_input
->
i_rate
*
2
;
else
if
(
i_type
==
INPUT_CONTROL_SET_RATE_FASTER
)
i_rate
=
p_input
->
i_rate
/
2
;
else
i_rate
=
val
.
i_int
;
if
(
i_rate
<
INPUT_RATE_MIN
)
{
msg_Dbg
(
p_input
,
"cannot set rate faster"
);
i_rate
=
INPUT_RATE_MIN
;
}
else
if
(
i_rate
>
INPUT_RATE_MAX
)
{
msg_Dbg
(
p_input
,
"cannot set rate slower"
);
i_rate
=
INPUT_RATE_MAX
;
}
if
(
i_rate
!=
INPUT_RATE_DEFAULT
&&
(
!
p_input
->
b_can_pace_control
||
!
p_input
->
b_out_pace_control
)
)
{
msg_Dbg
(
p_input
,
"cannot change rate"
);
i_rate
=
INPUT_RATE_DEFAULT
;
}
if
(
i_rate
!=
p_input
->
i_rate
)
{
p_input
->
i_rate
=
i_rate
;
val
.
i_int
=
i_rate
;
var_Change
(
p_input
,
"rate"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
/* We haven't send data to decoder when rate != default */
if
(
i_rate
==
INPUT_RATE_DEFAULT
)
input_EsOutDiscontinuity
(
p_input
->
p_es_out
,
VLC_TRUE
);
/* Reset clock */
es_out_Control
(
p_input
->
p_es_out
,
ES_OUT_RESET_PCR
);
b_force_update
=
VLC_TRUE
;
}
break
;
}
case
INPUT_CONTROL_SET_PROGRAM
:
/* No need to force update, es_out does it if needed */
es_out_Control
(
p_input
->
p_es_out
,
ES_OUT_SET_GROUP
,
val
.
i_int
);
break
;
case
INPUT_CONTROL_SET_ES
:
/* No need to force update, es_out does it if needed */
es_out_Control
(
p_input
->
p_es_out
,
ES_OUT_SET_ES
,
input_EsOutGetFromID
(
p_input
->
p_es_out
,
val
.
i_int
)
);
break
;
case
INPUT_CONTROL_SET_TITLE
:
case
INPUT_CONTROL_SET_TITLE_NEXT
:
case
INPUT_CONTROL_SET_TITLE_PREV
:
if
(
p_input
->
input
.
b_title_demux
&&
p_input
->
input
.
i_title
>
0
)
{
/* TODO */
/* FIXME handle demux title */
demux_t
*
p_demux
=
p_input
->
input
.
p_demux
;
int
i_title
;
if
(
i_type
==
INPUT_CONTROL_SET_TITLE_PREV
)
i_title
=
p_demux
->
info
.
i_title
-
1
;
else
if
(
i_type
==
INPUT_CONTROL_SET_TITLE_NEXT
)
i_title
=
p_demux
->
info
.
i_title
+
1
;
else
i_title
=
val
.
i_int
;
if
(
i_title
>=
0
&&
i_title
<
p_input
->
input
.
i_title
)
{
demux2_Control
(
p_demux
,
DEMUX_SET_TITLE
,
i_title
);
input_EsOutDiscontinuity
(
p_input
->
p_es_out
,
VLC_FALSE
);
es_out_Control
(
p_input
->
p_es_out
,
ES_OUT_RESET_PCR
);
input_ControlVarTitle
(
p_input
,
i_title
);
}
}
else
if
(
p_input
->
input
.
i_title
>
0
)
{
access_t
*
p_access
=
p_input
->
input
.
p_access
;
int
i_title
;
if
(
i_type
==
INPUT_CONTROL_SET_TITLE_PREV
)
i_title
=
p_access
->
info
.
i_title
-
1
;
else
if
(
i_type
==
INPUT_CONTROL_SET_TITLE_NEXT
)
i_title
=
p_access
->
info
.
i_title
+
1
;
else
i_title
=
val
.
i_int
;
if
(
i_title
>=
0
&&
i_title
<
p_input
->
input
.
i_title
)
{
access2_Control
(
p_access
,
ACCESS_SET_TITLE
,
i_title
);
stream_AccessReset
(
p_input
->
input
.
p_stream
);
input_EsOutDiscontinuity
(
p_input
->
p_es_out
,
VLC_FALSE
);
es_out_Control
(
p_input
->
p_es_out
,
ES_OUT_RESET_PCR
);
}
}
break
;
case
INPUT_CONTROL_SET_SEEKPOINT
:
case
INPUT_CONTROL_SET_SEEKPOINT_NEXT
:
case
INPUT_CONTROL_SET_SEEKPOINT_PREV
:
if
(
p_input
->
input
.
b_title_demux
&&
p_input
->
input
.
i_title
>
0
)
{
demux_t
*
p_demux
=
p_input
->
input
.
p_demux
;
int
i_seekpoint
;
if
(
i_type
==
INPUT_CONTROL_SET_SEEKPOINT_PREV
)
i_seekpoint
=
p_demux
->
info
.
i_seekpoint
-
1
;
else
if
(
i_type
==
INPUT_CONTROL_SET_TITLE_NEXT
)
i_seekpoint
=
p_demux
->
info
.
i_seekpoint
+
1
;
else
i_seekpoint
=
val
.
i_int
;
if
(
i_seekpoint
>=
0
&&
i_seekpoint
<
p_input
->
input
.
title
[
p_demux
->
info
.
i_title
]
->
i_seekpoint
)
{
demux2_Control
(
p_demux
,
DEMUX_SET_SEEKPOINT
,
i_seekpoint
);
input_EsOutDiscontinuity
(
p_input
->
p_es_out
,
VLC_FALSE
);
es_out_Control
(
p_input
->
p_es_out
,
ES_OUT_RESET_PCR
);
}
}
else
if
(
p_input
->
input
.
i_title
>
0
)
{
access_t
*
p_access
=
p_input
->
input
.
p_access
;
int
i_seekpoint
;
if
(
i_type
==
INPUT_CONTROL_SET_SEEKPOINT_PREV
)
i_seekpoint
=
p_access
->
info
.
i_seekpoint
-
1
;
else
if
(
i_type
==
INPUT_CONTROL_SET_TITLE_NEXT
)
i_seekpoint
=
p_access
->
info
.
i_seekpoint
+
1
;
else
i_seekpoint
=
val
.
i_int
;
if
(
i_seekpoint
>=
0
&&
i_seekpoint
<
p_input
->
input
.
title
[
p_access
->
info
.
i_title
]
->
i_seekpoint
)
{
access2_Control
(
p_access
,
ACCESS_SET_SEEKPOINT
,
i_seekpoint
);
stream_AccessReset
(
p_input
->
input
.
p_stream
);
input_EsOutDiscontinuity
(
p_input
->
p_es_out
,
VLC_FALSE
);
es_out_Control
(
p_input
->
p_es_out
,
ES_OUT_RESET_PCR
);
}
}
break
;
case
INPUT_CONTROL_SET_BOOKMARK
:
default:
msg_Err
(
p_input
,
"not yet implemented"
);
break
;
}
return
b_force_update
;
}
/*****************************************************************************
* UpdateFromDemux:
*****************************************************************************/
static
void
UpdateFromDemux
(
input_thread_t
*
p_input
)
{
demux_t
*
p_demux
=
p_input
->
input
.
p_demux
;
vlc_value_t
v
;
if
(
p_demux
->
info
.
i_update
&
INPUT_UPDATE_TITLE
)
{
v
.
i_int
=
p_demux
->
info
.
i_title
;
var_Change
(
p_input
,
"title"
,
VLC_VAR_SETVALUE
,
&
v
,
NULL
);
input_ControlVarTitle
(
p_input
,
p_demux
->
info
.
i_title
);
p_demux
->
info
.
i_update
&=
~
INPUT_UPDATE_TITLE
;
}
if
(
p_demux
->
info
.
i_update
&
INPUT_UPDATE_SEEKPOINT
)
{
v
.
i_int
=
p_demux
->
info
.
i_seekpoint
;
var_Change
(
p_input
,
"chapter"
,
VLC_VAR_SETVALUE
,
&
v
,
NULL
);
p_demux
->
info
.
i_update
&=
~
INPUT_UPDATE_SEEKPOINT
;
}
p_demux
->
info
.
i_update
&=
~
INPUT_UPDATE_SIZE
;
}
/*****************************************************************************
* UpdateFromAccess:
*****************************************************************************/
static
void
UpdateFromAccess
(
input_thread_t
*
p_input
)
{
access_t
*
p_access
=
p_input
->
input
.
p_access
;
vlc_value_t
v
;
if
(
p_access
->
info
.
i_update
&
INPUT_UPDATE_TITLE
)
{
v
.
i_int
=
p_access
->
info
.
i_title
;
var_Change
(
p_input
,
"title"
,
VLC_VAR_SETVALUE
,
&
v
,
NULL
);
input_ControlVarTitle
(
p_input
,
p_access
->
info
.
i_title
);
p_access
->
info
.
i_update
&=
~
INPUT_UPDATE_TITLE
;
}
if
(
p_access
->
info
.
i_update
&
INPUT_UPDATE_SEEKPOINT
)
{
v
.
i_int
=
p_access
->
info
.
i_seekpoint
;
var_Change
(
p_input
,
"chapter"
,
VLC_VAR_SETVALUE
,
&
v
,
NULL
);
p_access
->
info
.
i_update
&=
~
INPUT_UPDATE_SEEKPOINT
;
}
p_access
->
info
.
i_update
&=
~
INPUT_UPDATE_SIZE
;
}
/*****************************************************************************
/*****************************************************************************
* DecodeUrl: decode a given encoded url
* DecodeUrl: decode a given encoded url
*****************************************************************************/
*****************************************************************************/
...
@@ -1438,273 +1825,4 @@ static void ParseOption( input_thread_t *p_input, const char *psz_option )
...
@@ -1438,273 +1825,4 @@ static void ParseOption( input_thread_t *p_input, const char *psz_option )
return
;
return
;
}
}
/*****************************************************************************
* input_SetStatus: change the reading status
*****************************************************************************/
/* Status changing methods */
enum
{
INPUT_STATUS_END
=
0
,
INPUT_STATUS_PLAY
=
1
,
INPUT_STATUS_PAUSE
=
2
,
INPUT_STATUS_FASTER
=
3
,
INPUT_STATUS_SLOWER
=
4
};
static
void
input_SetStatus
(
input_thread_t
*
p_input
,
int
i_mode
)
{
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
switch
(
i_mode
)
{
case
INPUT_STATUS_END
:
p_input
->
stream
.
i_new_status
=
PLAYING_S
;
p_input
->
b_eof
=
1
;
msg_Dbg
(
p_input
,
"end of stream"
);
break
;
case
INPUT_STATUS_PLAY
:
p_input
->
stream
.
i_new_status
=
PLAYING_S
;
msg_Dbg
(
p_input
,
"playing at normal rate"
);
break
;
case
INPUT_STATUS_PAUSE
:
/* XXX: we don't need to check i_status, because input_clock.c
* does it for us */
p_input
->
stream
.
i_new_status
=
PAUSE_S
;
msg_Dbg
(
p_input
,
"toggling pause"
);
break
;
case
INPUT_STATUS_FASTER
:
if
(
p_input
->
stream
.
control
.
i_rate
*
4
<=
DEFAULT_RATE
)
{
msg_Dbg
(
p_input
,
"can not play any faster"
);
}
else
{
p_input
->
stream
.
i_new_status
=
FORWARD_S
;
p_input
->
stream
.
i_new_rate
=
p_input
->
stream
.
control
.
i_rate
/
2
;
if
(
p_input
->
stream
.
i_new_rate
<
DEFAULT_RATE
)
{
msg_Dbg
(
p_input
,
"playing at %i:1 fast forward"
,
DEFAULT_RATE
/
p_input
->
stream
.
i_new_rate
);
}
else
if
(
p_input
->
stream
.
i_new_rate
>
DEFAULT_RATE
)
{
msg_Dbg
(
p_input
,
"playing at 1:%i slow motion"
,
p_input
->
stream
.
i_new_rate
/
DEFAULT_RATE
);
}
else
if
(
p_input
->
stream
.
i_new_rate
==
DEFAULT_RATE
)
{
p_input
->
stream
.
i_new_status
=
PLAYING_S
;
msg_Dbg
(
p_input
,
"playing at normal rate"
);
}
}
break
;
case
INPUT_STATUS_SLOWER
:
if
(
p_input
->
stream
.
control
.
i_rate
>=
8
*
DEFAULT_RATE
)
{
msg_Dbg
(
p_input
,
"can not play any slower"
);
}
else
{
p_input
->
stream
.
i_new_status
=
FORWARD_S
;
p_input
->
stream
.
i_new_rate
=
p_input
->
stream
.
control
.
i_rate
*
2
;
if
(
p_input
->
stream
.
i_new_rate
<
DEFAULT_RATE
)
{
msg_Dbg
(
p_input
,
"playing at %i:1 fast forward"
,
DEFAULT_RATE
/
p_input
->
stream
.
i_new_rate
);
}
else
if
(
p_input
->
stream
.
i_new_rate
>
DEFAULT_RATE
)
{
msg_Dbg
(
p_input
,
"playing at 1:%i slow motion"
,
p_input
->
stream
.
i_new_rate
/
DEFAULT_RATE
);
}
else
if
(
p_input
->
stream
.
i_new_rate
==
DEFAULT_RATE
)
{
p_input
->
stream
.
i_new_status
=
PLAYING_S
;
msg_Dbg
(
p_input
,
"playing at normal rate"
);
}
}
break
;
default:
break
;
}
vlc_cond_signal
(
&
p_input
->
stream
.
stream_wait
);
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
}
/*****************************************************************************
* input_SetRate:
*****************************************************************************/
static
void
input_SetRate
(
input_thread_t
*
p_input
,
int
i_rate
)
{
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
if
(
i_rate
*
8
<
DEFAULT_RATE
)
{
msg_Dbg
(
p_input
,
"can not play faster than 8x"
);
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
return
;
}
if
(
i_rate
>
DEFAULT_RATE
*
8
)
{
msg_Dbg
(
p_input
,
"can not play slower than 1/8x"
);
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
return
;
}
p_input
->
stream
.
i_new_status
=
FORWARD_S
;
p_input
->
stream
.
i_new_rate
=
i_rate
;
if
(
p_input
->
stream
.
i_new_rate
<
DEFAULT_RATE
)
{
msg_Dbg
(
p_input
,
"playing at %i:1 fast forward"
,
DEFAULT_RATE
/
p_input
->
stream
.
i_new_rate
);
}
else
if
(
p_input
->
stream
.
i_new_rate
>
DEFAULT_RATE
)
{
msg_Dbg
(
p_input
,
"playing at 1:%i slow motion"
,
p_input
->
stream
.
i_new_rate
/
DEFAULT_RATE
);
}
else
if
(
p_input
->
stream
.
i_new_rate
==
DEFAULT_RATE
)
{
p_input
->
stream
.
i_new_status
=
PLAYING_S
;
msg_Dbg
(
p_input
,
"playing at normal rate"
);
}
vlc_cond_signal
(
&
p_input
->
stream
.
stream_wait
);
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
}
/*****************************************************************************
* Callbacks (position, time, state, rate )
*****************************************************************************/
static
int
PositionCallback
(
vlc_object_t
*
p_this
,
char
const
*
psz_cmd
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
p_data
)
{
input_thread_t
*
p_input
=
(
input_thread_t
*
)
p_this
;
msg_Dbg
(
p_input
,
"cmd=%s old=%f new=%f"
,
psz_cmd
,
oldval
.
f_float
,
newval
.
f_float
);
if
(
!
strcmp
(
psz_cmd
,
"position-offset"
)
)
{
vlc_value_t
val
;
var_Get
(
p_input
,
"position"
,
&
val
);
newval
.
f_float
+=
val
.
f_float
;
}
var_Change
(
p_input
,
"position"
,
VLC_VAR_SETVALUE
,
&
newval
,
NULL
);
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
p_input
->
stream
.
p_selected_area
->
i_seek
=
(
int64_t
)(
newval
.
f_float
*
(
double
)
p_input
->
stream
.
p_selected_area
->
i_size
);
if
(
p_input
->
stream
.
p_selected_area
->
i_seek
<
0
)
{
p_input
->
stream
.
p_selected_area
->
i_seek
=
0
;
}
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
return
VLC_SUCCESS
;
}
static
int
TimeCallback
(
vlc_object_t
*
p_this
,
char
const
*
psz_cmd
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
p_data
)
{
input_thread_t
*
p_input
=
(
input_thread_t
*
)
p_this
;
vlc_value_t
val
;
/* FIXME TODO FIXME */
msg_Dbg
(
p_input
,
"cmd=%s old=%lld new=%lld"
,
psz_cmd
,
oldval
.
i_time
,
newval
.
i_time
);
var_Get
(
p_input
,
"length"
,
&
val
);
if
(
val
.
i_time
>
0
)
{
val
.
f_float
=
(
double
)
newval
.
i_time
/
(
double
)
val
.
i_time
;
if
(
!
strcmp
(
psz_cmd
,
"time-offset"
)
)
{
vlc_value_t
t
;
var_Set
(
p_input
,
"position-offset"
,
val
);
var_Get
(
p_input
,
"time"
,
&
t
);
t
.
i_time
+=
newval
.
i_time
;
var_Change
(
p_input
,
"time"
,
VLC_VAR_SETVALUE
,
&
t
,
NULL
);
}
else
{
var_Set
(
p_input
,
"position"
,
val
);
var_Change
(
p_input
,
"time"
,
VLC_VAR_SETVALUE
,
&
newval
,
NULL
);
}
}
else
{
msg_Warn
(
p_input
,
"TimeCallback: length <= 0 -> can't seek"
);
}
return
VLC_SUCCESS
;
}
static
int
StateCallback
(
vlc_object_t
*
p_this
,
char
const
*
psz_cmd
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
p_data
)
{
input_thread_t
*
p_input
=
(
input_thread_t
*
)
p_this
;
msg_Dbg
(
p_input
,
"cmd=%s old=%d new=%d"
,
psz_cmd
,
oldval
.
i_int
,
newval
.
i_int
);
switch
(
newval
.
i_int
)
{
case
PLAYING_S
:
input_SetStatus
(
p_input
,
INPUT_STATUS_PLAY
);
return
VLC_SUCCESS
;
case
PAUSE_S
:
input_SetStatus
(
p_input
,
INPUT_STATUS_PAUSE
);
return
VLC_SUCCESS
;
case
END_S
:
input_SetStatus
(
p_input
,
INPUT_STATUS_END
);
return
VLC_SUCCESS
;
default:
msg_Err
(
p_input
,
"cannot set new state (invalid)"
);
return
VLC_EGENERIC
;
}
}
static
int
RateCallback
(
vlc_object_t
*
p_this
,
char
const
*
psz_cmd
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
p_data
)
{
input_thread_t
*
p_input
=
(
input_thread_t
*
)
p_this
;
if
(
!
strcmp
(
psz_cmd
,
"rate-slower"
)
)
{
input_SetStatus
(
p_input
,
INPUT_STATUS_SLOWER
);
}
else
if
(
!
strcmp
(
psz_cmd
,
"rate-faster"
)
)
{
input_SetStatus
(
p_input
,
INPUT_STATUS_FASTER
);
}
else
{
msg_Dbg
(
p_input
,
"cmd=%s old=%d new=%d"
,
psz_cmd
,
oldval
.
i_int
,
newval
.
i_int
);
input_SetRate
(
p_input
,
newval
.
i_int
);
}
return
VLC_SUCCESS
;
}
static
int
BookmarkCallback
(
vlc_object_t
*
p_this
,
char
const
*
psz_cmd
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
p_data
)
{
input_thread_t
*
p_input
=
(
input_thread_t
*
)
p_this
;
return
input_Control
(
p_input
,
INPUT_SET_BOOKMARK
,
newval
);
}
src/input/input_ext-plugins.c
deleted
100644 → 0
View file @
7d01a7e7
/*****************************************************************************
* input_ext-plugins.c: useful functions for access and demux plug-ins
*****************************************************************************
* Copyright (C) 2001-2004 VideoLAN
* $Id$
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include <vlc/vlc.h>
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
#include "input_ext-plugins.h"
/*
* Buffers management : internal functions
*
* All functions are static, but exported versions with mutex protection
* start with input_*. Not all of these exported functions are actually used,
* but they are included here for completeness.
*/
#define BUFFERS_CACHE_SIZE 500
#define DATA_CACHE_SIZE 1000
#define PES_CACHE_SIZE 1000
/*****************************************************************************
* data_buffer_t: shared data type
*****************************************************************************/
struct
data_buffer_t
{
data_buffer_t
*
p_next
;
/* number of data packets this buffer is referenced from - when it falls
* down to 0, the buffer is freed */
int
i_refcount
;
/* size of the current buffer (starting right after this byte) */
size_t
i_size
;
};
/*****************************************************************************
* input_buffers_t: defines a LIFO per data type to keep
*****************************************************************************/
#define PACKETS_LIFO( TYPE, NAME ) \
struct \
{ \
TYPE * p_stack; \
unsigned int i_depth; \
} NAME;
struct
input_buffers_t
{
vlc_mutex_t
lock
;
PACKETS_LIFO
(
pes_packet_t
,
pes
)
PACKETS_LIFO
(
data_packet_t
,
data
)
PACKETS_LIFO
(
data_buffer_t
,
buffers
)
size_t
i_allocated
;
};
/*****************************************************************************
* input_BuffersInit: initialize the cache structures, return a pointer to it
*****************************************************************************/
void
*
__input_BuffersInit
(
vlc_object_t
*
p_this
)
{
input_buffers_t
*
p_buffers
=
malloc
(
sizeof
(
input_buffers_t
)
);
if
(
p_buffers
==
NULL
)
{
return
NULL
;
}
memset
(
p_buffers
,
0
,
sizeof
(
input_buffers_t
)
);
vlc_mutex_init
(
p_this
,
&
p_buffers
->
lock
);
return
p_buffers
;
}
/*****************************************************************************
* input_BuffersEnd: free all cached structures
*****************************************************************************/
#define BUFFERS_END_PACKETS_LOOP \
while( p_packet != NULL ) \
{ \
p_next = p_packet->p_next; \
free( p_packet ); \
p_packet = p_next; \
}
void
input_BuffersEnd
(
input_thread_t
*
p_input
,
input_buffers_t
*
p_buffers
)
{
if
(
p_buffers
!=
NULL
)
{
msg_Dbg
(
p_input
,
"pes: %d packets"
,
p_buffers
->
pes
.
i_depth
);
msg_Dbg
(
p_input
,
"data: %d packets"
,
p_buffers
->
data
.
i_depth
);
msg_Dbg
(
p_input
,
"buffers: %d packets"
,
p_buffers
->
buffers
.
i_depth
);
{
/* Free PES */
pes_packet_t
*
p_next
,
*
p_packet
=
p_buffers
->
pes
.
p_stack
;
BUFFERS_END_PACKETS_LOOP
;
}
{
/* Free data packets */
data_packet_t
*
p_next
,
*
p_packet
=
p_buffers
->
data
.
p_stack
;
BUFFERS_END_PACKETS_LOOP
;
}
{
/* Free buffers */
data_buffer_t
*
p_next
,
*
p_buf
=
p_buffers
->
buffers
.
p_stack
;
while
(
p_buf
!=
NULL
)
{
p_next
=
p_buf
->
p_next
;
p_buffers
->
i_allocated
-=
p_buf
->
i_size
;
free
(
p_buf
);
p_buf
=
p_next
;
}
}
if
(
p_buffers
->
i_allocated
)
{
msg_Warn
(
p_input
,
"%u bytes have not been freed, "
"expect memory leak"
,
p_buffers
->
i_allocated
);
}
vlc_mutex_destroy
(
&
p_buffers
->
lock
);
free
(
p_buffers
);
}
}
/*****************************************************************************
* input_NewBuffer: return a pointer to a data buffer of the appropriate size
*****************************************************************************/
static
inline
data_buffer_t
*
NewBuffer
(
input_buffers_t
*
p_buffers
,
size_t
i_size
)
{
data_buffer_t
*
p_buf
;
/* Safety check */
if
(
p_buffers
->
i_allocated
>
INPUT_MAX_ALLOCATION
)
{
return
NULL
;
}
if
(
p_buffers
->
buffers
.
p_stack
!=
NULL
)
{
/* Take the buffer from the cache */
p_buf
=
p_buffers
->
buffers
.
p_stack
;
p_buffers
->
buffers
.
p_stack
=
p_buf
->
p_next
;
p_buffers
->
buffers
.
i_depth
--
;
/* Reallocate the packet if it is too small or too large */
if
(
p_buf
->
i_size
<
i_size
||
p_buf
->
i_size
>
3
*
i_size
)
{
p_buffers
->
i_allocated
-=
p_buf
->
i_size
;
free
(
p_buf
);
p_buf
=
malloc
(
sizeof
(
input_buffers_t
)
+
i_size
);
if
(
p_buf
==
NULL
)
{
return
NULL
;
}
p_buf
->
i_size
=
i_size
;
p_buffers
->
i_allocated
+=
i_size
;
}
}
else
{
/* Allocate a new buffer */
p_buf
=
malloc
(
sizeof
(
input_buffers_t
)
+
i_size
);
if
(
p_buf
==
NULL
)
{
return
NULL
;
}
p_buf
->
i_size
=
i_size
;
p_buffers
->
i_allocated
+=
i_size
;
}
/* Initialize data */
p_buf
->
p_next
=
NULL
;
p_buf
->
i_refcount
=
0
;
return
p_buf
;
}
data_buffer_t
*
input_NewBuffer
(
input_buffers_t
*
p_buffers
,
size_t
i_size
)
{
data_buffer_t
*
p_buf
;
vlc_mutex_lock
(
&
p_buffers
->
lock
);
p_buf
=
NewBuffer
(
p_buffers
,
i_size
);
vlc_mutex_unlock
(
&
p_buffers
->
lock
);
return
p_buf
;
}
/*****************************************************************************
* input_ReleaseBuffer: put a buffer back into the cache
*****************************************************************************/
static
inline
void
ReleaseBuffer
(
input_buffers_t
*
p_buffers
,
data_buffer_t
*
p_buf
)
{
/* Decrement refcount */
if
(
--
p_buf
->
i_refcount
>
0
)
{
return
;
}
if
(
p_buffers
->
buffers
.
i_depth
<
BUFFERS_CACHE_SIZE
)
{
/* Cache not full : store the buffer in it */
p_buf
->
p_next
=
p_buffers
->
buffers
.
p_stack
;
p_buffers
->
buffers
.
p_stack
=
p_buf
;
p_buffers
->
buffers
.
i_depth
++
;
}
else
{
p_buffers
->
i_allocated
-=
p_buf
->
i_size
;
free
(
p_buf
);
}
}
void
input_ReleaseBuffer
(
input_buffers_t
*
p_buffers
,
data_buffer_t
*
p_buf
)
{
vlc_mutex_lock
(
&
p_buffers
->
lock
);
ReleaseBuffer
(
p_buffers
,
p_buf
);
vlc_mutex_unlock
(
&
p_buffers
->
lock
);
}
/*****************************************************************************
* input_ShareBuffer: allocate a data_packet_t pointing to a given buffer
*****************************************************************************/
static
inline
data_packet_t
*
ShareBuffer
(
input_buffers_t
*
p_buffers
,
data_buffer_t
*
p_buf
)
{
data_packet_t
*
p_data
;
if
(
p_buffers
->
data
.
p_stack
!=
NULL
)
{
/* Take the packet from the cache */
p_data
=
p_buffers
->
data
.
p_stack
;
p_buffers
->
data
.
p_stack
=
p_data
->
p_next
;
p_buffers
->
data
.
i_depth
--
;
}
else
{
/* Allocate a new packet */
p_data
=
malloc
(
sizeof
(
data_packet_t
)
);
if
(
p_data
==
NULL
)
{
return
NULL
;
}
}
p_data
->
p_buffer
=
p_buf
;
p_data
->
p_next
=
NULL
;
p_data
->
b_discard_payload
=
0
;
p_data
->
p_payload_start
=
p_data
->
p_demux_start
=
(
byte_t
*
)
p_buf
+
sizeof
(
input_buffers_t
);
p_data
->
p_payload_end
=
p_data
->
p_demux_start
+
p_buf
->
i_size
;
p_buf
->
i_refcount
++
;
return
p_data
;
}
data_packet_t
*
input_ShareBuffer
(
input_buffers_t
*
p_buffers
,
data_buffer_t
*
p_buf
)
{
data_packet_t
*
p_data
;
vlc_mutex_lock
(
&
p_buffers
->
lock
);
p_data
=
ShareBuffer
(
p_buffers
,
p_buf
);
vlc_mutex_unlock
(
&
p_buffers
->
lock
);
return
p_data
;
}
/*****************************************************************************
* input_NewPacket: allocate a packet along with a buffer
*****************************************************************************/
static
inline
data_packet_t
*
NewPacket
(
input_buffers_t
*
p_buffers
,
size_t
i_size
)
{
data_buffer_t
*
p_buf
;
data_packet_t
*
p_data
;
p_buf
=
NewBuffer
(
p_buffers
,
i_size
);
if
(
p_buf
==
NULL
)
{
return
NULL
;
}
p_data
=
ShareBuffer
(
p_buffers
,
p_buf
);
if
(
p_data
==
NULL
)
{
ReleaseBuffer
(
p_buffers
,
p_buf
);
}
return
p_data
;
}
data_packet_t
*
input_NewPacket
(
input_buffers_t
*
p_buffers
,
size_t
i_size
)
{
data_packet_t
*
p_data
;
vlc_mutex_lock
(
&
p_buffers
->
lock
);
p_data
=
NewPacket
(
p_buffers
,
i_size
);
vlc_mutex_unlock
(
&
p_buffers
->
lock
);
return
p_data
;
}
/*****************************************************************************
* input_DeletePacket: deallocate a packet and its buffers
*****************************************************************************/
static
inline
void
DeletePacket
(
input_buffers_t
*
p_buffers
,
data_packet_t
*
p_data
)
{
while
(
p_data
!=
NULL
)
{
data_packet_t
*
p_next
=
p_data
->
p_next
;
ReleaseBuffer
(
p_buffers
,
p_data
->
p_buffer
);
if
(
p_buffers
->
data
.
i_depth
<
DATA_CACHE_SIZE
)
{
/* Cache not full : store the packet in it */
p_data
->
p_next
=
p_buffers
->
data
.
p_stack
;
p_buffers
->
data
.
p_stack
=
p_data
;
p_buffers
->
data
.
i_depth
++
;
}
else
{
free
(
p_data
);
}
p_data
=
p_next
;
}
}
void
input_DeletePacket
(
input_buffers_t
*
p_buffers
,
data_packet_t
*
p_data
)
{
vlc_mutex_lock
(
&
p_buffers
->
lock
);
DeletePacket
(
p_buffers
,
p_data
);
vlc_mutex_unlock
(
&
p_buffers
->
lock
);
}
/*****************************************************************************
* input_NewPES: return a pointer to a new PES packet
*****************************************************************************/
static
inline
pes_packet_t
*
NewPES
(
input_buffers_t
*
p_buffers
)
{
pes_packet_t
*
p_pes
;
if
(
p_buffers
->
pes
.
p_stack
!=
NULL
)
{
/* Take the packet from the cache */
p_pes
=
p_buffers
->
pes
.
p_stack
;
p_buffers
->
pes
.
p_stack
=
p_pes
->
p_next
;
p_buffers
->
pes
.
i_depth
--
;
}
else
{
/* Allocate a new packet */
p_pes
=
malloc
(
sizeof
(
pes_packet_t
)
);
if
(
p_pes
==
NULL
)
{
return
NULL
;
}
}
p_pes
->
p_next
=
NULL
;
p_pes
->
b_data_alignment
=
p_pes
->
b_discontinuity
=
VLC_FALSE
;
p_pes
->
i_pts
=
p_pes
->
i_dts
=
0
;
p_pes
->
p_first
=
p_pes
->
p_last
=
NULL
;
p_pes
->
i_pes_size
=
0
;
p_pes
->
i_nb_data
=
0
;
return
p_pes
;
}
pes_packet_t
*
input_NewPES
(
input_buffers_t
*
p_buffers
)
{
pes_packet_t
*
p_pes
;
vlc_mutex_lock
(
&
p_buffers
->
lock
);
p_pes
=
NewPES
(
p_buffers
);
vlc_mutex_unlock
(
&
p_buffers
->
lock
);
return
p_pes
;
}
/*****************************************************************************
* input_DeletePES: put a pes and all data packets and all buffers back into
* the cache
*****************************************************************************/
static
inline
void
DeletePES
(
input_buffers_t
*
p_buffers
,
pes_packet_t
*
p_pes
)
{
while
(
p_pes
!=
NULL
)
{
pes_packet_t
*
p_next
=
p_pes
->
p_next
;
/* Delete all data packets */
if
(
p_pes
->
p_first
!=
NULL
)
{
DeletePacket
(
p_buffers
,
p_pes
->
p_first
);
}
if
(
p_buffers
->
pes
.
i_depth
<
PES_CACHE_SIZE
)
{
/* Cache not full : store the packet in it */
p_pes
->
p_next
=
p_buffers
->
pes
.
p_stack
;
p_buffers
->
pes
.
p_stack
=
p_pes
;
p_buffers
->
pes
.
i_depth
++
;
}
else
{
free
(
p_pes
);
}
p_pes
=
p_next
;
}
}
void
input_DeletePES
(
input_buffers_t
*
p_buffers
,
pes_packet_t
*
p_pes
)
{
vlc_mutex_lock
(
&
p_buffers
->
lock
);
DeletePES
(
p_buffers
,
p_pes
);
vlc_mutex_unlock
(
&
p_buffers
->
lock
);
}
/*
* Buffers management : external functions
*
* These functions make the glu between the access plug-in (pf_read) and
* the demux plug-in (pf_demux). We fill in a large buffer (approx. 10s kB)
* with a call to pf_read, then allow the demux plug-in to have a peep at
* it (input_Peek), and to split it in data_packet_t (input_SplitBuffer).
*/
/*****************************************************************************
* input_FillBuffer: fill in p_data_buffer with data from pf_read
*****************************************************************************/
ssize_t
input_FillBuffer
(
input_thread_t
*
p_input
)
{
ptrdiff_t
i_remains
=
p_input
->
p_last_data
-
p_input
->
p_current_data
;
data_buffer_t
*
p_buf
=
NULL
;
ssize_t
i_ret
;
vlc_mutex_lock
(
&
p_input
->
p_method_data
->
lock
);
while
(
p_buf
==
NULL
)
{
p_buf
=
NewBuffer
(
p_input
->
p_method_data
,
i_remains
+
p_input
->
i_bufsize
);
if
(
p_buf
==
NULL
)
{
vlc_mutex_unlock
(
&
p_input
->
p_method_data
->
lock
);
msg_Err
(
p_input
,
"failed allocating a new buffer (decoder stuck?)"
);
msleep
(
INPUT_IDLE_SLEEP
);
if
(
p_input
->
b_die
||
p_input
->
b_error
||
p_input
->
b_eof
)
{
return
-
1
;
}
vlc_mutex_lock
(
&
p_input
->
p_method_data
->
lock
);
}
}
p_buf
->
i_refcount
=
1
;
if
(
p_input
->
p_data_buffer
!=
NULL
)
{
if
(
i_remains
)
{
p_input
->
p_vlc
->
pf_memcpy
(
(
byte_t
*
)
p_buf
+
sizeof
(
data_buffer_t
),
p_input
->
p_current_data
,
(
size_t
)
i_remains
);
}
ReleaseBuffer
(
p_input
->
p_method_data
,
p_input
->
p_data_buffer
);
}
p_input
->
p_data_buffer
=
p_buf
;
p_input
->
p_current_data
=
(
byte_t
*
)
p_buf
+
sizeof
(
data_buffer_t
);
p_input
->
p_last_data
=
p_input
->
p_current_data
+
i_remains
;
/* Do not hold the lock during pf_read (blocking call). */
vlc_mutex_unlock
(
&
p_input
->
p_method_data
->
lock
);
i_ret
=
p_input
->
pf_read
(
p_input
,
(
byte_t
*
)
p_buf
+
sizeof
(
data_buffer_t
)
+
i_remains
,
p_input
->
i_bufsize
);
if
(
i_ret
<
0
&&
i_remains
==
0
)
{
/* Our internal buffers are empty, we can signal the error */
return
-
1
;
}
if
(
i_ret
<
0
)
i_ret
=
0
;
p_input
->
p_last_data
+=
i_ret
;
return
(
ssize_t
)
i_remains
+
i_ret
;
}
/*****************************************************************************
* input_Peek: give a pointer to the next available bytes in the buffer
* (min. i_size bytes)
* Returns the number of bytes read, or -1 in case of error
*****************************************************************************/
ssize_t
input_Peek
(
input_thread_t
*
p_input
,
byte_t
**
pp_byte
,
size_t
i_size
)
{
ssize_t
i_data
=
p_input
->
p_last_data
-
p_input
->
p_current_data
;
while
(
i_data
<
(
ssize_t
)
i_size
)
{
/* Go to the next buffer */
ssize_t
i_ret
=
input_FillBuffer
(
p_input
);
if
(
i_ret
<
0
)
{
return
-
1
;
}
if
(
i_ret
==
i_data
)
{
/* We didn't get anymore data, must be the EOF */
i_size
=
i_data
;
break
;
}
i_data
=
i_ret
;
}
*
pp_byte
=
p_input
->
p_current_data
;
return
i_size
;
}
/*****************************************************************************
* input_SplitBuffer: give a pointer to a data packet containing i_size bytes
* Returns the number of bytes read, or -1 in case of error
*****************************************************************************/
ssize_t
input_SplitBuffer
(
input_thread_t
*
p_input
,
data_packet_t
**
pp_data
,
size_t
i_size
)
{
ssize_t
i_data
=
p_input
->
p_last_data
-
p_input
->
p_current_data
;
while
(
i_data
<
(
ssize_t
)
i_size
)
{
/* Go to the next buffer */
ssize_t
i_ret
=
input_FillBuffer
(
p_input
);
if
(
i_ret
<
0
)
{
return
-
1
;
}
if
(
i_ret
==
i_data
)
{
/* We didn't get anymore data, must be the EOF */
i_size
=
i_data
;
break
;
}
i_data
=
i_ret
;
}
if
(
i_size
<
0
)
{
return
0
;
}
*
pp_data
=
input_ShareBuffer
(
p_input
->
p_method_data
,
p_input
->
p_data_buffer
);
(
*
pp_data
)
->
p_demux_start
=
(
*
pp_data
)
->
p_payload_start
=
p_input
->
p_current_data
;
(
*
pp_data
)
->
p_payload_end
=
(
*
pp_data
)
->
p_demux_start
+
i_size
;
p_input
->
p_current_data
+=
i_size
;
/* Update stream position */
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
p_input
->
stream
.
p_selected_area
->
i_tell
+=
i_size
;
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
return
i_size
;
}
/*****************************************************************************
* input_AccessInit: initialize access plug-in wrapper structures
*****************************************************************************/
int
input_AccessInit
(
input_thread_t
*
p_input
)
{
p_input
->
p_method_data
=
input_BuffersInit
(
p_input
);
if
(
p_input
->
p_method_data
==
NULL
)
return
-
1
;
p_input
->
p_data_buffer
=
NULL
;
p_input
->
p_current_data
=
NULL
;
p_input
->
p_last_data
=
NULL
;
return
0
;
}
/*****************************************************************************
* input_AccessReinit: reinit structures before a random seek
*****************************************************************************/
void
input_AccessReinit
(
input_thread_t
*
p_input
)
{
if
(
p_input
->
p_data_buffer
!=
NULL
)
{
ReleaseBuffer
(
p_input
->
p_method_data
,
p_input
->
p_data_buffer
);
}
p_input
->
p_data_buffer
=
NULL
;
p_input
->
p_current_data
=
NULL
;
p_input
->
p_last_data
=
NULL
;
}
/*****************************************************************************
* input_AccessEnd: free access plug-in wrapper structures
*****************************************************************************/
void
input_AccessEnd
(
input_thread_t
*
p_input
)
{
if
(
p_input
->
p_data_buffer
!=
NULL
)
{
ReleaseBuffer
(
p_input
->
p_method_data
,
p_input
->
p_data_buffer
);
}
input_BuffersEnd
(
p_input
,
p_input
->
p_method_data
);
}
src/input/input_programs.c
deleted
100644 → 0
View file @
7d01a7e7
/*****************************************************************************
* input_programs.c: es_descriptor_t, pgrm_descriptor_t management
*****************************************************************************
* Copyright (C) 1999-2004 VideoLAN
* $Id$
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h>
#include <string.h>
/* memcpy(), memset() */
#include <vlc/vlc.h>
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
#include "input_ext-plugins.h"
/*
* NOTICE : all of these functions expect you to have taken the lock on
* p_input->stream.lock
*/
/* Navigation callbacks */
static
int
ProgramCallback
(
vlc_object_t
*
,
char
const
*
,
vlc_value_t
,
vlc_value_t
,
void
*
);
static
int
TitleCallback
(
vlc_object_t
*
,
char
const
*
,
vlc_value_t
,
vlc_value_t
,
void
*
);
static
int
ChapterCallback
(
vlc_object_t
*
,
char
const
*
,
vlc_value_t
,
vlc_value_t
,
void
*
);
static
int
NavigationCallback
(
vlc_object_t
*
,
char
const
*
,
vlc_value_t
,
vlc_value_t
,
void
*
);
static
int
ESCallback
(
vlc_object_t
*
,
char
const
*
,
vlc_value_t
,
vlc_value_t
,
void
*
);
/*****************************************************************************
* input_InitStream: init the stream descriptor of the given input
*****************************************************************************/
int
input_InitStream
(
input_thread_t
*
p_input
,
size_t
i_data_len
)
{
vlc_value_t
text
,
val
;
p_input
->
stream
.
i_stream_id
=
0
;
/* initialized to 0 since we don't give the signal to the interface
* before the end of input initialization */
p_input
->
stream
.
b_changed
=
0
;
p_input
->
stream
.
pp_es
=
NULL
;
p_input
->
stream
.
pp_selected_es
=
NULL
;
p_input
->
stream
.
p_removed_es
=
NULL
;
p_input
->
stream
.
p_newly_selected_es
=
NULL
;
p_input
->
stream
.
i_pgrm_number
=
0
;
p_input
->
stream
.
pp_programs
=
NULL
;
p_input
->
stream
.
p_selected_program
=
NULL
;
p_input
->
stream
.
p_new_program
=
NULL
;
if
(
i_data_len
)
{
if
(
(
p_input
->
stream
.
p_demux_data
=
malloc
(
i_data_len
))
==
NULL
)
{
msg_Err
(
p_input
,
"out of memory"
);
return
1
;
}
memset
(
p_input
->
stream
.
p_demux_data
,
0
,
i_data_len
);
}
else
{
p_input
->
stream
.
p_demux_data
=
NULL
;
}
var_Create
(
p_input
,
"intf-change"
,
VLC_VAR_BOOL
);
val
.
b_bool
=
VLC_TRUE
;
var_Set
(
p_input
,
"intf-change"
,
val
);
/* Create a few object variables used for navigation in the interfaces */
var_Create
(
p_input
,
"program"
,
VLC_VAR_INTEGER
|
VLC_VAR_HASCHOICE
|
VLC_VAR_DOINHERIT
);
var_Get
(
p_input
,
"program"
,
&
val
);
if
(
val
.
i_int
<=
0
)
var_Change
(
p_input
,
"program"
,
VLC_VAR_DELCHOICE
,
&
val
,
NULL
);
text
.
psz_string
=
_
(
"Program"
);
var_Change
(
p_input
,
"program"
,
VLC_VAR_SETTEXT
,
&
text
,
NULL
);
var_Create
(
p_input
,
"title"
,
VLC_VAR_INTEGER
|
VLC_VAR_HASCHOICE
);
text
.
psz_string
=
_
(
"Title"
);
var_Change
(
p_input
,
"title"
,
VLC_VAR_SETTEXT
,
&
text
,
NULL
);
var_Create
(
p_input
,
"chapter"
,
VLC_VAR_INTEGER
|
VLC_VAR_HASCHOICE
);
text
.
psz_string
=
_
(
"Chapter"
);
var_Change
(
p_input
,
"chapter"
,
VLC_VAR_SETTEXT
,
&
text
,
NULL
);
var_Create
(
p_input
,
"navigation"
,
VLC_VAR_VARIABLE
|
VLC_VAR_HASCHOICE
);
text
.
psz_string
=
_
(
"Navigation"
);
var_Change
(
p_input
,
"navigation"
,
VLC_VAR_SETTEXT
,
&
text
,
NULL
);
var_Create
(
p_input
,
"video-es"
,
VLC_VAR_INTEGER
|
VLC_VAR_HASCHOICE
);
text
.
psz_string
=
_
(
"Video Track"
);
var_Change
(
p_input
,
"video-es"
,
VLC_VAR_SETTEXT
,
&
text
,
NULL
);
var_Create
(
p_input
,
"audio-es"
,
VLC_VAR_INTEGER
|
VLC_VAR_HASCHOICE
);
text
.
psz_string
=
_
(
"Audio Track"
);
var_Change
(
p_input
,
"audio-es"
,
VLC_VAR_SETTEXT
,
&
text
,
NULL
);
var_Create
(
p_input
,
"spu-es"
,
VLC_VAR_INTEGER
|
VLC_VAR_HASCHOICE
);
text
.
psz_string
=
_
(
"Subtitles Track"
);
var_Change
(
p_input
,
"spu-es"
,
VLC_VAR_SETTEXT
,
&
text
,
NULL
);
var_AddCallback
(
p_input
,
"program"
,
ProgramCallback
,
NULL
);
var_AddCallback
(
p_input
,
"title"
,
TitleCallback
,
NULL
);
var_AddCallback
(
p_input
,
"chapter"
,
ChapterCallback
,
NULL
);
var_AddCallback
(
p_input
,
"video-es"
,
ESCallback
,
NULL
);
var_AddCallback
(
p_input
,
"audio-es"
,
ESCallback
,
NULL
);
var_AddCallback
(
p_input
,
"spu-es"
,
ESCallback
,
NULL
);
return
VLC_SUCCESS
;
}
/*****************************************************************************
* input_EndStream: free all stream descriptors
*****************************************************************************/
void
input_EndStream
(
input_thread_t
*
p_input
)
{
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
/* Free all programs and associated ES, and associated decoders. */
while
(
p_input
->
stream
.
i_pgrm_number
)
{
input_DelProgram
(
p_input
,
p_input
->
stream
.
pp_programs
[
0
]
);
}
/* Free standalone ES */
while
(
p_input
->
stream
.
i_es_number
)
{
input_DelES
(
p_input
,
p_input
->
stream
.
pp_es
[
0
]
);
}
/* Free all areas */
while
(
p_input
->
stream
.
i_area_nb
)
{
input_DelArea
(
p_input
,
p_input
->
stream
.
pp_areas
[
0
]
);
}
/* Free selected ES */
if
(
p_input
->
stream
.
pp_selected_es
!=
NULL
)
{
free
(
p_input
->
stream
.
pp_selected_es
);
}
if
(
p_input
->
stream
.
p_demux_data
!=
NULL
)
{
free
(
p_input
->
stream
.
p_demux_data
);
}
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
/* Free navigation variables */
var_Destroy
(
p_input
,
"program"
);
var_Destroy
(
p_input
,
"title"
);
var_Destroy
(
p_input
,
"chapter"
);
var_Destroy
(
p_input
,
"video-es"
);
var_Destroy
(
p_input
,
"audio-es"
);
var_Destroy
(
p_input
,
"spu-es"
);
var_Destroy
(
p_input
,
"intf-change"
);
}
/*****************************************************************************
* input_FindProgram: returns a pointer to a program described by its ID
*****************************************************************************/
pgrm_descriptor_t
*
input_FindProgram
(
input_thread_t
*
p_input
,
uint16_t
i_pgrm_id
)
{
unsigned
int
i
;
for
(
i
=
0
;
i
<
p_input
->
stream
.
i_pgrm_number
;
i
++
)
{
if
(
p_input
->
stream
.
pp_programs
[
i
]
->
i_number
==
i_pgrm_id
)
{
return
p_input
->
stream
.
pp_programs
[
i
];
}
}
return
NULL
;
}
/*****************************************************************************
* input_AddProgram: add and init a program descriptor
*****************************************************************************
* This program descriptor will be referenced in the given stream descriptor
*****************************************************************************/
pgrm_descriptor_t
*
input_AddProgram
(
input_thread_t
*
p_input
,
uint16_t
i_pgrm_id
,
size_t
i_data_len
)
{
/* Where to add the pgrm */
pgrm_descriptor_t
*
p_pgrm
=
malloc
(
sizeof
(
pgrm_descriptor_t
)
);
vlc_value_t
val
;
if
(
p_pgrm
==
NULL
)
{
msg_Err
(
p_input
,
"out of memory"
);
return
NULL
;
}
/* Init this entry */
p_pgrm
->
i_number
=
i_pgrm_id
;
p_pgrm
->
b_is_ok
=
0
;
p_pgrm
->
i_version
=
0
;
p_pgrm
->
i_es_number
=
0
;
p_pgrm
->
pp_es
=
NULL
;
input_ClockInit
(
p_pgrm
);
p_pgrm
->
i_synchro_state
=
SYNCHRO_START
;
if
(
i_data_len
)
{
p_pgrm
->
p_demux_data
=
malloc
(
i_data_len
);
if
(
p_pgrm
->
p_demux_data
==
NULL
)
{
msg_Err
(
p_input
,
"out of memory"
);
return
NULL
;
}
memset
(
p_pgrm
->
p_demux_data
,
0
,
i_data_len
);
}
else
{
p_pgrm
->
p_demux_data
=
NULL
;
}
/* Add an entry to the list of program associated with the stream */
INSERT_ELEM
(
p_input
->
stream
.
pp_programs
,
p_input
->
stream
.
i_pgrm_number
,
p_input
->
stream
.
i_pgrm_number
,
p_pgrm
);
val
.
i_int
=
i_pgrm_id
;
var_Change
(
p_input
,
"program"
,
VLC_VAR_ADDCHOICE
,
&
val
,
NULL
);
return
p_pgrm
;
}
/*****************************************************************************
* input_DelProgram: destroy a program descriptor
*****************************************************************************
* All ES descriptions referenced in the descriptor will be deleted.
*****************************************************************************/
void
input_DelProgram
(
input_thread_t
*
p_input
,
pgrm_descriptor_t
*
p_pgrm
)
{
unsigned
int
i_pgrm_index
;
vlc_value_t
val
;
/* Find the program in the programs table */
for
(
i_pgrm_index
=
0
;
i_pgrm_index
<
p_input
->
stream
.
i_pgrm_number
;
i_pgrm_index
++
)
{
if
(
p_input
->
stream
.
pp_programs
[
i_pgrm_index
]
==
p_pgrm
)
break
;
}
/* If the program wasn't found, do nothing */
if
(
i_pgrm_index
==
p_input
->
stream
.
i_pgrm_number
)
{
msg_Err
(
p_input
,
"program does not belong to this input"
);
return
;
}
val
.
i_int
=
p_input
->
stream
.
pp_programs
[
i_pgrm_index
]
->
i_number
;
var_Change
(
p_input
,
"program"
,
VLC_VAR_DELCHOICE
,
&
val
,
NULL
);
/* Free the structures that describe the es that belongs to that program */
while
(
p_pgrm
->
i_es_number
)
{
input_DelES
(
p_input
,
p_pgrm
->
pp_es
[
0
]
);
}
/* Free the demux data */
if
(
p_pgrm
->
p_demux_data
!=
NULL
)
{
free
(
p_pgrm
->
p_demux_data
);
}
/* Remove this program from the stream's list of programs */
REMOVE_ELEM
(
p_input
->
stream
.
pp_programs
,
p_input
->
stream
.
i_pgrm_number
,
i_pgrm_index
);
if
(
p_pgrm
==
p_input
->
stream
.
p_selected_program
)
p_input
->
stream
.
p_selected_program
=
NULL
;
/* Free the description of this program */
free
(
p_pgrm
);
}
/****************************************************************************
* input_ChangeProgram: interface request a program change (internal)
****************************************************************************/
static
int
input_ChangeProgram
(
input_thread_t
*
p_input
,
uint16_t
i_program_number
)
{
pgrm_descriptor_t
*
p_program
;
vlc_value_t
val
;
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
p_program
=
input_FindProgram
(
p_input
,
i_program_number
);
if
(
p_program
==
NULL
)
{
msg_Err
(
p_input
,
"could not find selected program"
);
return
-
1
;
}
p_input
->
stream
.
p_new_program
=
p_program
;
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
/* Update the navigation variables without triggering a callback */
val
.
i_int
=
i_program_number
;
var_Change
(
p_input
,
"program"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
return
0
;
}
/*****************************************************************************
* input_AddArea: add and init an area descriptor
*****************************************************************************
* This area descriptor will be referenced in the given stream descriptor
*****************************************************************************/
input_area_t
*
input_AddArea
(
input_thread_t
*
p_input
,
uint16_t
i_area_id
,
uint16_t
i_part_nb
)
{
/* Where to add the pgrm */
input_area_t
*
p_area
=
malloc
(
sizeof
(
input_area_t
)
);
vlc_value_t
val
;
int
i
;
if
(
p_area
==
NULL
)
{
msg_Err
(
p_input
,
"out of memory"
);
return
NULL
;
}
/* Init this entry */
p_area
->
i_id
=
i_area_id
;
p_area
->
i_part_nb
=
i_part_nb
;
p_area
->
i_part
=
0
;
p_area
->
i_start
=
0
;
p_area
->
i_size
=
0
;
p_area
->
i_tell
=
0
;
p_area
->
i_seek
=
NO_SEEK
;
/* Add an entry to the list of program associated with the stream */
INSERT_ELEM
(
p_input
->
stream
.
pp_areas
,
p_input
->
stream
.
i_area_nb
,
p_input
->
stream
.
i_area_nb
,
p_area
);
/* Don't add empty areas */
if
(
i_part_nb
==
0
)
return
NULL
;
/* Take care of the navigation variables */
val
.
i_int
=
i_area_id
;
var_Change
(
p_input
,
"title"
,
VLC_VAR_ADDCHOICE
,
&
val
,
NULL
);
val
.
psz_string
=
malloc
(
sizeof
(
"title "
)
+
5
);
if
(
val
.
psz_string
)
{
vlc_value_t
val2
,
text
,
text2
;
sprintf
(
val
.
psz_string
,
"title %2i"
,
i_area_id
);
var_Destroy
(
p_input
,
val
.
psz_string
);
var_Create
(
p_input
,
val
.
psz_string
,
VLC_VAR_INTEGER
|
VLC_VAR_HASCHOICE
|
VLC_VAR_ISCOMMAND
);
var_AddCallback
(
p_input
,
val
.
psz_string
,
NavigationCallback
,
(
void
*
)(
int
)
i_area_id
);
text
.
psz_string
=
malloc
(
strlen
(
_
(
"Title %i"
)
)
+
20
);
if
(
text
.
psz_string
)
sprintf
(
text
.
psz_string
,
_
(
"Title %i"
),
i_area_id
);
var_Change
(
p_input
,
"navigation"
,
VLC_VAR_ADDCHOICE
,
&
val
,
&
text
);
if
(
text
.
psz_string
)
free
(
text
.
psz_string
);
text2
.
psz_string
=
malloc
(
strlen
(
_
(
"Chapter %i"
)
)
+
20
);
for
(
i
=
1
;
i
<=
i_part_nb
;
i
++
)
{
val2
.
i_int
=
i
;
if
(
text2
.
psz_string
)
sprintf
(
text2
.
psz_string
,
_
(
"Chapter %i"
),
i
);
var_Change
(
p_input
,
val
.
psz_string
,
VLC_VAR_ADDCHOICE
,
&
val2
,
&
text2
);
}
if
(
text2
.
psz_string
)
free
(
text2
.
psz_string
);
free
(
val
.
psz_string
);
}
if
(
p_input
->
stream
.
i_area_nb
==
2
)
{
vlc_value_t
text
;
/* Add another bunch of navigation object variables */
var_Create
(
p_input
,
"next-title"
,
VLC_VAR_VOID
);
text
.
psz_string
=
_
(
"Next title"
);
var_Change
(
p_input
,
"next-title"
,
VLC_VAR_SETTEXT
,
&
text
,
NULL
);
var_Create
(
p_input
,
"prev-title"
,
VLC_VAR_VOID
);
text
.
psz_string
=
_
(
"Previous title"
);
var_Change
(
p_input
,
"prev-title"
,
VLC_VAR_SETTEXT
,
&
text
,
NULL
);
var_AddCallback
(
p_input
,
"next-title"
,
TitleCallback
,
NULL
);
var_AddCallback
(
p_input
,
"prev-title"
,
TitleCallback
,
NULL
);
var_Create
(
p_input
,
"next-chapter"
,
VLC_VAR_VOID
);
text
.
psz_string
=
_
(
"Next chapter"
);
var_Change
(
p_input
,
"next-chapter"
,
VLC_VAR_SETTEXT
,
&
text
,
NULL
);
var_Create
(
p_input
,
"prev-chapter"
,
VLC_VAR_VOID
);
text
.
psz_string
=
_
(
"Previous chapter"
);
var_Change
(
p_input
,
"prev-chapter"
,
VLC_VAR_SETTEXT
,
&
text
,
NULL
);
var_AddCallback
(
p_input
,
"next-chapter"
,
ChapterCallback
,
NULL
);
var_AddCallback
(
p_input
,
"prev-chapter"
,
ChapterCallback
,
NULL
);
}
return
p_area
;
}
/*****************************************************************************
* input_SetProgram: changes the current program
*****************************************************************************/
int
input_SetProgram
(
input_thread_t
*
p_input
,
pgrm_descriptor_t
*
p_new_prg
)
{
unsigned
int
i_es_index
;
int
i_required_audio_es
;
int
i_required_spu_es
;
int
i_audio_es
=
0
;
int
i_spu_es
=
0
;
vlc_value_t
val
;
if
(
p_input
->
stream
.
p_selected_program
)
{
for
(
i_es_index
=
1
;
/* 0 should be the PMT */
i_es_index
<
p_input
->
stream
.
p_selected_program
->
i_es_number
;
i_es_index
++
)
{
#define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
if
(
p_es
->
p_dec
)
/* if the ES was selected */
{
input_UnselectES
(
p_input
,
p_es
);
}
#undef p_es
}
}
/* Get the number of the required audio stream */
var_Get
(
p_input
,
"audio"
,
&
val
);
if
(
val
.
b_bool
)
{
/* Default is the first one */
var_Get
(
p_input
,
"audio-channel"
,
&
val
);
i_required_audio_es
=
val
.
i_int
;
if
(
i_required_audio_es
<
0
)
{
i_required_audio_es
=
1
;
}
}
else
{
i_required_audio_es
=
0
;
}
/* Same thing for subtitles */
var_Get
(
p_input
,
"video"
,
&
val
);
if
(
val
.
b_bool
)
{
/* for spu, default is none */
var_Get
(
p_input
,
"spu-channel"
,
&
val
);
i_required_spu_es
=
val
.
i_int
;
if
(
i_required_spu_es
<
0
)
{
i_required_spu_es
=
0
;
}
}
else
{
i_required_spu_es
=
0
;
}
for
(
i_es_index
=
0
;
i_es_index
<
p_new_prg
->
i_es_number
;
i_es_index
++
)
{
switch
(
p_new_prg
->
pp_es
[
i_es_index
]
->
i_cat
)
{
case
VIDEO_ES
:
msg_Dbg
(
p_input
,
"selecting video ES %x"
,
p_new_prg
->
pp_es
[
i_es_index
]
->
i_id
);
input_SelectES
(
p_input
,
p_new_prg
->
pp_es
[
i_es_index
]
);
break
;
case
AUDIO_ES
:
i_audio_es
+=
1
;
if
(
i_audio_es
<=
i_required_audio_es
)
{
msg_Dbg
(
p_input
,
"selecting audio ES %x"
,
p_new_prg
->
pp_es
[
i_es_index
]
->
i_id
);
input_SelectES
(
p_input
,
p_new_prg
->
pp_es
[
i_es_index
]);
}
break
;
/* Not sure this one is fully specification-compliant */
case
SPU_ES
:
i_spu_es
+=
1
;
if
(
i_spu_es
<=
i_required_spu_es
)
{
msg_Dbg
(
p_input
,
"selecting spu ES %x"
,
p_new_prg
->
pp_es
[
i_es_index
]
->
i_id
);
input_SelectES
(
p_input
,
p_new_prg
->
pp_es
[
i_es_index
]
);
}
break
;
default
:
msg_Dbg
(
p_input
,
"ES %x has unknown type"
,
p_new_prg
->
pp_es
[
i_es_index
]
->
i_id
);
break
;
}
}
p_input
->
stream
.
p_selected_program
=
p_new_prg
;
/* Update the navigation variables without triggering a callback */
val
.
i_int
=
p_new_prg
->
i_number
;
var_Change
(
p_input
,
"program"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
return
(
0
);
}
/*****************************************************************************
* input_DelArea: destroy a area descriptor
*****************************************************************************
* All ES descriptions referenced in the descriptor will be deleted.
*****************************************************************************/
void
input_DelArea
(
input_thread_t
*
p_input
,
input_area_t
*
p_area
)
{
unsigned
int
i_area_index
;
vlc_value_t
val
;
/* Find the area in the areas table */
for
(
i_area_index
=
0
;
i_area_index
<
p_input
->
stream
.
i_area_nb
;
i_area_index
++
)
{
if
(
p_input
->
stream
.
pp_areas
[
i_area_index
]
==
p_area
)
break
;
}
/* If the area wasn't found, do nothing */
if
(
i_area_index
==
p_input
->
stream
.
i_area_nb
)
{
msg_Err
(
p_input
,
"area does not belong to this input"
);
return
;
}
/* Take care of the navigation variables */
val
.
psz_string
=
malloc
(
sizeof
(
"title "
)
+
5
);
if
(
val
.
psz_string
)
{
sprintf
(
val
.
psz_string
,
"title %i"
,
p_area
->
i_id
);
var_Change
(
p_input
,
"navigation"
,
VLC_VAR_DELCHOICE
,
&
val
,
NULL
);
var_Destroy
(
p_input
,
val
.
psz_string
);
free
(
val
.
psz_string
);
}
/* Remove this area from the stream's list of areas */
REMOVE_ELEM
(
p_input
->
stream
.
pp_areas
,
p_input
->
stream
.
i_area_nb
,
i_area_index
);
/* Free the description of this area */
free
(
p_area
);
if
(
p_input
->
stream
.
i_area_nb
==
1
)
{
/* Del unneeded navigation object variables */
var_Destroy
(
p_input
,
"next-title"
);
var_Destroy
(
p_input
,
"prev-title"
);
var_Destroy
(
p_input
,
"next-chapter"
);
var_Destroy
(
p_input
,
"prev-chapter"
);
}
}
/****************************************************************************
* input_ChangeArea: interface request an area change (internal)
****************************************************************************/
static
int
input_ChangeArea
(
input_thread_t
*
p_input
,
input_area_t
*
p_area
)
{
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
p_input
->
stream
.
p_new_area
=
p_area
;
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
return
0
;
}
/*****************************************************************************
* input_FindES: returns a pointer to an ES described by its ID
*****************************************************************************/
es_descriptor_t
*
input_FindES
(
input_thread_t
*
p_input
,
uint16_t
i_es_id
)
{
unsigned
int
i
;
for
(
i
=
0
;
i
<
p_input
->
stream
.
i_es_number
;
i
++
)
{
if
(
p_input
->
stream
.
pp_es
[
i
]
->
i_id
==
i_es_id
)
{
return
p_input
->
stream
.
pp_es
[
i
];
}
}
return
NULL
;
}
/*****************************************************************************
* input_AddES:
*****************************************************************************
* Reserve a slot in the table of ES descriptors for the ES and add it to the
* list of ES of p_pgrm. If p_pgrm if NULL, then the ES is considered as stand
* alone (PSI ?)
*****************************************************************************/
es_descriptor_t
*
input_AddES
(
input_thread_t
*
p_input
,
pgrm_descriptor_t
*
p_pgrm
,
uint16_t
i_es_id
,
int
i_category
,
char
const
*
psz_desc
,
size_t
i_data_len
)
{
es_descriptor_t
*
p_es
;
vlc_value_t
val
,
text
;
char
*
psz_var
=
NULL
;
p_es
=
(
es_descriptor_t
*
)
malloc
(
sizeof
(
es_descriptor_t
)
);
if
(
p_es
==
NULL
)
{
msg_Err
(
p_input
,
"out of memory"
);
return
(
NULL
);
}
INSERT_ELEM
(
p_input
->
stream
.
pp_es
,
p_input
->
stream
.
i_es_number
,
p_input
->
stream
.
i_es_number
,
p_es
);
/* Init its values */
p_es
->
i_id
=
i_es_id
;
p_es
->
i_stream_id
=
0
;
p_es
->
p_pes
=
NULL
;
p_es
->
p_dec
=
NULL
;
p_es
->
i_cat
=
i_category
;
p_es
->
i_demux_fd
=
0
;
p_es
->
c_packets
=
0
;
p_es
->
c_invalid_packets
=
0
;
p_es
->
b_force_decoder
=
VLC_FALSE
;
es_format_Init
(
&
p_es
->
fmt
,
UNKNOWN_ES
,
0
);
p_es
->
fmt
.
b_packetized
=
VLC_FALSE
;
/* Only there for old mpeg demuxers */
if
(
i_data_len
)
{
p_es
->
p_demux_data
=
malloc
(
i_data_len
);
if
(
p_es
->
p_demux_data
==
NULL
)
{
msg_Err
(
p_input
,
"out of memory"
);
return
(
NULL
);
}
memset
(
p_es
->
p_demux_data
,
0
,
i_data_len
);
}
else
{
p_es
->
p_demux_data
=
NULL
;
}
p_es
->
p_waveformatex
=
NULL
;
p_es
->
p_bitmapinfoheader
=
NULL
;
p_es
->
p_spuinfo
=
NULL
;
/* Add this ES to the program definition if one is given */
if
(
p_pgrm
)
{
INSERT_ELEM
(
p_pgrm
->
pp_es
,
p_pgrm
->
i_es_number
,
p_pgrm
->
i_es_number
,
p_es
);
p_es
->
p_pgrm
=
p_pgrm
;
}
else
{
p_es
->
p_pgrm
=
NULL
;
}
switch
(
i_category
)
{
case
AUDIO_ES
:
psz_var
=
"audio-es"
;
break
;
case
SPU_ES
:
psz_var
=
"spu-es"
;
break
;
case
VIDEO_ES
:
psz_var
=
"video-es"
;
break
;
}
if
(
psz_var
)
{
/* Get the number of ES already added */
var_Change
(
p_input
,
psz_var
,
VLC_VAR_CHOICESCOUNT
,
&
val
,
NULL
);
if
(
val
.
i_int
==
0
)
{
vlc_value_t
val2
;
/* First one, we need to add the "Disable" choice */
val2
.
i_int
=
-
1
;
text
.
psz_string
=
_
(
"Disable"
);
var_Change
(
p_input
,
psz_var
,
VLC_VAR_ADDCHOICE
,
&
val2
,
&
text
);
val
.
i_int
++
;
}
/* Take care of the ES description */
if
(
psz_desc
&&
*
psz_desc
)
{
p_es
->
psz_desc
=
strdup
(
psz_desc
);
}
else
{
p_es
->
psz_desc
=
malloc
(
strlen
(
_
(
"Track %i"
)
)
+
20
);
if
(
p_es
->
psz_desc
)
sprintf
(
p_es
->
psz_desc
,
_
(
"Track %i"
),
val
.
i_int
);
}
val
.
i_int
=
p_es
->
i_id
;
text
.
psz_string
=
p_es
->
psz_desc
;
var_Change
(
p_input
,
psz_var
,
VLC_VAR_ADDCHOICE
,
&
val
,
&
text
);
}
else
p_es
->
psz_desc
=
NULL
;
return
p_es
;
}
/*****************************************************************************
* input_DelES:
*****************************************************************************/
void
input_DelES
(
input_thread_t
*
p_input
,
es_descriptor_t
*
p_es
)
{
unsigned
int
i_index
,
i_es_index
;
pgrm_descriptor_t
*
p_pgrm
;
char
*
psz_var
=
NULL
;
vlc_value_t
val
;
/* Find the ES in the ES table */
for
(
i_es_index
=
0
;
i_es_index
<
p_input
->
stream
.
i_es_number
;
i_es_index
++
)
{
if
(
p_input
->
stream
.
pp_es
[
i_es_index
]
==
p_es
)
break
;
}
/* If the ES wasn't found, do nothing */
if
(
i_es_index
==
p_input
->
stream
.
i_es_number
)
{
msg_Err
(
p_input
,
"ES does not belong to this input"
);
return
;
}
/* Remove es from its associated variable */
switch
(
p_es
->
i_cat
)
{
case
AUDIO_ES
:
psz_var
=
"audio-es"
;
break
;
case
SPU_ES
:
psz_var
=
"spu-es"
;
break
;
case
VIDEO_ES
:
psz_var
=
"video-es"
;
break
;
}
if
(
psz_var
)
{
val
.
i_int
=
p_es
->
i_id
;
var_Change
(
p_input
,
psz_var
,
VLC_VAR_DELCHOICE
,
&
val
,
NULL
);
/* Remove the "Disable" entry if needed */
var_Change
(
p_input
,
psz_var
,
VLC_VAR_CHOICESCOUNT
,
&
val
,
NULL
);
if
(
val
.
i_int
==
1
)
{
val
.
i_int
=
-
1
;
var_Change
(
p_input
,
psz_var
,
VLC_VAR_DELCHOICE
,
&
val
,
NULL
);
}
}
/* Kill associated decoder, if any. */
if
(
p_es
->
p_dec
!=
NULL
)
{
input_UnselectES
(
p_input
,
p_es
);
}
/* Remove this ES from the description of the program if it is associated
* to one */
p_pgrm
=
p_es
->
p_pgrm
;
if
(
p_pgrm
)
{
for
(
i_index
=
0
;
i_index
<
p_pgrm
->
i_es_number
;
i_index
++
)
{
if
(
p_pgrm
->
pp_es
[
i_index
]
==
p_es
)
{
REMOVE_ELEM
(
p_pgrm
->
pp_es
,
p_pgrm
->
i_es_number
,
i_index
);
break
;
}
}
}
/* Free the demux data */
if
(
p_es
->
p_demux_data
!=
NULL
)
{
free
(
p_es
->
p_demux_data
);
}
if
(
p_es
->
p_waveformatex
)
{
free
(
p_es
->
p_waveformatex
);
}
if
(
p_es
->
p_bitmapinfoheader
)
{
free
(
p_es
->
p_bitmapinfoheader
);
}
if
(
p_es
->
p_spuinfo
)
{
free
(
p_es
->
p_spuinfo
);
}
/* Free the description string */
if
(
p_es
->
psz_desc
!=
NULL
)
{
free
(
p_es
->
psz_desc
);
}
/* Clean the es format */
es_format_Clean
(
&
p_es
->
fmt
);
/* Find the ES in the ES table */
for
(
i_es_index
=
0
;
i_es_index
<
p_input
->
stream
.
i_es_number
;
i_es_index
++
)
{
if
(
p_input
->
stream
.
pp_es
[
i_es_index
]
==
p_es
)
break
;
}
/* Remove this ES from the stream's list of ES */
REMOVE_ELEM
(
p_input
->
stream
.
pp_es
,
p_input
->
stream
.
i_es_number
,
i_es_index
);
/* Free the ES */
free
(
p_es
);
}
/*****************************************************************************
* input_SelectES: selects an ES and spawns the associated decoder
*****************************************************************************
* Remember we are still supposed to have stream_lock when entering this
* function ?
*****************************************************************************/
int
input_SelectES
(
input_thread_t
*
p_input
,
es_descriptor_t
*
p_es
)
{
vlc_value_t
val
;
char
*
psz_var
=
NULL
;
if
(
p_es
==
NULL
)
{
msg_Err
(
p_input
,
"nothing to do in input_SelectES"
);
return
-
1
;
}
if
(
p_es
->
i_cat
==
VIDEO_ES
||
p_es
->
i_cat
==
SPU_ES
)
{
var_Get
(
p_input
,
"video"
,
&
val
);
if
(
val
.
b_bool
&&
p_input
->
stream
.
p_sout
)
{
var_Get
(
p_input
,
"sout-video"
,
&
val
);
}
if
(
!
val
.
b_bool
)
{
msg_Dbg
(
p_input
,
"video is disabled, not selecting ES 0x%x"
,
p_es
->
i_id
);
return
-
1
;
}
}
if
(
p_es
->
i_cat
==
AUDIO_ES
)
{
var_Get
(
p_input
,
"audio"
,
&
val
);
if
(
val
.
b_bool
&&
p_input
->
stream
.
p_sout
)
{
var_Get
(
p_input
,
"sout-audio"
,
&
val
);
}
if
(
!
val
.
b_bool
)
{
msg_Dbg
(
p_input
,
"audio is disabled, not selecting ES 0x%x"
,
p_es
->
i_id
);
return
-
1
;
}
}
msg_Dbg
(
p_input
,
"selecting ES 0x%x"
,
p_es
->
i_id
);
if
(
p_es
->
p_dec
!=
NULL
)
{
msg_Err
(
p_input
,
"ES 0x%x is already selected"
,
p_es
->
i_id
);
return
-
1
;
}
/* Release the lock, not to block the input thread during
* the creation of the thread. */
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
p_es
->
p_dec
=
input_RunDecoder
(
p_input
,
p_es
);
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
if
(
p_es
->
p_dec
==
NULL
)
{
return
-
1
;
}
/* Update the es variable without triggering a callback */
switch
(
p_es
->
i_cat
)
{
case
AUDIO_ES
:
psz_var
=
"audio-es"
;
break
;
case
SPU_ES
:
psz_var
=
"spu-es"
;
break
;
case
VIDEO_ES
:
psz_var
=
"video-es"
;
break
;
}
if
(
psz_var
)
{
val
.
i_int
=
p_es
->
i_id
;
var_Change
(
p_input
,
psz_var
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
}
return
0
;
}
/*****************************************************************************
* input_UnselectES: removes an ES from the list of selected ES
*****************************************************************************/
int
input_UnselectES
(
input_thread_t
*
p_input
,
es_descriptor_t
*
p_es
)
{
unsigned
int
i_index
=
0
;
vlc_value_t
val
;
char
*
psz_var
=
NULL
;
if
(
p_es
==
NULL
)
{
msg_Err
(
p_input
,
"nothing to do in input_UnselectES"
);
return
-
1
;
}
msg_Dbg
(
p_input
,
"unselecting ES 0x%x"
,
p_es
->
i_id
);
if
(
p_es
->
p_dec
==
NULL
)
{
msg_Err
(
p_input
,
"ES 0x%x is not selected"
,
p_es
->
i_id
);
return
(
-
1
);
}
/* Update the es variable without triggering a callback */
switch
(
p_es
->
i_cat
)
{
case
AUDIO_ES
:
psz_var
=
"audio-es"
;
break
;
case
SPU_ES
:
psz_var
=
"spu-es"
;
break
;
case
VIDEO_ES
:
psz_var
=
"video-es"
;
break
;
}
if
(
psz_var
)
{
val
.
i_int
=
-
1
;
var_Change
(
p_input
,
psz_var
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
}
/* FIXME: input_UnselectES() shouldn't actually be entered with the
* input lock, the locking should be done here and only where necessary. */
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
/* Actually unselect the ES */
input_EndDecoder
(
p_input
,
p_es
);
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
p_es
->
p_pes
=
NULL
;
if
(
(
p_es
->
p_dec
==
NULL
)
&&
(
p_input
->
stream
.
i_selected_es_number
>
0
)
)
{
while
(
(
i_index
<
p_input
->
stream
.
i_selected_es_number
-
1
)
&&
(
p_input
->
stream
.
pp_selected_es
[
i_index
]
!=
p_es
)
)
{
i_index
++
;
}
/* XXX: no need to memmove, we have unsorted data */
REMOVE_ELEM
(
p_input
->
stream
.
pp_selected_es
,
p_input
->
stream
.
i_selected_es_number
,
i_index
);
if
(
p_input
->
stream
.
i_selected_es_number
==
0
)
{
msg_Dbg
(
p_input
,
"no more selected ES"
);
return
1
;
}
}
return
0
;
}
/*****************************************************************************
* Navigation callback: a bunch of navigation variables are used as an
* alternative to the navigation API.
*****************************************************************************/
static
int
ProgramCallback
(
vlc_object_t
*
p_this
,
char
const
*
psz_cmd
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
p_data
)
{
input_thread_t
*
p_input
=
(
input_thread_t
*
)
p_this
;
vlc_value_t
val
;
if
(
oldval
.
i_int
==
newval
.
i_int
)
return
VLC_SUCCESS
;
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
if
(
(
newval
.
i_int
>
0
)
)
{
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
input_ChangeProgram
(
p_input
,
(
uint16_t
)
newval
.
i_int
);
var_SetInteger
(
p_input
,
"state"
,
PLAYING_S
);
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
}
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
val
.
b_bool
=
VLC_TRUE
;
var_Set
(
p_input
,
"intf-change"
,
val
);
return
VLC_SUCCESS
;
}
static
int
TitleCallback
(
vlc_object_t
*
p_this
,
char
const
*
psz_cmd
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
p_data
)
{
input_thread_t
*
p_input
=
(
input_thread_t
*
)
p_this
;
input_area_t
*
p_area
;
vlc_value_t
val
,
val_list
;
int
i
,
i_step
=
0
;
if
(
!
strcmp
(
psz_cmd
,
"next-title"
)
)
i_step
++
;
else
if
(
!
strcmp
(
psz_cmd
,
"prev-title"
)
)
i_step
--
;
if
(
!
i_step
&&
oldval
.
i_int
==
newval
.
i_int
)
return
VLC_SUCCESS
;
/* Sanity check should have already been done by var_Set(). */
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
if
(
i_step
)
{
var_Get
(
p_this
,
"title"
,
&
newval
);
var_Change
(
p_this
,
"title"
,
VLC_VAR_GETCHOICES
,
&
val_list
,
NULL
);
for
(
i
=
0
;
i
<
val_list
.
p_list
->
i_count
;
i
++
)
{
if
(
val_list
.
p_list
->
p_values
[
i
].
i_int
==
newval
.
i_int
&&
i
+
i_step
>=
0
&&
i
+
i_step
<
val_list
.
p_list
->
i_count
)
{
newval
.
i_int
=
val_list
.
p_list
->
p_values
[
i
+
i_step
].
i_int
;
break
;
}
}
var_Change
(
p_this
,
"title"
,
VLC_VAR_FREELIST
,
&
val_list
,
NULL
);
}
p_area
=
p_input
->
stream
.
pp_areas
[
newval
.
i_int
];
p_area
->
i_part
=
1
;
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
input_ChangeArea
(
p_input
,
p_area
);
var_SetInteger
(
p_input
,
"state"
,
PLAYING_S
);
val
.
b_bool
=
VLC_TRUE
;
var_Set
(
p_input
,
"intf-change"
,
val
);
return
VLC_SUCCESS
;
}
static
int
ChapterCallback
(
vlc_object_t
*
p_this
,
char
const
*
psz_cmd
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
p_data
)
{
input_thread_t
*
p_input
=
(
input_thread_t
*
)
p_this
;
input_area_t
*
p_area
;
vlc_value_t
val
,
val_list
;
int
i
,
i_step
=
0
;
if
(
!
strcmp
(
psz_cmd
,
"next-chapter"
)
)
i_step
++
;
else
if
(
!
strcmp
(
psz_cmd
,
"prev-chapter"
)
)
i_step
--
;
if
(
!
i_step
&&
oldval
.
i_int
==
newval
.
i_int
)
return
VLC_SUCCESS
;
/* Sanity check should have already been done by var_Set(). */
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
if
(
i_step
)
{
var_Get
(
p_this
,
"chapter"
,
&
newval
);
var_Change
(
p_this
,
"chapter"
,
VLC_VAR_GETCHOICES
,
&
val_list
,
NULL
);
for
(
i
=
0
;
i
<
val_list
.
p_list
->
i_count
;
i
++
)
{
if
(
val_list
.
p_list
->
p_values
[
i
].
i_int
==
newval
.
i_int
&&
i
+
i_step
>=
0
&&
i
+
i_step
<
val_list
.
p_list
->
i_count
)
{
newval
.
i_int
=
val_list
.
p_list
->
p_values
[
i
+
i_step
].
i_int
;
break
;
}
}
var_Change
(
p_this
,
"chapter"
,
VLC_VAR_FREELIST
,
&
val_list
,
NULL
);
}
p_area
=
p_input
->
stream
.
p_selected_area
;
p_input
->
stream
.
p_selected_area
->
i_part
=
newval
.
i_int
;
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
input_ChangeArea
(
p_input
,
p_area
);
var_SetInteger
(
p_input
,
"state"
,
PLAYING_S
);
val
.
b_bool
=
VLC_TRUE
;
var_Set
(
p_input
,
"intf-change"
,
val
);
return
VLC_SUCCESS
;
}
static
int
NavigationCallback
(
vlc_object_t
*
p_this
,
char
const
*
psz_cmd
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
p_data
)
{
input_thread_t
*
p_input
=
(
input_thread_t
*
)
p_this
;
uint16_t
i_area_id
=
(
int
)
p_data
;
vlc_value_t
val
;
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
if
(
p_input
->
stream
.
p_selected_area
->
i_id
==
i_area_id
&&
oldval
.
i_int
==
newval
.
i_int
)
{
/* Nothing to do */
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
return
VLC_SUCCESS
;
}
if
(
(
i_area_id
<
p_input
->
stream
.
i_area_nb
)
&&
(
newval
.
i_int
>
0
)
&&
(
(
uint16_t
)
newval
.
i_int
<=
p_input
->
stream
.
pp_areas
[
i_area_id
]
->
i_part_nb
)
)
{
input_area_t
*
p_area
=
p_input
->
stream
.
pp_areas
[
i_area_id
];
p_area
->
i_part
=
newval
.
i_int
;
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
input_ChangeArea
(
p_input
,
p_area
);
var_SetInteger
(
p_input
,
"state"
,
PLAYING_S
);
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
}
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
val
.
b_bool
=
VLC_TRUE
;
var_Set
(
p_input
,
"intf-change"
,
val
);
return
VLC_SUCCESS
;
}
static
int
ESCallback
(
vlc_object_t
*
p_this
,
char
const
*
psz_cmd
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
p_data
)
{
input_thread_t
*
p_input
=
(
input_thread_t
*
)
p_this
;
unsigned
int
i
;
vlc_value_t
val
;
unsigned
int
i_cat
=
UNKNOWN_ES
;
es_descriptor_t
*
p_es
=
NULL
;
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
/* First search old es type */
for
(
i
=
0
;
i
<
p_input
->
stream
.
i_es_number
;
i
++
)
{
if
(
p_input
->
stream
.
pp_es
[
i
]
->
i_id
==
oldval
.
i_int
)
{
i_cat
=
p_input
->
stream
.
pp_es
[
i
]
->
i_cat
;
}
}
/* Unselect all old ES */
for
(
i
=
0
;
i
<
p_input
->
stream
.
i_es_number
;
i
++
)
{
if
(
p_input
->
stream
.
pp_es
[
i
]
->
i_cat
==
i_cat
&&
p_input
->
stream
.
pp_es
[
i
]
->
i_id
!=
newval
.
i_int
&&
p_input
->
stream
.
pp_es
[
i
]
->
p_dec
!=
NULL
)
{
input_UnselectES
(
p_input
,
p_input
->
stream
.
pp_es
[
i
]
);
}
}
/* Select new ES */
for
(
i
=
0
;
i
<
p_input
->
stream
.
i_es_number
;
i
++
)
{
if
(
p_input
->
stream
.
pp_es
[
i
]
->
i_id
==
newval
.
i_int
)
{
p_es
=
p_input
->
stream
.
pp_es
[
i
];
if
(
p_es
->
p_dec
==
NULL
)
{
input_SelectES
(
p_input
,
p_es
);
}
}
}
if
(
p_es
)
{
/* Fix value (mainly for multiple selected ES */
val
.
i_int
=
p_es
->
i_id
;
switch
(
p_es
->
i_cat
)
{
case
AUDIO_ES
:
var_Change
(
p_input
,
"audio-es"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
break
;
case
SPU_ES
:
var_Change
(
p_input
,
"spu-es"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
break
;
case
VIDEO_ES
:
var_Change
(
p_input
,
"video-es"
,
VLC_VAR_SETVALUE
,
&
val
,
NULL
);
break
;
}
}
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
val
.
b_bool
=
VLC_TRUE
;
var_Set
(
p_input
,
"intf-change"
,
val
);
return
VLC_SUCCESS
;
}
src/input/stream.c
View file @
68d21786
...
@@ -25,576 +25,1138 @@
...
@@ -25,576 +25,1138 @@
#include <vlc/vlc.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#include <vlc/input.h>
#include "
ninput
.h"
#include "
input_internal
.h"
/****************************************************************************
/* TODO:
* stream_ReadLine:
* - tune the 2 methods
****************************************************************************/
* - compute cost for seek
/**
* - improve stream mode seeking with closest segments
* Read from the stream untill first newline.
* - ...
* \param s Stream handle to read from
* \return A null-terminated string. This must be freed,
*/
*/
/* FIXME don't use stupid MAX_LINE -> do the same than net_ReadLine */
#define MAX_LINE 1024
/* Two methods:
char
*
stream_ReadLine
(
stream_t
*
s
)
* - using pf_block
* One linked list of data read
* - using pf_read
* More complex scheme using mutliple track to avoid seeking
*/
/* How many track we have, currently only used for stream mode */
#define STREAM_CACHE_TRACK 3
/* Max size of our cache 4Mo per track */
#define STREAM_CACHE_SIZE (4*STREAM_CACHE_TRACK*1024*1024)
/* How many data we try to prebuffer */
#define STREAM_CACHE_PREBUFFER_SIZE (32767)
#define STREAM_CACHE_PREBUFFER_LENGTH (100*1000)
/* Maximum time we take to pre-buffer */
/* Method1: Simple, for pf_block.
* We get blocks and put them in the linked list.
* We release blocks once the total size is bigger than CACHE_BLOCK_SIZE
*/
#define STREAM_DATA_WAIT 40000
/* Time between before a pf_block retry */
/* Method2: A bit more complex, for pf_read
* - We use ring buffers, only one if unseekable, all if seekable
* - Upon seek date current ring, then search if one ring match the pos,
* yes: switch to it, seek the access to match the end of the ring
* no: search the ring with i_end the closer to i_pos,
* if close enough, read data and use this ring
* else use the oldest ring, seek and use it.
*
* TODO: - with access non seekable: use all space available for only one ring, but
* we have to support seekable/non-seekable switch on the fly.
* - compute a good value for i_read_size
* - ?
*/
#define STREAM_READ_ATONCE 32767
#define STREAM_CACHE_TRACK_SIZE (STREAM_CACHE_SIZE/STREAM_CACHE_TRACK)
typedef
struct
{
{
uint8_t
*
p_data
;
int64_t
i_date
;
char
*
p_line
;
int
i_data
;
int
i
=
0
;
i_data
=
stream_Peek
(
s
,
&
p_data
,
MAX_LINE
);
while
(
i
<
i_data
&&
p_data
[
i
]
!=
'\n'
&&
p_data
[
i
]
!=
'\r'
)
int64_t
i_start
;
int64_t
i_end
;
uint8_t
*
p_buffer
;
}
stream_track_t
;
struct
stream_sys_t
{
access_t
*
p_access
;
vlc_bool_t
b_block
;
/* Block method (1) or stream */
int64_t
i_pos
;
/* Current reading offset */
/* Method 1: pf_block */
struct
{
{
i
++
;
int64_t
i_start
;
/* Offset of block for p_first */
}
int
i_offset
;
/* Offset for data in p_current */
if
(
i_data
<=
0
)
block_t
*
p_current
;
/* Current block */
int
i_size
;
/* Total amount of data in the list */
block_t
*
p_first
;
block_t
**
pp_last
;
}
block
;
/* Method 2: for pf_read */
struct
{
{
return
NULL
;
int
i_offset
;
/* Buffer ofset in the current track */
}
int
i_tk
;
/* Current track */
else
stream_track_t
tk
[
STREAM_CACHE_TRACK
];
/* Global buffer */
uint8_t
*
p_buffer
;
/* */
int
i_used
;
/* Used since last read */
int
i_read_size
;
}
stream
;
/* Peek temporary buffer */
int
i_peek
;
uint8_t
*
p_peek
;
/* Stat for both method */
struct
{
{
p_line
=
malloc
(
i
+
1
);
vlc_bool_t
b_fastseek
;
/* From access */
if
(
p_line
==
NULL
)
{
msg_Err
(
s
,
"out of memory"
);
return
NULL
;
}
i
=
stream_Read
(
s
,
p_line
,
i
+
1
);
p_line
[
i
-
1
]
=
'\0'
;
return
p_line
;
/* Stat about reading data */
}
int64_t
i_read_count
;
}
int64_t
i_bytes
;
int64_t
i_read_time
;
/* Stat about seek */
int
i_seek_count
;
int64_t
i_seek_time
;
}
stat
;
};
/* Method 1: */
static
int
AStreamReadBlock
(
stream_t
*
,
void
*
p_read
,
int
i_read
);
static
int
AStreamPeekBlock
(
stream_t
*
,
uint8_t
**
p_peek
,
int
i_read
);
static
int
AStreamSeekBlock
(
stream_t
*
s
,
int64_t
i_pos
);
static
void
AStreamPrebufferBlock
(
stream_t
*
);
/* TODO: one day we should create a special module stream
/* Method 2 */
* when we would have a access wrapper, and stream filter
static
int
AStreamReadStream
(
stream_t
*
,
void
*
p_read
,
int
i_read
);
* (like caching, progessive, gunzip, ... )
static
int
AStreamPeekStream
(
stream_t
*
,
uint8_t
**
pp_peek
,
int
i_read
);
*/
static
int
AStreamSeekStream
(
stream_t
*
s
,
int64_t
i_pos
);
static
void
AStreamPrebufferStream
(
stream_t
*
);
/* private stream_sys_t for input_Stream* */
/* Common */
typedef
struct
static
int
AStreamControl
(
stream_t
*
,
int
i_query
,
va_list
);
{
input_thread_t
*
p_input
;
}
input_stream_sys_t
;
/* private pf_* functions declarations */
static
int
IStreamRead
(
stream_t
*
,
void
*
p_read
,
int
i_read
);
static
int
IStreamPeek
(
stream_t
*
,
uint8_t
**
pp_peek
,
int
i_peek
);
static
int
IStreamControl
(
stream_t
*
,
int
i_query
,
va_list
);
/****************************************************************************
/****************************************************************************
*
input_StreamNew: create a wrapper for p_input
access
*
stream_AccessNew: create a stream from a
access
****************************************************************************/
****************************************************************************/
stream_t
*
input_StreamNew
(
input_thread_t
*
p_input
)
stream_t
*
stream_AccessNew
(
access_t
*
p_access
)
{
{
stream_t
*
s
=
vlc_object_create
(
p_input
,
sizeof
(
stream_t
)
);
stream_t
*
s
=
vlc_object_create
(
p_access
,
VLC_OBJECT_STREAM
);
input_stream_sys_t
*
p_sys
;
stream_sys_t
*
p_sys
;
if
(
s
)
if
(
!
s
)
return
NULL
;
/* Attach it now, needed for b_die */
vlc_object_attach
(
s
,
p_access
);
s
->
pf_block
=
NULL
;
s
->
pf_read
=
NULL
;
/* Set up later */
s
->
pf_peek
=
NULL
;
s
->
pf_control
=
AStreamControl
;
s
->
p_sys
=
p_sys
=
malloc
(
sizeof
(
stream_sys_t
)
);
/* Common field */
p_sys
->
p_access
=
p_access
;
p_sys
->
b_block
=
p_access
->
pf_block
?
VLC_TRUE
:
VLC_FALSE
;
p_sys
->
i_pos
=
p_access
->
info
.
i_pos
;
/* Stats */
access2_Control
(
p_access
,
ACCESS_CAN_FASTSEEK
,
&
p_sys
->
stat
.
b_fastseek
);
p_sys
->
stat
.
i_bytes
=
0
;
p_sys
->
stat
.
i_read_time
=
0
;
p_sys
->
stat
.
i_read_count
=
0
;
p_sys
->
stat
.
i_seek_count
=
0
;
p_sys
->
stat
.
i_seek_time
=
0
;
/* Peek */
p_sys
->
i_peek
=
0
;
p_sys
->
p_peek
=
NULL
;
if
(
p_sys
->
b_block
)
{
s
->
pf_read
=
AStreamReadBlock
;
s
->
pf_peek
=
AStreamPeekBlock
;
/* Init all fields of p_sys->block */
p_sys
->
block
.
i_start
=
p_sys
->
i_pos
;
p_sys
->
block
.
i_offset
=
0
;
p_sys
->
block
.
p_current
=
NULL
;
p_sys
->
block
.
i_size
=
0
;
p_sys
->
block
.
p_first
=
NULL
;
p_sys
->
block
.
pp_last
=
&
p_sys
->
block
.
p_first
;
/* Do the prebuffering */
AStreamPrebufferBlock
(
s
);
if
(
p_sys
->
block
.
i_size
<=
0
)
{
msg_Err
(
s
,
"cannot pre fill buffer"
);
goto
error
;
}
}
else
{
{
s
->
pf_block
=
NULL
;
int
i
;
s
->
pf_read
=
IStreamRead
;
s
->
pf_peek
=
IStreamPeek
;
s
->
pf_read
=
AStreamReadStream
;
s
->
pf_control
=
IStreamControl
;
s
->
pf_peek
=
AStreamPeekStream
;
/* Allocate/Setup our tracks */
p_sys
->
stream
.
i_offset
=
0
;
p_sys
->
stream
.
i_tk
=
0
;
p_sys
->
stream
.
p_buffer
=
malloc
(
STREAM_CACHE_SIZE
);
p_sys
->
stream
.
i_used
=
0
;
access2_Control
(
p_access
,
ACCESS_GET_MTU
,
&
p_sys
->
stream
.
i_read_size
);
if
(
p_sys
->
stream
.
i_read_size
<=
0
)
p_sys
->
stream
.
i_read_size
=
STREAM_READ_ATONCE
;
else
if
(
p_sys
->
stream
.
i_read_size
<=
256
)
p_sys
->
stream
.
i_read_size
=
256
;
for
(
i
=
0
;
i
<
STREAM_CACHE_TRACK
;
i
++
)
{
p_sys
->
stream
.
tk
[
i
].
i_date
=
0
;
p_sys
->
stream
.
tk
[
i
].
i_start
=
p_sys
->
i_pos
;
p_sys
->
stream
.
tk
[
i
].
i_end
=
p_sys
->
i_pos
;
p_sys
->
stream
.
tk
[
i
].
p_buffer
=
&
p_sys
->
stream
.
p_buffer
[
i
*
STREAM_CACHE_TRACK_SIZE
];
}
/* Do the prebuffering */
AStreamPrebufferStream
(
s
);
s
->
p_sys
=
malloc
(
sizeof
(
input_stream_sys_t
)
);
if
(
p_sys
->
stream
.
tk
[
p_sys
->
stream
.
i_tk
].
i_end
<=
0
)
p_sys
=
(
input_stream_sys_t
*
)
s
->
p_sys
;
{
p_sys
->
p_input
=
p_input
;
msg_Err
(
s
,
"cannot pre fill buffer"
);
goto
error
;
}
}
}
return
s
;
return
s
;
error:
if
(
p_sys
->
b_block
)
{
/* Nothing yet */
}
else
{
free
(
p_sys
->
stream
.
p_buffer
);
}
free
(
s
->
p_sys
);
vlc_object_detach
(
s
);
vlc_object_destroy
(
s
);
return
NULL
;
}
}
/****************************************************************************
/****************************************************************************
*
input_Stream
Delete:
*
stream_Access
Delete:
****************************************************************************/
****************************************************************************/
void
input_Stream
Delete
(
stream_t
*
s
)
void
stream_Access
Delete
(
stream_t
*
s
)
{
{
stream_sys_t
*
p_sys
=
s
->
p_sys
;
vlc_object_detach
(
s
);
if
(
p_sys
->
b_block
)
{
block_ChainRelease
(
p_sys
->
block
.
p_first
);
}
else
{
free
(
p_sys
->
stream
.
p_buffer
);
}
if
(
p_sys
->
p_peek
)
free
(
p_sys
->
p_peek
);
free
(
s
->
p_sys
);
free
(
s
->
p_sys
);
vlc_object_destroy
(
s
);
vlc_object_destroy
(
s
);
}
}
/****************************************************************************
* stream_AccessReset:
****************************************************************************/
void
stream_AccessReset
(
stream_t
*
s
)
{
stream_sys_t
*
p_sys
=
s
->
p_sys
;
p_sys
->
i_pos
=
p_sys
->
p_access
->
info
.
i_pos
;
if
(
p_sys
->
b_block
)
{
block_ChainRelease
(
p_sys
->
block
.
p_first
);
/* Init all fields of p_sys->block */
p_sys
->
block
.
i_start
=
p_sys
->
i_pos
;
p_sys
->
block
.
i_offset
=
0
;
p_sys
->
block
.
p_current
=
NULL
;
p_sys
->
block
.
i_size
=
0
;
p_sys
->
block
.
p_first
=
NULL
;
p_sys
->
block
.
pp_last
=
&
p_sys
->
block
.
p_first
;
/* Do the prebuffering */
AStreamPrebufferBlock
(
s
);
}
else
{
int
i
;
/* Setup our tracks */
p_sys
->
stream
.
i_offset
=
0
;
p_sys
->
stream
.
i_tk
=
0
;
p_sys
->
stream
.
i_used
=
0
;
for
(
i
=
0
;
i
<
STREAM_CACHE_TRACK
;
i
++
)
{
p_sys
->
stream
.
tk
[
i
].
i_date
=
0
;
p_sys
->
stream
.
tk
[
i
].
i_start
=
p_sys
->
i_pos
;
p_sys
->
stream
.
tk
[
i
].
i_end
=
p_sys
->
i_pos
;
}
/* Do the prebuffering */
AStreamPrebufferStream
(
s
);
}
}
/****************************************************************************
/****************************************************************************
*
I
StreamControl:
*
A
StreamControl:
****************************************************************************/
****************************************************************************/
static
int
I
StreamControl
(
stream_t
*
s
,
int
i_query
,
va_list
args
)
static
int
A
StreamControl
(
stream_t
*
s
,
int
i_query
,
va_list
args
)
{
{
input_stream_sys_t
*
p_sys
=
(
input_stream_sys_t
*
)
s
->
p_sys
;
stream_sys_t
*
p_sys
=
s
->
p_sys
;
input_thread_t
*
p_input
=
p_sys
->
p_input
;
access_t
*
p_access
=
p_sys
->
p_access
;
vlc_bool_t
*
p_b
;
vlc_bool_t
*
p_b
ool
;
int64_t
*
p
_i64
,
i
64
;
int64_t
*
p
i_64
,
i_
64
;
int
*
p
_int
;
int
i
_int
;
switch
(
i_query
)
switch
(
i_query
)
{
{
case
STREAM_GET_SIZE
:
case
STREAM_GET_SIZE
:
p_i64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
pi_64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
*
pi_64
=
p_access
->
info
.
i_size
;
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
break
;
*
p_i64
=
p_input
->
stream
.
p_selected_area
->
i_size
;
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
return
VLC_SUCCESS
;
case
STREAM_CAN_SEEK
:
case
STREAM_CAN_SEEK
:
p_b
=
(
vlc_bool_t
*
)
va_arg
(
args
,
vlc_bool_t
*
);
p_bool
=
(
vlc_bool_t
*
)
va_arg
(
args
,
vlc_bool_t
*
);
access2_Control
(
p_access
,
ACCESS_CAN_SEEK
,
p_bool
);
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
break
;
*
p_b
=
p_input
->
stream
.
b_seekable
;
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
return
VLC_SUCCESS
;
case
STREAM_CAN_FASTSEEK
:
case
STREAM_CAN_FASTSEEK
:
p_b
=
(
vlc_bool_t
*
)
va_arg
(
args
,
vlc_bool_t
*
);
p_bool
=
(
vlc_bool_t
*
)
va_arg
(
args
,
vlc_bool_t
*
);
access2_Control
(
p_access
,
ACCESS_CAN_FASTSEEK
,
p_bool
);
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
break
;
*
p_b
=
p_input
->
stream
.
b_seekable
&&
p_input
->
stream
.
i_method
==
INPUT_METHOD_FILE
;
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
return
VLC_SUCCESS
;
case
STREAM_GET_POSITION
:
case
STREAM_GET_POSITION
:
p_i64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
pi_64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
*
pi_64
=
p_sys
->
i_pos
;
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
break
;
*
p_i64
=
p_input
->
stream
.
p_selected_area
->
i_tell
;
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
return
VLC_SUCCESS
;
case
STREAM_SET_POSITION
:
case
STREAM_SET_POSITION
:
{
i_64
=
(
int64_t
)
va_arg
(
args
,
int64_t
);
int64_t
i_skip
;
if
(
p_sys
->
b_block
)
i64
=
(
int64_t
)
va_arg
(
args
,
int64_t
);
return
AStreamSeekBlock
(
s
,
i_64
);
else
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
return
AStreamSeekStream
(
s
,
i_64
);
if
(
i64
<
0
||
(
p_input
->
stream
.
p_selected_area
->
i_size
>
0
&&
p_input
->
stream
.
p_selected_area
->
i_size
<
i64
)
)
{
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
msg_Warn
(
s
,
"seek out of bound"
);
return
VLC_EGENERIC
;
}
i_skip
=
i64
-
p_input
->
stream
.
p_selected_area
->
i_tell
;
if
(
i_skip
==
0
)
{
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
return
VLC_SUCCESS
;
}
if
(
i_skip
>
0
&&
i_skip
<
p_input
->
p_last_data
-
p_input
->
p_current_data
-
1
)
{
/* We can skip without reading/seeking */
p_input
->
p_current_data
+=
i_skip
;
p_input
->
stream
.
p_selected_area
->
i_tell
=
i64
;
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
return
VLC_SUCCESS
;
}
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
if
(
p_input
->
stream
.
b_seekable
&&
(
p_input
->
stream
.
i_method
==
INPUT_METHOD_FILE
||
i_skip
<
0
||
i_skip
>=
(
p_input
->
i_mtu
>
0
?
p_input
->
i_mtu
:
4096
)
)
)
{
input_AccessReinit
(
p_input
);
p_input
->
pf_seek
(
p_input
,
i64
);
return
VLC_SUCCESS
;
}
if
(
i_skip
>
0
)
{
data_packet_t
*
p_data
;
if
(
i_skip
>
1000
)
{
msg_Warn
(
s
,
"will skip "
I64Fd
" bytes, slow"
,
i_skip
);
}
while
(
i_skip
>
0
)
{
int
i_read
;
i_read
=
input_SplitBuffer
(
p_input
,
&
p_data
,
__MIN
(
(
int
)
p_input
->
i_bufsize
,
i_skip
)
);
if
(
i_read
<
0
)
{
return
VLC_EGENERIC
;
}
i_skip
-=
i_read
;
input_DeletePacket
(
p_input
->
p_method_data
,
p_data
);
if
(
i_read
==
0
&&
i_skip
>
0
)
{
return
VLC_EGENERIC
;
}
}
}
return
VLC_SUCCESS
;
}
case
STREAM_GET_MTU
:
case
STREAM_GET_MTU
:
p_int
=
(
int
*
)
va_arg
(
args
,
int
*
);
return
VLC_EGENERIC
;
*
p_int
=
p_input
->
i_mtu
;
return
VLC_SUCCESS
;
case
STREAM_CONTROL_ACCESS
:
case
STREAM_CONTROL_ACCESS
:
{
i_int
=
(
int
)
va_arg
(
args
,
int
);
int
i_int
=
(
int
)
va_arg
(
args
,
int
);
if
(
i_int
!=
ACCESS_SET_PRIVATE_ID_STATE
)
if
(
i_int
!=
ACCESS_SET_PRIVATE_ID_STATE
)
{
{
msg_Err
(
s
,
"Hey, what are you thinking ?"
msg_Err
(
s
,
"Hey, what are you thinking ?"
"DON'T USE STREAM_CONTROL_ACCESS !!!"
);
"DON'T USE STREAM_CONTROL_ACCESS !!!"
);
return
VLC_EGENERIC
;
return
VLC_EGENERIC
;
}
}
if
(
p_input
->
pf_access_control
)
return
access2_Control
(
p_access
,
i_int
,
args
);
{
return
p_input
->
pf_access_control
(
p_input
,
i_int
,
args
);
}
return
VLC_EGENERIC
;
}
default:
default:
msg_Err
(
s
,
"invalid stream_vaControl query=0x%x"
,
i_query
);
msg_Err
(
s
,
"invalid stream_vaControl query=0x%x"
,
i_query
);
return
VLC_EGENERIC
;
return
VLC_EGENERIC
;
}
}
return
VLC_SUCCESS
;
}
}
/****************************************************************************
/****************************************************************************
*
IStreamRead
:
*
Method 1
:
****************************************************************************/
****************************************************************************/
static
int
IStreamRead
(
stream_t
*
s
,
void
*
p_data
,
int
i_data
)
static
void
AStreamPrebufferBlock
(
stream_t
*
s
)
{
{
input_stream_sys_t
*
p_sys
=
(
input_stream_sys_t
*
)
s
->
p_sys
;
stream_sys_t
*
p_sys
=
s
->
p_sys
;
input_thread_t
*
p_input
=
p_sys
->
p_input
;
access_t
*
p_access
=
p_sys
->
p_access
;
uint8_t
*
p
=
(
uint8_t
*
)
p_data
;
int
i_read
=
0
;
int64_t
i_first
=
0
;
int64_t
i_start
;
if
(
p_data
==
NULL
&&
i_data
>
0
)
msg_Dbg
(
s
,
"pre buffering"
);
i_start
=
mdate
();
for
(
;;
)
{
{
int64_t
i_pos
;
int64_t
i_date
=
mdate
();
block_t
*
b
;
stream_Control
(
s
,
STREAM_GET_POSITION
,
&
i_pos
);
if
(
s
->
b_die
||
p_sys
->
block
.
i_size
>
STREAM_CACHE_PREBUFFER_SIZE
||
(
i_first
>
0
&&
i_first
+
STREAM_CACHE_PREBUFFER_LENGTH
<
i_date
)
)
{
int64_t
i_byterate
;
/* Update stat */
p_sys
->
stat
.
i_bytes
=
p_sys
->
block
.
i_size
;
p_sys
->
stat
.
i_read_time
=
i_date
-
i_start
;
i_byterate
=
(
I64C
(
1000000
)
*
p_sys
->
stat
.
i_bytes
)
/
(
p_sys
->
stat
.
i_read_time
+
1
);
msg_Dbg
(
s
,
"prebuffering done %lld bytes in %llds - %lld kbytes/s"
,
p_sys
->
stat
.
i_bytes
,
p_sys
->
stat
.
i_read_time
/
I64C
(
1000000
),
i_byterate
/
1024
);
break
;
}
i_pos
+=
i_data
;
/* Fetch a block */
if
(
stream_Control
(
s
,
STREAM_SET_POSITION
,
i_pos
)
)
if
(
(
b
=
p_access
->
pf_block
(
p_access
)
)
==
NULL
)
{
{
return
0
;
if
(
p_access
->
info
.
b_eof
)
break
;
msleep
(
STREAM_DATA_WAIT
);
continue
;
}
}
return
i_data
;
if
(
i_first
==
0
)
i_first
=
mdate
();
/* Append the block */
p_sys
->
block
.
i_size
+=
b
->
i_buffer
;
*
p_sys
->
block
.
pp_last
=
b
;
p_sys
->
block
.
pp_last
=
&
b
->
p_next
;
p_sys
->
stat
.
i_read_count
++
;
}
}
while
(
i_data
>
0
&&
!
p_input
->
b_die
)
p_sys
->
block
.
p_current
=
p_sys
->
block
.
p_first
;
}
static
int
AStreamRefillBlock
(
stream_t
*
s
);
static
int
AStreamReadBlock
(
stream_t
*
s
,
void
*
p_read
,
int
i_read
)
{
stream_sys_t
*
p_sys
=
s
->
p_sys
;
uint8_t
*
p_data
=
(
uint8_t
*
)
p_read
;
int
i_data
=
0
;
/* It means EOF */
if
(
p_sys
->
block
.
p_current
==
NULL
)
return
0
;
while
(
i_data
<
i_read
)
{
{
ssize_t
i_count
=
p_input
->
p_last_data
-
p_input
->
p_current_data
;
int
i_current
=
p_sys
->
block
.
p_current
->
i_buffer
-
p_sys
->
block
.
i_offset
;
int
i_copy
=
__MIN
(
i_current
,
i_read
-
i_data
);
if
(
i_count
<=
0
)
/* Copy data */
if
(
p_data
)
{
{
/* Go to the next buffer */
memcpy
(
p_data
,
&
p_sys
->
block
.
p_current
->
p_buffer
[
p_sys
->
block
.
i_offset
],
i_copy
);
i_count
=
input_FillBuffer
(
p_input
);
p_data
+=
i_copy
;
}
i_data
+=
i_copy
;
if
(
i_count
<
0
)
return
-
1
;
p_sys
->
block
.
i_offset
+=
i_copy
;
else
if
(
i_count
==
0
)
if
(
p_sys
->
block
.
i_offset
>=
p_sys
->
block
.
p_current
->
i_buffer
)
{
/* Current block is now empty, switch to next */
if
(
p_sys
->
block
.
p_current
)
{
p_sys
->
block
.
i_offset
=
0
;
p_sys
->
block
.
p_current
=
p_sys
->
block
.
p_current
->
p_next
;
}
/*Get a new block */
if
(
AStreamRefillBlock
(
s
)
)
{
{
/* We reached the EOF */
break
;
break
;
}
}
}
}
i_count
=
__MIN
(
i_data
,
i_count
);
memcpy
(
p
,
p_input
->
p_current_data
,
i_count
);
p_input
->
p_current_data
+=
i_count
;
p
+=
i_count
;
i_data
-=
i_count
;
i_read
+=
i_count
;
/* Update stream position */
vlc_mutex_lock
(
&
p_input
->
stream
.
stream_lock
);
p_input
->
stream
.
p_selected_area
->
i_tell
+=
i_count
;
vlc_mutex_unlock
(
&
p_input
->
stream
.
stream_lock
);
}
}
return
i_read
;
p_sys
->
i_pos
+=
i_data
;
return
i_data
;
}
}
/****************************************************************************
static
int
AStreamPeekBlock
(
stream_t
*
s
,
uint8_t
**
pp_peek
,
int
i_read
)
* IStreamPeek:
****************************************************************************/
static
int
IStreamPeek
(
stream_t
*
s
,
uint8_t
**
pp_peek
,
int
i_peek
)
{
{
input_stream_sys_t
*
p_sys
=
(
input_stream_sys_t
*
)
s
->
p_sys
;
stream_sys_t
*
p_sys
=
s
->
p_sys
;
return
input_Peek
(
p_sys
->
p_input
,
pp_peek
,
i_peek
);
uint8_t
*
p_data
;
int
i_data
=
0
;
block_t
*
b
;
int
i_offset
;
if
(
p_sys
->
block
.
p_current
==
NULL
)
return
0
;
/* EOF */
/* We can directly give a pointer over our buffer */
if
(
i_read
<=
p_sys
->
block
.
p_current
->
i_buffer
-
p_sys
->
block
.
i_offset
)
{
*
pp_peek
=
&
p_sys
->
block
.
p_current
->
p_buffer
[
p_sys
->
block
.
i_offset
];
return
i_read
;
}
/* We need to create a local copy */
if
(
p_sys
->
i_peek
<
i_read
)
{
if
(
p_sys
->
p_peek
)
free
(
p_sys
->
p_peek
);
p_sys
->
i_peek
=
i_read
;
p_sys
->
p_peek
=
malloc
(
p_sys
->
i_peek
);
}
/* Fill enough data */
while
(
p_sys
->
block
.
i_size
-
(
p_sys
->
i_pos
-
p_sys
->
block
.
i_start
)
<
i_read
)
{
block_t
**
pp_last
=
p_sys
->
block
.
pp_last
;
if
(
AStreamRefillBlock
(
s
)
)
break
;
/* Our buffer are probably filled enough, don't try anymore */
if
(
pp_last
==
p_sys
->
block
.
pp_last
)
break
;
}
/* Copy what we have */
b
=
p_sys
->
block
.
p_current
;
i_offset
=
p_sys
->
block
.
i_offset
;
p_data
=
p_sys
->
p_peek
;
while
(
b
&&
i_data
<
i_read
)
{
int
i_current
=
b
->
i_buffer
-
i_offset
;
int
i_copy
=
__MIN
(
i_current
,
i_read
-
i_data
);
memcpy
(
p_data
,
&
b
->
p_buffer
[
i_offset
],
i_copy
);
i_data
+=
i_copy
;
p_data
+=
i_copy
;
i_offset
+=
i_copy
;
if
(
i_offset
>=
b
->
i_buffer
)
{
i_offset
=
0
;
b
=
b
->
p_next
;
}
}
*
pp_peek
=
p_sys
->
p_peek
;
return
i_data
;
}
}
/****************************************************************************
static
int
AStreamSeekBlock
(
stream_t
*
s
,
int64_t
i_pos
)
* stream_Demux*: create a demuxer for an outpout stream (allow demuxer chain)
****************************************************************************/
typedef
struct
{
{
/* Data buffer */
stream_sys_t
*
p_sys
=
s
->
p_sys
;
vlc_mutex_t
lock
;
access_t
*
p_access
=
p_sys
->
p_access
;
int
i_buffer
;
int64_t
i_offset
=
i_pos
-
p_sys
->
block
.
i_start
;
int
i_buffer_size
;
vlc_bool_t
b_seek
;
uint8_t
*
p_buffer
;
int64_t
i_pos
;
/* We already have thoses data, just update p_current/i_offset */
if
(
i_offset
>=
0
&&
i_offset
<
p_sys
->
block
.
i_size
)
{
block_t
*
b
=
p_sys
->
block
.
p_first
;
int
i_current
=
0
;
/* Demuxer */
while
(
i_current
+
b
->
i_buffer
<
i_offset
)
char
*
psz_name
;
{
es_out_t
*
out
;
i_current
+=
b
->
i_buffer
;
demux_t
*
p_demux
;
b
=
b
->
p_next
;
}
d_stream_sys_t
;
}
static
int
DStreamRead
(
stream_t
*
,
void
*
p_read
,
int
i_read
);
p_sys
->
block
.
p_current
=
b
;
static
int
DStreamPeek
(
stream_t
*
,
uint8_t
**
pp_peek
,
int
i_peek
);
p_sys
->
block
.
i_offset
=
i_offset
-
i_current
;
static
int
DStreamControl
(
stream_t
*
,
int
i_query
,
va_list
);
static
int
DStreamThread
(
stream_t
*
);
p_sys
->
i_pos
=
i_pos
;
stream_t
*
__stream_DemuxNew
(
vlc_object_t
*
p_obj
,
char
*
psz_demux
,
es_out_t
*
out
)
return
VLC_SUCCESS
;
{
}
/* We create a stream reader, and launch a thread */
stream_t
*
s
;
d_stream_sys_t
*
p_sys
;
if
(
psz_demux
==
NULL
||
*
psz_demux
==
'\0'
)
/* We may need to seek or to read data */
if
(
i_offset
<
0
)
{
{
return
NULL
;
vlc_bool_t
b_aseek
;
access2_Control
(
p_access
,
ACCESS_CAN_SEEK
,
&
b_aseek
);
if
(
!
b_aseek
)
{
msg_Err
(
s
,
"backward seek impossible (access non seekable)"
);
return
VLC_EGENERIC
;
}
b_seek
=
VLC_TRUE
;
}
}
else
{
vlc_bool_t
b_aseek
,
b_aseekfast
;
s
=
vlc_object_create
(
p_obj
,
sizeof
(
stream_t
)
);
access2_Control
(
p_access
,
ACCESS_CAN_SEEK
,
&
b_aseek
);
s
->
pf_block
=
NULL
;
access2_Control
(
p_access
,
ACCESS_CAN_FASTSEEK
,
&
b_aseekfast
);
s
->
pf_read
=
DStreamRead
;
s
->
pf_peek
=
DStreamPeek
;
if
(
!
b_aseek
)
s
->
pf_control
=
DStreamControl
;
{
b_seek
=
VLC_FALSE
;
s
->
p_sys
=
malloc
(
sizeof
(
d_stream_sys_t
)
);
msg_Warn
(
s
,
"%lld bytes need to be skipped (access non seekable)"
,
p_sys
=
(
d_stream_sys_t
*
)
s
->
p_sys
;
i_offset
-
p_sys
->
block
.
i_size
);
}
vlc_mutex_init
(
s
,
&
p_sys
->
lock
);
else
p_sys
->
i_buffer
=
0
;
{
p_sys
->
i_buffer_size
=
1000000
;
int64_t
i_skip
=
i_offset
-
p_sys
->
block
.
i_size
;
p_sys
->
p_buffer
=
malloc
(
p_sys
->
i_buffer_size
);
p_sys
->
i_pos
=
0
;
/* Avg bytes per packets */
p_sys
->
psz_name
=
strdup
(
psz_demux
);
int
i_avg
=
p_sys
->
stat
.
i_bytes
/
p_sys
->
stat
.
i_read_count
;
p_sys
->
out
=
out
;
/* TODO compute a seek cost instead of fixed threshold */
p_sys
->
p_demux
=
NULL
;
int
i_th
=
b_aseekfast
?
1
:
5
;
if
(
vlc_thread_create
(
s
,
"stream out"
,
DStreamThread
,
VLC_THREAD_PRIORITY_INPUT
,
VLC_FALSE
)
)
if
(
i_skip
<=
i_th
*
i_avg
&&
{
i_skip
<
STREAM_CACHE_SIZE
)
vlc_mutex_destroy
(
&
p_sys
->
lock
);
b_seek
=
VLC_FALSE
;
vlc_object_destroy
(
s
);
else
free
(
p_sys
);
b_seek
=
VLC_TRUE
;
return
NULL
;
msg_Dbg
(
s
,
"b_seek=%d th*avg=%d skip=%lld"
,
b_seek
,
i_th
*
i_avg
,
i_skip
);
}
}
}
return
s
;
if
(
b_seek
)
}
{
int64_t
i_start
,
i_end
;
/* Do the access seek */
i_start
=
mdate
();
if
(
p_access
->
pf_seek
(
p_access
,
i_pos
)
)
return
VLC_EGENERIC
;
i_end
=
mdate
();
void
stream_DemuxSend
(
stream_t
*
s
,
block_t
*
p_block
)
/* Release data */
{
block_ChainRelease
(
p_sys
->
block
.
p_first
);
d_stream_sys_t
*
p_sys
=
(
d_stream_sys_t
*
)
s
->
p_sys
;
/* Reinit */
p_sys
->
block
.
i_start
=
p_sys
->
i_pos
=
i_pos
;
p_sys
->
block
.
i_offset
=
0
;
p_sys
->
block
.
p_current
=
NULL
;
p_sys
->
block
.
i_size
=
0
;
p_sys
->
block
.
p_first
=
NULL
;
p_sys
->
block
.
pp_last
=
&
p_sys
->
block
.
p_first
;
if
(
p_block
->
i_buffer
>
0
)
/* Refill a block */
if
(
AStreamRefillBlock
(
s
)
)
{
msg_Err
(
s
,
"cannot re fill buffer"
);
return
VLC_EGENERIC
;
}
/* Update stat */
p_sys
->
stat
.
i_seek_time
+=
i_end
-
i_start
;
p_sys
->
stat
.
i_seek_count
++
;
return
VLC_SUCCESS
;
}
else
{
{
vlc_mutex_lock
(
&
p_sys
->
lock
);
/* Read enought data */
/* Realloc if needed */
while
(
p_sys
->
block
.
i_start
+
p_sys
->
block
.
i_size
<
i_pos
)
if
(
p_sys
->
i_buffer
+
p_block
->
i_buffer
>
p_sys
->
i_buffer_size
)
{
{
if
(
p_sys
->
i_buffer_size
>
5000000
)
if
(
AStreamRefillBlock
(
s
)
)
{
msg_Err
(
s
,
"can't read enough data in seek"
);
return
VLC_EGENERIC
;
}
while
(
p_sys
->
block
.
p_current
&&
p_sys
->
i_pos
+
p_sys
->
block
.
p_current
->
i_buffer
<
i_pos
)
{
{
vlc_mutex_unlock
(
&
p_sys
->
lock
);
p_sys
->
i_pos
+=
p_sys
->
block
.
p_current
->
i_buffer
;
msg_Err
(
s
,
"stream_DemuxSend: buffer size > 5000000"
);
p_sys
->
block
.
p_current
=
p_sys
->
block
.
p_current
->
p_next
;
block_Release
(
p_block
);
return
;
}
}
/* I know, it's more than needed but that's perfect */
p_sys
->
i_buffer_size
+=
p_block
->
i_buffer
;
/* FIXME won't work with PEEK -> segfault */
p_sys
->
p_buffer
=
realloc
(
p_sys
->
p_buffer
,
p_sys
->
i_buffer_size
);
msg_Dbg
(
s
,
"stream_DemuxSend: realloc to %d"
,
p_sys
->
i_buffer_size
);
}
}
/* copy data */
p_sys
->
block
.
i_offset
=
i_pos
-
p_sys
->
i_pos
;
memcpy
(
&
p_sys
->
p_buffer
[
p_sys
->
i_buffer
],
p_block
->
p_buffer
,
p_block
->
i_buffer
);
p_sys
->
i_pos
=
i_pos
;
p_sys
->
i_buffer
+=
p_block
->
i_buffer
;
vlc_mutex_unlock
(
&
p_sys
->
lock
);
/* TODO read data */
return
VLC_SUCCESS
;
}
}
block_Release
(
p_block
)
;
return
VLC_EGENERIC
;
}
}
void
stream_DemuxDelete
(
stream_t
*
s
)
static
int
AStreamRefillBlock
(
stream_t
*
s
)
{
{
d_stream_sys_t
*
p_sys
=
(
d_stream_sys_t
*
)
s
->
p_sys
;
stream_sys_t
*
p_sys
=
s
->
p_sys
;
access_t
*
p_access
=
p_sys
->
p_access
;
int64_t
i_start
,
i_stop
;
block_t
*
b
;
/* Release data */
while
(
p_sys
->
block
.
i_size
>=
STREAM_CACHE_SIZE
&&
p_sys
->
block
.
p_first
!=
p_sys
->
block
.
p_current
)
{
block_t
*
b
=
p_sys
->
block
.
p_first
;
s
->
b_die
=
VLC_TRUE
;
p_sys
->
block
.
i_start
+=
b
->
i_buffer
;
p_sys
->
block
.
i_size
-=
b
->
i_buffer
;
p_sys
->
block
.
p_first
=
b
->
p_next
;
vlc_mutex_lock
(
&
p_sys
->
lock
);
block_Release
(
b
);
if
(
p_sys
->
p_demux
)
}
if
(
p_sys
->
block
.
i_size
>=
STREAM_CACHE_SIZE
&&
p_sys
->
block
.
p_current
==
p_sys
->
block
.
p_first
&&
p_sys
->
block
.
p_current
->
p_next
)
/* At least 2 packets */
{
{
p_sys
->
p_demux
->
b_die
=
VLC_TRUE
;
/* Enough data, don't read more */
return
VLC_SUCCESS
;
}
}
vlc_mutex_unlock
(
&
p_sys
->
lock
);
vlc_thread_join
(
s
);
if
(
p_sys
->
p_demux
)
/* Now read a new block */
i_start
=
mdate
();
for
(
;;
)
{
{
demux2_Delete
(
p_sys
->
p_demux
);
if
(
s
->
b_die
)
return
VLC_EGENERIC
;
/* Fetch a block */
if
(
(
b
=
p_access
->
pf_block
(
p_access
)
)
)
break
;
if
(
p_access
->
info
.
b_eof
)
return
VLC_EGENERIC
;
msleep
(
STREAM_DATA_WAIT
);
}
}
vlc_mutex_destroy
(
&
p_sys
->
lock
);
i_stop
=
mdate
();
free
(
p_sys
->
psz_name
);
free
(
p_sys
->
p_buffer
);
/* Append the block */
free
(
p_sys
);
p_sys
->
block
.
i_size
+=
b
->
i_buffer
;
vlc_object_destroy
(
s
);
*
p_sys
->
block
.
pp_last
=
b
;
p_sys
->
block
.
pp_last
=
&
b
->
p_next
;
/* Fix p_current */
if
(
p_sys
->
block
.
p_current
==
NULL
)
p_sys
->
block
.
p_current
=
b
;
/* Update stat */
p_sys
->
stat
.
i_bytes
+=
b
->
i_buffer
;
p_sys
->
stat
.
i_read_time
+=
i_stop
-
i_start
;
p_sys
->
stat
.
i_read_count
++
;
return
VLC_SUCCESS
;
}
}
static
int
DStreamRead
(
stream_t
*
s
,
void
*
p_read
,
int
i_read
)
/****************************************************************************
* Method 2:
****************************************************************************/
static
int
AStreamRefillStream
(
stream_t
*
s
);
static
int
AStreamReadStream
(
stream_t
*
s
,
void
*
p_read
,
int
i_read
)
{
{
d_stream_sys_t
*
p_sys
=
(
d_stream_sys_t
*
)
s
->
p_sys
;
stream_sys_t
*
p_sys
=
s
->
p_sys
;
int
i_copy
;
stream_track_t
*
tk
=
&
p_sys
->
stream
.
tk
[
p_sys
->
stream
.
i_tk
]
;
//msg_Dbg( s, "DStreamRead: wanted %d bytes", i_read );
uint8_t
*
p_data
=
(
uint8_t
*
)
p_read
;
for
(
;;
)
int
i_data
=
0
;
{
vlc_mutex_lock
(
&
p_sys
->
lock
);
//msg_Dbg( s, "DStreamRead: buffer %d", p_sys->i_buffer );
if
(
p_sys
->
i_buffer
>=
i_read
||
s
->
b_die
)
{
break
;
}
vlc_mutex_unlock
(
&
p_sys
->
lock
);
msleep
(
10000
);
}
//msg_Dbg( s, "DStreamRead: read %d buffer %d", i_read, p_sys->i_buffer );
if
(
tk
->
i_start
>=
tk
->
i_end
)
return
0
;
/* EOF */
i_copy
=
__MIN
(
i_read
,
p_sys
->
i_buffer
);
/*msg_Dbg( s, "AStreamReadStream: %d pos=%lld tk=%d start=%lld offset=%d end=%lld",
if
(
i_copy
>
0
)
i_read,
p_sys->i_pos,
p_sys->stream.i_tk,
tk->i_start, p_sys->stream.i_offset, tk->i_end );*/
while
(
i_data
<
i_read
)
{
{
if
(
p_read
)
int
i_off
=
(
tk
->
i_start
+
p_sys
->
stream
.
i_offset
)
%
STREAM_CACHE_TRACK_SIZE
;
int
i_current
=
__MIN
(
tk
->
i_end
-
tk
->
i_start
-
p_sys
->
stream
.
i_offset
,
STREAM_CACHE_TRACK_SIZE
-
i_off
);
int
i_copy
=
__MIN
(
i_current
,
i_read
-
i_data
);
/* Copy data */
//msg_Dbg( s, "AStreamReadStream: copy %d", i_copy );
if
(
p_data
)
{
{
memcpy
(
p_read
,
p_sys
->
p_buffer
,
i_copy
);
memcpy
(
p_data
,
&
tk
->
p_buffer
[
i_off
],
i_copy
);
p_data
+=
i_copy
;
}
}
p_sys
->
i_buffer
-=
i_copy
;
i_data
+=
i_copy
;
p_sys
->
stream
.
i_offset
+=
i_copy
;
/* Update pos now */
p_sys
->
i_pos
+=
i_copy
;
p_sys
->
i_pos
+=
i_copy
;
if
(
p_sys
->
i_buffer
>
0
)
/* */
p_sys
->
stream
.
i_used
+=
i_copy
;
if
(
tk
->
i_start
+
p_sys
->
stream
.
i_offset
>=
tk
->
i_end
||
p_sys
->
stream
.
i_used
>=
p_sys
->
stream
.
i_read_size
)
{
{
memmove
(
p_sys
->
p_buffer
,
&
p_sys
->
p_buffer
[
i_copy
],
p_sys
->
i_buffer
);
if
(
AStreamRefillStream
(
s
)
)
{
/* Eof */
if
(
tk
->
i_start
>=
tk
->
i_end
)
break
;
}
}
}
}
}
vlc_mutex_unlock
(
&
p_sys
->
lock
);
return
i_
copy
;
return
i_
data
;
}
}
static
int
DStreamPeek
(
stream_t
*
s
,
uint8_t
**
pp_peek
,
int
i_peek
)
static
int
AStreamPeekStream
(
stream_t
*
s
,
uint8_t
**
pp_peek
,
int
i_read
)
{
{
d_stream_sys_t
*
p_sys
=
(
d_stream_sys_t
*
)
s
->
p_sys
;
stream_sys_t
*
p_sys
=
s
->
p_sys
;
int
i_copy
;
stream_track_t
*
tk
=
&
p_sys
->
stream
.
tk
[
p_sys
->
stream
.
i_tk
];
int64_t
i_off
;
//msg_Dbg( s, "DStreamPeek: wanted %d bytes", i_peek );
if
(
tk
->
i_start
>=
tk
->
i_end
)
for
(
;;
)
return
0
;
/* EOF */
/*msg_Dbg( s, "AStreamPeekStream: %d pos=%lld tk=%d start=%lld offset=%d end=%lld",
i_read,
p_sys->i_pos,
p_sys->stream.i_tk,
tk->i_start, p_sys->stream.i_offset, tk->i_end );*/
/* Avoid problem, but that should *never* happen */
if
(
i_read
>
STREAM_CACHE_TRACK_SIZE
/
2
)
i_read
=
STREAM_CACHE_TRACK_SIZE
/
2
;
while
(
tk
->
i_end
-
tk
->
i_start
-
p_sys
->
stream
.
i_offset
<
i_read
)
{
{
vlc_mutex_lock
(
&
p_sys
->
lock
);
if
(
AStreamRefillStream
(
s
)
)
//msg_Dbg( s, "DStreamPeek: buffer %d", p_sys->i_buffer );
if
(
p_sys
->
i_buffer
>=
i_peek
||
s
->
b_die
)
{
break
;
break
;
}
vlc_mutex_unlock
(
&
p_sys
->
lock
);
msleep
(
10000
);
}
}
*
pp_peek
=
p_sys
->
p_buffer
;
i_copy
=
__MIN
(
i_peek
,
p_sys
->
i_buffer
);
vlc_mutex_unlock
(
&
p_sys
->
lock
);
if
(
tk
->
i_end
-
tk
->
i_start
-
p_sys
->
stream
.
i_offset
<
i_read
)
i_read
=
tk
->
i_end
-
tk
->
i_start
-
p_sys
->
stream
.
i_offset
;
return
i_copy
;
/* Now, direct pointer or a copy ? */
i_off
=
(
tk
->
i_start
+
p_sys
->
stream
.
i_offset
)
%
STREAM_CACHE_TRACK_SIZE
;
if
(
i_off
+
i_read
<=
STREAM_CACHE_TRACK_SIZE
)
{
*
pp_peek
=
&
tk
->
p_buffer
[
i_off
];
return
i_read
;
}
if
(
p_sys
->
i_peek
<
i_read
)
{
if
(
p_sys
->
p_peek
)
free
(
p_sys
->
p_peek
);
p_sys
->
i_peek
=
i_read
;
p_sys
->
p_peek
=
malloc
(
i_read
);
}
memcpy
(
p_sys
->
p_peek
,
&
tk
->
p_buffer
[
i_off
],
STREAM_CACHE_TRACK_SIZE
-
i_off
);
memcpy
(
&
p_sys
->
p_peek
[
STREAM_CACHE_TRACK_SIZE
-
i_off
],
&
tk
->
p_buffer
[
0
],
i_read
-
(
STREAM_CACHE_TRACK_SIZE
-
i_off
)
);
*
pp_peek
=
p_sys
->
p_peek
;
return
i_read
;
}
}
static
int
DStreamControl
(
stream_t
*
s
,
int
i_query
,
va_list
arg
s
)
static
int
AStreamSeekStream
(
stream_t
*
s
,
int64_t
i_po
s
)
{
{
d_stream_sys_t
*
p_sys
=
(
d_stream_sys_t
*
)
s
->
p_sys
;
stream_sys_t
*
p_sys
=
s
->
p_sys
;
int64_t
*
p_i64
;
access_t
*
p_access
=
p_sys
->
p_access
;
vlc_bool_t
*
p_b
;
vlc_bool_t
b_aseek
;
int
*
p_int
;
vlc_bool_t
b_afastseek
;
switch
(
i_query
)
int
i_maxth
;
int
i_new
;
int
i
;
/*
msg_Dbg( s, "AStreamSeekStream: to %lld pos=%lld tk=%d start=%lld offset=%d end=%lld",
i_pos,
p_sys->i_pos,
p_sys->stream.i_tk,
p_sys->stream.tk[p_sys->stream.i_tk].i_start, p_sys->stream.i_offset, p_sys->stream.tk[p_sys->stream.i_tk].i_end );*/
/* Seek in our current track ? */
if
(
i_pos
>=
p_sys
->
stream
.
tk
[
p_sys
->
stream
.
i_tk
].
i_start
&&
i_pos
<
p_sys
->
stream
.
tk
[
p_sys
->
stream
.
i_tk
].
i_end
)
{
{
case
STREAM_GET_SIZE
:
//msg_Dbg( s, "AStreamSeekStream: current track" );
p_i64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
p_sys
->
i_pos
=
i_pos
;
*
p_i64
=
0
;
p_sys
->
stream
.
i_offset
=
i_pos
-
p_sys
->
stream
.
tk
[
p_sys
->
stream
.
i_tk
].
i_start
;
return
VLC_SUCCESS
;
return
VLC_SUCCESS
;
}
case
STREAM_CAN_SEEK
:
access2_Control
(
p_access
,
ACCESS_CAN_SEEK
,
&
b_aseek
);
p_b
=
(
vlc_bool_t
*
)
va_arg
(
args
,
vlc_bool_t
*
);
if
(
!
b_aseek
)
*
p_b
=
VLC_FALSE
;
{
return
VLC_SUCCESS
;
/* We can't do nothing */
return
VLC_EGENERIC
;
}
case
STREAM_CAN_FASTSEEK
:
/* Date the current track */
p_b
=
(
vlc_bool_t
*
)
va_arg
(
args
,
vlc_bool_t
*
);
p_sys
->
stream
.
tk
[
p_sys
->
stream
.
i_tk
].
i_date
=
mdate
();
*
p_b
=
VLC_FALSE
;
return
VLC_SUCCESS
;
case
STREAM_GET_POSITION
:
/* Try to reuse already read data */
p_i64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
for
(
i
=
0
;
i
<
STREAM_CACHE_TRACK
;
i
++
)
*
p_i64
=
p_sys
->
i_pos
;
{
return
VLC_SUCCESS
;
stream_track_t
*
tk
=
&
p_sys
->
stream
.
tk
[
i
]
;
case
STREAM_SET_POSITION
:
if
(
i_pos
>=
tk
->
i_start
&&
i_pos
<=
tk
->
i_end
)
return
VLC_EGENERIC
;
{
/*msg_Dbg( s, "AStreamSeekStream: reusing %d start=%lld end=%lld",
i,
tk->i_start, tk->i_end );*/
/* Seek at the end of the buffer */
if
(
p_access
->
pf_seek
(
p_access
,
tk
->
i_end
)
)
return
VLC_EGENERIC
;
/* That's it */
p_sys
->
i_pos
=
i_pos
;
p_sys
->
stream
.
i_tk
=
i
;
p_sys
->
stream
.
i_offset
=
i_pos
-
tk
->
i_start
;
if
(
p_sys
->
stream
.
i_used
<
1024
)
p_sys
->
stream
.
i_used
=
1024
;
if
(
AStreamRefillStream
(
s
)
)
return
VLC_EGENERIC
;
case
STREAM_GET_MTU
:
p_int
=
(
int
*
)
va_arg
(
args
,
int
*
);
*
p_int
=
0
;
return
VLC_SUCCESS
;
return
VLC_SUCCESS
;
}
}
default:
access2_Control
(
p_access
,
ACCESS_CAN_SEEK
,
&
b_afastseek
);
msg_Err
(
s
,
"invalid DStreamControl query=0x%x"
,
i_query
);
/* FIXME compute seek cost (instead of static 'stupid' value) */
return
VLC_EGENERIC
;
i_maxth
=
__MIN
(
p_sys
->
stream
.
i_read_size
,
STREAM_READ_ATONCE
/
2
);
if
(
!
b_afastseek
)
i_maxth
*=
3
;
/* FIXME TODO */
#if 0
/* Search closest segment TODO */
for( i = 0; i < STREAM_CACHE_TRACK; i++ )
{
stream_track_t *tk = &p_sys->stream.tk[i];
if( i_pos + i_maxth >= tk->i_start )
{
msg_Dbg( s, "good segment before current pos, TODO" );
}
if( i_pos - i_maxth <= tk->i_end )
{
msg_Dbg( s, "good segment after current pos, TODO" );
}
}
}
#endif
/* Nothing good, seek and choose oldest segment */
if
(
p_access
->
pf_seek
(
p_access
,
i_pos
)
)
return
VLC_EGENERIC
;
p_sys
->
i_pos
=
i_pos
;
i_new
=
0
;
for
(
i
=
1
;
i
<
STREAM_CACHE_TRACK
;
i
++
)
{
if
(
p_sys
->
stream
.
tk
[
i
].
i_date
<
p_sys
->
stream
.
tk
[
i_new
].
i_date
)
i_new
=
i
;
}
/* Reset the segment */
p_sys
->
stream
.
i_tk
=
i_new
;
p_sys
->
stream
.
i_offset
=
0
;
p_sys
->
stream
.
tk
[
i_new
].
i_start
=
i_pos
;
p_sys
->
stream
.
tk
[
i_new
].
i_end
=
i_pos
;
/* Read data */
if
(
p_sys
->
stream
.
i_used
<
STREAM_READ_ATONCE
/
2
)
p_sys
->
stream
.
i_used
=
STREAM_READ_ATONCE
/
2
;
if
(
AStreamRefillStream
(
s
)
)
return
VLC_EGENERIC
;
return
VLC_SUCCESS
;
}
}
static
int
DStreamThread
(
stream_t
*
s
)
static
int
AStreamRefillStream
(
stream_t
*
s
)
{
{
d_stream_sys_t
*
p_sys
=
(
d_stream_sys_t
*
)
s
->
p_sys
;
stream_sys_t
*
p_sys
=
s
->
p_sys
;
demux_t
*
p_demux
;
access_t
*
p_access
=
p_sys
->
p_access
;
stream_track_t
*
tk
=
&
p_sys
->
stream
.
tk
[
p_sys
->
stream
.
i_tk
];
/* We read but won't increase i_start after initial start+offset */
int
i_toread
=
__MIN
(
p_sys
->
stream
.
i_used
,
STREAM_CACHE_TRACK_SIZE
-
(
tk
->
i_end
-
tk
->
i_start
-
p_sys
->
stream
.
i_offset
)
);
int64_t
i_start
,
i_stop
;
/
* Create the demuxer */
/
/msg_Dbg( s, "AStreamRefillStream: toread=%d", i_toread );
if
(
(
p_demux
=
demux2_New
(
s
,
""
,
p_sys
->
psz_name
,
""
,
s
,
p_sys
->
out
)
)
==
NULL
)
i_start
=
mdate
();
while
(
i_toread
>
0
)
{
{
return
VLC_EGENERIC
;
int
i_off
=
tk
->
i_end
%
STREAM_CACHE_TRACK_SIZE
;
int
i_read
;
if
(
s
->
b_die
)
return
VLC_EGENERIC
;
i_read
=
__MIN
(
i_toread
,
STREAM_CACHE_TRACK_SIZE
-
i_off
);
i_read
=
p_access
->
pf_read
(
p_access
,
&
tk
->
p_buffer
[
i_off
],
i_read
);
//msg_Dbg( s, "AStreamRefillStream: read=%d", i_read );
if
(
i_read
<
0
)
{
msleep
(
STREAM_DATA_WAIT
);
continue
;
}
else
if
(
i_read
==
0
)
{
return
VLC_EGENERIC
;
}
/* Update end */
tk
->
i_end
+=
i_read
;
/* Windows of STREAM_CACHE_TRACK_SIZE */
if
(
tk
->
i_end
-
tk
->
i_start
>
STREAM_CACHE_TRACK_SIZE
)
{
int
i_invalid
=
tk
->
i_end
-
tk
->
i_start
-
STREAM_CACHE_TRACK_SIZE
;
tk
->
i_start
+=
i_invalid
;
p_sys
->
stream
.
i_offset
-=
i_invalid
;
}
i_toread
-=
i_read
;
p_sys
->
stream
.
i_used
-=
i_read
;
p_sys
->
stat
.
i_bytes
+=
i_read
;
p_sys
->
stat
.
i_read_count
++
;
}
}
i_stop
=
mdate
();
p_sys
->
stat
.
i_read_time
+=
i_stop
-
i_start
;
return
VLC_SUCCESS
;
}
static
void
AStreamPrebufferStream
(
stream_t
*
s
)
{
stream_sys_t
*
p_sys
=
s
->
p_sys
;
access_t
*
p_access
=
p_sys
->
p_access
;
vlc_mutex_lock
(
&
p_sys
->
lock
);
int64_t
i_first
=
0
;
p_sys
->
p_demux
=
p_demux
;
int64_t
i_start
;
vlc_mutex_unlock
(
&
p_sys
->
lock
);
/* Main loop */
msg_Dbg
(
s
,
"pre buffering"
);
while
(
!
s
->
b_die
&&
!
p_demux
->
b_die
)
i_start
=
mdate
();
for
(
;;
)
{
{
if
(
p_demux
->
pf_demux
(
p_demux
)
<=
0
)
stream_track_t
*
tk
=
&
p_sys
->
stream
.
tk
[
p_sys
->
stream
.
i_tk
];
int64_t
i_date
=
mdate
();
int
i_read
;
if
(
s
->
b_die
||
tk
->
i_end
>=
STREAM_CACHE_PREBUFFER_SIZE
||
(
i_first
>
0
&&
i_first
+
STREAM_CACHE_PREBUFFER_LENGTH
<
i_date
)
)
{
{
int64_t
i_byterate
;
/* Update stat */
p_sys
->
stat
.
i_bytes
=
tk
->
i_end
-
tk
->
i_start
;
p_sys
->
stat
.
i_read_time
=
i_date
-
i_start
;
i_byterate
=
(
I64C
(
1000000
)
*
p_sys
->
stat
.
i_bytes
)
/
(
p_sys
->
stat
.
i_read_time
+
1
);
msg_Dbg
(
s
,
"prebuffering done %lld bytes in %llds - %lld kbytes/s"
,
p_sys
->
stat
.
i_bytes
,
p_sys
->
stat
.
i_read_time
/
I64C
(
1000000
),
i_byterate
/
1024
);
break
;
break
;
}
}
/* */
i_read
=
__MIN
(
p_sys
->
stream
.
i_read_size
,
STREAM_CACHE_TRACK_SIZE
-
tk
->
i_end
);
i_read
=
p_access
->
pf_read
(
p_access
,
&
tk
->
p_buffer
[
tk
->
i_end
],
i_read
);
if
(
i_read
<
0
)
{
msleep
(
STREAM_DATA_WAIT
);
continue
;
}
else
if
(
i_read
==
0
)
{
/* EOF */
break
;
}
if
(
i_first
==
0
)
i_first
=
mdate
();
tk
->
i_end
+=
i_read
;
p_sys
->
stat
.
i_read_count
++
;
}
}
p_demux
->
b_die
=
VLC_TRUE
;
return
VLC_SUCCESS
;
}
}
/****************************************************************************
* stream_ReadLine:
****************************************************************************/
/**
* Read from the stream untill first newline.
* \param s Stream handle to read from
* \return A null-terminated string. This must be freed,
*/
/* FIXME don't use stupid MAX_LINE -> do the same than net_ReadLine */
#define MAX_LINE 1024
char
*
stream_ReadLine
(
stream_t
*
s
)
{
uint8_t
*
p_data
;
char
*
p_line
;
int
i_data
;
int
i
=
0
;
i_data
=
stream_Peek
(
s
,
&
p_data
,
MAX_LINE
);
while
(
i
<
i_data
&&
p_data
[
i
]
!=
'\n'
&&
p_data
[
i
]
!=
'\r'
)
{
i
++
;
}
if
(
i_data
<=
0
)
{
return
NULL
;
}
else
{
p_line
=
malloc
(
i
+
1
);
if
(
p_line
==
NULL
)
{
msg_Err
(
s
,
"out of memory"
);
return
NULL
;
}
i
=
stream_Read
(
s
,
p_line
,
i
+
1
);
p_line
[
i
-
1
]
=
'\0'
;
return
p_line
;
}
}
src/input/subtitles.c
View file @
68d21786
...
@@ -31,8 +31,6 @@
...
@@ -31,8 +31,6 @@
#include <vlc/vlc.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#include <vlc/input.h>
#include "ninput.h"
#ifdef HAVE_DIRENT_H
#ifdef HAVE_DIRENT_H
# include <dirent.h>
# include <dirent.h>
#else
#else
...
...
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